STM32 RTC自适应校准算法

       公司负责硬件的同事测试发现,RTC使用外部晶振时,由于一些干扰(高频信号之类的),外部晶振会出现不起振的情况,于是就决定把外部晶振取消了,又因为设备要低功耗的,就没用有源的晶振,于是乎就用了STM32内部的RC时钟

RC时钟的两个分频值都可以设置,校准的原理很简单,固定一个分频值,然后动态调整另一个分频值ji就OK了。

校准步骤:

1、首先随便设置两个个分频值,比如127,255,其中固定的值为127,另一个分频值为Y1(此处的Y1就是255)

2、然后利用秒中断(或者与秒中断等效的代码),获取RTC发生一次秒中断所需要的实际时间T1,单位是ms

3、利用公式 Y2=Y1*1000/T1,得到新的分频值Y2。

4、然后用127(固定值),和新的分频值Y2,重新配置RTC,至此,一次校准就完成了,然后可以利用RTC做计时

5、把Y2写入RTC的备份寄存器或者Flash或者EEPROM,以备下次使用

6、把Y2当作Y1,重复1到5的步骤

具体代码实现:

void vRtcCalibrate(void)
{
    uint32_t ulStartTime;
    uint32_t ulEndTime;
    
    uint32_t ulSynchPrediv = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);
    DEBUG0("ulSynchPrediv:%u\r\n",ulSynchPrediv);
    
    /* 备份寄存器上电值为0 */
    if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) == 0){
        hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
        hrtc.Init.AsynchPrediv = 36;
        hrtc.Init.SynchPrediv = 999;
        hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
        hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
        hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
        hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
        if (HAL_RTC_Init(&hrtc) != HAL_OK)
        {
            DEBUG0("RTC校准失败1\r\n");
            return ;
        }
        
        /* 等待RTC时钟运行稳定 */
        HAL_Delay(500);
    }else{
        hrtc.Init.AsynchPrediv = 36;
        hrtc.Init.SynchPrediv = ulSynchPrediv;
    }
    
    DEBUG0("hrtc.Init.AsynchPrediv: %u\r\n",hrtc.Init.AsynchPrediv);
    DEBUG0("hrtc.Init.SynchPrediv:  %u\r\n",hrtc.Init.SynchPrediv);
    
    ulStartTime = HAL_GetTick();
    uint32_t temp = hrtc.Instance->SSR;
    HAL_Delay(2);
    while(temp!=hrtc.Instance->SSR && HAL_GetTick()-ulStartTime< 3000);
    ulEndTime = HAL_GetTick();
    if( ulEndTime >= ulStartTime + 3000)
    {
        DEBUG0("RTC校准失败2\r\n");
        return ;
    }
    DEBUG0("%u\r\n",ulEndTime - ulStartTime);

    uint32_t ulCalibrateTime = (hrtc.Init.SynchPrediv) * 1000/(ulEndTime-ulStartTime);

    DEBUG0("ulCalibrateTime:%u\r\n",ulCalibrateTime);
    if( ulCalibrateTime > INT_LEAST16_MAX )
    {
        DEBUG0("RTC校准失败3\r\n");
        return ;
    }
    

    hrtc.Init.AsynchPrediv = 36;
    hrtc.Init.SynchPrediv = ulCalibrateTime;
    
    if (HAL_RTC_Init(&hrtc) != HAL_OK)
    {
        DEBUG0("RTC校准失败4\r\n");
    }
    /* 等待RTC时钟运行稳定 */
    HAL_Delay(500);
    DEBUG0("实测RTC频率:%uHz\r\n",(hrtc.Init.AsynchPrediv+1)*(hrtc.Init.SynchPrediv+1));
    HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,ulCalibrateTime);
}
 

其中:

  ulStartTime = HAL_GetTick();
    uint32_t temp = hrtc.Instance->SSR;
    HAL_Delay(2);
    while(temp!=hrtc.Instance->SSR && HAL_GetTick()-ulStartTime< 3000);

相当于一次秒中断

 

此代码可以解决不同STM32内部RC时钟的误差,不管是什么频率,都可以得到一个比较准确的秒中断,实测误差不超过5ms,每隔一段时间,校准一次RTC时钟,还可以解决RC时钟温漂的问题。

此代码是基于STM32的滴答时钟做的校准,若滴答时钟不准,那就没办法了

 

未经允许,不得转载

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章