驗(yàn)室儀器開發(fā)實(shí)戰(zhàn):從ADC精度到實(shí)時(shí)固件架構(gòu))
做基于MCU的實(shí)驗(yàn)室儀器Lab Instruments這個(gè)事我前前后后折騰了快五年。一開始是給實(shí)驗(yàn)室搭一套溫度采集系統(tǒng)后來逐漸做到LCR表級(jí)別的阻抗分析、微型光譜儀的信號(hào)鏈甚至給無人機(jī)遙控器的地面站做了個(gè)通道校準(zhǔn)儀。這一類項(xiàng)目有個(gè)共同點(diǎn)看起來好像就是“單片機(jī)加傳感器再連個(gè)屏”但真要把精度、穩(wěn)定性和實(shí)時(shí)性做到位里面全是細(xì)節(jié)。這篇東西我打算把從選型到固件再到調(diào)試的完整思路捋一遍重點(diǎn)講清楚那些只會(huì)在實(shí)操中踩到的坑。這套內(nèi)容適合兩類人。一類是剛接手儀器類項(xiàng)目的嵌入式工程師很多坑我在踩過之后能幫你直接繞開另一類是想把MCU性能榨干的老手尤其是對(duì)ADC精度、實(shí)時(shí)閉環(huán)控制和多任務(wù)調(diào)度有要求的人。我會(huì)結(jié)合STM32H7、TI AM261x這類常見器件來講也會(huì)提到普冉這類國產(chǎn)MCU在開發(fā)環(huán)境上的特殊處理。總之核心不是教你抄一份代碼而是建立一套做儀器類項(xiàng)目的方法論。1. 整體設(shè)計(jì)思路核心是需求拆分而不是先選芯片1.1 實(shí)驗(yàn)室儀器到底需要什么樣的MCU很多剛上手的人會(huì)犯一個(gè)錯(cuò)上來就選個(gè)頂級(jí)芯片覺得主頻高、內(nèi)存大就一定能把儀器做好。其實(shí)實(shí)驗(yàn)室儀器對(duì)MCU的需求通常集中在三件事上。第一是模擬鏈路的精度ADC和DAC的位數(shù)、參考電壓的溫漂、信號(hào)調(diào)理電路的噪聲這些決定了這臺(tái)儀器測(cè)出來的數(shù)可不可信。第二是實(shí)時(shí)控制能力比如FOC電機(jī)控制里的電流環(huán)、鎖相放大器的參考信號(hào)生成、PID反饋閉環(huán)都要求MCU在微秒級(jí)內(nèi)完成計(jì)算和輸出更新。第三是數(shù)據(jù)交互與通信上位機(jī)指令解析、波形上傳、固件升級(jí)這些需要穩(wěn)定的協(xié)議棧和足夠的通信帶寬。我做過一個(gè)簡單的對(duì)照拿我常用的幾類芯片來舉例需求場(chǎng)景代表芯片選型理由代價(jià)高精度采樣為主STM32H743內(nèi)置16位ADC、FMAC和CORDIC加速器FOC運(yùn)算幾乎不占主核功耗偏高封裝大多通道同步采集TI AM261x異構(gòu)架構(gòu)有專用實(shí)時(shí)控制核適合多回路并行開發(fā)復(fù)雜度高低成本電化學(xué)儀器普冉PY32F002Cortex-M0內(nèi)核夠跑基本采樣和邏輯資源緊張需精簡代碼有一點(diǎn)我特別想強(qiáng)調(diào)儀器的精度20%靠MCU選型80%靠你外圍電路和固件算不算法對(duì)。你用一個(gè)16位ADC但參考電壓是直接從LDO拉的那實(shí)際有效位數(shù)可能不到10位。反過來說用普通12位ADC配上低噪聲運(yùn)放和軟件過采樣也能做到等效14位的效果。1.2 方案選型的兩個(gè)核心判斷標(biāo)準(zhǔn)第一個(gè)判斷標(biāo)準(zhǔn)是信號(hào)鏈的瓶頸分析。你先確定傳感器出來的信號(hào)大小、帶寬、阻抗和噪聲水平倒推需要的ADC位數(shù)、采樣率和前端增益。舉個(gè)例子做電化學(xué)伏安法檢測(cè)電流信號(hào)通常在μA級(jí)別那你需要的不是更高分辨率的ADC而是一個(gè)低偏置電流的跨阻放大器把電流轉(zhuǎn)成2-3V的電壓再進(jìn)ADC。第二個(gè)判斷標(biāo)準(zhǔn)是實(shí)時(shí)環(huán)路的算力估算。以FOC電機(jī)控制為例典型的電流環(huán)執(zhí)行周期是10-20kHz每次需要做Clarke變換、Park變換、PID計(jì)算、反Park變換和SVPWM調(diào)制。STM32H7系列內(nèi)置硬件CORDIC和FMAC一次完整的變換計(jì)算可以從軟件純算的幾十微秒壓縮到幾微秒。你在選型時(shí)不要只看主頻要看有沒有針對(duì)性的硬件加速器。我自己踩過一個(gè)很深的坑一開始用某國產(chǎn)M3核單片機(jī)做電機(jī)電流環(huán)主頻72MHz也不算低但算一次SVPWM加PID要將近15微秒10kHz中斷加起來根本跑不滿。后來換了帶FPU和硬件除法器的芯片同樣的算法直接縮到3微秒以內(nèi)。這件事讓我意識(shí)到算力評(píng)估一定要具體到每個(gè)數(shù)學(xué)運(yùn)算的周期數(shù)而不是籠統(tǒng)看主頻。1.3 別忽略研發(fā)效率這個(gè)隱形指標(biāo)選型這件事容易被忽略的是開發(fā)工具鏈和生態(tài)。比如普冉MCU價(jià)格便宜、貨源穩(wěn)定但官方SDK和文檔相對(duì)薄弱用VS Code搭建開發(fā)環(huán)境時(shí)就沒有ST那樣成熟的工具鏈支持。如果你的項(xiàng)目周期緊張優(yōu)先選那些你能快速上手、社區(qū)資料豐富的芯片。如果非要選偏門型號(hào)就要預(yù)留出至少一到兩周的環(huán)境搭建和踩坑時(shí)間。2. 深入ADC信號(hào)鏈從工作原理到精度實(shí)踐2.1 理解SAR ADC的工作節(jié)奏是第一步現(xiàn)在MCU里集成的ADC絕大多數(shù)是逐次逼近型SAR它的基本原理說簡單點(diǎn)就是拿一個(gè)內(nèi)部DAC不斷和你輸入信號(hào)比大小從最高位到最低位逐位逼近。STM32H7的16位ADC和普通12位ADC在工作原理上沒本質(zhì)區(qū)別都是靠比較器和電容陣列CDAC完成轉(zhuǎn)換。你如果看完這個(gè)原理就應(yīng)該明白一件事ADC的輸入引腳在采樣瞬間會(huì)開一個(gè)采樣電容這個(gè)電容會(huì)從你的信號(hào)源“吸”走一定電荷。如果信號(hào)源輸出阻抗太高采樣瞬間的電壓就會(huì)被拉低導(dǎo)致測(cè)量結(jié)果偏低尤其是在測(cè)量高阻抗傳感器和高頻信號(hào)時(shí)會(huì)很明顯。解決方式有兩個(gè)。一是降低信號(hào)源阻抗通常在ADC輸入端加一個(gè)運(yùn)放緩沖器用低輸出阻抗去驅(qū)動(dòng)ADC的采樣電容。二是延長采樣時(shí)間STM32的ADC可以配置采樣周期數(shù)比如從1.5個(gè)周期拉長到810個(gè)周期這樣采樣電容就有足夠時(shí)間充到穩(wěn)定值。但這會(huì)犧牲吞吐率需要平衡。2.2 參考電壓被忽視的精度天花板我見過太多人買了高分辨率ADC的開發(fā)板結(jié)果一測(cè)發(fā)現(xiàn)噪聲大得離譜排查半天發(fā)現(xiàn)是參考電壓引腳直接接到了3.3V電源上。你要知道ADC輸出的數(shù)字量本質(zhì)是輸入電壓和參考電壓的比例值參考電壓抖一下子你的所有測(cè)量結(jié)果都會(huì)跟著抖。這個(gè)比例關(guān)系是數(shù)字輸出 Vin / Vref × 2^N。如果Vref不穩(wěn)定就等于在模擬信號(hào)上疊加了一個(gè)乘性噪聲。在儀器類項(xiàng)目里參考電壓必須用專門的基準(zhǔn)源芯片。常用的是REF50252.5V溫漂3ppm/°C或者ADR4525這類低噪聲基準(zhǔn)。PCB布局上要注意基準(zhǔn)輸出到ADC的VREF引腳走線要短、要粗旁邊加一個(gè)1-10uF的鉭電容并聯(lián)一個(gè)100nF陶瓷電容壓低高頻和低頻噪聲。另外如果你用同一個(gè)LDO既給模擬電路供電又給數(shù)字電路供電那基本就告別高精度了。數(shù)字引腳翻轉(zhuǎn)時(shí)會(huì)產(chǎn)生大量地彈噪聲通過電源網(wǎng)絡(luò)耦合到模擬部分。我也不是說要你用完全隔離的兩路電源但至少要在模擬供電入口加一個(gè)磁珠或者LC濾波把數(shù)字和模擬電源域分開。2.3 過采樣用軟件換精度的有效手段如果你的MCU自帶的ADC只有12位但儀器需要14位以上的分辨率可以通過過采樣加均值來實(shí)現(xiàn)。原理是白噪聲是隨機(jī)分布的采樣四次平均信噪比能提升約3dB對(duì)應(yīng)約0.5位有效精度。每多采樣4倍并取平均就能多獲得約0.5位的有效分辨率。想從12位提升到14位理論上需要過采樣4^216倍也就是每個(gè)輸出數(shù)據(jù)點(diǎn)要采16次。但要注意這個(gè)方法只對(duì)高斯白噪聲有效如果噪聲里有固定頻率的干擾比如50Hz工頻你過采樣多少次都消不掉。遇到這種問題正確的做法是先在信號(hào)鏈里做好工頻陷波或者采用相關(guān)的數(shù)字濾波算法。我一般習(xí)慣在過采樣之后加一個(gè)滑動(dòng)平均或者IIR濾波效果比單純過采樣好很多。3. 核心固件架構(gòu)保證實(shí)時(shí)性又不丟數(shù)據(jù)3.1 DMA雙緩沖是數(shù)據(jù)采集的基本盤做儀器類固件最忌諱的就是在中斷里用阻塞方式讀ADC數(shù)據(jù)。如果你采樣的速率是100kHz每10微秒來一次中斷你在中斷里做幾行除法都可能超時(shí)更別提還要做濾波、存儲(chǔ)、通信。我在項(xiàng)目里一律采用DMA雙緩沖模式。這個(gè)模式的思路是ADC轉(zhuǎn)換完成后由DMA自動(dòng)把結(jié)果搬運(yùn)到內(nèi)存緩沖區(qū)不需要CPU介入。當(dāng)緩沖A填滿時(shí)DMA自動(dòng)切換到緩沖B繼續(xù)填充同時(shí)觸發(fā)中斷通知CPU去處理緩沖A里的數(shù)據(jù)。這樣CPU處理數(shù)據(jù)和DMA采集數(shù)據(jù)完全并行不會(huì)互相拖累。關(guān)鍵配置是DMA的中斷優(yōu)先級(jí)要高于普通外設(shè)中斷且緩沖區(qū)的內(nèi)存要放在SRAM且對(duì)齊到緩存行Cortex-M7如果開了D-Cache這一步尤其重要否則會(huì)出現(xiàn)緩存一致性問題。STM32H7在開啟D-Cache的情況下DMA寫入的數(shù)據(jù)不會(huì)馬上被CPU看到必須在DMA傳輸完成中斷里做SCB_InvalidateDCache_by_Addr操作否則你讀到的還是舊數(shù)據(jù)。3.2 用狀態(tài)機(jī)而不是RTOS處理多任務(wù)儀器固件通常需要同時(shí)處理采樣、UI刷新、通信、按鍵掃描等任務(wù)。很多人第一反應(yīng)是引入RTOS比如FreeRTOS。但以我的經(jīng)驗(yàn)除非你的系統(tǒng)真的需要嚴(yán)格的多線程調(diào)度和任務(wù)間通信否則裸機(jī)狀態(tài)機(jī)是更穩(wěn)的選擇。原因也很簡單RTOS的調(diào)度延遲和上下文切換開銷雖然不大但在高精度采樣場(chǎng)景下你很難保證某個(gè)關(guān)鍵任務(wù)能精確地在某個(gè)時(shí)刻被執(zhí)行。狀態(tài)機(jī)把所有任務(wù)拆成有限狀態(tài)配合定時(shí)器輪詢和中斷優(yōu)先級(jí)管理執(zhí)行時(shí)序是完全確定的排錯(cuò)也容易。我常用的架構(gòu)是這樣SysTick產(chǎn)生1ms時(shí)基作為主循環(huán)心跳ADC和DMA在后臺(tái)持續(xù)運(yùn)行。主循環(huán)里跑狀態(tài)機(jī)狀態(tài)A處理按鍵掃描和菜單邏輯狀態(tài)B處理實(shí)時(shí)數(shù)據(jù)緩存和顯示刷新狀態(tài)C處理通信協(xié)議解析。每個(gè)狀態(tài)的執(zhí)行時(shí)間被嚴(yán)格控制在1ms以內(nèi)跑完一圈回到起點(diǎn)。3.3 測(cè)量算法濾波、校準(zhǔn)與線性化現(xiàn)實(shí)世界的傳感器幾乎沒有完美線性的。做儀器必須要有校準(zhǔn)和線性化這一步。我的做法是出廠前用標(biāo)準(zhǔn)源做多點(diǎn)校準(zhǔn)在每個(gè)校準(zhǔn)點(diǎn)記錄ADC原始值和實(shí)際物理量然后擬合成多項(xiàng)式或查表。運(yùn)行時(shí)把ADC值代入校正算法就能得到比原始量程精度高得多的結(jié)果。以熱電偶為例溫度與電壓的關(guān)系是分度表直接查表會(huì)更準(zhǔn)。此時(shí)MCU里要存一個(gè)斷點(diǎn)分度表用線性插值計(jì)算中間值。這個(gè)查表插值的過程對(duì)MCU來說代價(jià)很低但能把精度從單純查表的1°C提升到0.1°C以內(nèi)。4. 開發(fā)環(huán)境實(shí)操VS Code下完成從零到下載調(diào)試4.1 搭建cortex-m系列通用開發(fā)環(huán)境不管你用的是ST、TI還是普冉只要是Cortex-M系列內(nèi)核開發(fā)環(huán)境的搭建思路基本是相通的。我目前主力用VS Code加四條工具鏈arm-none-eabi-gcc編譯器、OpenOCD調(diào)試器、Cortex-Debug插件、Makefile或CMake構(gòu)建系統(tǒng)。這套組合免費(fèi)、跨平臺(tái)而且比某些廠商自己的IDE更輕量。安裝流程大概是先裝VS Code和插件然后裝ARM GCC工具鏈最后裝OpenOCD。以普冉MCU為例調(diào)試器可以用DAPLink或者J-Link在launch.json里指定device類型和接口速度就行。我踩過的坑是OpenOCD默認(rèn)的CMSIS-DAP配置文件有時(shí)會(huì)對(duì)特定MCU報(bào)錯(cuò)需要根據(jù)芯片的Flash大小和RAM起始地址手動(dòng)調(diào)整。另外普冉的某些型號(hào)默認(rèn)代碼讀保護(hù)是開啟的第一次連接前就要注意否則可能直接把芯片鎖死。真鎖死了也別慌運(yùn)氣好在boot引腳拉低后擦除全片就能救回來。4.2 構(gòu)建腳本里的兩個(gè)關(guān)鍵點(diǎn)編寫Makefile時(shí)要特別注意鏈接腳本.ld文件。MCU的內(nèi)部Flash和RAM地址必須和手冊(cè)嚴(yán)格對(duì)應(yīng)這個(gè)不對(duì)的話代碼燒進(jìn)去要么跑不起來要么直接進(jìn)HardFault。另外一個(gè)關(guān)鍵是-specsnano.specs和-u _printf_float的處理如果要用printf打印浮點(diǎn)數(shù)必須把float打印功能鏈接進(jìn)來否則串口輸出全是亂碼或者直接不輸出。但鏈接了浮點(diǎn)打印固件體積會(huì)增大幾十KB對(duì)Flash緊張的小容量MCU來說要慎重。4.3 在線調(diào)試時(shí)的實(shí)用觀察手法真正調(diào)試儀器算法時(shí)我很少單步執(zhí)行更多是用實(shí)時(shí)變量監(jiān)視和波形圖。Cortex-Debug插件支持SWO引腳輸出可以把printf重定向到一個(gè)單獨(dú)的調(diào)試通道不占用串口。這個(gè)功能在調(diào)試實(shí)時(shí)控制算法時(shí)真的很好用因?yàn)樗粫?huì)因?yàn)檎{(diào)試而影響程序運(yùn)行時(shí)序。配置方法是在啟動(dòng)文件里初始化SWO然后在代碼里用ITM_SendChar輸出調(diào)試信息。5. 儀器通信接口設(shè)計(jì)讓數(shù)據(jù)更穩(wěn)定地上位5.1 MCU串口接收端口是否需要上拉這個(gè)問題在網(wǎng)上被問得非常多原因是不同教程給出了相反的答案。關(guān)于MCU串口接收端RX是否需要上拉核心要看空閑狀態(tài)時(shí)的電平是否確定。UART協(xié)議規(guī)定總線在空閑時(shí)必須保持高電平這樣起始位的下降沿才能被識(shí)別。如果你的RX引腳懸空且內(nèi)部沒有上拉那空閑狀態(tài)的電平就會(huì)處于不定區(qū)很容易產(chǎn)生誤中斷和雜波。大部分MCU的USART模塊在啟用時(shí)RX引腳的內(nèi)部上拉會(huì)默認(rèn)開啟但內(nèi)部上拉電阻通常在30-50kΩ對(duì)于高速通信或長走線來說效果有限。我的建議是如果板內(nèi)走線短使用內(nèi)部上拉就夠了如果有外部連接器或線纜尤其超過10cm的最好在RX到GND之間加一個(gè)10kΩ外部上拉電阻。這一點(diǎn)在連接無人機(jī)接收機(jī)這類PWM轉(zhuǎn)串口設(shè)備時(shí)尤其重要因?yàn)樗鼈兊男盘?hào)是單向的很多模塊并不會(huì)主動(dòng)拉高TX空閑電平。5.2 儀器通信的精髓命令幀設(shè)計(jì)給儀器設(shè)計(jì)一個(gè)健壯的通信協(xié)議核心就是把“數(shù)據(jù)怎么打包”和“數(shù)據(jù)怎么解析”這兩件事標(biāo)準(zhǔn)化。我常用的幀格式是幀頭0xAA 0x55 設(shè)備地址 命令字 數(shù)據(jù)長度 數(shù)據(jù)部分 CRC校驗(yàn)。CRC校驗(yàn)這一項(xiàng)千萬不能省。很多人在初期聯(lián)調(diào)時(shí)覺得加CRC麻煩但一旦通信鏈路受到干擾數(shù)據(jù)錯(cuò)一個(gè)字節(jié)你得到的測(cè)量結(jié)果可能錯(cuò)得離譜而且極難排查。算CRC16的代價(jià)非常低幾微秒就夠但能幫你過濾掉幾乎所有偶發(fā)錯(cuò)誤。解析時(shí)要注意幀超時(shí)處理收到字節(jié)后如果連續(xù)超過xxx毫秒沒接收完整就丟棄當(dāng)前幀重新開始。避免長時(shí)間停在等待狀態(tài)。5.3 高速數(shù)據(jù)上傳的緩沖策略儀器的采樣率做高了以后串口就成了瓶頸。比如你以100kHz采樣每個(gè)點(diǎn)20字節(jié)那一秒鐘就是2MB這早就超過普通串口115200bps的能力了。我一般用USB虛擬串口或者以太網(wǎng)STM32H7自帶的USB HS加外部PHY可以做到幾十Mbps幾乎不占CPU。但USB還有個(gè)麻煩就是它的事務(wù)是以包為單位的你必須在固件里做好流控設(shè)置好合適的緩沖區(qū)不然很容易丟數(shù)據(jù)。6. 實(shí)戰(zhàn)案例從零做一臺(tái)簡易LCR表6.1 信號(hào)源和鑒相電路怎么配合拿一個(gè)我做過的迷你LCR表來說核心思路和理論說一遍。LCR表要測(cè)的是待測(cè)元件的阻抗和相位角方法是用DDS產(chǎn)生一個(gè)固定頻率的正弦波激勵(lì)經(jīng)過待測(cè)器件后用ADC采集電壓和電流信號(hào)再在MCU里做數(shù)字鑒相算出實(shí)部和虛部得到電阻、電容或電感值。這里有個(gè)關(guān)鍵點(diǎn)為了測(cè)出相位ADC必須對(duì)輸入信號(hào)和參考信號(hào)同步采樣。我在硬件上用的是兩路同步采樣ADC一路采激勵(lì)源的參考電壓一路采通過待測(cè)件的電流。如果在同一個(gè)MCU內(nèi)做這件事要注意兩路ADC觸發(fā)時(shí)序的同步否則相位就有固定的系統(tǒng)誤差。6.2 FFT頻域分析在MCU上的可行性很多人一聽到FFT就覺得MCU做不了。實(shí)際上做256點(diǎn)FFT在STM32H7這種帶FPU的芯片上耗時(shí)大約在幾百微秒到1毫秒之間完全可以在1kHz-10kHz激勵(lì)頻率下實(shí)時(shí)運(yùn)行。關(guān)鍵是選用Cortex-M4/M7內(nèi)核或帶DSP指令集對(duì)FFT的蝶形運(yùn)算會(huì)有明顯加速。如果你需要做更高分辨率的頻譜分析可以把FFT放在上位機(jī)做MCU只負(fù)責(zé)原始數(shù)據(jù)采集和傳輸。6.3 校準(zhǔn)數(shù)據(jù)的存儲(chǔ)與管理每次上電開機(jī)儀器都需要把校準(zhǔn)參數(shù)從Flash加載到RAM里關(guān)機(jī)時(shí)再保存回去。這里最怕的就是頻繁擦寫Flash廠家給的Flash擦寫壽命一般在1萬到10萬次之間。所以一定要把校準(zhǔn)參數(shù)的存儲(chǔ)分成多區(qū)輪轉(zhuǎn)寫入每次只寫一個(gè)區(qū)寫滿才擦除。我一般用一個(gè)簡單的計(jì)數(shù)器做輪轉(zhuǎn)這樣即使每天校準(zhǔn)10次也能用上好幾年。7. 常見問題與排查技巧實(shí)錄7.1 采樣數(shù)據(jù)跳變既不是噪聲也不是代碼問題有一次我做一塊四通道數(shù)據(jù)采集卡測(cè)量一通道正常二通道偶爾跳變幾十個(gè)數(shù)。排查思路我整理成了一張問題排查參考表現(xiàn)象可能原因排查方向單一通道數(shù)值跳變采樣引腳虛焊或受到數(shù)字信號(hào)串?dāng)_檢查PCB布線引腳加100pF濾波電容所有通道共模跳變參考電壓不穩(wěn)定用示波器看VREF波形檢查基準(zhǔn)源輸出隨輸入電壓增大跳變?cè)矫黠@運(yùn)放接近輸出軌或超出線性區(qū)檢查運(yùn)放輸出是否超過規(guī)格偶發(fā)大量錯(cuò)誤數(shù)據(jù)DMA緩沖區(qū)越界或指針錯(cuò)亂檢查DMA中斷處理時(shí)序增加環(huán)形緩沖保護(hù)那次最終發(fā)現(xiàn)是第二通道的數(shù)字地回流路徑被一條高速SPI線截?cái)喔蓴_耦合進(jìn)了模擬輸入。解決辦法是把SPI的IO改到另一組引腳把模擬部分的地平面完整鋪通就好了。這種問題用代碼是排查不出來的必須對(duì)PCB布局做檢查。另外ADC結(jié)果寄存器的數(shù)據(jù)對(duì)齊問題也容易踩坑。不同MCU的ADC結(jié)果寄存器數(shù)據(jù)對(duì)齊方式不一樣左對(duì)齊和右對(duì)齊相差很大如果你只讀了高字節(jié)可能得到的結(jié)果是真實(shí)值的256倍。初始化的時(shí)候要認(rèn)真看手冊(cè)這是很多新手最常碰到的bug之一。7.2 中斷搶占導(dǎo)致實(shí)時(shí)控制偶爾抖一下實(shí)時(shí)控制系統(tǒng)最怕的是一切正常但偶爾出現(xiàn)一次控制量突變。這塊我在做FOC驅(qū)動(dòng)時(shí)遇到過一次找了很久才發(fā)現(xiàn)是UART發(fā)送中斷和定時(shí)器中斷發(fā)生了競(jìng)爭。UART一次發(fā)送一個(gè)字節(jié)發(fā)送完成中斷如果優(yōu)先級(jí)高于定時(shí)器中斷它就可能打斷正在執(zhí)行的電流環(huán)導(dǎo)致控制周期被拉長或者抖動(dòng)。解決方法一個(gè)是把定時(shí)器中斷優(yōu)先級(jí)設(shè)為最高UART中斷降低讓控制環(huán)始終優(yōu)先執(zhí)行。另一個(gè)更徹底的辦法是UART發(fā)送改成DMA方式發(fā)送數(shù)據(jù)根本不進(jìn)入CPU中斷徹底杜絕搶占問題。7.3 程序跑飛后不能自動(dòng)恢復(fù)有些儀器需要長時(shí)間無人值守運(yùn)行比如溫濕度記錄儀一旦程序卡死就會(huì)導(dǎo)致數(shù)據(jù)斷檔。這種場(chǎng)景建議開啟獨(dú)立看門狗IWDG在主循環(huán)里按要求周期地喂狗。但要注意看門狗超時(shí)時(shí)間必須大于所有中斷處理的最壞情況耗時(shí)否則系統(tǒng)在正常滿載工作時(shí)可能被誤復(fù)位。我一般取超時(shí)時(shí)間500ms到2s并在停機(jī)前用RTC保存現(xiàn)場(chǎng)狀態(tài)方便復(fù)位后快速恢復(fù)工作狀態(tài)。8. 真實(shí)分享儀器類MCU項(xiàng)目的幾條心得體會(huì)做MCU儀器和做普通消費(fèi)電子最大的不同就在于“測(cè)量鏈路”的存在。消費(fèi)電子你只要把功能跑通就完事儀器項(xiàng)目你得花一大半時(shí)間在精度、穩(wěn)定性、校準(zhǔn)和驗(yàn)證上。很多細(xì)節(jié)是我反復(fù)踩坑后才體會(huì)到的我挑幾條最直觀的和大家分享。第一永遠(yuǎn)不要相信首次上電就是這么準(zhǔn)的。任何儀器項(xiàng)目都要預(yù)留校準(zhǔn)環(huán)節(jié)軟件里做一個(gè)校準(zhǔn)模式硬件上預(yù)留標(biāo)準(zhǔn)源的接口。這樣量產(chǎn)或現(xiàn)場(chǎng)部署時(shí)才能把個(gè)體差異的誤差消掉。第二示波器是調(diào)試工具不是測(cè)量標(biāo)準(zhǔn)。我見過很多人在調(diào)試時(shí)直接拿示波器的“測(cè)量”功能當(dāng)作可信的精度參考其實(shí)示波器的ADC只有8-12位用來做精度基準(zhǔn)完全不夠。真正驗(yàn)證精度要購買或借用一個(gè)更高精度的標(biāo)準(zhǔn)源或者校準(zhǔn)過的萬用表作為參考。第三儀器的“手感”很重要。同樣是數(shù)據(jù)刷新的界面采樣后延遲50ms展示和實(shí)時(shí)展示使用者的主觀體驗(yàn)差別巨大。做儀器固件的時(shí)候不要為了省電把刷新率壓的太狠要時(shí)刻關(guān)注從物理量變化到屏幕顯示出數(shù)值的總延遲時(shí)間。再一點(diǎn)經(jīng)驗(yàn)如果你要在多個(gè)項(xiàng)目里復(fù)用代碼我建議把所有儀器相關(guān)模塊ADC采集、DMA緩沖、濾波算法、協(xié)議解析獨(dú)立成純C庫把硬件相關(guān)部分通過函數(shù)指針注入。這樣你從STM32換到普冉或者TI平臺(tái)時(shí)應(yīng)用層代碼幾乎不用改只需要適配BSP層。我現(xiàn)在的項(xiàng)目基本都是這種結(jié)構(gòu)新平臺(tái)的開發(fā)周期可以從兩個(gè)月壓縮到三周。做儀器類MCU開發(fā)最難的不是某個(gè)算法或多高的性能而是把精度、實(shí)時(shí)性、穩(wěn)定性、易用性這四個(gè)互相沖突的訴求壓在一個(gè)小芯片上做平衡。希望這篇長文能讓你少走一些彎路尤其是那些只會(huì)在真實(shí)項(xiàng)目中暴露出來的細(xì)節(jié)和坑。后續(xù)如果有機(jī)會(huì)我還會(huì)單獨(dú)寫一篇關(guān)于儀器固件測(cè)試驗(yàn)證方法的文章講講怎么用自動(dòng)化腳本把長時(shí)間穩(wěn)定性測(cè)試做扎實(shí)。