简介
RTC本质是一个定时器,有后备区域,该区域用来保证持续计时,需要单独供电。当复位或唤醒后,后备区域有写保护,所以需要修改后备区域时即修改时间时,需要先取消后备区域BKP的写保护。
RTC核心有两个模块,20位的预分频器与32位的可编程计数器。
RTC可以产生三种中断,
一般设置预分频器产生1秒的时间基准TR_CLK,通过RTC_CR寄存器设置,可以每秒产生一次秒中断。
计数器有一个RTC_ALR闹钟寄存器,通过设置RTC_CR寄存器,当RTC_CNT与RTC_ALR的值匹配时,发生一次闹钟中断。
当RTC_CNT溢出时,会产生溢出中断。
由于RTC可以单独运行,而我们通过软件访问RTC的计数器是通过APB1总线接口,如果APB1上电后直接访问RTC的寄存器,而此时RTC内部寄存器还没有更新,那么读取的数据往往是0,所以需要等到RTC_CRL寄存器的RFS位(寄存器同步标志位,bit3)被硬件置1后,再读取。
RTC配置步骤
1.使能电源时钟,并使能 RTC 及 RTC 后备寄存器写访问。
首先要使能RTC电源时钟与RTC后备区域时钟,同时关闭写保护
__HAL_RCC_PWR_CLK_ENABLE(); /* 使能电源时钟 PWR */
__HAL_RCC_BKP_CLK_ENABLE(); /* 使能备份时钟 */
HAL_PWR_EnableBkUpAccess(); /* 取消备份区域写保护 */
2.初始化 RTC,设置 RTC 的分频,以及配置 RTC 参数。
RTC_HandleTypeDef g_rtc_handle; /* RTC控制句柄 */
g_rtc_handle.Instance = RTC;
g_rtc_handle.Init.AsynchPrediv = 32767; /*时钟周期设置,理论值:32767, 这里也可以用 RTC_AUTO_1_SECOND */
g_rtc_handle.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
HAL_RTC_Init(&g_rtc_handle);
__HAL_RTC_ALARM_ENABLE_IT(&g_rtc_handle, RTC_IT_SEC); /* 允许秒中断 */
HAL_NVIC_SetPriority(RTC_IRQn, 0x2, 0); /* 优先级设置 */
HAL_NVIC_EnableIRQ(RTC_IRQn); /* 使能RTC中断通道 */
3.开启外部低速振荡器LSE,选择 RTC 时钟,并使能。
RCC_OscInitTypeDef rcc_oscinitstruct = {0};
RCC_PeriphCLKInitTypeDef rcc_periphclkinitstruct = {0};
__HAL_RCC_RTC_ENABLE(); /* RTC时钟使能 */
/* 使用寄存器的方式去检测LSE是否可以正常工作 */
RCC->BDCR |= 1 << 0; /* 开启外部低速振荡器LSE */
while (retry && ((RCC->BDCR & 0X02) == 0)) /* 等待LSE准备好 */
{
delay_ms(5);
}
rcc_oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_LSE ; /* 选择要配置的振荡器 */
rcc_oscinitstruct.LSEState = RCC_LSE_ON; /* LSE状态:开启 */
rcc_oscinitstruct.PLL.PLLState = RCC_PLL_NONE; /* PLL不配置 */
HAL_RCC_OscConfig(&rcc_oscinitstruct); /* 配置设置的rcc_oscinitstruct */
rcc_periphclkinitstruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; /* 选择要配置外设 RTC */
rcc_periphclkinitstruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; /* RTC时钟源选择LSE */
HAL_RCCEx_PeriphCLKConfig(&rcc_periphclkinitstruct); /* 配置设置的rcc_periphclkinitstruct */
HAL_PWR_EnableBkUpAccess(); /* 取消备份区写保护 */
HAL_RTCEx_BKUPWrite(&g_rtc_handle, 0+ 1, 0x5050);
时间设置
RTC第一次上电初始化时间流程:
由于第一次未对RTC初始化设置BKP寄存器时, BKP寄存器0的值非0x5050 且非 0x5051,往往此时对RTC进行第一次时间设置。
uint16_t bkpflag = HAL_RTCEx_BKUPRead(&g_rtc_handle, 0 + 1);
if ((bkpflag != 0X5050) && (bkpflag != 0x5051)) /* 之前未初始化过,重新配置 */
{
rtc_set_time(2025, 5, 19, 11, 43, 00); /* 设置时间 */
}
后续复位上电等,时间都会默认设置为这个时间。
更改时钟步骤如下:
__HAL_RCC_PWR_CLK_ENABLE(); /* 使能电源时钟 */
__HAL_RCC_BKP_CLK_ENABLE(); /* 使能备份域时钟 */
HAL_PWR_EnableBkUpAccess(); /* 取消备份域写保护 */
RTC->CRL |= 1 << 4; /* 允许配置 */
/* 更改时间,修改RTC_CNT寄存器
* RTC->CNTL
* RTC->CNTH
*/
RTC->CRL &= ~(1 << 4); /* 配置更新 */
while (!__HAL_RTC_ALARM_GET_FLAG(&g_rtc_handle, RTC_FLAG_RTOFF)); /* 等待RTC寄存器操作完成, 即等待RTOFF == 1 */