恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

STM32外挂DS1302实时时钟驱动实战与调试解析

  • 首页
  • 资讯中心
  • /
  • STM32外挂DS1302实时时钟驱动实战与调试解析

相关资讯

基于Django与协同过滤的电影推荐系统实践 2026/10/14 16:44:11
HASP加密狗驱动安装与V2C授权导入全指南 2026/10/14 16:44:10
不会还有人既当运动员又当裁判吧?审核门禁必须分角色 | 主 Agent 与审核 2026/10/14 16:44:10

最新资讯

STM32三路超声波跟随小车:从测距到测方位的完整实现与避坑指南
屏幕直接数字化书籍!NDLOCR-Lite 屏幕捕获 OCR 功能完整教程
朱雀查AI率100%总是被退稿?盘点3款超好用的朱雀降AI工具
从CPU到App:一套教学框架让你亲手写透计算机系统
Spring 4.0.3整合Redis:spring-data-redis与Jedis配置实战
少儿信息学复赛试题拆解:从模拟到动态规划的竞赛避坑指南

今日推荐

IBM Verify Identity Access 修复 22 个漏洞:两个 9.8 严重 RCE 无需认证
小区物业管理系统
小型超市仓库管理系统

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

STM32外挂DS1302实时时钟驱动实战与调试解析

