RTC(实时时钟)

内置 RTC,提供日历时钟 + 秒中断,供数字时钟、模拟时钟、计数器、倒计时等控件使用。

一、读写时间

#include "rtc.h"
extern _calendar_obj calendar;      // w_year / w_month / w_date / hour / min / sec / week

RTC_Get();                          // 读硬件 → 刷新 calendar
LTPrintf("%04d-%02d-%02d %02d:%02d:%02d week=%d\r\n",
         calendar.w_year, calendar.w_month, calendar.w_date,
         calendar.hour, calendar.min, calendar.sec, calendar.week);

RTC_Set(2026, 10, 20, 14, 30, 0);   // 设置时间
RTC_Get();                          // 立即生效
函数 说明
RTC_Get() 读硬件刷新 calendar,返回天计数
RTC_Set(y,m,d,h,mi,s) 设置时间
RTC_Set_alarm(tm) 设闹钟
RTC_Get_Week(y,m,d) 算星期 0~6
LT_RtcInit() 初始化,main.c 里已调用

二、注意:年份有 2000 偏移

硬件只存「天计数 + 时:分:秒」,年月日是软件从 RTC_BASE_YEAR(rtc.h)换算的。

写到 UI 变量时,年要减 2000:

地址 内容
0x7002 年(存 年 − 2000,2026 → 0x001A)
0x7003 ~ 0x7007 月 / 日 / 时 / 分 / 秒
0x7008 星期

RTC_Set() 内部会 +2000,用函数就不用管;直接写 UI 变量或上位机下发时要自己换算。

上位机写时间(0x7002 起连续 6 个字):

5A A5 11 10 70 02 00 1A 00 0A 00 14 00 0E 00 1E 00 00 70 3F
              │    年=26  月=10  日=20  时=14  分=30  秒=0
              └ 首地址 0x7002,连续写 6 个字
  • LEN = 1 + 2 + 12 + 2 = 0x11
  • 只改部分字段时改首地址与字数(只改时分秒 → 首地址 0x7005,3 个字)

这个坑很常见:写指令里第一个数据字容易被误写成数量(0x0006),
正确应为年份偏移值。上面的帧已按 Modbus CRC16、低字节在前 校验。

三、秒中断:每秒刷新三个标志

// Function/rtc.c —— RTC_Handler(),IRQ 13(EIC_IT_RTC)
RTC->PRCSR = prcsr | (1 << 19);         // 写 1 清标志
RTC_Get();                              // 刷新 calendar
RTC_flag = 1;  Clock_flag = 1;  Count_flag = 1;
标志 消费方
RTC_flag 数字时钟 Widget/digitalClock.c
Clock_flag 模拟时钟 Widget/analogClock.c
Count_flag 计数器 / 倒计时 Widget/uiCounter.c、varCounter.c

目前只开了秒中断(Sec_IEN)和闹钟(Ala_IEN),其余 Min_IEN/Hou_IEN/Day_IEN 是注释掉的。

中断里没有喂狗,往里加耗时逻辑时注意主循环是否还在喂,避免被复位。

四、改常用参数

需求 位置
首次上电默认时间 rtc.c 里 if (timer.day == 0) 分支的 RTC_Set(...)
闹钟时间 RTC_Set_alarm(tm)
开分钟中断 取消 LT_RtcInit() 里 Min_IEN 的注释,并在 RTC_Handler() 里加对应分支

五、改底层

  • RTC_Get() 跨天才重算年月日(先减整年再减整月),时分秒每次刷新 —— 可放心高频调用
  • 改 PRCSR 前必须解锁:RTC->PRKEYR = 0x5aa55aa5;
  • 主要寄存器:PRT1R(天计数)、PRT2R(时/分/秒)、PRCSR(控制+状态)、
    PRKEYR(钥匙)、PRENR(总使能)

六、注意事项

项 说明
解锁 改 PRCSR 前必须写 PRKEYR = 0x5aa55aa5
清标志 写 1 清,不是写 0
年份 UI 变量存的是 年 − 2000
分频 rtc_wclk_div = SYS_CLOCK/10000000 - 1,主频变了自动算
看门狗 起振等待 3 s 内有喂狗;自行加长等待要补喂狗
掉电保持 依赖硬件备用电源;天计数为 0 会写默认时间
作者:罗珍雪  创建时间:2026-10-20 12:01
最后编辑:罗珍雪  更新时间:2026-11-02 20:02