STM32的RTC外设
基本概念

框图分析

控制流程


程序设计


/**
* @brief RTC 实时时钟初始化配置函数
* @note 功能链:解锁备份域写保护 → NVIC + EXTI22 配置唤醒中断 →
* 启动 LSE 并选为 RTC 时钟源 → 设置初始时间/日期 →
* 配置预分频产生 1Hz 秒时钟 → 开启唤醒定时器
*/
void RTC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure; // 定义 NVIC 中断优先级配置结构体变量,用于配置内核中断控制器
EXTI_InitTypeDef EXTI_InitStructure; // 定义外部中断/事件线配置结构体变量,用于配置 EXTI 线
/* ---------- 解锁备份域写保护 ---------- */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // 使能 APB1 总线上的 PWR(电源控制外设)时钟;访问备份域前必须先开 PWR 时钟
PWR_BackupAccessCmd(ENABLE); // 解除备份域(RTC、备份寄存器)写保护,此后才能修改 RTC 时钟源、时间、日期等寄存器
/* ---------- 1. NVIC:配置 RTC 唤醒定时器中断 ---------- */
NVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn; // 指定中断通道为 RTC 唤醒定时器中断(RTC_WKUP_IRQn)
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级设为 1(数值越小,抢占优先级越高)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级设为 0,与抢占优先级配合决定中断嵌套顺序
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能该 NVIC 通道,允许内核响应此中断请求
NVIC_Init(&NVIC_InitStructure); // 将结构体参数写入 NVIC 寄存器,完成优先级分组与通道使能配置
/* ---------- 2. EXTI:RTC 唤醒事件固定映射到 EXTI 线 22 ---------- */
EXTI_ClearITPendingBit(EXTI_Line22); // 先清除 EXTI22 线的中断挂起标志,避免配置前残留标志导致中断立即误触发
EXTI_InitStructure.EXTI_Line = EXTI_Line22; // 选择 EXTI 第 22 线(该线在芯片内部固定连接到 RTC 唤醒事件)
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 工作模式选中断模式(产生中断请求送到 NVIC,而非事件输出)
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; // 触发方式为上升沿触发(RTC 唤醒事件有效时输出上升沿)
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能该 EXTI 线,允许该线产生中断请求
EXTI_Init(&EXTI_InitStructure); // 参数写入 EXTI 寄存器,完成 EXTI22 的中断配置
/* ---------- 3. 启动 LSE 外部晶振,选为 RTC 时钟源 ---------- */
RCC_LSEConfig(RCC_LSE_ON); // 启动外部低速晶振 LSE(板上外接 32.768kHz 晶振,走时精度高、功耗低)
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); // 循环轮询 LSE 就绪标志,直到晶振起振稳定后才继续,防止后续配置失步
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // 选择 LSE 作为 RTC 时钟源(备选:LSI 内部 RC、HSE 外部高速晶振分频)
RCC_RTCCLKCmd(ENABLE); // 使能 RTC 时钟,将时钟送入 RTC 外设
RTC_WaitForSynchro(); // 等待 RTC 影子寄存器与时钟同步完成,保证后续写时间/日期/预分频寄存器有效
/* ---------- 4. 设置初始时间:23:59:50(BCD 码格式) ---------- */
RTC_TimeStructure.RTC_Hours = 0x23; // 小时 = 23;BCD 格式下高 4 位是十位、低 4 位是个位,0x23 即十进制 23
RTC_TimeStructure.RTC_Minutes = 0x59; // 分钟 = 59(BCD 格式,0x59 即十进制 59)
RTC_TimeStructure.RTC_Seconds = 0x50; // 秒 = 50(BCD 格式,0x50 即十进制 50)
RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure); // 把时间写入 RTC 时间寄存器,格式参数指定为 BCD 码
/* ---------- 5. 设置初始日期:2026 年 10 月 27 日 星期二(BCD 码格式) ---------- */
RTC_DateStructure.RTC_Month = 0x10; // 月份 = 10 月(BCD 格式,0x10 即十进制 10)
RTC_DateStructure.RTC_Date = 0x27; // 日 = 27 日(BCD 格式,0x27 即十进制 27)
RTC_DateStructure.RTC_Year = 0x26; // 年份后两位 = 26(RTC 只存两位年份,工程上约定代表 2026 年)
RTC_DateStructure.RTC_WeekDay = 0x02; // 星期 = 星期二(取值约定:1=星期一,2=星期二……7=星期日)
RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure); // 把日期写入 RTC 日期寄存器,格式参数指定为 BCD 码
/* ---------- 6. RTC 预分频与小时格式配置 ---------- */
RTC_InitStructure.RTC_AsynchPrediv = 128-1; // 异步预分频系数 = 127(计数区间 0~127,共 128 个时钟);32.768kHz 先经异步级分频
RTC_InitStructure.RTC_SynchPrediv = 256-1; // 同步预分频系数 = 255(计数区间 0~255,共 256 个时钟);再经同步级分频得到秒时钟
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24; // 小时格式选 24 小时制(备选 RTC_HourFormat_12 为 12 小时制,带 AM/PM)
RTC_Init(&RTC_InitStructure); // 参数写入 RTC 配置寄存器;分频结果 = 32768 ÷ 128 ÷ 256 = 1Hz,即每秒产生一次日历更新
/* ---------- 7. 配置并启动 RTC 唤醒定时器 ---------- */
RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits); // 唤醒定时器时钟源选内部 1Hz 备用时钟 CK_SPRE(16 位计数器模式),不直接依赖 LSE 分频
RTC_SetWakeUpCounter(1-1); // 写入唤醒计数值 0;计数器在所选时钟沿递减,减到 0 后产生唤醒事件(等效 1 个时钟周期)
RTC_ITConfig(RTC_IT_WUT, ENABLE); // 在 RTC 内核侧使能唤醒定时器中断(WUT 中断),RTC 才会向外发出中断请求
RTC_ClearITPendingBit(RTC_IT_WUT); // 清除 RTC 内部唤醒中断挂起标志,避免配置前的残留标志导致首次进中断
RTC_WakeUpCmd(ENABLE); // 使能唤醒定时器开始递减计数;计数到 0 后经 EXTI22 触发 NVIC 的 RTC_WKUP_IRQn,进入 RTC_WKUP_IRQHandler
}
void RTC_WKUP_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_WUT) != RESET)
{
uwTimeDisplay = 1;
RTC_ClearITPendingBit(RTC_IT_WUT);
EXTI_ClearITPendingBit(EXTI_Line22);
}
}
int main()
{
//1.硬件的初始化
USART1_Config(9600);
RTC_Config();
while(1)
{
if (uwTimeDisplay == 1)
{
//显示时间
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);
sprintf((char*)aShowTime,"%0.2d:%0.2d:%0.2d\r\n",RTC_TimeStructure.RTC_Hours, RTC_TimeStructure.RTC_Minutes, RTC_TimeStructure.RTC_Seconds);
sprintf((char*)aShowDate,"20%0.2d-%0.2d-%0.2d\r\n",RTC_DateStructure.RTC_Year, RTC_DateStructure.RTC_Month, RTC_DateStructure.RTC_Date);
USART1_SendString((char*)aShowTime);
USART1_SendString((char*)aShowDate);
uwTimeDisplay = 0;
}
}
}
作者:bbzhu04@gmail.com ,多有不妥之处,望批评指正
本文原创,欢迎转载;转载请在文章显著位置标明原文链接: href="https://www.cnblogs.com/zhubb/p/23456248"
保留所有权限,未经许可禁止篡改、商用发布。

浙公网安备 33010602011771号