外观
RTC DS1307 示例
2026-07-07
概述
本文介绍如何在 睿擎工业开发平台 中创建并运行 RTC DS1307 实时时钟 示例工程。通过驱动 DS1307 实时时钟芯片,演示了基于 RT-Thread I2C 驱动框架完成时间读取、时间设置、BCD 码转换、12/24 小时制自适应解析等 RTC 专属功能。
DS1307 RTC
DS1307 是一款低功耗、全 BCD 码时钟日历实时时钟芯片。它通过 I2C 接口提供秒、分、时、日、星期、月和年信息,并支持闰年补偿。芯片内部包含一个电池备份电路,在主电源掉电时可自动切换到备用电池供电,确保时钟持续稳定运行。
关键特性
- I2C 串行接口,从设备地址
0x68 - 内部振荡器可通过
CH(Clock Halt)位控制启停 - 支持 12 小时制(AM/PM)与 24 小时制两种时间格式
- 片上 56 字节非易失性 SRAM
- 备份电池自动切换,保证掉电走时
硬件连接
开发板的 I2C 与 RTC 硬件已经连接,RTC 芯片位置如图所示:

查手册获取 DS1307 的设备地址
根据 DS1307 数据手册可知:
- DS1307 的 I2C 从设备地址为固定的
0x68(7 位地址)

构建与烧录
创建工程点击展开
依次点击 “文件” -> “新建” -> "RT-Thread RuiChing App 项目"。

在弹出新建向导中选择 开发版 、BSP: 、示例 、 调试器/下载器。选择好之后点击 “完成”。

点击 “完成” 后,等待工程创建完成。

创建完成。

构建工程点击展开
单击工程使工程进入 Active-Debug 模式。

点击工具栏上的构建按钮进行工程编译。

构建成功后,会显示构建成功的信息。

固件下载点击展开
固化驱动

固化 APP

