×
单片机 > 单片机程序设计 > 详情

STM32 RTC时钟源LSE

发布时间:2020-06-09 发布时间:
|
一开始,所有实验都是在神舟板上去完成,根本就没有发现RTC的问题。直到我们自己画板来后调试时,才发现STM32 RTC的外部时钟源存在问题。

这也算是STM32的一个鸡肋,对于LSE外部晶振太过于苛刻,手册上要求使用6pf,这个规格的晶振市场上太少,鱼龙混杂,中招的高手菜鸟不在少数。我们自己的板也是如此,几经波折,反反复复尝试使用不同的规格的晶振,替换外部的电容,电阻都没有能让这个32.768K的LSE起振。但是又需要有RTC来提供时间,考虑的方法主要有2种,第一采用外部RTC时钟芯片,如DS1302。第二是使用内部其它的时钟源来提供RTC时钟。毫无疑问,目前板已经制好,添加时钟芯片肯定造成板上布局更改,还得重新打板,这里采用了第二种方法。

查看STM32的手册上时钟树,如下:

除去不能起振的外部低速LSE外,可供使用的只有LSI和HSE的128分频,LSI这个是内部的40KHz RC振荡器,频率在30~60KHz浮动,自然这个不能用于RTC计时,误差太大。

我们的板上配的是STM32F107这款芯片,外部高速晶振是25MHz的。128分频后频率为 25000000 / 128 = 195312.5 Hz,很显然这里也不能做到很精确,有小许误差。

然后设置RTC_PRL寄存器,写入195312这个分频值,便可以得到1Hz的频率。使用HSE作为RTC时钟,缺点就是无法在断开电源后使用后备电池进行供电,维持RTC的正常。下次需要上位机重新去设置时间。

 

