關於STM32中RTC的校準方法


最近看了一些關於RTC校準的帖子,發現很多人存在疑惑。正好最近我也在STM32中實現了RTC校準。發些心得。這些對老手來說有些羅索,但對新手有益處。

實現RTC 校準的核心之一是庫文件Stm321f0x_bkp.c中的void BKP_SetRTCCalibrationValue (uint8_t CalibrationValue) 函數。談到RTC校準的相關參考文檔包括AN2604.pdf,AN2821.pdf和AN2821.zip。這三個文檔都可以從STM32官方網站下載。

按照AN2604.pdf描述的原理,RTC 的校準值應在0-127之間。可實現的校準誤差對應爲0-121ppm。相當於每30天跑快的秒數爲0-314s。

這裏應注意的一個關鍵問題是,RTC只能對跑快進行校準,不能對跑慢進行校準。如果手錶晶振的標稱頻率是32768Hz,設其可能的誤差範圍是±2Hz,則實際頻率會在32766Hz-32770Hz之間。如果RTC的內部分頻係數設定爲32768,則32768Hz是不需要校準的頻率,32768Hz-32770Hz是可以校準的頻率(最大校準能力大概是32772Hz)。但是32766Hz-32768Hz的跑慢頻率段則無法實現校準。爲此,在推薦的校準方法中,使用32766代替32768作爲分頻係數。這樣一來,32766Hz是不需要校準的頻率,32766Hz-32770Hz是可以校準的頻率範圍。

剩下的問題是,如何測量誤差,並以此得出校準值。一般來說有兩種方法,一是測量TamperPin的頻率值,然後計算ppm誤差;二是實際運行一定的天數,與標準時鍾做對比,先得到每30天跑快的秒數,然後計算ppm誤差。

AN2604.pdf,AN2821.pdf裏都詳細描述了第一種方法。AN2821.zip則使用定時器T2對TamperPin的頻率值進行自動測量,實現了自動校準。自動校準確實簡化了用戶操作,但是它要依賴於8MHz主時鐘的精度。自動校準不可能達到比8MHz主時鐘精度更高的結果。所以給用戶留有手動校準界面仍是萬全之策。即使有自動校準,也可以手動、自動疊加作用。

另一方面,使用第一種方法進行校準,需要準確測量TamperPin的頻率值,比如達到511.xxxHz的精度。普通示波器做不到這一點,一般的頻率計也不行,高精度的頻率計纔可以。只有搞計量的專業人士纔會有這種設備。作爲搞控制系統的人,搞一個非計量精度的時鐘,使用第一種方法還是有困難的。

第一種方法也好,第二種方法也罷,核心都是計算ppm誤差。我們先看一下第一種方法是如何計算ppm誤差的。由於使用了32766作爲分頻係數,因此32766Hz是不需要校準的基準頻率。不要把32768Hz看得太重,現在它啥也不是,32766Hz可看成新的標稱頻率。TamperPin的頻率應爲32766Hz/64=511.968Hz。這也就是文檔中計算誤差時反覆使用的基準頻率。按照文檔中所舉的例子,若實測TamperPin的頻率爲511.982Hz,則誤差爲27.35ppm。計算過程爲(511.982Hz-511.968Hz)/ 511.968Hz *10^6 = 27.35ppm。文檔最後給出最接近的校準值爲28。注意這裏是最後的校準值28,是由27 ppm查表得到的,而不是有些帖子中誤解的將27.35ppm近似成28ppm。

其實ppm誤差的計算公式爲:ppm誤差=偏差/基準值*10的6次方。據此,採用第二種方法時,先得到了每30天跑快的秒數。這跑快的秒數就是偏差,而30天就是基準值。所以ppm誤差=每30天跑快的秒數/(30天*24小時*3600秒)*10的6次方。用這個公式可以容易地解釋文檔AN2604.pdf中提到的“0.65ppm大約是每月誤差1.7秒”。因爲:1.7/(30*24*3600)*10^6 = 0.65ppm。

計算出了ppm誤差,還要解決查表。對文檔中給出的表格也不必看重。弄明白這個表格是怎麼來的之後,可以使用簡單的計算公式代替查表。AN2604.pdf中說,若校準值爲1,則RTC 校準時,每2的20次方個時鐘週期扣除1個時鐘脈衝。這相當於0.954ppm(1/2^20*10^6 = 0.954)。而校準值最大爲127,所以最大可以減慢121ppm(0.954ppm*127 = 121)。所以這個校準表就是由簡單的乘除運算得來的,當然要使用浮點運算纔可以得到準確結果。

以下是採用第二種方法實現的RTC 校準程序。
首先定義了兩個常數,一是PPM_PER_STEP,準確到浮點數可表示的精度數0.9536743ppm。另一個是PPM_PER_SEC,即每30天快一秒對應的ppm誤差,準確到浮點數可表示的精度數0. 3858025ppm。  

#define PPM_PER_STEP  0.9536743 //10^6/2^20.
#define PPM_PER_SEC   0.3858025 //10^6/(30d*24h*3600s).

然後定義全局變量FastSecPer30days。通過用戶菜單設定並傳遞到RTC校準程序裏。

u16 FastSecPer30days = 117; //菜單輸入。117只用於演示。

實現的校準函數爲:

void RTC_Calibration(void)
{
  float Deviation = 0.0;
  u8 CalibStep = 0;
  
  Deviation = FastSecPer30days * PPM_PER_SEC; //得到ppm誤差
  Deviation /= PPM_PER_STEP; //得到校準值的浮點數
  CalibStep = (u8)Deviation; // 得到校準值的整形數
  if(Deviation >= (CalibStep + 0.5))
    CalibStep += 1; //四捨五入
  if(CalibStep > 127) 
    CalibStep = 127; // 校準值應在0—127之間
  
  BKP_SetRTCCalibrationValue(CalibStep); //調用庫函數
    
}
//函數結束RTC_Calibration

=========================================================================

回覆【26樓】mynice  
回覆【樓主位】xizi 
這裏應注意的一個關鍵問題是,rtc只能對跑快進行校準,
-----------------------------------------------------------------------
我現在用內部的32khz的時鐘,結果真的跑慢了,看來不可校準了,還有沒有其他辦法可以讓跑慢的時鐘跑快一點呢?
-----------------------------------------------------------------------

"rtc只能對跑快進行校準"這一原則無法改變,但我們總是可以做到讓跑慢的時鐘跑快。你發現跑慢時所用分頻係數應是32768,當你改爲32766分頻係數時,它就會跑得比原來快一些。如果仍然比標準時鐘慢,那就再減小分頻係數,總可以使之跑(得比標準)快,這樣就可以進行校準了。當然如果分頻係數弄得太小,使之跑(得比標準)快太多,可能會

發佈了1 篇原創文章 · 獲贊 31 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章