发布时间:2026/10/14 16:44:11
STM32外挂DS1302实时时钟驱动实战与调试解析 1. 从够用到好用为什么我最后选择给 STM32 外挂一颗 DS1302做第一版带时间显示的小项目时我用的是 STM32 内置的 RTC。当时想得很简单芯片手册上写着有 RTC 功能那不就是直接能用吗。结果真调起来才发现内置 RTC 牵扯到备份域电源、低速外部晶振 LSE、以及一堆 RCC 和备份寄存器配置流程稍微错一步时间就停在那儿不动了。后来换用外置的 DS1302 实时时钟芯片三根 IO 线一接寄存器一写时间就跑起来了整个学习曲线平坦得多。这篇文章就把我在 STM32 上写 DS1302 驱动的完整过程做个记录包括硬件接线、三线协议拆解、驱动代码、以及我实际调试时踩过的几个坑。适合刚接触 STM32、没专门玩过外部 RTC 芯片的朋友也适合想把手头项目的时间模块换成独立方案的人随手参考。1.1 内置 RTC 的几个软肋不是说内置 RTC 不能用而是使用前提比较多。首先要给 VBAT 引脚接一个备份电源否则主电源掉电后时间全丢其次时钟源推荐用 32.768kHz 的 LSE但 LSE 在某些板子上起振很慢甚至需要额外配置才能稳定工作。更关键的是备份域寄存器一般有访问保护需要先操作相关电源管理寄存器解锁这个步骤一旦漏掉写进去的时间会被莫名其妙地重置。如果你只是做一个功能相对单一的小工具不想把系统时钟树和备份域的细节全部吃透外挂一颗 RTC 芯片反而是更省心的路径。1.2 DS1302 能解决什么问题DS1302 是一颗非常经典的实时时钟芯片内部自带秒、分、时、日、月、周、年的计数电路还有闰年补偿电一供上就开始走秒。它通过一个三线串行接口与主机通信占用的 MCU 资源极少一颗 32.768kHz 晶振再加一颗纽扣电池就能长期工作。另外它还带了 31 字节的掉电不丢失 RAM可以顺手存配置参数、开机次数这类小数据。对于需要一个稳定、独立、不依赖主控内部电源域的时间源的项目来说这个方案便宜、可靠、资料也多。我最后就是看中它独立供电、三线通信、寄存器直观这三个特点才把它写进学习笔记里的。2. 硬件接线和电源设计三个引脚怎么接才不会翻车2.1 DS1302 引脚功能速览写代码之前先得把硬件说清楚。DS1302 常见是 8 脚封装引脚分配如下。引脚名称方向说明1VCC2电源输入主电源接 3.3V2X1晶振输入接 32.768kHz 晶振一脚3X2晶振输出接 32.768kHz 晶振另一脚4GND地与 STM32 共地5CE输入芯片使能高电平有效6SCLK输入串行时钟7I/O双向数据线8VCC1备份电源接纽扣电池正极我习惯用 PB12、PB13、PB14 三根引脚来驱动接线关系是固定的CE 接 PB12SCLK 接 PB13I/O 接 PB14。选这三个引脚没有特殊原因纯粹是它们在标准板卡上位置顺、不容易和常用外设冲突。你完全可以根据自己的板子改后面代码里引脚宏是单独定义的挪位置只改一个头文件就行。2.2 晶振和负载电容DS1302 的时基来自外接的 32.768kHz 晶振。晶振两端各接一个 6pF 左右的负载电容电容的另一端接地。这里有一个焊接和布线细节晶振要尽量贴近芯片引脚走线越短越好否则晶振容易停振或者时间误差变大。我第一次搭板子时图省事把晶振飞线拉得很长结果秒针时快时慢后来把晶振挪到芯片旁边才恢复正常。如果你用的是带晶振的模块这一步就不用操心模块上已经处理好了。2.3 VCC1 和 VCC2 的关系DS1302 的电源设计有点意思它有两个电源引脚。VCC2 是主电源正常情况下由 STM32 板子的 3.3V 供电VCC1 是备份电源接纽扣电池正极。当 VCC2 掉电后芯片会自动切换到 VCC1 继续走时这就是系统断电后时间还能保持的原因。有一个很多人容易忽略的点VCC1 不能悬空。官方数据手册明确要求 VCC1 必须接一个电压如果你不打算接电池最省事的做法是把 VCC1 和 VCC2 直接连到一起。我曾经见过有人把 VCC1 丢空结果芯片上电后读出的时间完全是乱的接上 VCC1 就正常了。2.4 涓流充电要不要用用多大电阻DS1302 支持对备用电池涓流充电相关配置在涓流充电寄存器写地址 0x90里。我个人的建议是能不用就不用默认写 0x00 关闭充电功能。原因很简单给纽扣电池充电需要严格限制电流配置错了轻则缩短电池寿命重则发热甚至漏液。如果你的主电源长期在线、电池只是断电时的后备不充电也能用很久。如果确实需要充电常见的配置值是 0xA7表示一个二极管 8KΩ 限流电阻充电电流大致估算为 (3.3V - 0.7V) / 8KΩ约 0.3mA属于比较保守的安全范围。需要说明的是不同电池的允许充电电流不一样这里只是给出一个相对稳妥的起步值量产环境还是得根据电池规格重新算。3. DS1302 三线协议拆解命令字节、时序边沿和为什么不用 SPI3.1 命令字节的组成DS1302 每次访问寄存器通信的第一个字节必须是命令字节。命令字节的结构很固定bit7 恒为 1bit6 到 bit1 是寄存器地址bit0 是方向位1 表示读0 表示写。所有数据包括命令字节本身都是先传输最低位也就是 LSB first。bit7bit6bit5bit4bit3bit2bit1bit01A5A4A3A2A1A0R/W举个例子读秒寄存器的命令字节就是 0x81二进制是 1000 0001最高位固定为 1地址是秒寄存器的 0x00最低位是读方向 1。写秒寄存器则用 0x80。理解了这一条后面的寄存器表就能直接看懂。3.2 寄存器地址表DS1302 的时间寄存器和一些特殊寄存器地址如下。功能写地址读地址说明秒0x800x81bit7 是 CH1 表示时钟停止分钟0x820x83BCD 码小时0x840x85bit7 是 12/24 小时制标志日期0x860x871 到 31月份0x880x891 到 12星期0x8A0x8B1 到 7年份0x8C0x8D00 到 99控制0x8E0x8Fbit7 是 WP 写保护涓流充电0x900x91充电配置时钟突发0xBE0xBF一次性读写 8 字节这里有几个特殊位一定要心里有数。秒寄存器的 bit7 是时钟暂停位新芯片上电后这一位可能是 1时钟因此不走必须写 0 才能启动。小时寄存器的 bit7 是 12/24 小时制选择1 表示 12 小时制0 表示 24 小时制很多驱动异常都出在这一位。控制寄存器的 bit7 是写保护默认是 1写任何时间寄存器之前都要先清零。3.3 读写时序的关键边沿DS1302 的通信以 CE 拉高为开始CE 拉低为结束。在 CE 高电平期间SCLK 负责节奏I/O 负责传数据。写入和读取的边沿规则不一样这是整个驱动最容易出错的地方。写入时主机在 SCLK 为低电平时先把 I/O 上的数据设置好然后拉高 SCLK 产生上升沿芯片在上升沿锁存数据。也就是说写入数据是在上升沿生效的。读取时则反过来芯片在 SCLK 的下降沿把数据放到 I/O 线上数据在下降沿之后保持稳定主机可以在电平稳定后再采样。我封装读字节函数时采用的就是先采样当前位再用下降沿把下一位顶出来的思路。第一次写驱动的人经常把两个边沿搞反结果读回来要么全 0要么隔一位错一位。写代码之前先把这两条规则刻在脑子里后面会省很多事。3.4 为什么坚持用 GPIO 模拟而不是 SPI 外设看到三线协议第一反应可能是这不就是 SPI 吗用 SPI 外设不就行了。我试过结论是能整但没啥必要。DS1302 的协议和标准 SPI 有几点不一样所有数据都是 LSB 先出标准 SPI 默认为 MSB 先出时钟极性和相位需要专门配置成特殊组合而且它是半双工总线命令字节完成后同一根线要从输出切换成输入。用 SPI 外设硬做配置项多、方向切换容易出问题调试成本反而更高。用 GPIO 位操作模拟三根线的电平变化完全可控逻辑一目了然换平台也只需要改三个引脚的宏定义。所以我最终选择的就是位带方式驱动。4. STM32 驱动代码实战从 GPIO 配置到读写时间4.1 引脚映射和 GPIO 初始化我用的开发环境是 STM32CubeIDE 加 HAL 库主控型号以常见的 F103 系列为例。引脚映射单独放在头文件里方便以后换引脚。// ds1302.h #ifndef DS1302_H #define DS1302_H #include main.h // 引脚映射换板子只改这里 #define DS1302_GPIO_PORT GPIOB #define DS1302_CE_PIN GPIO_PIN_12 #define DS1302_SCLK_PIN GPIO_PIN_13 #define DS1302_IO_PIN GPIO_PIN_14 void DS1302_Init(void); void DS1302_SetTime(uint8_t year, uint8_t month, uint8_t day, uint8_t week, uint8_t hour, uint8_t minute, uint8_t second); void DS1302_GetTime(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *week, uint8_t *hour, uint8_t *minute, uint8_t *second); #endifGPIO 初始化有一个细节值得说明CE 和 SCLK 是纯输出引脚用推挽模式I/O 是双向引脚我把它配置成开漏输出并加上拉。这样一来读数据之前只要对 I/O 写 1引脚就自动释放为高电平不需要反复切换输入输出方向代码更干净。// ds1302.c #include ds1302.h static void DelayUs(uint32_t us) { // 简易忙等待延时数值需要按主频微调 for (volatile uint32_t i 0; i us * 16; i); } static void DS1302_GPIO_Init(void) { GPIO_InitTypeDef gpio {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); // CE 和 SCLK推挽输出 gpio.Pin DS1302_CE_PIN | DS1302_SCLK_PIN; gpio.Mode GPIO_MODE_OUTPUT_PP; gpio.Pull GPIO_PULLUP; gpio.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(DS1302_GPIO_PORT, gpio); // I/O开漏输出 上拉天然适配双向线 gpio.Pin DS1302_IO_PIN; gpio.Mode GPIO_MODE_OUTPUT_OD; gpio.Pull GPIO_PULLUP; HAL_GPIO_Init(DS1302_GPIO_PORT, gpio); // 初始状态CE 和 SCLK 拉低I/O 释放 HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_CE_PIN | DS1302_SCLK_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_IO_PIN, GPIO_PIN_SET); }DelayUs 里的延时倍数是按主频 72MHz 粗略估的实际值最好用逻辑分析仪或者直接观察能否正确读写来校准。驱动对延时精度要求不高只要单 bit 的时钟高电平持续时间在 1 微秒以上就行。4.2 底层字节收发函数先写通信的启动和停止。CE 拉高代表一次传输开始CE 拉低代表结束。注意 CE 拉高之前要确保 SCLK 处于低电平这是数据手册里明确要求的。static void DS1302_Start(void) { HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_SCLK_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_CE_PIN, GPIO_PIN_SET); DelayUs(2); } static void DS1302_Stop(void) { HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_CE_PIN, GPIO_PIN_RESET); DelayUs(2); }写字节函数遵循低电平时放数据上升沿锁存的规则。每写一个位先把数据摆到 I/O 上再拉高 SCLK最后拉低 SCLK 为下一个位做准备。static void DS1302_WriteByte(uint8_t data) { for (uint8_t i 0; i 8; i) { HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_IO_PIN, (data (1 i)) ? GPIO_PIN_SET : GPIO_PIN_RESET); DelayUs(1); HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_SCLK_PIN, GPIO_PIN_SET); DelayUs(1); HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_SCLK_PIN, GPIO_PIN_RESET); DelayUs(1); } }读字节函数稍微绕一点。每次进入读状态前先对 I/O 写 1让开漏引脚处于释放状态避免和芯片的输出打架。然后按先采样当前位再翻一次 SCLK 产生下降沿的顺序循环 8 次。static uint8_t DS1302_ReadByte(void) { uint8_t val 0; // 释放 I/O让芯片可以正常驱动数据线 HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_IO_PIN, GPIO_PIN_SET); for (uint8_t i 0; i 8; i) { // 先采样芯片在下降沿更新数据此刻线上是稳定电平 if (HAL_GPIO_ReadPin(DS1302_GPIO_PORT, DS1302_IO_PIN)) { val | (1 i); } // 拉高再拉低产生下降沿芯片把下一位放到 I/O 上 HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_SCLK_PIN, GPIO_PIN_SET); DelayUs(1); HAL_GPIO_WritePin(DS1302_GPIO_PORT, DS1302_SCLK_PIN, GPIO_PIN_RESET); DelayUs(1); } return val; }有些资料里的读函数是先下降沿再采样只要时序满足也能工作但上面的写法从原理上更贴合数据手册对输出边沿的描述移植到任何主控上都不会因为边沿习惯不同而出错。4.3 寄存器读写封装有了字节收发函数寄存器访问就是一层薄封装。注意地址参数要区分读写读寄存器传读地址写寄存器传写地址。static uint8_t DS1302_ReadReg(uint8_t addr) { uint8_t val 0; DS1302_Start(); DS1302_WriteByte(addr); // 命令字节addr 是读地址 val DS1302_ReadByte(); DS1302_Stop(); return val; } static void DS1302_WriteReg(uint8_t addr, uint8_t data) { DS1302_Start(); DS1302_WriteByte(addr); // 命令字节addr 是写地址 DS1302_WriteByte(data); DS1302_Stop(); }4.4 BCD 码转换和时间结构体DS1302 内部存储时间用的是 BCD 码每个字节的高 4 位是十位低 4 位是个位。比如 25 秒在寄存器里是 0x25而不是 0x19。所以读写时间必须经过转换否则读出来的分钟会在 0x0A 到 0x0F 这些非法值附近乱跳。typedef struct { uint8_t year; // 00-99 uint8_t month; // 1-12 uint8_t day; // 1-31 uint8_t week; // 1-7 uint8_t hour; // 0-23 uint8_t minute; // 0-59 uint8_t second; // 0-59 } DS1302_Time_t; static uint8_t BinToBcd(uint8_t bin) { return ((bin / 10) 4) | (bin % 10); } static uint8_t BcdToBin(uint8_t bcd) { return ((bcd 4) * 10) (bcd 0x0F); }4.5 初始化、设置时间和读取时间初始化函数主要做三件事初始化 GPIO、关闭写保护、把小时寄存器切到 24 小时制。关闭写保护意味着后续代码可以自由写时间寄存器小时寄存器则通过读改写的方式把它的 bit7 清成 0同时保留当前的小时值。void DS1302_Init(void) { DS1302_GPIO_Init(); DS1302_WriteReg(0x8E, 0x00); // 关闭写保护 DS1302_WriteReg(0x90, 0x00); // 关闭涓流充电 // 读取小时寄存器清除 bit712/24小时制标志切到24小时制 uint8_t hour DS1302_ReadReg(0x85); hour 0x7F; DS1302_WriteReg(0x84, hour); }设置时间时秒寄存器写入的内容要注意把 CH 位置 0否则芯片处于暂停状态时间不会走动。我习惯把秒值转换 BCD 后再与 0x7F 做与运算确保高位清零。void DS1302_SetTime(const DS1302_Time_t *t) { DS1302_WriteReg(0x8E, 0x00); // 关写保护 DS1302_WriteReg(0x80, BinToBcd(t-second) 0x7F); // 清 CH启动时钟 DS1302_WriteReg(0x82, BinToBcd(t-minute)); DS1302_WriteReg(0x84, BinToBcd(t-hour)); // 24 小时制 DS1302_WriteReg(0x86, BinToBcd(t-day)); DS1302_WriteReg(0x88, BinToBcd(t-month)); DS1302_WriteReg(0x8A, BinToBcd(t-week)); DS1302_WriteReg(0x8C, BinToBcd(t-year)); DS1302_WriteReg(0x8E, 0x80); // 开写保护 }读取时间时直接按寄存器顺序读即可。这里有一个值得注意的业务逻辑如果秒寄存器显示的时间已经走过了你预期的边界那么读到的分、时可能因为进位而和秒不匹配这是正常现象不是芯片坏了。void DS1302_GetTime(DS1302_Time_t *t) { t-second BcdToBin(DS1302_ReadReg(0x81) 0x7F); t-minute BcdToBin(DS1302_ReadReg(0x83) 0x7F); t-hour BcdToBin(DS1302_ReadReg(0x85) 0x3F); t-day BcdToBin(DS1302_ReadReg(0x87) 0x3F); t-month BcdToBin(DS1302_ReadReg(0x89) 0x1F); t-week BcdToBin(DS1302_ReadReg(0x8B) 0x07); t-year BcdToBin(DS1302_ReadReg(0x8D)); }4.6 一个可以直接跑的主程序例子下面放一个完整的主程序片段串口每秒钟打印一次当前时间。print 函数走的是标准库 printf 重定向串口初始化部分省略。#include ds1302.h int main(void) { HAL_Init(); SystemClock_Config(); MX_USART1_UART_Init(); DS1302_Init(); DS1302_Time_t t {24, 1, 15, 3, 18, 30, 45}; // 年份241月15日周三18:30:45 DS1302_SetTime(t); uint32_t last HAL_GetTick(); while (1) { if (HAL_GetTick() - last 1000) { last HAL_GetTick(); DS1302_GetTime(t); printf(20%02d-%02d-%02d 周%d %02d:%02d:%02d\r\n, t.year, t.month, t.day, t.week, t.hour, t.minute, t.second); } } }实测下来这段代码在 F103 和 F407 上都能直接跑区别只是 GPIO 时钟使能宏不同。如果换成其他型号的 STM32把开头那句 __HAL_RCC_GPIOB_CLK_ENABLE 换成对应 GPIO 组的时钟宏就行。5. 调试时最容易踩的六个坑5.1 读回来全是 0x00CE 时序和收发方向现象是串口打印的所有时间字段都是 0或者某几个寄存器读出来全是 0。第一个怀疑对象是 CE。DS1302 在工作期间 CE 必须保持高电平而且在 CE 拉高之前 SCLK 必须是低电平。如果代码里先拉高 CE再拉高 SCLK或者在 CE 拉高期间误操作了 SCLK 的初始电平通信就可能根本没建立起来。另外命令字节如果传成了写地址读出来的也会是空数据。排查时可以把 CE 和 SCLK 的波形引到逻辑分析仪上对照数据手册的时序图看一遍基本能定位。5.2 读回来全是 0xFFI/O 线没松手全 0xFF 通常是读阶段的 I/O 方向问题。如果 I/O 配置成推挽输出读的时候引脚还在主动驱动电平芯片输出就会被你的代码按住读回的自然全是 1。解决思路有两个一是在读字节之前把 I/O 切换成输入模式读完再切回输出二是用我在前面代码里写的开漏加外置或上拉方案对 I/O 写 1 就等于释放总线芯片可以自由驱动。后一种方式少了很多模式切换也不容易出现方向搞反的隐性 bug。5.3 时间写不进去WP 写保护DS1302 上电默认打开写保护控制寄存器 0x8F 的 bit7 是 1。在这个状态下所有时间寄存器的写入都会被忽略但读取不受影响。所以如果出现读正常、写无效的诡异现象先检查代码里有没有在写时间前执行 DS1302_WriteReg(0x8E, 0x00)。还有一个细节写完时间后是否打开写保护是可选的但打开更稳妥可以防止程序跑飞时误操作时间寄存器。我在 SetTime 函数里写完之后恢复 0x80就是出于这个考虑。5.4 时钟走几下就停CH 位没处理干净芯片上电时秒寄存器的最高位 CH 可能是 1此时内部振荡器不工作。很多教程会在初始化里写秒寄存器把 CH 清零但如果你只是读时间、从没写过秒寄存器时钟就会一直停着。解决方法是设置时间时对秒值跟 0x7F 做与运算再写入确保 CH 位始终为 0。另一个情况是主电源掉电后如果 VCC1 电压低于芯片工作阈值芯片也可能自动进入停止状态重新上电后要再确认一次 CH 位。5.5 小时显示成 1-12分秒错位BCD 转换写反读出来的小时范围变成 1 到 12说明小时寄存器的高位把 12/24 小时制标志也带出来解析了。正确做法是读小时寄存器时先跟 0x3F 做与运算把 bit7 和 bit6 屏蔽掉再转 BCD。分秒错位则通常是 BCD 和二进制转换写反比如把 0x45 当成十进制的 45然后换算出的分钟数会在 40 到 49 之间跳来跳去。调试这种问题最简单的办法是固定写入一个已知时间比如 12:34:56然后看读回来的原始寄存器值是不是 0x12、0x34、0x56。5.6 晶振不走或者秒跳变硬件问题如果代码逻辑全对时间就是不流畅问题大概率在晶振电路。常见原因有三个晶振引脚虚焊、负载电容太大、走线过长。32.768kHz 晶振对负载电容很敏感市面上常用于手表晶振的负载电容是 6pF 到 12.5pF你按 6pF 起步试不行再换。另外别用有源晶振去接 DS1302DS1302 需要的是无源晶振。秒跳变还有一个少见原因是主控和 DS1302 之间地线接触不良数字信号在高频下出现毛刺把 I/O 上的数据采样错了检查共地比什么都实在。6. 驱动封装的一点个人建议给将来的自己留条路做完基础驱动后我强烈建议你把代码按三个层次整理一下底层是引脚操作和字节收发中间层是寄存器读写上层是时间结构体相关的设置和获取。这样将来换芯片、换引脚或者把驱动从 HAL 库改成裸机寄存器版都不会牵一发动全身。我自己的做法是把所有引脚宏集中在头文件顶部并在文件头写两行注释说明接线方式半年后回来看代码也能三分钟上手。如果你对读取的一致性有要求可以用时钟突发模式替代逐个寄存器读取。突发读的命令字节是 0xBF一次连续读 8 个字节分别是秒、分、时、日、月、周、年、控制。这样能减少多次启动通信之间的时间差秒进位导致的前后不一致会小很多。void DS1302_ReadTimeBurst(DS1302_Time_t *t) { uint8_t buf[8]; DS1302_Start(); DS1302_WriteByte(0xBF); for (uint8_t i 0; i 8; i) { buf[i] DS1302_ReadByte(); } DS1302_Stop(); t-second BcdToBin(buf[0] 0x7F); t-minute BcdToBin(buf[1] 0x7F); t-hour BcdToBin(buf[2] 0x3F); t-day BcdToBin(buf[3] 0x3F); t-month BcdToBin(buf[4] 0x1F); t-week BcdToBin(buf[5] 0x07); t-year BcdToBin(buf[6]); }写完这套驱动之后我又顺手把 DS1302 的 31 字节 RAM 利用起来用来保存设备的上电次数和最后一次校准偏移。这个 RAM 的访问方式和时间寄存器完全一样地址从 0xC0 到 0xFE 附近读写时同样要先处理写保护。实测下来它的掉电保持能力和时间寄存器一样可靠非常适合存一些系统配置类的小数据。最后说一句个人体会。DS1302 这颗芯片并不算快也不支持复杂的通信协议但它最大的优点是确定性寄存器就那么几个时序就那么几条出了问题很容易排查。相比把时间模块放进 STM32 内部那套备份域配置里我反而更喜欢这种一眼能看透的方案。如果你也正在为到底用内置 RTC 还是外挂芯片纠结我的建议是先拿 DS1302 把功能跑通把时间显示、断电保持、闹钟这些需求都验证完再回头看内置 RTC 也不迟。等你对整套时间链路有了手感自然就知道哪种方案更适合你的项目了。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号