今天调试RTC使用LSI调试,后来改外部晶振不起振。可是使用内部晶振使用后备电池又不走时。网上找到答案
http://blog.chinaunix.net/uid-27106528-id-4288509.html
最初调试STM32的万年历,使用的是内部的 LSI晶振作为RTC晶振来源,发现有两个问题:
第一:由于LSI晶振频率大约在40KHZ附近,实际上会在30~60KHZ之间波动,导致计时不准,基本上一个小时会有1分钟左右的偏差。
第二: 由于LSI内部晶振,在断电的时候,并不在后备供电区域范围内,而外接的3.3V电池连接到VBAT上,只给后备供电区域供电,导致系统断电后,电池只能维持后备RTC的计数,并没有给LSI晶振供电(见下图所示:),导致RTC总是保持在断电之前的时间。虽然重新上电后又可以继续运行。但是需要重新校准了
。
最后使用了外界的32.768KHZ的外部LSE晶振作为RTC晶振来源,调试过程中发现,反复修改,问题和之前使用LSI没有区别。
后面仔细回想才发现了问题所在,因为调试过程中加了if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)的判断,由于电池一直接到MCU上,
虽然反复的刷程序,都没有改变备份数据寄存器的值。而RTC的晶振来源一经确定,中途是不能改变的,除非全部复位备份域。
最后通过暂时取下电池(或暂时短路电池),又或者复位备份域,才成功重新设置为外部LSE晶振。时间精度的问题和断电RTC依旧运行的问题得到了解决。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
结论:使用LSI掉电使用后备电池不能走时。要改用LSE要系统全掉电并重启,否则LSE无法就绪。
#include"RTC.h"
Time sysTime;
//是否使用外部晶振
#define USE_EXTERNEL_CRYSTAL
void RTC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //指定是RTC全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void RTC_Configuration(void)
{
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE);
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
{
BKP_DeInit();//BKP寄存器全部设为缺省值
#ifdef USE_EXTERNEL_CRYSTAL
RCC_LSEConfig(RCC_LSE_ON); //RCC打开了LSE时钟
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);//等待LSE就绪,如果谐振不对,就会死在这里.
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//RTC使用时钟源LSE
#else
RCC_LSICmd(ENABLE);// Enable the LSI OSC
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET); // Wait till LSI is ready
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);// Select the RTC Clock Source
#endif
RCC_RTCCLKCmd(ENABLE);// Enable RTC Clock
RTC_WaitForSynchro();//RTC等待同步
RTC_WaitForLastTask();//等待就绪
RTC_ITConfig(RTC_IT_SEC, ENABLE); // 使能RTC秒中断
//RTC_SetPrescaler(32767);//RTC预分频,32768HZ
RTC_SetPrescaler(40000);//RTC预分频,32768HZ
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);//往备份域寄存器中写一个特殊的字符
// SetDateTime((TagDateTime *)&DefaultSystime); //设置一个初始时间
PWR_BackupAccessCmd(DISABLE);//禁止RTC后备寄存器
RCC_ClearFlag(); //清除RCC重启标志
}
else
{
#ifdef USE_EXTERNEL_CRYSTAL
RCC_LSEConfig(RCC_LSE_ON); //RCC打开了LSE时钟
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);//等待LSE就绪,如果谐振不对,就会死在这里.
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//RTC使用时钟源LSE
#else
RCC_LSICmd(ENABLE);// Enable the LSI OSC
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);// Wait till LSI is ready
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); // Select the RTC Clock Source
#endif
// Enable RTC Clock
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();//RTC等待同步
//AdjustRtcTime();//配置系统时间,主要是考虑到断电重启如何恢复系统时间
RTC_ITConfig(RTC_IT_SEC, ENABLE); // 使能RTC秒中断
RTC_WaitForLastTask();
PWR_BackupAccessCmd(DISABLE);//禁止RTC后备寄存器
RCC_ClearFlag(); //清除RCC重启标志
}
RTC_NVIC_Config();
}