STM32F10x RTC闹钟无效不触发的原因和解决方案
本篇文章希望通过自己解决RTC闹钟的问题经验帮助到您。
RTC闹钟原理
STM32F10x系列的RTC闹钟不同于STM32L系列,只有一个计数器。需要外部有一个RTC作为时钟晶振,由于RTC寄存器属于备份域(所谓备份域就是寄存器可以在电池供电状态下仍然保持活跃,这样即使没有外部电源,依靠电池供电是,时钟仍然会继续工作),所以在时钟配置是,需要使能PWR和BKP的时钟源,并正确初始化响应的寄存器。
从上图可以看出,如果配置好时钟后,RTC_CNT会自动开始计数,如果需要设置闹钟,那么设置RTC_ALR到一个未来的RTC_CNT值(上图标志1处),那么当相等的时候,就会产生一个RTC_Alarm信号,如果此时ALRIE(闹钟使能标志),那么ALRF置位(上图位置2),信号就到位图上位置3,如果NVIC正确配置,那么NVIC将会产生中断。
如何通过调试快速定位问题
第一步,检查中断标志是否使能
检查NVIC的RTC Global Interrupt的Enable状态是否设置。
如果上面没有使能,那么RTC的闹钟中断是不会产生的,这是RTC闹钟的是否产生中断的最后一关。
第二步,检查RTC寄存器的状态
如果RTC->CRH->ARLIE没有设置,则很闹钟功能没有使能,很大可能的原因是设置RTC的时候,RTC是无效的。一般情况下查看RTC.CRL.RTOFF的状态十分为设置状态(1),如果不是,那么就是RTC初始化出现了问题,导致写寄存器无效。
请注意,这个RTOFF非常重要,如果不是这个状态,那么表明RTC寄存器操作失败,中断就不用考虑了
RTOFF没有置位一般就是在RTC初始化过程中没有合理使用指令导致初始化进入了一个未知的状态。RTC寄存器的操作有一套流程,必须按照这个流程才可以正确访问寄存器,因此,如果中断产生不了,请仔细核对初始化代码。
下图是RTC初始化的流程:
在STM32F10x的基础库中,RTC_WaitForLastTask就是等待RTOFF到1.
设置CNF位在基础库的函数中都有正确设置,所以无需再进行设置。
可用最简单代码
int rtc_main(){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit ();
RCC_LSEConfig(RCC_LSE_ON); // Enable LSE
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro(); // 这里需要等待RTC时钟可用
// 这是操作RTC的寄存器(RTC_PRL, RTC_CNT, RTC_ALR)需要等待的流程
RTC_WaitForLastTask();
RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
RTC_WaitForLastTask();
// 使能RTC Global Interrupt中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RTC_WaitForLastTask();
RTC_SetAlarm(RTC_GetCounter() + 60);
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_ALR, ENABLE); // 使能ALRIE
while(1){}
}