字溫度模塊,實現(xiàn)本地與遠(yuǎn)程溫度監(jiān)測系統(tǒng))
1. 方案思路與器件分工為什么是 PIC24 配一體式溫度模塊1.1 先別急著選型把需求拆清楚再動手我這邊的項目背景是給一套 HVAC 集中控制系統(tǒng)做溫度監(jiān)測節(jié)點的升級。原來的方案是每個溫度點用 NTC 熱敏電阻 運放調(diào)理 ADC 采樣主控用的是 8 位單片機PCB 上一堆分壓電阻、濾波電容生產(chǎn)校準(zhǔn)還要逐臺調(diào)零。隨著監(jiān)測點位從十幾路增加到五十幾路遠(yuǎn)程點位也要接入老方案的痛點就非常明顯了布線難、誤差大、維護靠人工抄表。所以這次項目立項的時候我定的硬性指標(biāo)是支持本地溫度采集至少兩路用于 PID 調(diào)節(jié)和報警聯(lián)動。支持遠(yuǎn)程溫度采集通過總線方式接入節(jié)點數(shù)不低于 30 個??刂坪诵墓囊吞貏e是待機模式下系統(tǒng)不能長時間滿載運行。通信協(xié)議盡量標(biāo)準(zhǔn)化方便上位機對接不搞私有協(xié)議全家桶。主控要有足夠的代碼空間和 RAM后續(xù)要擴展數(shù)據(jù)記錄功能?;谶@些需求我最終選了PIC24FV16KA301做主控搭配PJ85718DM作為溫度前端模塊。這一組合的核心思路是把“測溫度”這件事從前端電路徹底剝離出去主控只負(fù)責(zé)讀取數(shù)字量、做邏輯、跑協(xié)議不碰模擬電路省掉標(biāo)定環(huán)節(jié)也大幅降低了硬件調(diào)試難度。1.2 PIC24FV16KA301 到底贏在哪里先聊聊主控選型。HVAC 場景和消費電子不一樣設(shè)備常年 7×24 小時掛在墻面上或者機柜里控制板空間緊湊很多情況下沒有風(fēng)扇、沒有密封防護等級高的外殼所以我對主控有幾個硬性要求供電電壓要寬3.3V 是主流但系統(tǒng)里可能還有電池后備供電。靜態(tài)功耗要低休眠時最好能到微安級。外設(shè)要夠用至少兩路 UART、一路 I2C/SPI、若干 ADC 通道。引腳不能太多封裝小方便塞進(jìn)現(xiàn)有控制板結(jié)構(gòu)。PIC24FV16KA301 屬于 PIC24F 系列的 XLP 超低功耗型號VDD 范圍 1.8V 到 3.6V深度睡眠模式電流可以做到幾百納安級別。它內(nèi)部有 16 KB Flash 和 1.5 KB RAM寫小型協(xié)議棧和溫度采集調(diào)度邏輯完全夠用。更重要的是它的外設(shè)映射Peripheral Pin Select非常靈活UART、I2C、定時器這些模塊可以映射到不同引腳上這給 PCB 布線省了極大的力氣。從成本角度看這顆芯片不算貴而且 16 位內(nèi)核相比 8 位機做 Modbus RTU 的 CRC 運算也輕松很多。我在調(diào)試階段甚至直接開著調(diào)試器跑輪詢循環(huán)單步跟蹤時序沒有出現(xiàn) 8 位機那種中斷優(yōu)先級互相打架的問題。1.3 PJ85718DM 模塊的角色定位把溫度檢測變成讀寄存器PJ85718DM 這個模塊我拿到的是數(shù)字輸出型內(nèi)部集成了溫度傳感元件、信號調(diào)理、ADC 和數(shù)字通信接口。對外輸出直接就是溫度數(shù)據(jù)不需要額外做冷端補償或者查分度表。這就相當(dāng)于把以前一整套模擬前端全部封裝進(jìn)了一個小模塊主控通過 I2C 或者單總線讀取寄存器拿到的是已經(jīng)換算好的數(shù)據(jù)單位是 0.1℃ 或 0.01℃ 之類。實際項目中我用了兩種接法本地溫度模塊直接焊接在主板上通過 I2C 接到 PIC24 的 I2C1 外設(shè)用于采集送風(fēng)溫度、回水溫度。遠(yuǎn)程溫度使用同型號模塊通過一根三芯屏蔽線引出接到遠(yuǎn)程風(fēng)機盤管或者冷梁末端模塊工作在單總線模式下通過地址尋址掛到同一根總線上。這種“本地 I2C 遠(yuǎn)程單總線”的雙模式設(shè)計是參照了模塊手冊里給出的典型應(yīng)用圖。實測下來效果不錯因為本地數(shù)據(jù)要進(jìn) PID 調(diào)節(jié)刷新率要求高I2C 的時鐘可以跑到 400 kbps而遠(yuǎn)程節(jié)點數(shù)量多單總線只需要一根數(shù)據(jù)線走線成本低輪詢幾十個點也夠用。注意如果你用的溫度模塊是模擬輸出類型那主控選型就得另外考慮 ADC 通道和基準(zhǔn)電壓的問題。我這里說的 PJ85718DM 是數(shù)字輸出模組整個方案的接線和驅(qū)動代碼都是按數(shù)字接口寫的。2. 硬件設(shè)計與接線細(xì)節(jié)本地測溫、遠(yuǎn)程總線、電源與電平匹配2.1 主控最小系統(tǒng)不要忽略去耦和調(diào)試接口PIC24FV16KA301 最小系統(tǒng)不算復(fù)雜但每個引腳都不能想當(dāng)然。我這次畫板子的時候總結(jié)了幾個關(guān)鍵點供電部分3.3V LDO 輸出端要并聯(lián) 10 μF 鉭電容和 100 nF 陶瓷電容LDO 輸入端的 5V 電源也要先經(jīng)過一個磁珠隔離開關(guān)電源的高頻噪聲。HVAC 現(xiàn)場經(jīng)常有大功率變頻設(shè)備電源線上如果不處理溫度采樣的數(shù)據(jù)會明顯跳動。復(fù)位電路用 MCLR 引腳外接 10 kΩ 上拉電阻和 100 nF 電容到地。有些工程師圖省事直接把 MCLR 接 VDD但后期如果要用 ICSP 調(diào)試就會發(fā)現(xiàn)連接不上還得飛線。ICSP 調(diào)試接口一定要留出 5 針或 6 針的排針接口我見過太多次“焊完板子發(fā)現(xiàn)沒法燒錄”的場面。引腳順序固定好另外串聯(lián) 100 Ω 電阻可以避免調(diào)試線過長導(dǎo)致信號振鈴。晶振選擇系統(tǒng)時鐘我用內(nèi)部 FRC 振蕩器配合 PLL 倍頻到 8 MHz做 Modbus 輪詢和 I2C 時序足夠了。休眠喚醒用 32.768 kHz 外部晶振接到 SOSCI 和 SOSCO這樣深度睡眠喚醒后的時鐘切換比較平滑。如果項目對時間戳有要求這枚晶振還可以給 RTCC 模塊用實現(xiàn)掉電后的日期時間保持。2.2 PJ85718DM 本地接法上拉電阻、濾波電容與線長限制本地模塊我放在主控旁邊間距控制在 20 mm 以內(nèi)走線盡量短減少天線效應(yīng)。I2C 接口的上拉電阻我用了 4.7 kΩ對于 400 kbps 的總線速率來說是標(biāo)準(zhǔn)值。如果總線距離超過 50 cm建議改成 2.2 kΩ 或者降低速率到 100 kbps否則上升沿太緩數(shù)據(jù)容易錯位。電源引腳上必須放 100 nF 去耦電容位置越靠近模塊的 VDD 引腳越好。有些模塊內(nèi)部有線性穩(wěn)壓器電源軌對紋波并不敏感但去耦電容不能省畢竟現(xiàn)場可能有靜電放電和浪涌干擾。還有一個細(xì)節(jié)模塊的 AD0/AD1 地址引腳我直接做了跳線焊盤默認(rèn)接地通過 0 Ω 電阻選擇。這樣同一塊主板上如果需要掛兩個本地模塊可以改地址不用改 PCB。踩坑提示我第一次畫板子的時候把模塊地址引腳懸空了結(jié)果兩個模塊地址沖突I2C 總線直接鎖死主控讀到的全是 0xFF。這種問題在實驗室里不容易復(fù)現(xiàn)但是一接入總線就隨機出現(xiàn)。所以地址引腳要么接固定電平要么用排針跳線絕不能懸空。2.3 遠(yuǎn)程溫度總線設(shè)計單總線怎么挑線、怎么并接遠(yuǎn)程溫度節(jié)點我采用的是單總線拓?fù)?。一主多從所有模塊的數(shù)據(jù)線并接在一起通過一根線串聯(lián)所有節(jié)點。主干線我用的是 RVSP 屏蔽雙絞線其中一對線作為電源和數(shù)據(jù)返回屏蔽層單端接地接在主控的電源地。這里有幾個參數(shù)要記好單總線典型速率在 15.4 kbps 左右理論上可以支持較長的線長。建議節(jié)點數(shù)不超過 32 個距離控制在 100 米以內(nèi)超過就要考慮中繼器。每個節(jié)點在數(shù)據(jù)線上需要加一個 4.7 kΩ 上拉電阻到本地 3.3V這樣保證在空閑狀態(tài)數(shù)據(jù)線被穩(wěn)定拉高。數(shù)據(jù)線上的寄生電容是最大的敵人。每米雙絞線大約有 50~60 pF 的分布電容50 米線就有 3 nF 左右拉著這根線信號上升沿會變慢。所以遠(yuǎn)端節(jié)點的上拉電阻可以適當(dāng)減小到 2.2 kΩ但注意不要低于 1 kΩ否則總線上灌電流太大模塊輸出級可能會過載。實際調(diào)試的時候我在主控端的數(shù)據(jù)線上串聯(lián)了一個 100 Ω 電阻這能有效抑制反射。對于單總線來說線的末端不建議并聯(lián) 120 Ω 終端匹配因為沒有規(guī)定特征阻抗加了反而增加直流負(fù)載。2.4 RS-485 遠(yuǎn)程通信鏈路選收發(fā)器、處理方向控制既然標(biāo)題里說“本地與遠(yuǎn)程”遠(yuǎn)程點位采集回來后還要上報給上位機。這部分我用的是 RS-485 總線主控的 UART1 連接到一顆半雙工 RS-485 收發(fā)器通過 DE/RE 引腳控制發(fā)送和接收方向。選型上我用了帶失效保護的收發(fā)器型號不唯一只要滿足以下條件即可支持 3.3V 供電這樣不用額外做電平轉(zhuǎn)換。驅(qū)動器輸出帶限流短路不損壞。接收器帶失效保護總線開路或短路時輸出為確定高電平避免收到隨機噪聲。方向控制這里有個容易犯的錯誤DE 和 RE 如果分別用兩個引腳控制固件里必須保證先切換方向再操作 UART。我這邊偷了個懶把 DE 和 RE 短接在一起用一根 I/O 控制高電平發(fā)送、低電平接收雖然犧牲了一點靈活性但穩(wěn)定可靠。A、B 輸出端各串一個 10 Ω 電阻防止現(xiàn)場浪涌打壞芯片??偩€兩端各接一個 120 Ω 終端電阻這個不能省長線反射會直接導(dǎo)致 CRC 錯誤率飆升。3. 軟件架構(gòu)與核心代碼實現(xiàn)輪詢、協(xié)議棧與低功耗調(diào)度3.1 主程序的循環(huán)思路一個狀態(tài)機搞定本地和遠(yuǎn)程整個固件我是用狀態(tài)機寫的主循環(huán)不斷輪詢事件標(biāo)志位所有耗時操作都拆到中斷里完成保證溫度刷新率和通信響應(yīng)速度。先看整體結(jié)構(gòu)#define LOCAL_SAMPLE_INTERVAL_MS 200 #define REMOTE_POLL_INTERVAL_MS 1000 #define DEFAULT_MODBUS_ADDR 0x01 #define LOCAL_SENSOR_ADDR 0x50 typedef enum { EVT_NONE 0, EVT_LOCAL_SAMPLE, EVT_REMOTE_POLL, EVT_MODBUS_RX, EVT_UART_TX_DONE, } event_t; volatile event_t evtFlag; uint16_t localTemp; // 本地溫度單位 0.1℃ uint16_t remoteTemp[32]; // 遠(yuǎn)程溫度數(shù)組 uint8_t remoteCnt; // 有效的遠(yuǎn)程節(jié)點數(shù)事件標(biāo)志在定時器中斷或者 UART 接收中斷里置位主循環(huán)里統(tǒng)一處理。這樣做的好處是邏輯清晰不會出現(xiàn)“在中斷里跑協(xié)議棧導(dǎo)致時序亂掉”的情況。主循環(huán)大致如下while (1) { if (evtFlag EVT_LOCAL_SAMPLE) { evtFlag ~EVT_LOCAL_SAMPLE; readLocalSensor(); } if (evtFlag EVT_REMOTE_POLL) { evtFlag ~EVT_REMOTE_POLL; pollRemoteNodes(); } if (evtFlag EVT_MODBUS_RX) { evtFlag ~EVT_MODBUS_RX; parseModbusFrame(); } }3.2 讀取 PJ85718DM 溫度I2C 時序與數(shù)據(jù)轉(zhuǎn)換讀取本地傳感器時我走的是 I2C 接口。模塊內(nèi)部有若干 8 位寄存器溫度數(shù)據(jù)是 16 位補碼形式地址指針會自動遞增。我每次連續(xù)讀 2 個字節(jié)組合成一個 uint16_t。關(guān)鍵代碼片段uint8_t i2cReadReg(uint8_t devAddr, uint8_t regAddr, uint8_t *buf, uint8_t len) { // 發(fā)送起始條件 設(shè)備地址寫方向 寄存器地址 I2C1CONbits.SEN 1; while (I2C1CONbits.SEN); I2C1TRN (devAddr 1) | 0; while (!I2C1STATbits.TRSTAT); if (I2C1STATbits.ACKSTAT) { I2C1CONbits.PEN 1; return 1; } I2C1TRN regAddr; while (!I2C1STATbits.TRSTAT); if (I2C1STATbits.ACKSTAT) { I2C1CONbits.PEN 1; return 1; } // 重復(fù)起始 設(shè)備地址讀方向 I2C1CONbits.RSEN 1; while (I2C1CONbits.RSEN); I2C1TRN (devAddr 1) | 1; while (!I2C1STATbits.TRSTAT); if (I2C1STATbits.ACKSTAT) { I2C1CONbits.PEN 1; return 1; } for (uint8_t i 0; i len; i) { I2C1CONbits.RCEN 1; while (!I2C1STATbits.RBF); buf[i] I2C1RCV; if (i len - 1) { I2C1CONbits.ACKDT 0; // ACK } else { I2C1CONbits.ACKDT 1; // NACK } I2C1CONbits.ACKEN 1; while (I2C1CONbits.ACKEN); } I2C1CONbits.PEN 1; while (I2C1CONbits.PEN); return 0; }溫度換算很簡單模塊手冊里給了公式我直接照搬int16_t raw (int16_t)((buf[0] 8) | buf[1]); temperatureC raw * 0.01f;如果模塊精度是 0.1℃就乘 0.1如果是 0.01℃就乘 0.01。我這里明確一點不要憑感覺猜必須翻手冊確定分辨率。本地采樣我做了軟件滑動平均取最近 5 次讀數(shù)的平均值輸出給 PID 模塊。因為 HVAC 現(xiàn)場有氣流擾動瞬時值波動很大但 5 次平均后溫度曲線平滑多了同時延遲也只有 1 秒左右完全不影響調(diào)節(jié)響應(yīng)。3.3 遠(yuǎn)程節(jié)點輪詢單總線協(xié)議的精確時序單總線的難點在于時序要求苛刻讀寫時隙都是微秒級的。PIC24FV16KA301 跑 8 MHz 的時候一個指令周期是 500 ns用來計時隙剛剛好。我用的是查詢方式不進(jìn)中斷避免時序被中斷破壞。單總線協(xié)議的時序我記得大概是這樣的參考常見協(xié)議實現(xiàn)復(fù)位脈沖總線拉低 480 μs 然后釋放。存在檢測從設(shè)備在釋放后拉低 60~240 μs。寫 0 時隙拉低 60 μs。寫 1 時隙拉低 1~15 μs然后釋放。讀時隙拉低 1~15 μs釋放后采樣數(shù)據(jù)線。代碼里我封裝了一個 delayMicro 函數(shù)用定時器做基準(zhǔn)保證延時準(zhǔn)確。注意在單總線上操作必須關(guān)閉中斷仲裁就是別讓 I2C 或者其他外設(shè)來打斷這微秒級的時序。輪詢的邏輯是先發(fā)復(fù)位脈沖找到所有在線節(jié)點然后逐節(jié)點發(fā)送讀取命令。PJ85718DM 的地址是 64 位激光刻錄的通過 ROM 命令匹配。流程大致是復(fù)位。發(fā)送 0x55 匹配命令。發(fā)送 64 位 ROM 地址。發(fā)送 0x44 啟動溫度轉(zhuǎn)換。等待轉(zhuǎn)換完成典型時間是 500 ms。發(fā)送 0xBE 讀取寄存器。遠(yuǎn)程節(jié)點的數(shù)量我做了動態(tài)掃描。系統(tǒng)啟動時廣播復(fù)位命令統(tǒng)計總線上返回的存在脈沖數(shù)量然后逐個嘗試讀取地址存到一個數(shù)組里。這樣后續(xù)輪詢就只訪問實際存在的節(jié)點速度更快。注意單總線的轉(zhuǎn)換時間比較長遠(yuǎn)程節(jié)點不能每個都等轉(zhuǎn)換完成再讀下一個。我的做法是先廣播啟動所有節(jié)點轉(zhuǎn)換等待 750 ms 后再逐個讀取這樣總耗時基本恒定不會隨著節(jié)點數(shù)線性增加。3.4 Modbus RTU 上報協(xié)議主從幀怎么解析和打包遠(yuǎn)程數(shù)據(jù)匯總到主控后主控要作為從機響應(yīng)上位機的請求。我用標(biāo)準(zhǔn) Modbus RTU 功能碼 03讀保持寄存器來上報溫度和狀態(tài)上位機只要支持 Modbus 協(xié)議就能直接接入不需要定制驅(qū)動。幀格式大概是從機地址1 字節(jié)。功能碼1 字節(jié)。起始地址2 字節(jié)。寄存器數(shù)量2 字節(jié)。CRC162 字節(jié)。PIC24 發(fā)送溫度數(shù)據(jù)之前要先把溫度值填充到寄存器映射表里。例如溫度 25.6℃如果單位是 0.1℃存的是 256也就是 0x0100。CRC16 的實現(xiàn)我是查表發(fā)的速度很快uint16_t calcCRC16(uint8_t *buf, uint8_t len) { uint16_t crc 0xFFFF; for (uint8_t i 0; i len; i) { crc ^ buf[i]; for (uint8_t j 0; j 8; j) { if (crc 0x0001) { crc (crc 1) ^ 0xA001; } else { crc 1; } } } return crc; }收到上位機幀之后我先解析地址確認(rèn)是本機地址再校驗 CRC最后判斷功能碼和寄存器地址。非法請求直接回異常碼不響應(yīng)會造成上位機長時間等待反而更容易觸發(fā)它那邊的超時重試。3.5 定時器調(diào)度本地快、遠(yuǎn)程慢、Modbus 響應(yīng)快系統(tǒng)的三個關(guān)鍵循環(huán)我設(shè)了不同的周期并不是所有事件都用同樣節(jié)奏任務(wù)周期優(yōu)先級說明本地溫度采樣200 ms高閉環(huán)控制需要不能太慢遠(yuǎn)程溫度輪詢1 s中能效監(jiān)測和報警秒級刷新足夠Modbus 請求解析事件觸發(fā)高上位機等待響應(yīng)越短越好看門狗清狗視需求高死循環(huán)保護必須進(jìn)主循環(huán)TMR1 配置為 1 ms 中斷每 200 個 tick 置位一次本地采樣事件每 1000 個 tick 置位一次遠(yuǎn)程輪詢事件??撮T狗我用了 PIC24 內(nèi)部的 WDT超時周期設(shè)置在 2 秒左右主循環(huán)里每次循環(huán)末尾清狗。如果哪次運行卡死在某個 I2C 等待循環(huán)里WDT 會強制復(fù)位比人工復(fù)位快多了。調(diào)試階段我把 WDT 關(guān)掉了因為單步調(diào)試會被反復(fù)復(fù)位。正式燒錄的時候才打開。這個一定要列到發(fā)布檢查清單里。4. 實操過程與調(diào)優(yōu)記錄從裸板到穩(wěn)定運行的幾個關(guān)鍵節(jié)點4.1 裸板調(diào)試J-Link 用不了MPLAB X 才是正路我拿到樣板后第一步先不焊溫度模塊只焊主控、晶振、電源和 ICSP 接口。先用 MPLAB X IDE 連接 PICkit4確認(rèn)目標(biāo)板能正常識別再燒一個閃爍 LED 的測試程序驗證 GPIO、時鐘和復(fù)位電路都沒問題。這期間我遇到一個很典型的坑晶振死活不起振后來發(fā)現(xiàn)是晶振負(fù)載電容焊錯了方向兩個電容焊成了一樣大的導(dǎo)致振蕩裕量不足。HVAC 控制板常有震動環(huán)境晶振如果起振不穩(wěn)定后期會偶發(fā)復(fù)位很難排查。我最終用了兩個 18 pF 的 NPO 電容布局上盡量靠近晶振引腳。4.2 本地溫度采樣調(diào)試數(shù)據(jù)跳變的三個階段第一階段我把 PJ85718DM 焊到主板上讀取到的數(shù)據(jù)在 24℃ 到 32℃ 之間亂跳明顯不是真實室溫。我先懷疑是天線的干擾于是用示波器量了 I2C 數(shù)據(jù)線發(fā)現(xiàn) SDA 邊沿有明顯的振鈴。解決辦法是降低 I2C 速率到 100 kbps同時把上拉電阻從 4.7 kΩ 換成 2.2 kΩ。這樣處理后信號確實好了很多但溫度依然還有 ±1℃ 的波動。我又去查模塊的電源引腳才發(fā)現(xiàn) 3.3V 上疊加了約 50 mV 的噪聲這是 LDO 后級濾波不足導(dǎo)致的。最后在模塊電源引腳旁邊又加了一顆 4.7 μF 的電容和一個 10 Ω 的串聯(lián)電阻組成低通濾波噪聲降到了 10 mV 以內(nèi)溫度讀數(shù)穩(wěn)定到 ±0.2℃。這個經(jīng)歷給我的啟發(fā)是溫度模塊雖然輸出數(shù)字量但對電源質(zhì)量依然敏感濾波不能省。4.3 單總線遠(yuǎn)程調(diào)試從一根線到三十個節(jié)點的進(jìn)化遠(yuǎn)程節(jié)點我一開始只掛了兩個接了一根十幾米的屏蔽線調(diào)試還算順利。后來擴展到 16 個節(jié)點后輪詢開始出現(xiàn)漏數(shù)據(jù)有的節(jié)點每隔幾輪才響應(yīng)一次有的直接沒有響應(yīng)。排查過程從軟件入手先是懷疑地址沖突逐個驗證 ROM 地址后發(fā)現(xiàn)每個節(jié)點的地址都唯一。接著換了一根質(zhì)量更好的屏蔽雙絞線把屏蔽層在終端做了單端接地問題依然存在。后來翻到模塊手冊發(fā)現(xiàn)單總線的轉(zhuǎn)換電流和電源電流加起來每節(jié)點大約 8 mA16 個節(jié)點就是 128 mA而我的遠(yuǎn)程電源走線用的是長距離細(xì)線線壓降把遠(yuǎn)端節(jié)點的電壓拉低到了 2.9V 左右。解決方法是把遠(yuǎn)程供電改成 5V 傳輸在模塊附近用電容降壓或者穩(wěn)壓到 3.3V。每個節(jié)點前端放一顆 100 μF 的電容做儲能這樣瞬時電流有保障電壓跌落問題就消失了。后面我又?jǐn)U展到 28 個節(jié)點輪詢周期保持在 1.5 秒左右數(shù)據(jù)穩(wěn)定。4.4 功耗實測記錄標(biāo)稱和實際往往差一截PIC24FV16KA301 的低功耗性能不錯但我按照手冊里的參數(shù)估算過一版發(fā)現(xiàn)如果只做數(shù)字采集和 Modbus 從機待機功耗大概可以做到 20 μA 左右。實際上我測到的整板待機電流是 240 μA多出來的部分基本來自 RS-485 收發(fā)器的靜態(tài)功耗、LDO 自身靜態(tài)電流和 PJ85718DM 的空閑電流。如果想要進(jìn)一步壓低待機功耗可以考慮RS-485 收發(fā)器在待機時由 GPIO 控制關(guān)斷電源。溫度模塊進(jìn)入關(guān)斷模式只留 I2C 地址喚醒。LDO 換成低靜態(tài)電流型號。不過 HVAC 系統(tǒng)一般不需要電池供電220V 交流轉(zhuǎn) 5V 再轉(zhuǎn) 3.3V 的架構(gòu)下幾十微安的差異無關(guān)痛癢。如果做電池供電的溫濕度記錄儀這步調(diào)優(yōu)就非常值得了。5. 常見問題與排查技巧現(xiàn)場實錄速查表5.1 溫度讀數(shù)偏高且一直不降典型現(xiàn)象某臺遠(yuǎn)程節(jié)點讀到的溫度恒定在 35℃但現(xiàn)場用紅外測溫槍測只有 28℃。我第一次碰到時差點懷疑傳感器壞了后來把模塊用手捂熱再松開發(fā)現(xiàn)讀數(shù)能變化說明傳感元件正常。問題出在安裝位置模塊被塞進(jìn)了一個密封的接線盒里接線盒被太陽直射局部溫度偏高。解決辦法是把探頭延長出來讓傳感器部分接觸被測介質(zhì)而不是把整個模塊埋在盒子里。5.2 單總線輪詢偶爾丟節(jié)點這類問題要分三步排除第一步查電源電壓遠(yuǎn)端節(jié)點是否低于最小工作電壓。第二步查線纜屏蔽層是否只在單端接地數(shù)據(jù)線是否遠(yuǎn)離動力線。第三步查時序示波器看總線上的復(fù)位脈沖和存在檢測看看波形下沖是否過大。我最終遇到的情況是動力線和信號線走在了同一個線槽里變頻器啟動瞬間數(shù)據(jù)線上出現(xiàn)幾十伏的耦合尖峰導(dǎo)致模塊復(fù)位。物理上把信號線挪到另一個線槽并且數(shù)據(jù)線上并了一個 TVS 管之后問題徹底消失。5.3 Modbus 通信偶發(fā)超時超時的原因百分之五十是接線接觸不良百分之三十是收發(fā)器方向切換太晚百分之二十是波特率偏差。方向切換這里最容易踩坑PIC24 的 UART 發(fā)送完成后如果不等待移位寄存器為空就立刻把 DE 拉低最后幾個字節(jié)會直接被截掉。固件里要用 while 等待 TXIF 和 TRMT 標(biāo)志位然后再切換方向不能只等發(fā)送中斷標(biāo)志。5.4 看門狗頻繁復(fù)位但找不到原因我的經(jīng)驗是先跑一個只閃 LED 的最小程序看是否復(fù)位。不復(fù)位問題出在應(yīng)用程序大概率是某個 while 死等外設(shè)標(biāo)志位。依然復(fù)位硬件問題可能是電源跌落或者強干擾。針對固件建議把所有 I2C 讀寫的等待循環(huán)加上超時判斷比如循環(huán) 1000 次后無條件退出返回錯誤碼。即使出錯也保證了主循環(huán)能流轉(zhuǎn)起來清狗不會餓死。5.5 排查速查表問題現(xiàn)象可能原因處理辦法本地溫度跳變 ±1℃電源紋波太大、I2C 速率過高加強濾波、降速到 100 kbps遠(yuǎn)程節(jié)點響應(yīng)不穩(wěn)定遠(yuǎn)端電壓跌落提高供電電壓、節(jié)點端加儲能電容單總線全部無響應(yīng)數(shù)據(jù)線接反或總線未上拉檢查線序、確認(rèn)上拉電阻Modbus 偶發(fā)超時收發(fā)器方向切換過早等待 TRMT 置位再拉低 DE整板待機電流偏大外設(shè)未進(jìn)入低功耗模式配置模塊掉電模式、關(guān)掉 RS-485 電源讀數(shù)比實際高很多傳感器被局部熱源烘烤延長探頭、避免密封位置6. 我的一點個人體會整套方案從選型到穩(wěn)定運行前前后后花了兩周時間真正卡的環(huán)節(jié)其實不在驅(qū)動代碼而在硬件細(xì)節(jié)。溫度模塊雖然扛起了模擬前端的大頭但供電、總線上拉、屏蔽接地這些外圍工作依然是決定成敗的關(guān)鍵。PIC24FV16KA301 的低功耗特性和靈活引腳映射給了整個設(shè)計很大余量特別是后期因為結(jié)構(gòu)限制改了兩次 PCB 布局引腳映射不用大改省了很多事。如果現(xiàn)在讓我重來一次我會在一開始就把將來可能擴展的功能考慮進(jìn)去比如預(yù)留一路備用 I2C 接口和一路 ADC 輸入不要等現(xiàn)場提出新需求再去飛線。溫度監(jiān)測這類項目最大的成本往往不是元器件而是改板和現(xiàn)場排查。把基礎(chǔ)架構(gòu)做扎實后面加節(jié)點、加協(xié)議都是水到渠成的事。