// RTC DS1307 I2C address
#define DS1307_ADDRESS 0x68
// Initialize ports for seven-segment display, switches, and buzzer
#define BUZZER_PIN 8
#define SWITCH_HOUR_PIN 2
#define SWITCH_MINUTE_PIN 3
#define SWITCH_ALARM_PIN 4
void init_ports() {
DDRF = 0xFF; // Set PORTF as output (for the segments)
DDRK = 0x1F; // Set lower 5 bits of PORTK as output (for digit select)
DDRD &= ~(1 << SWITCH_HOUR_PIN | 1 << SWITCH_MINUTE_PIN | 1 << SWITCH_ALARM_PIN); // Set switch pins as input
PORTD |= (1 << SWITCH_HOUR_PIN | 1 << SWITCH_MINUTE_PIN | 1 << SWITCH_ALARM_PIN); // Enable pull-up resistors
DDRB |= (1 << BUZZER_PIN); // Set buzzer pin as output
}
// Function to start I2C communication
void i2c_start() {
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
while (!(TWCR & (1 << TWINT))); // Wait for start to be transmitted
}
// Function to stop I2C communication
void i2c_stop() {
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
}
// Function to write a byte over I2C
void i2c_write(uint8_t data) {
TWDR = data;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT))); // Wait for the transmission to complete
}
// Function to read a byte from I2C (ack = 1 to acknowledge, ack = 0 for NACK)
uint8_t i2c_read(uint8_t ack) {
TWCR = (1 << TWINT) | (1 << TWEN) | (ack << TWEA);
while (!(TWCR & (1 << TWINT))); // Wait for the data to be received
return TWDR;
}
// Function to initialize RTC DS1307
void rtc_init() {
i2c_start();
i2c_write(DS1307_ADDRESS << 1); // Send address + write bit
i2c_write(0x00); // Start at register 0x00 (seconds)
i2c_write(0x00); // Write 0 to seconds to start the clock
i2c_stop();
}
// Function to read time from RTC DS1307
void rtc_get_time(uint8_t *hours, uint8_t *minutes) {
i2c_start();
i2c_write(DS1307_ADDRESS << 1); // Send address + write bit
i2c_write(0x00); // Start reading at register 0x00 (seconds)
i2c_start();
i2c_write((DS1307_ADDRESS << 1) | 1); // Send address + read bit
i2c_read(1); // Read seconds, but discard
*minutes = i2c_read(1); // Read minutes
*hours = i2c_read(0); // Read hours
i2c_stop();
}
// Convert BCD to decimal
uint8_t bcd_to_dec(uint8_t val) {
return ((val / 16 * 10) + (val % 16));
}
// Seven-segment display digit patterns for 0-9
long seven_segment[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
// Function to display a number on 4-digit seven-segment display
void display_time(uint8_t hours, uint8_t minutes) {
int digits[4] = {
seven_segment[hours / 10],
seven_segment[hours % 10],
seven_segment[minutes / 10],
seven_segment[minutes % 10]
};
int digit_select[4] = {0x1E, 0x1D, 0x1B, 0x17}; // Digit select for multiplexing
for (int i = 0; i < 4; i++) {
PORTF = digits[i]; // Output digit to seven-segment
PORTK = digit_select[i]; // Select corresponding digit
delay(5); // Short delay to allow multiplexing
PORTK = 0x1F; // Turn off all digits
}
}
void setup() {
init_ports(); // Initialize ports
rtc_init(); // Initialize RTC
Serial.begin(9600);
}
void loop() {
static uint8_t alarm_hours = 0;
static uint8_t alarm_minutes = 0;
static bool alarm_set = false;
uint8_t hours, minutes;
// Get the current time from the RTC
rtc_get_time(&hours, &minutes);
// Convert BCD to decimal
hours = bcd_to_dec(hours);
minutes = bcd_to_dec(minutes);
// Display time on the 4-digit seven-segment display
display_time(hours, minutes);
// Check for switch presses to set hours and minutes
if (!(PIND & (1 << SWITCH_HOUR_PIN))) { // If hour switch is pressed
alarm_hours = (alarm_hours + 1) % 24; // Increment hour
delay(200); // Debounce delay
}
if (!(PIND & (1 << SWITCH_MINUTE_PIN))) { // If minute switch is pressed
alarm_minutes = (alarm_minutes + 1) % 60; // Increment minute
delay(200); // Debounce delay
}
if (!(PIND & (1 << SWITCH_ALARM_PIN))) { // If alarm switch is pressed
alarm_set = true; // Set the alarm
delay(200); // Debounce delay
}
// Check if the alarm time matches the current time
if (alarm_set && hours == alarm_hours && minutes == alarm_minutes) {
PORTB |= (1 << BUZZER_PIN); // Turn on the buzzer
delay(1000); // Buzzer duration
PORTB &= ~(1 << BUZZER_PIN); // Turn off the buzzer
alarm_set = false; // Reset alarm state
}
delay(1000); // Update every second
}