公司負責硬件的同事測試發現,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的滴答時鐘做的校準,若滴答時鐘不準,那就沒辦法了
未經允許,不得轉載