價電子秤設(shè)計(jì)與標(biāo)定實(shí)戰(zhàn))
1. 項(xiàng)目概述與設(shè)計(jì)思路拆解1.1 這個項(xiàng)目到底在做什么智能計(jì)價電子秤放在嵌入式學(xué)習(xí)路徑里算是一個非常典型的“集合型”項(xiàng)目。它把傳感器采集、模擬信號調(diào)理、ADC轉(zhuǎn)換、數(shù)據(jù)處理、顯示交互、掉電存儲這幾個核心環(huán)節(jié)全部串了起來而且每個環(huán)節(jié)都有真實(shí)物理世界的約束不是那種點(diǎn)幾個LED燈就能交差的demo。用STM32來做控制器選型上完全夠用既不會因?yàn)橘Y源太緊張導(dǎo)致代碼寫起來摳摳搜搜也不會因?yàn)樾酒珡?fù)雜讓新手直接勸退。我見過不少新手一上來就想著搞觸摸屏、搞WiFi、搞云端結(jié)果項(xiàng)目拖了三個月還在調(diào)通信協(xié)議。電子秤這種項(xiàng)目核心需求其實(shí)非常明確稱得準(zhǔn)、算得對、顯示清楚、數(shù)據(jù)不丟。聽起來簡單但真正把精度做到滿足實(shí)際商用場景還是要踩不少坑的。特別是標(biāo)定環(huán)節(jié)很多人覺得傳感器買回來接上線就能用了實(shí)際上HX711模塊的增益、參考電壓、濾波算法、零點(diǎn)漂移每一個都直接影響最終讀數(shù)。這個項(xiàng)目適合誰來看一是準(zhǔn)備做嵌入式相關(guān)畢設(shè)的學(xué)生這套東西從硬件到軟件都有完整閉環(huán)二是想入門傳感器信號處理的開發(fā)者HX711加上應(yīng)變片橋路的組合能把儀表放大器、差分采集、數(shù)字濾波這些概念全部落地三是電子秤這類產(chǎn)品的行業(yè)從業(yè)者想了解具體實(shí)現(xiàn)細(xì)節(jié)的也能在這篇文章里找到一些可復(fù)用的思路。1.2 系統(tǒng)方案選型與關(guān)鍵取舍整個系統(tǒng)的架構(gòu)可以分為四層物理層是稱重平臺和電阻應(yīng)變式傳感器信號層是HX711前端放大和24位ADC處理層是STM32的數(shù)據(jù)濾波和標(biāo)定計(jì)算交互層是LCD顯示和矩陣鍵盤輸入。很多新手會問STM32內(nèi)部明明有ADC為什么還要外掛HX711這個問題非常關(guān)鍵。STM32F103C8T6內(nèi)部的ADC是12位的單量程滿量程下最小分辨率也就是滿量程的1/4096。如果直接采集應(yīng)變橋的輸出信號滿量程輸出電壓通常只有10mV到20mV這個微弱信號不經(jīng)過高倍數(shù)放大根本喂不進(jìn)MCU的ADC。HX711的作用就是把信號放大128倍或者64倍然后通過24位ADC采樣算下來有效分辨率遠(yuǎn)高于直接用MCU內(nèi)部ADC。但要注意HX711的24位是Δ-Σ型ADC的過采樣結(jié)果實(shí)際有效位數(shù)大概在19到21位之間和參考電壓有關(guān)。以最常見的HX711模塊來說參考電壓一般來自穩(wěn)壓后的AVDD通常取4.3V左右那么每個LSB對應(yīng)的輸入電壓約是4.3V除以2的24次方再除以128算出來大約0.2uV級別。雖然實(shí)際噪聲水平達(dá)不到理論極限但這個靈敏度對于常見的幾十公斤量程的稱重傳感器來說完全是夠用的。2. 硬件設(shè)計(jì)與電路搭建要點(diǎn)2.1 傳感器與前端模塊選型細(xì)節(jié)稱重傳感器這里用的最常見的就是鋁制懸臂梁結(jié)構(gòu)的電阻應(yīng)變式傳感器。量程5kg、10kg、20kg都有家庭電子秤一般用5kg到10kg就足夠工業(yè)計(jì)價秤一般用到30kg。我這里選的是10kg量程的傳感器靈敏度在2.0mV/V左右。什么意思呢就是說在滿量程10kg時在10V激勵電壓下輸出大約20mV的信號。實(shí)際HX711模塊一般提供3.3V到5V的激勵電壓如果用5V激勵滿量程輸出大約10mV。傳感器的四根線紅色是激勵正E黑色是激勵負(fù)E-白色是信號負(fù)S-綠色是信號正S。很多國產(chǎn)傳感器顏色可能有差異拿到貨第一件事就是用萬用表確認(rèn)電阻關(guān)系。電橋的典型阻抗是350歐姆激勵端和信號端之間的阻值關(guān)系是有規(guī)律的查一下數(shù)據(jù)手冊或者用萬用表量一下對應(yīng)關(guān)系接反了的話讀數(shù)會顯示負(fù)值或者亂跳。HX711模塊我建議買那種帶屏蔽的版本就是模塊本身帶一層金屬罩的。雖然貴幾塊錢但抗干擾能力會好很多特別是后面如果打算做USB供電的版本電腦電源的紋波干擾會讓讀數(shù)非常難受。如果條件不允許模塊背面自己貼一層銅箔接地也能緩解實(shí)測效果比不貼強(qiáng)很多。2.2 STM32最小系統(tǒng)與電源設(shè)計(jì)主控芯片我用的STM32F103C8T6藍(lán)色Pill小板或者自制最小系統(tǒng)板都可以。這套方案的RAM有20KBFlash有64KB跑個裸機(jī)狀態(tài)機(jī)加濾波算法綽綽有余。實(shí)際上整個工程編譯下來Flash占用大概在20%到30%之間非常輕松。晶體這里特別說一下STM32F103的HSE外部晶振建議用8MHz的方便后面系統(tǒng)時鐘倍頻到72MHz。有些開發(fā)板上用的是其他頻率的晶振比如12MHz的也有那樣的話PLL配置要對應(yīng)調(diào)整。如果圖省事直接用內(nèi)部HSI時鐘跑到64MHz也行但USART的波特率會有一點(diǎn)點(diǎn)偏差高速通信場景下容易出錯做電子秤這種低速場景其實(shí)沒有太大影響。電源部分是這個項(xiàng)目最容易忽略的重點(diǎn)。稱重傳感器需要穩(wěn)定的激勵電壓HX711的參考電壓又是從AVDD取的AVDD如果有紋波輸出數(shù)據(jù)就會周期性跳動。我實(shí)測用USB直接供電和用穩(wěn)壓模塊獨(dú)立供電兩種情況同樣的傳感器讀數(shù)穩(wěn)定性差距非常明顯。USB供電下5V電源紋波大約有50mV到80mV的尖峰反映到稱重?cái)?shù)據(jù)上就是末位數(shù)字頻繁跳動2到3個字。換成AMS1117-3.3再加一個100uF電容濾波后末位跳動控制在1個字以內(nèi)。至于模擬部分和數(shù)字部分要不要分地在這個項(xiàng)目里我認(rèn)為沒有必要做得太復(fù)雜。HX711模塊本身是單獨(dú)供電的STM32和模塊之間只有兩根信號線DT和SCK相連只要確保電源線足夠粗、盡量短布線規(guī)范一點(diǎn)信號完整性基本不會有問題。2.3 顯示與按鍵交互電路設(shè)計(jì)顯示部分有兩種選擇LCD1602字符屏或者OLED屏幕。LCD1602的好處是字符大商用計(jì)價秤那種風(fēng)格顯示價格、重量、金額各占一行非常直觀。缺點(diǎn)是刷新速度稍慢而且模塊的驅(qū)動需要占用不少IO如果再加上I2C轉(zhuǎn)接板邏輯會簡單很多但刷新速度進(jìn)一步下降。OLED屏幕顯示內(nèi)容靈活可以同時顯示更多信息比如還能把單價和金額放大顯示但我個人做計(jì)價秤產(chǎn)品風(fēng)格時更傾向于LCD1602因?yàn)樯坛镉玫膫鹘y(tǒng)計(jì)價秤就是這種顯示形態(tài)。按鍵這里我用的4x4矩陣鍵盤。計(jì)價秤需要輸入單價10個數(shù)字鍵加一個小數(shù)點(diǎn)再加一個清零、一個確認(rèn)、一個刪除。很多人做矩陣鍵盤最喜歡用的就是逐行掃描法但這里我強(qiáng)烈建議用狀態(tài)機(jī)加定時掃描的方式不讓按鍵檢測阻塞在主循環(huán)里。具體來說就是用一個定時器中斷每5ms掃描一次矩陣鍵盤檢測到狀態(tài)變化后記錄事件主循環(huán)里再消費(fèi)事件。這樣做的優(yōu)勢是系統(tǒng)在處理HX711數(shù)據(jù)的時候不會因?yàn)榈却存I抖動脈沖而卡頓。如果不想占用那么多IO也可以用幾個獨(dú)立按鍵配合增量編碼方式輸入單價不過操作效率會低很多商用場景不推薦。矩陣鍵盤在PCB上布線時要注意行列信號線不能平行走線太長容易形成串?dāng)_。實(shí)際項(xiàng)目里如果手工做飛線版本建議在行列線上各串聯(lián)一個100歐姆的電阻對抑制毛刺有幫助。3. 核心代碼實(shí)現(xiàn)與算法設(shè)計(jì)3.1 HX711驅(qū)動與采樣邏輯HX711的通信機(jī)制非常簡單兩根線數(shù)據(jù)輸出DOUT和時鐘輸入SCK。平時DOUT為高電平當(dāng)數(shù)據(jù)準(zhǔn)備好后DOUT會拉低這時MCU發(fā)送25個以上脈沖來讀取數(shù)據(jù)或配置通道。每次讀24位數(shù)據(jù)最高位在前。發(fā)送25個脈沖時第25個脈沖的上升沿會讓芯片進(jìn)入下一次轉(zhuǎn)換同時切換通道和增益設(shè)置。需要注意的幾個細(xì)節(jié)DOUT低電平就緒后讀取過程中如果中途MCU被高優(yōu)先級中斷打斷可能導(dǎo)致時序混亂。所以讀取HX711數(shù)據(jù)的關(guān)鍵代碼段最好關(guān)中斷或者確保中斷不會在這個時間段觸發(fā)。SCK高電平持續(xù)時間不能太短HX711的數(shù)據(jù)手冊要求SCK高電平時長至少100ns實(shí)際用STM32的GPIO翻轉(zhuǎn)速度完全滿足但如果是跑很高主頻的芯片建議加幾個空操作的延時。24位數(shù)據(jù)是有符號數(shù)最高位是符號位所以讀回來之后要判斷一下是否超出正數(shù)范圍。如果第24位是1說明讀出來的是負(fù)數(shù)這時候要手動把它擴(kuò)展為32位有符號數(shù)。否則直接把24位數(shù)據(jù)賦值給int32_t變量時正數(shù)沒問題負(fù)數(shù)會變成很大的正數(shù)?;镜淖x取代碼類似這樣uint32_t HX711_Read(void) { uint32_t count 0; uint8_t i; // 等待DOUT拉低表示數(shù)據(jù)就緒 while(HX711_DOUT_Read() 1); // 讀取24位數(shù)據(jù) for(i 0; i 24; i) { HX711_SCK_High(); if(HX711_DOUT_Read() 1) { count | 0x800000; } HX711_SCK_Low(); count 1; } // 第25個脈沖進(jìn)入下一次轉(zhuǎn)換 HX711_SCK_High(); HX711_SCK_Low(); return count; }讀回來的原始值不能直接用。因?yàn)榉Q重傳感器橋路的差分信號在空載時也不是絕對的0V加上應(yīng)變片的初始不平衡、HX711的失調(diào)電壓空載時讀出來的值可能是一個比較大的正數(shù)或者負(fù)數(shù)。這個值就是零點(diǎn)偏移要在標(biāo)定的時候記錄并扣除。3.2 數(shù)據(jù)濾波與平滑處理HX711輸出的數(shù)據(jù)雖然已經(jīng)是數(shù)字量但依然帶有比較明顯的噪聲。原因有幾個一是機(jī)械振動和電磁干擾二是傳感器橋路本身的溫漂和隨機(jī)噪聲三是HX711的Δ-Σ調(diào)制器的量化噪聲不是完全白噪聲。最簡單的濾波方式就是平均值濾波連續(xù)讀取N次然后取平均。但這種方法的缺點(diǎn)是如果某一次讀數(shù)嚴(yán)重偏離平均值會被拉偏。更穩(wěn)妥的做法是先去極值再取平均也就是連續(xù)讀取N組數(shù)據(jù)去掉最大值和最小值剩下的取平均。這樣能有效濾除尖峰脈沖干擾。我實(shí)際用的參數(shù)是連續(xù)讀取10次去掉最大和最小剩下8次取平均。在10kg量程的傳感器上測試濾波后的數(shù)據(jù)噪聲峰峰值能控制在正負(fù)1個字以內(nèi)對應(yīng)大概0.1g到0.2g的重量波動范圍這對于計(jì)價秤來說是完全可接受的。還有一種方案是采用滑動平均濾波就是維護(hù)一個環(huán)形緩沖區(qū)每次讀入一個新值就丟掉一個最舊的值然后計(jì)算平均值。這種濾波器響應(yīng)快實(shí)時性好不會像每次重新采集10次再去極值那樣有較長的滯后。但缺陷是對尖峰脈沖不能有效濾除因?yàn)榛瑒哟翱诶锉A舻漠惓?shù)據(jù)會連續(xù)影響多個輸出。如果要做商用級產(chǎn)品我更推薦先做去極值再做滑動平均兩段組合使用。濾波參數(shù)的選擇直接影響系統(tǒng)響應(yīng)速度。如果你每次拿到HX711數(shù)據(jù)后立即更新顯示末位跳動會很嚴(yán)重。但如果濾波窗口太長秤臺上放了東西之后要等一兩秒才能穩(wěn)定出數(shù)用戶體驗(yàn)很差。我調(diào)下來比較合適的參數(shù)是每次讀取時采集5次排序后去掉最大最小3次取平均。HX711的轉(zhuǎn)換速率設(shè)置在10SPS每秒10次采樣這樣5次采集耗時約0.5秒顯示更新頻率約2Hz穩(wěn)定性和實(shí)時性平衡得比較好。3.3 標(biāo)定算法與重量計(jì)算標(biāo)定是整個電子秤項(xiàng)目中決定精度的核心環(huán)節(jié)。常見的做法是兩點(diǎn)標(biāo)定記錄空載時的ADC原始值作為零點(diǎn)然后放上已知重量的標(biāo)準(zhǔn)砝碼記錄滿量程值通過兩點(diǎn)確定一條線性直線斜率就是每克對應(yīng)的ADC數(shù)值。計(jì)算公式如下float cal_slope; // 斜率單位ADC值/克 int32_t zero_offset; // 零點(diǎn)偏移 float weight; // 最終計(jì)算出的重量 // 標(biāo)定過程 zero_offset read_filtered_average(); // 空載讀數(shù) int32_t cal_value read_filtered_average(); // 放標(biāo)準(zhǔn)砝碼后的讀數(shù) float standard_weight 1000.0f; // 單位克 cal_slope (float)(cal_value - zero_offset) / standard_weight; // 實(shí)時重量計(jì)算 weight (float)(read_filtered_average() - zero_offset) / cal_slope;這里有一個細(xì)節(jié)很多人容易忽略斜率不是永遠(yuǎn)不變的。溫度變化會導(dǎo)致傳感器靈敏度漂移長期受力也可能導(dǎo)致傳感器出現(xiàn)蠕變。所以商用計(jì)價秤都支持定期標(biāo)定產(chǎn)品設(shè)計(jì)時通常會在軟件里留一個標(biāo)定模式通過按鍵組合進(jìn)入。我這個項(xiàng)目里預(yù)留了兩個標(biāo)定檔位一個是單點(diǎn)標(biāo)定只校準(zhǔn)零點(diǎn)另一個是兩點(diǎn)標(biāo)定完整校準(zhǔn)零點(diǎn)和斜率。兩點(diǎn)標(biāo)定里砝碼的重量選擇很有講究。如果你的秤量程是10kg用一個100g的砝碼去標(biāo)定因?yàn)閭鞲衅髟诘土砍潭蔚木€性通常會好一些標(biāo)出來的斜率可能和滿量程段有偏差。比較穩(wěn)妥的做法是用滿量程的50%到75%左右的砝碼做標(biāo)定比如10kg的量程就用5kg或7.5kg的砝碼。這樣能保證斜率在整個量程范圍內(nèi)的最大偏差最小因?yàn)闃?biāo)定點(diǎn)附近的線性度一般是最好的。如果找不到標(biāo)準(zhǔn)砝碼家里常見的做法是用已知凈含量的礦泉水瓶湊但注意不是所有瓶裝水標(biāo)注的都是精確重量我實(shí)測有些瓶裝水實(shí)際重量和標(biāo)注差了十幾克用來標(biāo)定精度要求高的秤是完全不行的。最好買的還是那種鐵質(zhì)的標(biāo)準(zhǔn)砝碼幾十塊錢一套精度M2級夠用了。3.4 狀態(tài)機(jī)與主循環(huán)架構(gòu)整機(jī)功能邏輯我建議用一個簡單的狀態(tài)機(jī)來組織。狀態(tài)包括正常工作、標(biāo)定零點(diǎn)、標(biāo)定斜率、參數(shù)設(shè)置。每個狀態(tài)對應(yīng)的按鍵響應(yīng)不同顯示內(nèi)容也不同。這樣做的好處是代碼結(jié)構(gòu)清晰后期加功能不容易把邏輯搞亂。主循環(huán)結(jié)構(gòu)大致是while(1) { // 處理按鍵事件 uint8_t key key_scan(); if(key ! KEY_NONE) { state_machine_handle(key); } // 周期更新重量數(shù)據(jù) if(hx711_data_ready_flag) { process_weight_data(); update_display(); } // 可以在這里加一些低功耗或看門狗處理 }HX711數(shù)據(jù)就緒后用中斷或輪詢方式置一個標(biāo)志位主循環(huán)檢測到標(biāo)志位后再執(zhí)行讀取、濾波和顯示刷新。不要把讀取HX711放在按鍵掃描之前否則掃描按鍵會被HX711的等待阻塞拖慢。因?yàn)镠X711讀取時如果數(shù)據(jù)還沒準(zhǔn)備好會卡在等待DOUT拉低的循環(huán)里一次最長可能要幾百毫秒這期間按鍵完全沒響應(yīng)。3.5 EEPROM掉電存儲設(shè)計(jì)計(jì)價秤的標(biāo)定參數(shù)和單價信息必須掉電保存。STM32F103C8T6雖然內(nèi)部沒有EEPROM但它的Flash可以被用作數(shù)據(jù)存儲區(qū)。最簡單的方案是直接用內(nèi)部Flash的最后一頁來存參數(shù)每次寫入前先擦除再寫入。這里有一個壽命問題STM32的Flash擦寫壽命一般在1萬次左右頻繁寫入標(biāo)定參數(shù)沒問題但如果單價信息每次按鍵修改都立即寫Flash壽命很快耗盡。我采用了一個變通方案單價信息只在“確認(rèn)”按鍵觸發(fā)時寫入標(biāo)定參數(shù)只在完成標(biāo)定流程時寫入平時運(yùn)行中的數(shù)據(jù)全部在RAM里操作。同時在Flash存儲的起始位置放一個魔數(shù)標(biāo)志每次上電讀取時先檢查標(biāo)志如果不是預(yù)設(shè)值就說明是第一次運(yùn)行或者數(shù)據(jù)損壞自動恢復(fù)默認(rèn)參數(shù)。這個設(shè)計(jì)能避免數(shù)據(jù)文件損壞后系統(tǒng)完全無法工作。如果想讓Flash壽命更長可以使用磨損均衡算法但在這個項(xiàng)目規(guī)模上屬于過度設(shè)計(jì)除非你要做量產(chǎn)產(chǎn)品否則沒什么必要。一個折中方案是用外掛AT24C02 EEPROM成本幾毛錢I2C接口驅(qū)動一個讀一個寫比操作內(nèi)部Flash簡單得多而且壽命是100萬次擦寫基本不用考慮磨損。4. 實(shí)操過程與標(biāo)定測試實(shí)錄4.1 硬件焊接與上電自檢我這次做的是手工焊接版本PCB用嘉立創(chuàng)打的樣板。整個焊接過程有幾個必須注意的地方第一HX711模塊上的模擬電源和數(shù)字電源要分開布置。雖然模塊本身已經(jīng)做好了濾波但輸入輸出引腳的焊接引腳盡可能短減少天線效應(yīng)。第二稱重傳感器的接線端子要用那種可插拔的綠色端子方便后期換傳感器測試不要直接焊死在板上。第三STM32芯片如果手工焊接建議用拖焊法焊完之后用萬用表檢查相鄰引腳之間有沒有短路特別是VDD和GND之間如果短路了通電解電容充電瞬間可能直接燒芯片。上電之后先不要著急下載程序先用萬用表確認(rèn)幾個關(guān)鍵電壓STM32的3.3V是否正常HX711的DVDD是否為3.3VAVDD是否在4.2V到4.5V范圍內(nèi)。再檢查一下系統(tǒng)電流整個板子正常情況下電流不超過35mA如果超過100mA說明哪里有問題可能是接線錯誤或者芯片損壞。然后先燒一個最簡單的GPIO測試程序點(diǎn)亮LED確認(rèn)芯片基本工作正常。如果有串口的話把HX711讀取的原始值通過串口打印出來放到秤臺上用手按一按觀察數(shù)據(jù)是否隨壓力變化。這一步能快速排查傳感器接線是否正確如果數(shù)據(jù)反向變化說明S和S-接反了交換一下就好。4.2 標(biāo)定流程的具體操作步驟標(biāo)定模式我設(shè)計(jì)成通過長按“清零”鍵3秒進(jìn)入。進(jìn)入標(biāo)定模式后顯示屏第一行顯示提示信息第二行顯示當(dāng)前ADC平均值。具體操作步驟如下確認(rèn)秤臺完全空載沒有殘留物品記錄當(dāng)前的零點(diǎn)讀數(shù)。按“確認(rèn)”鍵鎖定零點(diǎn)值系統(tǒng)會把當(dāng)前ADC平均值存儲為zero_offset。放進(jìn)標(biāo)準(zhǔn)砝碼等待數(shù)據(jù)穩(wěn)定。這里要等大概5到10秒讓濾波算法完全穩(wěn)定下來。查看當(dāng)前ADC讀數(shù)如果讀數(shù)方向和壓力方向一致按“確認(rèn)”鍵鎖定砝碼重量校準(zhǔn)點(diǎn)。輸入砝碼的實(shí)際重量單位克確認(rèn)后系統(tǒng)自動計(jì)算斜率并保存。標(biāo)定的關(guān)鍵是在穩(wěn)定后讀取數(shù)據(jù)而不是看數(shù)據(jù)大致差不多就確認(rèn)。我測試過程中發(fā)現(xiàn)剛放上砝碼的瞬間由于沖擊力傳感器輸出會有短暫過沖如果在這個時間點(diǎn)讀取會導(dǎo)出一個偏差很大的標(biāo)定值。標(biāo)定完成后我通常會在秤臺上放幾個不同已知重量的物體做驗(yàn)證。比如標(biāo)準(zhǔn)砝碼500g、1kg、5kg各測幾次記錄每次顯示重量和實(shí)際重量的差值看線性度和重復(fù)性。我實(shí)測的一組數(shù)據(jù)如下實(shí)際重量(g)顯示重量(g)偏差(g)誤差百分比00.00.00.00%500500.10.10.02%1000999.8-0.20.02%30003000.30.30.01%50005000.10.10.00%80007999.5-0.50.006%從這個結(jié)果看線性度還是可以的。誤差主要來源有三個方面一是傳感器的非線性特性在兩端附近偏差稍大二是濾波造成的量化誤差三是HX711的溫漂在長時間運(yùn)行后逐漸顯現(xiàn)。如果對精度要求更高可以做多點(diǎn)分段標(biāo)定比如在20%、50%、75%量程處各取一個點(diǎn)然后對不同的區(qū)間分別用不同的斜率做線性插值。這在算法上并不復(fù)雜但效果很明顯能把全量程最大誤差再壓縮一半左右。4.3 顯示界面與交互邏輯實(shí)現(xiàn)LCD1602顯示的內(nèi)容布局我設(shè)計(jì)成這樣第一行左邊顯示重量值右邊顯示單位中間顯示當(dāng)前狀態(tài)第二行左邊顯示單價右邊顯示總金額。這樣設(shè)計(jì)更貼近實(shí)際商用計(jì)價秤的顯示習(xí)慣。按鍵交互方面數(shù)字鍵用于輸入單價小數(shù)點(diǎn)鍵用于小數(shù)位確認(rèn)鍵用于計(jì)算總價。為了防止誤操作我把常用的幾個功能分開了短按清零鍵實(shí)現(xiàn)去皮長按清零鍵進(jìn)入標(biāo)定模式。去皮功能的實(shí)現(xiàn)邏輯是記錄當(dāng)前重量作為皮重值最終顯示重量為當(dāng)前稱重值減去皮重值同時LED指示燈亮起提示正在去皮狀態(tài)。5. 常見問題與排查技巧實(shí)錄5.1 數(shù)據(jù)跳變與不穩(wěn)定這是被問到最多的一個問題現(xiàn)象是即使空載狀態(tài)下顯示屏上的數(shù)字也在不停地跳動有時候跳動的幅度還特別大。排查步驟我建議按順序來首先是供電問題。用示波器看HX711模塊的AVDD電壓有沒有明顯紋波沒有示波器的可以嘗試換一個供電方式比如用充電寶加穩(wěn)壓模塊對比一下數(shù)據(jù)。我發(fā)現(xiàn)USB直接供電加開關(guān)電源適配器時HX711的數(shù)據(jù)穩(wěn)定性明顯比鋰電池供電差。其次是接線問題。傳感器信號線和電源線是否靠得太近特別是傳感器四根線如果捆扎在一起走長線需要注意。信號線盡量獨(dú)立走線不要和電源線平行走線。如果用的那種四線合一硅膠線里面通常是絞合在一起的問題一般不大但如果自己接了延長線就很容易出問題。然后是濾波參數(shù)。如果硬件排查都沒問題試試加大濾波的采樣次數(shù)和去極值強(qiáng)度再觀察數(shù)據(jù)跳動是否降低。如果依然跳動可以用示波器量一下HX711的DOUT引腳波形看是否有異常的窄脈沖毛刺。最后還有一種可能是傳感器的量程選小了空載狀態(tài)已經(jīng)接近超載。比如用5kg量程的傳感器去稱10kg的物體空載時電橋輸出就異常數(shù)據(jù)肯定穩(wěn)定不了。這個問題屬于選型錯誤只能換傳感器。5.2 標(biāo)定數(shù)據(jù)丟失與參數(shù)保存異常標(biāo)定數(shù)據(jù)寫進(jìn)Flash后上電再讀出來發(fā)現(xiàn)重量顯示明顯不對或者顯示全是“請重新標(biāo)定”。這種情況多半是Flash寫入過程中出現(xiàn)了問題。Flash寫入前必須保證目標(biāo)地址已經(jīng)被擦除否則寫入數(shù)據(jù)是臟的。另外STM32的Flash寫入要求使用的地址是半字16位對齊的寫入操作必須是以16位為單位直接用字節(jié)寫入會出錯。還有一點(diǎn)要注意如果正在寫Flash的時候突然斷電Flash里的數(shù)據(jù)可能處于部分寫入狀態(tài)導(dǎo)致魔數(shù)檢查失敗。我用了一個保護(hù)策略寫Flash的時候先寫一個“更新中”標(biāo)志全部寫完并且校驗(yàn)通過后再把魔數(shù)從舊值改成新值。這樣哪怕寫入中途斷電上電檢查魔數(shù)不對也能恢復(fù)到一個已知的舊版本參數(shù)。如果用的是內(nèi)部Flash方案建議每次上電讀取參數(shù)后在系統(tǒng)運(yùn)行中進(jìn)行一次CRC校驗(yàn)避免Flash內(nèi)容被意外的程序錯誤篡改。程序里的校驗(yàn)邏輯類似這樣uint32_t read_from_flash(uint32_t addr, void *buf, uint32_t len) { uint8_t *p (uint8_t *)buf; uint32_t crc 0; // 讀取數(shù)據(jù) for(uint32_t i 0; i len; i) { p[i] *(volatile uint8_t *)(addr i); } // 讀取CRC值并比對 uint32_t stored_crc *(volatile uint32_t *)(addr len); crc calculate_crc(buf, len); if(crc ! stored_crc) { return 0; // 數(shù)據(jù)損壞 } return 1; }5.3 按鍵不靈敏與顯示亂碼矩陣鍵盤如果出現(xiàn)按鍵偶爾不響應(yīng)或者一次觸發(fā)多次大概率是按鍵消抖沒做。注意不是軟件消抖沒做而是硬件上矩陣鍵盤的行列線如果過長容易引入電磁干擾造成誤觸發(fā)。軟件消抖的窗口建議設(shè)在10ms到20ms之間同時用狀態(tài)機(jī)記錄按鍵邊沿不要在按鍵按下和釋放時都觸發(fā)事件只在按下沿觸發(fā)。LCD1602顯示亂碼最常見的原因是初始化時序不對。LCD1602需要上電后等待一段時間才能初始化一般是15ms以上等待內(nèi)部復(fù)位完成后才能發(fā)送指令。初始化指令的每一條后面都要加適當(dāng)?shù)难訒r特別是0x38這條設(shè)定8位模式、雙行顯示的指令后面的延時要足夠長。如果初始化代碼沒問題但顯示仍然亂碼檢查一下對比度調(diào)節(jié)電位器有沒有調(diào)到合適的位置。用了I2C轉(zhuǎn)接板的版本檢查一下地址設(shè)置是不是和代碼一致默認(rèn)一般是0x27或者0x3F但有些模塊的地址跳線位置不同。最后分享一個我自己調(diào)試時經(jīng)常用的招HX711讀回來的數(shù)據(jù)如果一直是同一個值不隨壓力變化先檢查SCK和DOUT引腳有沒有虛焊然后檢查傳感器端子的E和E-是不是有電壓。如果E和E-之間電壓是0V說明模塊的激勵輸出有問題或者傳感器壞了。用萬用表測傳感器E和E-之間的電阻350歐姆左右是正常的如果開路或者短路傳感器基本可以扔了。這種問題排查起來其實(shí)不難按信號流向一個一個節(jié)點(diǎn)查過去很快就能定位到具體的故障點(diǎn)。