代码大致如下:

 
  1. void RTC_Configuration(void)  
  2. {  
  3.     u8 i = 0;  
  4.     /* Enable PWR and BKP clocks */  
  5.     /* PWR时钟(电源控制)与BKP时钟(RTC后备寄存器)使能 */  
  6.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);  
  7.   
  8.     /* Allow access to BKP Domain */  
  9.     /*使能RTC和后备寄存器访问 */  
  10.     PWR_BackupAccessCmd(ENABLE);  
  11.   
  12.     /* Reset Backup Domain */  
  13.     /* 将外设BKP的全部寄存器重设为缺省值 */  
  14.     BKP_DeInit();  
  15.   
  16.     /* Enable LSE */  
  17.     /* 使能LSE(外部32.768KHz低速晶振)*/  
  18.     RCC_LSEConfig(RCC_LSE_ON);  
  19.     
  20.     /* Wait till LSE is ready */  
  21.     /* 等待外部晶振震荡稳定输出 */  
  22.     TIM5_Init_Query(CALC_TYPE_MS); //ms 级别  
  23.     for (i = 0;i 
  24.     {  
  25.         if (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != RESET)  
  26.             break;  
  27.         TIM5_MS_CALC(1); //1ms延时  
  28.     }  
  29.     //while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}  
  30.     if (i == 10)  
  31.     {  
  32.         //RCC->CSR |= 0x1; //开启内部低速晶振  
  33.         //while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);  
  34.         //RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //使用LSI提供RTC时钟  
  35.         //使用外部高速晶振 128分频  
  36.         RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);   
  37.     }else  
  38.     {  
  39.         /* Select LSE as RTC Clock Source */  
  40.         /*使用外部32.768KHz晶振作为RTC时钟 */                           
  41.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);  
  42.     }  
  43.   
  44.     /* Enable RTC Clock */  
  45.     /* 使能 RTC 的时钟供给 */  
  46.     RCC_RTCCLKCmd(ENABLE);  
  47.   
  48.     /* Wait for RTC registers synchronization */  
  49.     /*等待RTC寄存器同步 */  
  50.     RTC_WaitForSynchro();  
  51.   
  52.     /* Wait until last write operation on RTC registers has finished */  
  53.     /* 等待上一次对RTC寄存器的写操作完成 */  
  54.     RTC_WaitForLastTask();  
  55.   
  56.     /* Enable the RTC Second */  
  57.     /* 使能RTC的秒中断 */  
  58.     RTC_ITConfig(RTC_IT_SEC, ENABLE);  
  59.   
  60.     /* Wait until last write operation on RTC registers has finished */  
  61.     /* 等待上一次对RTC寄存器的写操作完成 */  
  62.     RTC_WaitForLastTask();  
  63.     
  64.     /* Set RTC prescaler: set RTC period to 1sec */  
  65.     /* 32.768KHz晶振预分频值是32767,如果对精度要求很高可以修改此分频值来校准晶振 */  
  66.     if (i != 10) //LSE不能正常  
  67.         RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */  
  68.     else  
  69.         RTC_SetPrescaler(195312); //25000000 / 128 = 195312.5,如果是8M / 128 = 62500,则这里应该填为62499  
  70.   
  71.     /* Wait until last write operation on RTC registers has finished */  
  72.     /* 等待上一次对RTC寄存器的写操作完成 */  
  73.     RTC_WaitForLastTask();  
  74. }  
  75.   
  76. void Init_RTC(void)  
  77. {  
  78.     /* 以下if...else.... if判断系统时间是否已经设置,判断RTC后备寄存器1的值 
  79.      是否为事先写入的0XA5A5,如果不是,则说明RTC是第一次上电,需要配置RTC, 
  80.      提示用户通过串口更改系统时间,把实际时间转化为RTC计数值写入RTC寄存器, 
  81.      并修改后备寄存器1的值为0XA5A5。 
  82.      else表示已经设置了系统时间,打印上次系统复位的原因,并使能RTC秒中断 
  83.     */  
  84.     if (BKP_ReadBackupRegister(BKP_DR1) != RTC_SEQ_ID)  
  85.     {  
  86.         /* Backup data register value is not correct or not yet programmed (when 
  87.            the first time the program is executed) */  
  88.       
  89.         /* RTC Configuration */  
  90.         RTC_Configuration();  
  91.   
  92.    
  93.         /* Adjust time by values entred by the user on the hyperterminal */  
  94.         RTC_SetCounter(Time_Regulate(YEAR_BASE,01,01,0,0,0)); //2008-1-1 0:0:0  
  95.         /* 修改后备寄存器1的值为0XA5A5 */  
  96.         BKP_WriteBackupRegister(BKP_DR1, RTC_SEQ_ID);  
  97.     }else  
  98.     {  
  99.         /* Check if the Power On Reset flag is set */  
  100.         //RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET  
  101.         //  printf("\r\n\n Power On Reset occurred....");  
  102.           
  103.         /* Check if the Pin Reset flag is set */  
  104.         //else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)  
  105.         //  printf("\r\n\n External Reset occurred....");  
  106.         if (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)  
  107.         {  
  108.             //RCC->CSR |= 0x1; //开启内部低速晶振  
  109.             //while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);  
  110.             //RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //使用LSI提供RTC时钟  
  111.             //RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);  
  112.             RTC_Configuration();  
  113.         }  
  114.         //printf("\r\n No need to configure RTC....");  
  115.         /* Wait for RTC registers synchronization */  
  116.         RTC_WaitForSynchro();  
  117.   
  118.         /* Enable the RTC Second */  
  119.         RTC_ITConfig(RTC_IT_SEC, ENABLE);  
  120.       
  121.         /* Wait until last write operation on RTC registers has finished */  
  122.         RTC_WaitForLastTask();  
  123.     }  
  124.   
  125. #ifdef RTCClockOutput_Enable  
  126.   /* Enable PWR and BKP clocks */  
  127.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);  
  128.         
  129.   /* Allow access to BKP Domain */  
  130.   PWR_BackupAccessCmd(ENABLE);  
  131.   
  132.   /* Disable the Tamper Pin */  
  133.   BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamper 
  134.                                  functionality must be disabled */  
  135.   
  136.   /* Enable RTC Clock Output on Tamper Pin */  
  137.   BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);  
  138. #endif  
  139.   
  140.   /* Clear reset flags */  
  141.   RCC_ClearFlag();  
  142. }  


实际测试,RTC效果还行,然后配合上位机隔一定的时间后同步时间基本上能够满足要求。

万恶的LSE晶振,这东西简直不能忍受......

关键字:STM32  RTC时钟源  LSE 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
msp430的中断优先级和中断嵌套(及容易理解错误的说明)