最近在使用野火的板子学习rtc时钟时,由于LSE外部晶振老是无法起振,所以使用LSi内部低速时钟作为rtc时钟,为了验证rtc备用电源的作用,也就是说当有备用电源时,系统复位或者系统掉电时rtc内的计数器的值都不会改变。写了以下实验代码
void My_RTC_Config(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
{
RCC_LSICmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != SET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_SetPrescaler(40000 - 1);
RTC_WaitForLastTask();
RTC_SetCounter(1356969600);
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
}
else
{
RTC_WaitForSynchro();
RTC_WaitForLastTask();
}
主函数内调用液晶显示函数显示RTC_GetCounter()的值。但是实验发现,复位时其中的值不会改变,但是掉电时候rtc计数器的值复位了。按照参考手册上的只有备份域复位信号才能使rtc计数器的值复位,明明有备份电源,未产生复位信号,为什么rtc计数器的值复位呢而且rtc计数器的值复位的同时BKP寄存器的值又没有改变,也就是说备用电源功能是存在的?
找了很久发现一个问题:我们上述代码用的是LSI作为RTC时钟,使用读取BKP的值来判断是否是第一次初始化RTC,即当系统复位或者系统掉电时,通过读取BKP寄存器的值来使RTC_SetCounter(1356969600);这条语句只执行一次,保证RTC计数器的值不改变。但是由于我们使用的是LSI作为RTC时钟,当系统复位或者系统掉电时,我们也需要再次开启LSI时钟。因此正确的初始化函数应该是下面这个:
void My_RTC_Config(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
{
RCC_LSICmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != SET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_SetPrescaler(40000 - 1);
RTC_WaitForLastTask();
RTC_SetCounter(1356969600);
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
}
else
{
RCC_LSICmd(ENABLE); //即使不是第一次配置,也需要再次开启LSI时钟
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != SET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
}
}
这样系统复位或者vdd掉电重启rtc计数器里的值就不会被复位了。但是由于使用的是LSI作为rtc时钟,所以当系统复位或者vdd掉电重启时,rtc不会工作,即cnt的值不会改变,而不是会保持1秒递增的原则。