STM32 RTC掉电不走时

今天调试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();
}




猜你喜欢

转载自blog.csdn.net/diyer_zhou/article/details/44106399