#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
// I2C configuration
#define I2C_PORT i2c0
#define I2C0_SDA_PIN 4
#define I2C0_SCL_PIN 5
#define BAUD_RATE 400000
#define DS1307_ADDR 0x68
// DS1307 Register Addresses
#define DS1307_REG_SECONDS 0x00
#define DS1307_REG_MINUTES 0x01
#define DS1307_REG_HOURS 0x02
#define DS1307_REG_DAY 0x03
#define DS1307_REG_DATE 0x04
#define DS1307_REG_MONTH 0x05
#define DS1307_REG_YEAR 0x06
#define DS1307_REG_CONTROL 0x07
// Time format selection
typedef enum {
TIME_FORMAT_24H = 0,
TIME_FORMAT_12H = 1
} time_format_t;
// AM/PM indicator for 12-hour format
typedef enum {
TIME_AM = 0,
TIME_PM = 1
} time_period_t;
// Enhanced datetime structure with format support
typedef struct {
uint8_t seconds; // 0-59
uint8_t minutes; // 0-59
uint8_t hours; // 1-12 (12h) or 0-23 (24h)
uint8_t day; // 1-7 (1=Sunday)
uint8_t date; // 1-31
uint8_t month; // 1-12
uint8_t year; // 0-99 (2000-2099)
time_format_t format; // 12-hour or 24-hour
time_period_t period; // AM/PM (only valid for 12-hour format)
} ds1307_datetime_t;
// Global format preference (can be changed at runtime)
static time_format_t display_format = TIME_FORMAT_24H;
// ------------ Helper Functions --------------
// BCD to Decimal conversion
uint8_t bcd_to_dec(uint8_t val) {
return ((val >> 4) * 10) + (val & 0x0F);
}
// Decimal to BCD conversion
uint8_t dec_to_bcd(uint8_t val) {
return ((val / 10) << 4) | (val % 10);
}
// Convert 24-hour to 12-hour format
void convert_24h_to_12h(uint8_t hour_24, uint8_t *hour_12, time_period_t *period) {
if (hour_24 == 0) {
*hour_12 = 12; // Midnight
*period = TIME_AM;
} else if (hour_24 < 12) {
*hour_12 = hour_24;
*period = TIME_AM;
} else if (hour_24 == 12) {
*hour_12 = 12; // Noon
*period = TIME_PM;
} else {
*hour_12 = hour_24 - 12;
*period = TIME_PM;
}
}
// Convert 12-hour to 24-hour format
uint8_t convert_12h_to_24h(uint8_t hour_12, time_period_t period) {
if (period == TIME_AM) {
if (hour_12 == 12) {
return 0; // Midnight
}
return hour_12;
} else { // PM
if (hour_12 == 12) {
return 12; // Noon
}
return hour_12 + 12;
}
}
// ------------ I2C Helper Functions --------------
void ds1307_write_register(uint8_t reg, uint8_t value) {
uint8_t data[2] = {reg, value};
i2c_write_blocking(I2C_PORT, DS1307_ADDR, data, 2, false);
}
void ds1307_read_register(uint8_t reg, uint8_t *buf, uint8_t len) {
i2c_write_blocking(I2C_PORT, DS1307_ADDR, ®, 1, true);
i2c_read_blocking(I2C_PORT, DS1307_ADDR, buf, len, false);
}
// ------------ DS1307 Initialization ------------
void ds1307_init(void) {
uint8_t seconds;
ds1307_read_register(DS1307_REG_SECONDS, &seconds, 1);
// Enable oscillator if disabled
if (seconds & 0x80) {
ds1307_write_register(DS1307_REG_SECONDS, seconds & 0x7F);
}
// Disable square wave output
ds1307_write_register(DS1307_REG_CONTROL, 0x00);
}
// ------------ Set Date and Time ------------
void ds1307_set_datetime(const ds1307_datetime_t *dt) {
uint8_t hours_reg;
// Handle hours based on format
if (dt->format == TIME_FORMAT_12H) {
// Set bit 6 for 12-hour mode, bit 5 for PM
hours_reg = dec_to_bcd(dt->hours) & 0x1F; // Clear bit 6 and 5
hours_reg |= 0x40; // Set bit 6 for 12-hour mode
if (dt->period == TIME_PM) {
hours_reg |= 0x20; // Set bit 5 for PM
}
} else {
// 24-hour mode: bit 6 = 0
hours_reg = dec_to_bcd(dt->hours) & 0x3F; // Clear bit 6
}
ds1307_write_register(DS1307_REG_SECONDS, dec_to_bcd(dt->seconds) & 0x7F);
ds1307_write_register(DS1307_REG_MINUTES, dec_to_bcd(dt->minutes));
ds1307_write_register(DS1307_REG_HOURS, hours_reg);
ds1307_write_register(DS1307_REG_DAY, dec_to_bcd(dt->day));
ds1307_write_register(DS1307_REG_DATE, dec_to_bcd(dt->date));
ds1307_write_register(DS1307_REG_MONTH, dec_to_bcd(dt->month));
ds1307_write_register(DS1307_REG_YEAR, dec_to_bcd(dt->year));
}
// ------------ Read Current Date and Time ------------
void ds1307_get_datetime(ds1307_datetime_t *dt) {
uint8_t data[7];
ds1307_read_register(DS1307_REG_SECONDS, data, 7);
dt->seconds = bcd_to_dec(data[0] & 0x7F);
dt->minutes = bcd_to_dec(data[1] & 0x7F);
// Check if DS1307 is in 12-hour or 24-hour mode
if (data[2] & 0x40) {
// 12-hour mode
dt->format = TIME_FORMAT_12H;
dt->hours = bcd_to_dec(data[2] & 0x1F);
dt->period = (data[2] & 0x20) ? TIME_PM : TIME_AM;
} else {
// 24-hour mode
dt->format = TIME_FORMAT_24H;
dt->hours = bcd_to_dec(data[2] & 0x3F);
dt->period = TIME_AM; // Not applicable
}
dt->day = bcd_to_dec(data[3] & 0x07);
dt->date = bcd_to_dec(data[4] & 0x3F);
dt->month = bcd_to_dec(data[5] & 0x1F);
dt->year = bcd_to_dec(data[6]);
}
// ------------ Print Functions ------------
// Print in 24-hour format
void print_datetime_24h(const ds1307_datetime_t *dt) {
const char* days[] = {"", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
uint8_t hour_24;
if (dt->format == TIME_FORMAT_12H) {
// Convert 12h to 24h for display
hour_24 = convert_12h_to_24h(dt->hours, dt->period);
} else {
hour_24 = dt->hours;
}
printf("Day: %s, 20%02d-%02d-%02d Time: %02d:%02d:%02d (24h)\n",
days[dt->day],
dt->year, dt->month, dt->date,
hour_24, dt->minutes, dt->seconds);
}
// Print in 12-hour format
void print_datetime_12h(const ds1307_datetime_t *dt) {
const char* days[] = {"", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
uint8_t hour_12;
time_period_t period;
if (dt->format == TIME_FORMAT_12H) {
hour_12 = dt->hours;
period = dt->period;
} else {
// Convert 24h to 12h for display
convert_24h_to_12h(dt->hours, &hour_12, &period);
}
printf("Day: %s, 20%02d-%02d-%02d Time: %02d:%02d:%02d %s (12h)\n",
days[dt->day],
dt->year, dt->month, dt->date,
hour_12, dt->minutes, dt->seconds,
period == TIME_AM ? "AM" : "PM");
}
// Print in both formats
void print_datetime_both(const ds1307_datetime_t *dt) {
printf("┌─────────────────────────────────────────────┐\n");
printf("│ ");
const char* days[] = {"", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
printf("Date: %s, 20%02d-%02d-%02d", days[dt->day], dt->year, dt->month, dt->date);
printf(" │\n");
printf("├─────────────────────────────────────────────┤\n");
// 24-hour format
uint8_t hour_24 = (dt->format == TIME_FORMAT_12H)
? convert_12h_to_24h(dt->hours, dt->period)
: dt->hours;
printf("│ 24-hour: %02d:%02d:%02d", hour_24, dt->minutes, dt->seconds);
printf(" │\n");
// 12-hour format
uint8_t hour_12;
time_period_t period;
if (dt->format == TIME_FORMAT_12H) {
hour_12 = dt->hours;
period = dt->period;
} else {
convert_24h_to_12h(dt->hours, &hour_12, &period);
}
printf("│ 12-hour: %02d:%02d:%02d %s", hour_12, dt->minutes, dt->seconds,
period == TIME_AM ? "AM" : "PM");
printf(" │\n");
printf("└─────────────────────────────────────────────┘\n");
}
// Smart print based on current display format
void print_datetime(const ds1307_datetime_t *dt) {
if (display_format == TIME_FORMAT_24H) {
print_datetime_24h(dt);
} else {
print_datetime_12h(dt);
}
}
// ------------ Format Switching ------------
void set_display_format(time_format_t format) {
display_format = format;
}
// ------------ Main ------------
int main() {
stdio_init_all();
// Initialize I2C
i2c_init(I2C_PORT, BAUD_RATE);
gpio_set_function(I2C0_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(I2C0_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C0_SDA_PIN);
gpio_pull_up(I2C0_SCL_PIN);
sleep_ms(2000);
ds1307_init();
printf("DS1307 RTC Initialized\n\n");
// Example 1: Set time in 24-hour format
ds1307_datetime_t initial_time_24h = {
.seconds = 0,
.minutes = 30,
.hours = 17, // 5:30 PM in 24h
.day = 6, // Saturday
.date = 15,
.month = 11,
.year = 25,
.format = TIME_FORMAT_24H,
.period = TIME_AM // Not used in 24h format
};
// Example 2: Set time in 12-hour format
ds1307_datetime_t initial_time_12h = {
.seconds = 0,
.minutes = 30,
.hours = 5, // 5:30 PM in 12h
.day = 6,
.date = 15,
.month = 11,
.year = 25,
.format = TIME_FORMAT_12H,
.period = TIME_PM
};
// Choose which format to set
ds1307_set_datetime(&initial_time_12h); // Set in 12-hour format
printf("Time set in 12-hour format!\n\n");
ds1307_datetime_t current_time;
int count = 0;
printf("Press Enter to switch format (automatically switches every 10 seconds)\n\n");
while (1) {
ds1307_get_datetime(¤t_time);
// Display in both formats
print_datetime_both(¤t_time);
printf("\n");
// Alternate between formats every 10 seconds
count++;
if (count % 10 == 0) {
display_format = (display_format == TIME_FORMAT_24H)
? TIME_FORMAT_12H
: TIME_FORMAT_24H;
printf("\n>>> Switched to %s format <<<\n\n",
display_format == TIME_FORMAT_24H ? "24-hour" : "12-hour");
}
sleep_ms(1000);
}
return 0;
}