核心示例代码
- BCD 码与二进制互转
static rt_uint8_t bcd_to_bin(rt_uint8_t bcd)
{
return ((bcd >> 4) * 10) + (bcd & 0x0F);
}
static rt_uint8_t bin_to_bcd(rt_uint8_t bin)
{
return ((bin / 10) << 4) | (bin % 10);
}- I2C 寄存器写入
static rt_err_t ds1307_write_reg(rt_uint8_t reg, rt_uint8_t data)// ds1307 写寄存器
{
rt_uint8_t buf[2];
buf[0] = reg;
buf[1] = data;
struct rt_i2c_msg msg;
msg.addr = DS1307_I2C_ADDR;
msg.flags = RT_I2C_WR;
msg.buf = buf;
msg.len = 2;
if (rt_i2c_transfer(ds1307_i2c_bus, &msg, 1) == 1)
return RT_EOK;
return -RT_ERROR;
}- I2C 寄存器连续读取
static rt_err_t ds1307_read_regs(rt_uint8_t reg, rt_uint8_t *buf, rt_uint8_t len)// ds1307 读寄存器
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = DS1307_I2C_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = DS1307_I2C_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = buf;
msgs[1].len = len;
if (rt_i2c_transfer(ds1307_i2c_bus, msgs, 2) == 2)
return RT_EOK;
return -RT_ERROR;
}- 初始化与振荡器启动
rt_err_t ds1307_init(const char *i2c_bus_name)
{
rt_uint8_t sec_reg = 0;
ds1307_i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(i2c_bus_name);//寻找 i2c 设备
if (ds1307_i2c_bus == RT_NULL)
{
rt_kprintf("Can't find I2C bus: %s\n", i2c_bus_name);
return -RT_ERROR;
}
if (ds1307_read_regs(DS1307_REG_SEC, &sec_reg, 1) == RT_EOK)// ds1307 读寄存器
{
if (sec_reg & DS1307_CH_BIT)
{
rt_kprintf("DS1307 oscillator is halted! Enabling it now...\n");
ds1307_write_reg(DS1307_REG_SEC, sec_reg & ~DS1307_CH_BIT);
}
}
rt_kprintf("DS1307 RTC driver init success.\n");
return RT_EOK;
}- 时间读取
rt_err_t ds1307_get_time(struct ds1307_time *time)// ds1307 获取时间
{
rt_uint8_t rtc_buf[7];
if (ds1307_i2c_bus == RT_NULL) return -RT_ERROR;
if (ds1307_read_regs(DS1307_REG_SEC, rtc_buf, 7) != RT_EOK)// ds1307 读寄存器
{
return -RT_ERROR;
}
time->sec = bcd_to_bin(rtc_buf[0] & 0x7F);
time->min = bcd_to_bin(rtc_buf[1]);
if (rtc_buf[2] & DS1307_12_24_BIT)
{
rt_uint8_t hour = bcd_to_bin(rtc_buf[2] & 0x1F);
if (rtc_buf[2] & 0x20)
{
time->hour = (hour == 12) ? 12 : (hour + 12);
}
else
{
time->hour = (hour == 12) ? 0 : hour;
}
}
else
{
time->hour = bcd_to_bin(rtc_buf[2] & 0x3F);
}
time->week = bcd_to_bin(rtc_buf[3]);
time->day = bcd_to_bin(rtc_buf[4]);
time->month = bcd_to_bin(rtc_buf[5]);
time->year = bcd_to_bin(rtc_buf[6]) + 2000;
return RT_EOK;
}- 时间设置
rt_err_t ds1307_set_time(struct ds1307_time *time)// ds1307 设置时间
{
rt_uint8_t write_buf[8];
if (ds1307_i2c_bus == RT_NULL) return -RT_ERROR;
write_buf[0] = DS1307_REG_SEC;
write_buf[1] = bin_to_bcd(time->sec);
write_buf[2] = bin_to_bcd(time->min);
write_buf[3] = bin_to_bcd(time->hour);
write_buf[4] = bin_to_bcd(time->week);
write_buf[5] = bin_to_bcd(time->day);
write_buf[6] = bin_to_bcd(time->month);
write_buf[7] = bin_to_bcd(time->year - 2000);
struct rt_i2c_msg msg;
msg.addr = DS1307_I2C_ADDR;
msg.flags = RT_I2C_WR;
msg.buf = write_buf;
msg.len = 8;
if (rt_i2c_transfer(ds1307_i2c_bus, &msg, 1) == 1)
{
return RT_EOK;
}
return -RT_ERROR;
}- 示例代码
rtc_ds1307_example.c
static void rtc_ds1307_example(int argc, char **argv)
{
if (ds1307_init("i2c1") != RT_EOK)
{
rt_kprintf("DS1307 init failed.\n");
return;
}
if (argc > 1 && rt_strcmp(argv[1], "set") == 0)
{
if (argc < 9)
{
rt_kprintf("Usage: rtc_ds1307_example set <year> <mon> <day> <hour> <min> <sec> <week>\n");
return;
}
struct ds1307_time set_tm;
set_tm.year = (rt_uint16_t)atoi(argv[2]);
set_tm.month = (rt_uint8_t)atoi(argv[3]);
set_tm.day = (rt_uint8_t)atoi(argv[4]);
set_tm.hour = (rt_uint8_t)atoi(argv[5]);
set_tm.min = (rt_uint8_t)atoi(argv[6]);
set_tm.sec = (rt_uint8_t)atoi(argv[7]);
set_tm.week = (rt_uint8_t)atoi(argv[8]);
if (ds1307_set_time(&set_tm) == RT_EOK)
rt_kprintf("Set time success!\n");
else
rt_kprintf("Set time failed!\n");
}
else
{
struct ds1307_time get_tm;
if (ds1307_get_time(&get_tm) == RT_EOK)
{
rt_kprintf("DS1307 Time: %04d-%02d-%02d %02d:%02d:%02d Week:%d\n",
get_tm.year, get_tm.month, get_tm.day,
get_tm.hour, get_tm.min, get_tm.sec, get_tm.week);
}
else
{
rt_kprintf("Get time failed!\n");
}
}
}运行示例
操作步骤
- 将程序下载到开发板
- 打开串口终端连接开发板
- 系统在启动后
main函数会自动调用rtc_ds1307_example读取当前时间 - 也可在终端输入
rtc_ds1307_example命令读取时间 - 输入
rtc_ds1307_example set 2026 7 7 12 0 0 2设置时间为 2026-07-07 12:00:00 星期二
预期结果
RT-Thread 终端
msh />DS1307 oscillator is halted! Enabling it now...
DS1307 RTC driver init success.
DS1307 Time: 2000-01-01 00:00:00 Week:1
msh />rtc_ds1307_example
DS1307 RTC driver init success.
DS1307 Time: 2000-01-01 00:00:32 Week:1
msh />rtc_ds1307_example set 2026 7 7 12 0 0 2
DS1307 RTC driver init success.
Set time success!
msh />rtc_ds1307_example
DS1307 RTC driver init success.
DS1307 Time: 2026-07-07 12:00:05 Week:2