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的滴答時鐘做的校準,若滴答時鐘不準,那就沒辦法了

 

未經允許,不得轉載

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