償完整指南:從晶振溫漂原理到STM32校準(zhǔn)實(shí)踐)
做嵌入式的朋友應(yīng)該都有過這種經(jīng)歷設(shè)備跑了一個(gè)月顯示屏上的時(shí)間比手機(jī)慢了五分鐘或者凌晨自動(dòng)上報(bào)的數(shù)據(jù)時(shí)間戳對不上。問題不大不小但就是膈應(yīng)人。這類問題十有八九出在RTC實(shí)時(shí)時(shí)鐘身上而RTC走不準(zhǔn)的背后溫度往往就是罪魁禍?zhǔn)?。RTC溫度補(bǔ)償這件事說白了就是讓時(shí)鐘在溫度變化時(shí)依然走準(zhǔn)。但真正落地時(shí)涉及晶振選型、補(bǔ)償算法、校準(zhǔn)流程、低功耗喚醒等一系列環(huán)節(jié)遠(yuǎn)沒有想象中那么簡單。這篇文章把我做過的幾個(gè)帶RTC產(chǎn)品的經(jīng)驗(yàn)整理出來從原理到代碼再到排查方法一次性說清楚。不管你是剛接觸RTC的新手還是被走時(shí)誤差折磨過的老工程師應(yīng)該都能從中找到有用的東西。1. 為什么溫度一變RTC就走不準(zhǔn)1.1 石英晶振的“拋物線”溫漂RTC的計(jì)時(shí)基準(zhǔn)幾乎都是32.768kHz的石英晶振。這個(gè)頻率是2的15次方用15級(jí)分頻就能得到1Hz的秒脈沖硬件實(shí)現(xiàn)最簡單所以成了行業(yè)標(biāo)準(zhǔn)。石英晶體本身有壓電效應(yīng)它的振蕩頻率由晶體的切割角度、尺寸和彈性模量共同決定而這三樣?xùn)|西都會(huì)隨溫度變化。頻率和溫度的關(guān)系并不是線性的而是一條近似拋物線。大多數(shù)32.768kHz晶振的拐點(diǎn)也就是頻率最準(zhǔn)的點(diǎn)設(shè)計(jì)在25℃附近偏離這個(gè)溫度后頻率會(huì)以二次方的關(guān)系往下掉。典型的溫漂曲線可以用下面這個(gè)公式近似Δf / f a(T - T0)2 b(T - T0) c其中T0是參考溫度通常是25℃a是二次溫度系數(shù)典型值在-0.04 ppm/℃2左右b和c是一次項(xiàng)和初始偏差項(xiàng)。這個(gè)公式是理解所有溫度補(bǔ)償方案的基石。我實(shí)測過一批國產(chǎn)貼片晶振在25℃時(shí)誤差只有2ppm看著很不錯(cuò)。但溫度拉到0℃時(shí)頻偏掉到-8ppm到了60℃直接變成-32ppm。也就是說晶振的常溫指標(biāo)再漂亮也代表不了它在整個(gè)工作溫度范圍的表現(xiàn)。1.2 ppm誤差到底有多夸張很多朋友對ppm沒有直觀概念。ppm是parts per million百萬分之一。對時(shí)間來說1ppm的誤差意味著每天偏差0.0864秒一年偏差約31.5秒??雌饋聿欢嗟懿蛔≌`差是累積的。我列一張表把ppm換算成實(shí)際時(shí)間誤差大家感受一下頻偏(ppm)每天誤差每月誤差每年誤差±2±0.17s±5.2s±63s±5±0.43s±13s±2.6min±10±0.86s±26s±5.2min±20±1.73s±52s±10.4min±30±2.59s±1.3min±15.6min普通晶振的標(biāo)稱精度一般是±20ppm這個(gè)精度只在室溫附近能保證。設(shè)備放到戶外晝夜溫差一拉夏天中午機(jī)殼里溫度到50℃很正常冬天北方凌晨能到-15℃這時(shí)候頻偏往往超過30ppm。換算下來一天慢2秒多一個(gè)月就是1分鐘以上。對智能電表、車載記錄儀、安防攝像頭這種需要長期可靠計(jì)時(shí)的設(shè)備來說這種誤差完全不可接受。2. 硬件方案直接選帶TCXO的RTC2.1 TCXO是怎么把誤差壓下去的解決溫漂最省事的方法是從源頭就買一顆內(nèi)置溫度補(bǔ)償?shù)腞TC芯片。這類芯片內(nèi)部集成了一顆溫度傳感器和一套補(bǔ)償電路用軟件或者說固化的邏輯實(shí)時(shí)修正晶振頻率原理就是前面那個(gè)拋物線模型的反向應(yīng)用。廠商在出廠前把每顆芯片的溫漂參數(shù)測好寫進(jìn)芯片工作時(shí)根據(jù)當(dāng)前溫度查內(nèi)部補(bǔ)償表輸出穩(wěn)定的頻率。這種技術(shù)叫TCXO溫度補(bǔ)償晶體振蕩器。它跟恒溫晶振OCXO不一樣OCXO是把晶體放在恒溫槽里用加熱器穩(wěn)住溫度精度更高但功耗大、體積大、貴。TCXO是“主動(dòng)補(bǔ)償溫度造成的影響”不需要加熱功耗很小而且精度足夠日常設(shè)備使用。最典型的例子是Maxim現(xiàn)在歸ADI的DS3231系列。DS3231內(nèi)部集成TCXO標(biāo)稱精度±2ppm工作溫度范圍-40℃到85℃而且這個(gè)精度是整個(gè)溫度范圍內(nèi)都保證的。EPSON的RX8025T、RX8900系列也是帶溫度補(bǔ)償?shù)腞TC日系方案在計(jì)量和工業(yè)設(shè)備里用得很多。2.2 主流帶溫補(bǔ)RTC芯片怎么選我把幾顆常用的帶溫補(bǔ)RTC芯片擺在一起對比一下大家可以根據(jù)項(xiàng)目需求對號(hào)入座芯片型號(hào)精度接口特點(diǎn)大致參考價(jià)DS3231±2ppm(-40~85℃)I2C內(nèi)置TCXO帶溫度傳感器電池備份中等偏高DS3231M±5ppmI2CMEMS版本體積更小中等RX8025T±5ppm(-40~85℃)I2C內(nèi)置數(shù)字溫度補(bǔ)償EPSON主力型號(hào)中等RX8900CE±5ppmI2C低功耗適合電池設(shè)備中等偏高PCF2129±3ppm(-40~85℃)SPI/I2CNXP方案帶溫補(bǔ)和電池切換中等選型時(shí)除了看精度的常溫值更要看整個(gè)工作溫度范圍內(nèi)的最大值這個(gè)數(shù)據(jù)通常在數(shù)據(jù)手冊里有曲線圖。有些常規(guī)RTC芯片常溫精度標(biāo)得不錯(cuò)但數(shù)據(jù)手冊里根本不敢給全溫范圍的精度曲線這種芯片對溫漂基本是放任不管的。經(jīng)驗(yàn)之談如果產(chǎn)品的工作溫度范圍寬戶外、車載、且出貨量不大直接上帶TCXO的RTC芯片是最劃算的選擇。很多人一算成本貴了幾塊錢就想自己做軟件補(bǔ)償結(jié)果樣機(jī)調(diào)試、測試、現(xiàn)場維護(hù)的時(shí)間成本遠(yuǎn)超省下的芯片差價(jià)。反過來如果產(chǎn)品的成本壓力極大、出貨量幾百萬臺(tái)那才值得在軟件補(bǔ)償上投入精力。3. 軟件方案自己上手做溫度補(bǔ)償3.1 溫度數(shù)據(jù)從哪來怎么放測溫點(diǎn)硬件方案省事但貴軟件方案就是用MCU自己感知溫度、修正頻率。第一步當(dāng)然是把溫度測準(zhǔn)。有三個(gè)常見的測溫途徑外接NTC熱敏電阻。成本最低一個(gè)電阻加一個(gè)分壓網(wǎng)絡(luò)搞定但需要校準(zhǔn)。NTC的B值一致性、電阻精度都會(huì)影響測溫結(jié)果量產(chǎn)后每臺(tái)設(shè)備可能有差異。想讓NTC測溫精度到±0.5℃級(jí)別必須做多點(diǎn)校準(zhǔn)這工作量不小。數(shù)字溫度傳感器比如DS18B20、TMP117。DS18B20便宜且普及分辨率能到12位但出廠精度只有±0.5℃實(shí)際使用中自發(fā)熱也會(huì)引入誤差。TMP117是TI的高精度傳感器精度±0.1℃適合對時(shí)間精度要求苛刻的場景。MCU內(nèi)部溫度傳感器。STM32的片上溫度傳感器幾乎零成本但出廠精度一般在±1.5℃左右而且測的是裸片溫度不是晶振的實(shí)際溫度。MCU運(yùn)行時(shí)的功耗會(huì)影響裸片溫度跟晶振周圍的環(huán)境溫度差個(gè)幾度很正常。測溫點(diǎn)到晶振的距離非常關(guān)鍵。晶振自身的功耗極低幾乎不發(fā)熱所以測溫點(diǎn)應(yīng)該盡量靠近晶振位置但又要避開MCU、功率器件這些發(fā)熱源。我做過一臺(tái)采集器一開始用MCU內(nèi)部溫度傳感器做補(bǔ)償夏天中午設(shè)備內(nèi)部溫度比外部高10℃補(bǔ)償出來反而越補(bǔ)越偏。后來改成在晶振旁邊放了一顆NTC問題立刻解決了。3.2 建“溫度-頻偏”模型從實(shí)測到擬合軟件補(bǔ)償?shù)暮诵氖堑玫揭粋€(gè)準(zhǔn)確可靠的“溫度-頻偏”曲線模型。這里分兩步實(shí)測數(shù)據(jù)然后擬合公式或建表。實(shí)測最好用恒溫箱。把設(shè)備放進(jìn)去從-20℃到60℃每隔10℃設(shè)一個(gè)點(diǎn)每個(gè)點(diǎn)保溫至少30分鐘讓溫度均勻然后用頻率計(jì)測量32.768kHz信號(hào)的實(shí)際頻率。需要注意測頻率時(shí)最好讓MCU進(jìn)入低功耗狀態(tài)、只保留RTC和晶振工作避免其他外設(shè)產(chǎn)生干擾。沒有恒溫箱的話也可以用“對時(shí)統(tǒng)計(jì)法”近似測量設(shè)備放在一個(gè)溫度會(huì)變化的環(huán)境里每隔一段時(shí)間記錄當(dāng)前溫度和與參考時(shí)間源的時(shí)間差參考時(shí)間源可以用GPS模塊或者NTP服務(wù)器。跑個(gè)2-3天溫度變化范圍夠大一樣能擬合出曲線。這個(gè)方法精度稍差但做前期摸底足夠。拿到一系列溫度, 頻偏的數(shù)據(jù)點(diǎn)后最常用的擬合方式是最小二乘法擬合二次多項(xiàng)式。比如我在某個(gè)項(xiàng)目里實(shí)測得到的數(shù)據(jù)大致如下溫度(℃)頻偏(ppm)-10-11.20-8.010-3.5200.5252.0301.840-2.250-9.060-20.1把這些點(diǎn)用最小二乘法擬合成二次曲線得到大致是ppm(T) -0.018(T - 25)2 2.0這條曲線就是補(bǔ)償依據(jù)。MCU在運(yùn)行時(shí)測量當(dāng)前溫度T用這個(gè)公式算出當(dāng)前頻偏再把頻偏換算成RTC校準(zhǔn)寄存器的值寫入芯片。3.3 補(bǔ)償怎么落到STM32寄存器里知道了頻偏怎么在STM32上把它變成實(shí)際的物理時(shí)間修正這是很多人卡住的地方。STM32的內(nèi)部RTC校準(zhǔn)原理是利用一個(gè)可配置的校準(zhǔn)寄存器把“秒”的長度微調(diào)。以STM32F1/F4系列為例RTC配有CALR寄存器由CALP位和CALM[8:0]字段組成。校準(zhǔn)的基本思想是在一個(gè)很長的校準(zhǔn)周期內(nèi)2^20秒約12.1天如果CALM不為零就扣掉對應(yīng)數(shù)量的RTC時(shí)鐘脈沖。每個(gè)CALM的LSB對應(yīng)的頻率調(diào)整量約0.954ppm也就是校準(zhǔn)量(ppm) CALM × 0.954如果頻偏是負(fù)的時(shí)鐘走快需要把頻率拉低就要用CALP位增加額外的校正脈沖配合CALM使用。不同系列芯片的RTC校準(zhǔn)寄存器布局和含義有差異F0、F1、F4、L4都可能不同但思路是一樣的。動(dòng)手之前務(wù)必翻開對應(yīng)型號(hào)的參考手冊找到RTC校準(zhǔn)章節(jié)對比CALP、CALM位的確切定義。下面是一段在STM32F1上根據(jù)ppm誤差設(shè)置CALR寄存器的示意代碼重點(diǎn)看思路不要直接照抄因?yàn)榧拇嫫骱甓x在不同庫版本里差別較大void rtc_set_calibration(int16_t ppm) { uint32_t calm; uint16_t tmpreg; // 關(guān)閉校準(zhǔn)寫入使能確保配置期間RTC不受影響 RTC_CalibrationCmd(DISABLE); tmpreg RTC-CR ~RTC_CR_CALP; if (ppm 0) { // 正ppm時(shí)鐘偏快需要拉慢走CALM扣脈沖 tmpreg ~RTC_CR_CALP; } else { // 負(fù)ppm時(shí)鐘偏慢需要走快置CALP加脈沖 tmpreg | RTC_CR_CALP; ppm -ppm; } RTC-CR tmpreg; // 每個(gè)CALM步進(jìn)約0.954ppm向上取整后限幅 calm (uint32_t)((ppm * 1000) / 954); if (calm 0x1FF) { calm 0x1FF; } RTC-CALR calm; RTC_CalibrationCmd(ENABLE); }整個(gè)補(bǔ)償流程放在主循環(huán)里做可能不夠及時(shí)更穩(wěn)妥的做法是用定時(shí)器周期性觸發(fā)溫度采樣在采樣回調(diào)里計(jì)算ppm值更新CALR寄存器。溫度變化緩慢每隔幾秒或者幾十秒更新一次就足夠了。有一點(diǎn)必須提醒CALR校準(zhǔn)是基于一個(gè)約12天周期的累計(jì)調(diào)整相位誤差在短時(shí)間內(nèi)是分散的不會(huì)導(dǎo)致秒脈沖的劇烈抖動(dòng)這是它比“改分頻器重裝值”更平滑的原因。改分頻值做補(bǔ)償雖然直觀但每次調(diào)整都會(huì)引起秒沿的相位突變用在需要精確秒同步的場景比如電力采集對時(shí)會(huì)有隱患。4. 低功耗場景RTC喚醒與溫度補(bǔ)償?shù)慕Y(jié)合4.1 喚醒后動(dòng)態(tài)校準(zhǔn)的完整流程用電池供電的物聯(lián)網(wǎng)設(shè)備越來越多這類設(shè)備的特點(diǎn)是一天大部分時(shí)間在睡眠靠RTC周期喚醒干活。這正是STM32 RTC喚醒的典型應(yīng)用場景。設(shè)備在Stop模式下RTC自身用LSE保持計(jì)時(shí)定期產(chǎn)生喚醒事件MCU醒來執(zhí)行采集、上報(bào)然后重新睡下。但這種低功耗設(shè)計(jì)會(huì)給溫度補(bǔ)償帶來一個(gè)麻煩設(shè)備大部分時(shí)間是涼的只有醒來那幾十毫秒才通電發(fā)熱。晶振的溫度主要取決于環(huán)境溫度而不是MCU的溫度所以測溫必須在“設(shè)備剛醒來、MCU還沒怎么發(fā)熱”的時(shí)候完成否則測出來的溫度早就偏了。我整理了一套完整的“低功耗喚醒動(dòng)態(tài)溫度補(bǔ)償”流程項(xiàng)目里用過很多次配置RTC喚醒定時(shí)器設(shè)定喚醒周期比如60秒或10分鐘。進(jìn)入Stop模式LSE繼續(xù)運(yùn)行。喚醒事件觸發(fā)MCU啟動(dòng)但先不做任何重負(fù)載工作。立即讀取溫度傳感器NTC或數(shù)字傳感器此時(shí)MCU還沒明顯發(fā)熱測得的是環(huán)境溫度。根據(jù)溫度查表或擬合公式計(jì)算當(dāng)前頻偏ppm值。將ppm值換算后寫入RTC校準(zhǔn)寄存器。執(zhí)行正常的數(shù)據(jù)采集、存儲(chǔ)、上報(bào)等業(yè)務(wù)邏輯。重新進(jìn)入Stop模式。這樣每次喚醒都會(huì)進(jìn)行一次補(bǔ)償校準(zhǔn)把溫度變化帶來的誤差消化在一個(gè)喚醒周期內(nèi)。喚醒后校準(zhǔn)耗時(shí)極短整個(gè)補(bǔ)償流程加在一起不超過幾百微秒對功耗的影響可以忽略。4.2 喚醒初始化與時(shí)鐘切換的坑低功耗喚醒和RTC配置是STM32開發(fā)中踩坑重災(zāi)區(qū)這里分享幾個(gè)最常見的坑??右粡腟top模式喚醒后系統(tǒng)時(shí)鐘沒有重新配置。Stop模式會(huì)停掉主時(shí)鐘喚醒后MCU往往以HSI內(nèi)部高速時(shí)鐘運(yùn)行頻率不對導(dǎo)致串口波特率、定時(shí)器周期全部跑偏。解決辦法是在喚醒后調(diào)用時(shí)鐘重構(gòu)函數(shù)把系統(tǒng)時(shí)鐘恢復(fù)到正常運(yùn)行頻率。坑二RTC喚醒定時(shí)器的時(shí)鐘源沒搞清楚。STM32的RTC喚醒定時(shí)器可以使用RTC時(shí)鐘的1/2、1/4、1/8、1/16分頻也可以直接使用1Hz的秒時(shí)鐘。不少新手直接把計(jì)數(shù)值設(shè)成期望的秒數(shù)結(jié)果發(fā)現(xiàn)喚醒周期完全不對就是因?yàn)闆]有正確配置WUCKSEL位??尤{(diào)試器連接和低功耗模式?jīng)_突。用ST-Link調(diào)試時(shí)SWD接口和調(diào)試邏輯會(huì)阻止MCU真正進(jìn)入Stop模式導(dǎo)致功耗無法降下來。遇到這種情況不要懷疑硬件先斷開調(diào)試器再測。還有一點(diǎn)容易被忽略RTC備份寄存器里保存的時(shí)間數(shù)據(jù)在電池沒接或者首次上電時(shí)是隨機(jī)的。正式產(chǎn)品里必須在首次啟動(dòng)時(shí)做“RTC是否有效”的檢查否則時(shí)間可能是1970年或者某個(gè)亂值后續(xù)的一切補(bǔ)償都建立在錯(cuò)誤的時(shí)間基準(zhǔn)上毫無意義。5. 常見問題與排查技巧實(shí)錄5.1 現(xiàn)象、原因、對策速查表我把這些年遇到的RTC和溫度補(bǔ)償問題整理成一張速查表按現(xiàn)象對號(hào)入座現(xiàn)象可能原因排查與解決辦法晶振完全不起振RTC不走負(fù)載電容不匹配、晶振損壞、LSE驅(qū)動(dòng)能力不足核對晶振規(guī)格書的CL值用示波器看LSE引腳波形必要時(shí)降低負(fù)載電容排查走時(shí)偏差極大每天幾十秒晶振質(zhì)量差、頻率偏差超規(guī)格換知名品牌晶振用頻率計(jì)實(shí)測32.768kHz輸出溫度升高后誤差顯著變大補(bǔ)償表沒有覆蓋工作溫度范圍把實(shí)測溫度區(qū)間擴(kuò)展到-20℃到60℃甚至更寬補(bǔ)償后仍然走不準(zhǔn)測溫點(diǎn)位置不對、溫度傳感器誤差大測溫點(diǎn)靠近晶振用高精度數(shù)字溫度傳感器剛開始很準(zhǔn)幾個(gè)月后越走越偏晶振老化效應(yīng)老化的確存在定期對時(shí)或更換老化指標(biāo)更好的晶振從Stop喚醒后時(shí)間亂跳RTC配置丟失、備份域被復(fù)位檢查備份域供電初始化時(shí)增加RTC有效性判斷喚不醒按復(fù)位才恢復(fù)正常喚醒定時(shí)器配置錯(cuò)誤、標(biāo)志位沒清除檢查WUCKSEL和計(jì)數(shù)值喚醒后及時(shí)清除喚醒標(biāo)志位5.2 幾條獨(dú)家校準(zhǔn)經(jīng)驗(yàn)最后分享三條用真金白銀換來的經(jīng)驗(yàn)每一句都是踩過坑才總結(jié)出來的。第一批量生產(chǎn)的設(shè)備出廠校準(zhǔn)不能只依賴個(gè)體樣本的溫漂曲線。同一批晶振的溫漂參數(shù)是有離散性的常溫初始頻率可能差±5ppm甚至更多。最穩(wěn)的做法是每臺(tái)設(shè)備先做一次常溫單點(diǎn)校準(zhǔn)測出初始偏差然后在擬合曲線上做整體平移。這樣既保證了個(gè)體準(zhǔn)確性又避免了逐臺(tái)做全溫標(biāo)定的巨大工作量。第二軟件補(bǔ)償?shù)纳舷奘芟抻跍囟葴y量的精度。溫度測量每偏1℃如果二次系數(shù)是-0.018 ppm/℃2在偏離拐點(diǎn)30℃時(shí)會(huì)產(chǎn)生約1ppm的補(bǔ)償誤差也就是每天0.086秒這還能接受。但如果溫度本身偏了5℃補(bǔ)償誤差就會(huì)明顯暴漏出來。所以測溫精度永遠(yuǎn)是軟件補(bǔ)償方案的天花板。第三補(bǔ)償不是越頻繁越好。溫度每變化1℃才需要更新的校準(zhǔn)量很小如果每隔幾秒就重新寫入CALR寄存器寄存器擦寫的次數(shù)會(huì)增加內(nèi)部電荷泵反復(fù)調(diào)整反而可能引入噪聲。合理的做法是讓校準(zhǔn)值的更新帶上遲滯比如溫度變化超過1℃才更新一次校準(zhǔn)寄存器或者校準(zhǔn)結(jié)果和上一次偏差超過0.5ppm才寫入。說個(gè)真實(shí)的事。我曾經(jīng)做一批戶外監(jiān)測設(shè)備出廠時(shí)25℃校準(zhǔn)得很好到了冬天客戶陸續(xù)反映一天慢10秒以上。我一開始以為是晶振批次問題換了晶振也沒用。后來查了氣象數(shù)據(jù)發(fā)現(xiàn)設(shè)備安裝環(huán)境長期在-10℃左右回去把溫漂曲線補(bǔ)測到-20℃重新標(biāo)定誤差壓到每天1秒以內(nèi)。溫度補(bǔ)償不是跑一次擬合就完事的必須覆蓋產(chǎn)品真實(shí)的工作溫度區(qū)間最好現(xiàn)場實(shí)測。如果只能選一個(gè)關(guān)鍵點(diǎn)我建議優(yōu)先保證-20℃到60℃這個(gè)區(qū)間的補(bǔ)償精度大多數(shù)常規(guī)電子設(shè)備的安裝環(huán)境都落在這個(gè)范圍里。再分享一個(gè)小技巧正式量產(chǎn)前拿3到5個(gè)樣本做溫漂一致性測試看看同型號(hào)晶振的溫漂曲線有多分散。如果樣本之間的差異很小軟件補(bǔ)償模型可以做得簡單可靠如果離散性大就要考慮換更穩(wěn)定的晶振或者每臺(tái)設(shè)備增加出廠單點(diǎn)校準(zhǔn)流程。晶振的一致性不好軟件算法再精巧也救不回來。