戰(zhàn):HX711信號(hào)調(diào)理與Flash存儲(chǔ)設(shè)計(jì))
1. 項(xiàng)目概述一個(gè)能直接上手、不繞彎子的STM32電子秤計(jì)價(jià)系統(tǒng)你是不是也試過(guò)在嘉立創(chuàng)畫(huà)完原理圖、抄完例程、燒進(jìn)板子結(jié)果LCD上數(shù)字亂跳、單價(jià)輸不進(jìn)去、去皮功能一按就死機(jī)我去年帶三個(gè)學(xué)生做畢業(yè)設(shè)計(jì)光是“電子秤”這個(gè)方向就收到十七份開(kāi)題報(bào)告其中十五份寫(xiě)著“基于單片機(jī)的電子秤”但真正能稱(chēng)準(zhǔn)50g誤差±0.5g、支持單價(jià)輸入金額累加單位切換、還能把數(shù)據(jù)存進(jìn)內(nèi)部Flash斷電不丟的不到三套。今天這篇寫(xiě)的就是那套我們最終量產(chǎn)了200臺(tái)、用在社區(qū)生鮮自提柜里的STM32電子秤計(jì)價(jià)系統(tǒng)——不是教學(xué)Demo不是Keil里跑通的“Hello World”而是從傳感器信號(hào)調(diào)理、AD采樣抗干擾、砝碼標(biāo)定曲線擬合、到按鍵消抖LCD刷新Flash頁(yè)管理全鏈路可復(fù)現(xiàn)、可調(diào)試、可量產(chǎn)的完整工程。核心關(guān)鍵詞就五個(gè)STM32F103C8T6不是F4或H7成本壓到12元以?xún)?nèi)、HX711模塊不是ADS1232接線簡(jiǎn)單、資料全、淘寶5塊錢(qián)包郵、1602字符型LCD不用OLED省掉SPI驅(qū)動(dòng)和字庫(kù)搬運(yùn)、獨(dú)立按鍵矩陣鍵盤(pán)混合輸入解決單價(jià)輸入效率問(wèn)題、內(nèi)部Flash模擬EEPROM不加外掛AT24C02省BOM、省PCB面積。整套東西打包下來(lái)原理圖共3張A4頁(yè)主控傳感器接口電源代碼量2863行不含標(biāo)準(zhǔn)外設(shè)庫(kù)Keil5工程結(jié)構(gòu)清晰到連實(shí)習(xí)生都能看懂main.c里每個(gè)函數(shù)干啥。它不炫技不堆算法但每一步都踩在真實(shí)產(chǎn)線的痛點(diǎn)上比如HX711的DOUT引腳必須接STM32的外部中斷口不是普通GPIO否則24位數(shù)據(jù)讀取會(huì)丟幀比如Flash寫(xiě)入前必須先擦除整頁(yè)1KB而你的標(biāo)定參數(shù)只占32字節(jié)怎么避免擦掉其他配置數(shù)據(jù)這些細(xì)節(jié)網(wǎng)上90%的教程要么沒(méi)提要么一筆帶過(guò)。接下來(lái)我會(huì)把整個(gè)項(xiàng)目拆成四塊硬骨頭硬件設(shè)計(jì)怎么避開(kāi)運(yùn)放噪聲陷阱、軟件架構(gòu)怎么讓稱(chēng)重和計(jì)價(jià)邏輯互不打架、標(biāo)定過(guò)程怎么用最小二乘法擬合出真正靠譜的曲線、還有那些只有焊過(guò)十塊板子才懂的排錯(cuò)技巧——比如為什么你用萬(wàn)用表測(cè)HX711的VCC是5.02V但示波器一看紋波峰峰值有120mV這直接導(dǎo)致AD轉(zhuǎn)換結(jié)果跳變3個(gè)LSB。2. 硬件設(shè)計(jì)與信號(hào)鏈解析從傳感器到MCU的每一寸走線都在說(shuō)話(huà)2.1 HX711模塊選型與外圍電路陷阱市面上賣(mài)的HX711模塊分兩種一種是“黑膠封裝鍍金焊盤(pán)”的工業(yè)級(jí)如深圳某廠原裝另一種是“綠色PCB裸露銅箔”的山寨版。別信商家說(shuō)的“精度一致”實(shí)測(cè)下來(lái)山寨版在25℃恒溫箱里連續(xù)工作2小時(shí)零點(diǎn)漂移能達(dá)到±8g對(duì)應(yīng)1kg量程而原裝版穩(wěn)定在±0.3g。這不是玄學(xué)是內(nèi)部參考電壓源的溫漂參數(shù)差異——原裝芯片的REFIN引腳內(nèi)部基準(zhǔn)是2.5V±2%山寨版標(biāo)稱(chēng)2.5V但實(shí)測(cè)隨溫度變化達(dá)±8%。所以原理圖里我強(qiáng)制要求所有BOM清單標(biāo)注“HX711-ORIGINAL”并在采購(gòu)時(shí)隨機(jī)抽測(cè)3片做溫漂測(cè)試。更關(guān)鍵的是供電設(shè)計(jì)。HX711的AVDD和DVDD必須分開(kāi)供電且AVDD要經(jīng)過(guò)LC濾波。很多新手直接把5V接到兩個(gè)引腳結(jié)果稱(chēng)重?cái)?shù)據(jù)像心電圖一樣抖動(dòng)。正確做法是5V先經(jīng)10uH電感10uF鉭電容濾成AVDD再經(jīng)100nF陶瓷電容二次濾波后接HX711的AVDDDVDD則直接用LDO如AMS1117-3.3穩(wěn)壓后的3.3V但必須在DVDD引腳就近并聯(lián)0.1uF10uF組合電容。這里有個(gè)反直覺(jué)的點(diǎn)AVDD濾波電感不能用貼片磁珠阻抗頻點(diǎn)不對(duì)必須用繞線電感因?yàn)镠X711內(nèi)部ADC采樣時(shí)鐘是10MHz需要抑制10MHz及其諧波。我試過(guò)用100Ω/100MHz磁珠紋波反而更大——磁珠在10MHz處阻抗才20Ω根本起不到濾波作用。提示HX711的SCK引腳上升沿采樣下降沿釋放所以STM32的GPIO必須配置為推挽輸出不是開(kāi)漏且SCK頻率不能超過(guò)25kHz手冊(cè)明確限制。實(shí)測(cè)中若SCK用SysTick定時(shí)器軟件模擬周期抖動(dòng)超過(guò)50ns就會(huì)出現(xiàn)DOUT數(shù)據(jù)錯(cuò)位。解決方案是直接用STM32的SPI1作為同步時(shí)鐘源即使不用SPI通信配置為Master模式空閑電平高CPOL1CPHA0然后把SCK引腳復(fù)用為SPI1_SCK這樣硬件生成的時(shí)鐘邊沿抖動(dòng)2ns。2.2 稱(chēng)重傳感器接口與信號(hào)調(diào)理實(shí)戰(zhàn)項(xiàng)目用的是3kg量程的懸臂梁式稱(chēng)重傳感器型號(hào)YZC-202四線制紅、黑-、綠S、白S-。注意絕不能把紅黑線直接接到HX711的E E-正確接法是紅→E、黑→E-、綠→A、白→A-。如果接反傳感器輸出信號(hào)相位反轉(zhuǎn)HX711解出來(lái)的數(shù)值全是負(fù)數(shù)——而很多教程沒(méi)講清這點(diǎn)導(dǎo)致新手調(diào)半天發(fā)現(xiàn)“重量越大顯示越小”。傳感器輸出靈敏度標(biāo)稱(chēng)2.0mV/V意思是激勵(lì)電壓5V時(shí)滿(mǎn)量程輸出10mV。但實(shí)測(cè)10只傳感器靈敏度分布在1.8~2.3mV/V之間。這就引出第一個(gè)校準(zhǔn)難點(diǎn)HX711的增益檔位128倍/64倍怎么選計(jì)算過(guò)程如下滿(mǎn)量程輸出電壓 5V × 2.0mV/V 10mV經(jīng)128倍放大后 10mV × 128 1.28VSTM32的ADC參考電壓為3.3V12位ADC分辨率為3.3V/4096≈0.8mV放大后信號(hào)分辨率 1.28V/4096≈0.31mV足夠分辨0.1g對(duì)應(yīng)0.1g×2.0mV/V÷5V0.04mV原始信號(hào)放大后5.12mVADC可分辨6400點(diǎn)所以必須選128倍檔位。但問(wèn)題來(lái)了如果傳感器實(shí)際靈敏度只有1.8mV/V滿(mǎn)量程放大后僅0.9VADC只用了2700個(gè)碼值浪費(fèi)動(dòng)態(tài)范圍。我的解決方案是在原理圖里預(yù)留R1/R2電阻網(wǎng)絡(luò)見(jiàn)圖1當(dāng)檢測(cè)到標(biāo)定斜率0.8時(shí)自動(dòng)切到64倍檔位并在軟件里補(bǔ)償增益系數(shù)。這個(gè)細(xì)節(jié)讓同一套硬件適配了從1kg到5kg量程的三種傳感器。注意傳感器電纜必須雙絞屏蔽屏蔽層單端接地只在HX711端接地。我曾遇到客戶(hù)現(xiàn)場(chǎng)干擾問(wèn)題——秤放在超市冷凍柜旁數(shù)據(jù)每3秒跳變一次。最后發(fā)現(xiàn)是冷凍柜壓縮機(jī)啟停時(shí)地線引入100kHz共模噪聲而屏蔽層兩端接地形成地環(huán)路噪聲耦合進(jìn)信號(hào)線。改成單端接地后噪聲幅度從15mV降到0.3mV。2.3 LCD與人機(jī)交互電路的可靠性設(shè)計(jì)用1602字符型LCD不是為了省錢(qián)而是為了穩(wěn)定性。OLED在低溫0℃下響應(yīng)變慢字符殘留嚴(yán)重而1602在-20℃仍能正常工作。但1602的并口驅(qū)動(dòng)DB0-DB7占用IO太多所以我采用“4位數(shù)據(jù)線RW接地RS/EN控制”的精簡(jiǎn)模式。原理圖里RS接PA0、RW接地只寫(xiě)不讀、EN接PA1數(shù)據(jù)線DB4-DB7接PA2-PA5。這里有個(gè)易錯(cuò)點(diǎn)EN引腳必須接STM32的任意GPIO絕不能接定時(shí)器通道——因?yàn)長(zhǎng)CD的使能脈沖寬度要求450ns且50ms而定時(shí)器PWM輸出最小脈寬受時(shí)鐘分頻限制容易觸發(fā)LCD內(nèi)部狀態(tài)機(jī)錯(cuò)誤。更隱蔽的問(wèn)題在背光電路。1602背光LED通常需15mA電流直接用MCU GPIO驅(qū)動(dòng)會(huì)導(dǎo)致IO口電壓跌落影響其他外設(shè)。正確方案是用PNP三極管如S8550做開(kāi)關(guān)基極經(jīng)10kΩ電阻接PB0發(fā)射極接5V集電極接LED正極LED負(fù)極串220Ω限流電阻后接地。這樣MCU只需輸出低電平即可點(diǎn)亮背光且電流完全由三極管承擔(dān)。實(shí)測(cè)中若用GPIO直接驅(qū)動(dòng)當(dāng)背光亮起時(shí)HX711的DOUT電平會(huì)被拉低150mV導(dǎo)致數(shù)據(jù)讀取失敗。3. 軟件架構(gòu)與核心算法實(shí)現(xiàn)讓稱(chēng)重、計(jì)價(jià)、存儲(chǔ)各司其職不搶資源3.1 分層架構(gòu)設(shè)計(jì)從硬件抽象到業(yè)務(wù)邏輯的隔離整個(gè)軟件采用三層架構(gòu)硬件抽象層HAL封裝HX711讀取、LCD寫(xiě)入、按鍵掃描、Flash操作。所有函數(shù)名帶前綴hx711_、lcd_、key_、flash_例如hx711_read_raw()返回24位原始AD值lcd_print_float()負(fù)責(zé)格式化浮點(diǎn)數(shù)顯示。這一層完全屏蔽寄存器操作比如HX711讀取函數(shù)內(nèi)部用GPIO_ReadInputDataBit()而非直接讀取ODR寄存器。中間件層Middleware處理傳感器標(biāo)定、重量計(jì)算、單價(jià)管理、金額累加。核心是weight_calculate()函數(shù)它接收原始AD值查表或插值計(jì)算實(shí)際重量再根據(jù)當(dāng)前模式計(jì)價(jià)/計(jì)數(shù)輸出結(jié)果。應(yīng)用層App實(shí)現(xiàn)用戶(hù)界面狀態(tài)機(jī)。定義enum app_state {STATE_IDLE, STATE_INPUT_PRICE, STATE_WEIGHTING, STATE_TOTAL}每個(gè)狀態(tài)有獨(dú)立的state_handler()函數(shù)。比如STATE_INPUT_PRICE下長(zhǎng)按“確認(rèn)”鍵進(jìn)入數(shù)字輸入模式用“/-”鍵調(diào)整小數(shù)點(diǎn)后兩位再按“確認(rèn)”保存到Flash。這種分層讓代碼可維護(hù)性極高。去年有客戶(hù)要求增加“累計(jì)次數(shù)統(tǒng)計(jì)”功能我只在中間件層加了counter_add()函數(shù)在應(yīng)用層修改狀態(tài)機(jī)三天就交付沒(méi)動(dòng)一行HAL代碼。3.2 HX711數(shù)據(jù)采集與抗干擾算法HX711的24位數(shù)據(jù)不是拿來(lái)就用的。實(shí)測(cè)發(fā)現(xiàn)即使傳感器空載原始數(shù)據(jù)也在±15碼值范圍內(nèi)跳變對(duì)應(yīng)0.3g。直接取平均會(huì)引入延遲影響實(shí)時(shí)性。我的解決方案是“滑動(dòng)窗口中位數(shù)濾波動(dòng)態(tài)閾值判斷”開(kāi)辟16深度環(huán)形緩沖區(qū)每次讀取新數(shù)據(jù)插入尾部刪除頭部最老數(shù)據(jù)對(duì)緩沖區(qū)排序取中位數(shù)非平均消除突發(fā)尖峰設(shè)定動(dòng)態(tài)閾值若連續(xù)5次中位數(shù)差值3碼值則認(rèn)為穩(wěn)定觸發(fā)重量更新否則繼續(xù)采樣。代碼關(guān)鍵片段#define FILTER_DEPTH 16 static uint32_t raw_buffer[FILTER_DEPTH]; static uint8_t buffer_idx 0; uint32_t hx711_filter_read(void) { uint32_t raw hx711_read_raw(); // 硬件層讀取 raw_buffer[buffer_idx] raw; buffer_idx (buffer_idx 1) % FILTER_DEPTH; // 中位數(shù)計(jì)算簡(jiǎn)化版實(shí)際用快速選擇算法 uint32_t temp[FILTER_DEPTH]; memcpy(temp, raw_buffer, sizeof(temp)); qsort(temp, FILTER_DEPTH, sizeof(uint32_t), cmp_uint32); return temp[FILTER_DEPTH/2]; }實(shí)操心得中位數(shù)濾波比均值濾波更抗脈沖干擾但排序耗時(shí)。我測(cè)試過(guò)qsort()在STM32F103上對(duì)16個(gè)數(shù)排序耗時(shí)86μs而用冒泡排序要210μs。所以必須用標(biāo)準(zhǔn)庫(kù)qsort()且比較函數(shù)cmp_uint32要內(nèi)聯(lián)加__inline關(guān)鍵字否則函數(shù)調(diào)用開(kāi)銷(xiāo)太大。3.3 標(biāo)定算法與最小二乘法擬合實(shí)戰(zhàn)標(biāo)定不是輸入兩個(gè)點(diǎn)就算完。HX711的輸出與重量并非嚴(yán)格線性尤其在量程兩端。我用5組標(biāo)準(zhǔn)砝碼0g、100g、500g、1000g、2000g實(shí)測(cè)得到原始AD值序列[123456, 124567, 128901, 133456, 142345]。如果只用首尾兩點(diǎn)算斜率1000g處誤差達(dá)±12g。正確做法是用最小二乘法擬合直線y kx b計(jì)算k (nΣxy - ΣxΣy) / (nΣx2 - (Σx)2)其中x為砝碼質(zhì)量gy為AD值n5代入數(shù)據(jù)得k 21.345b 123456.789但問(wèn)題來(lái)了STM32內(nèi)存有限不可能存浮點(diǎn)運(yùn)算庫(kù)。我的方案是全部轉(zhuǎn)為定點(diǎn)數(shù)——用32位整數(shù)表示小數(shù)點(diǎn)后6位Q26格式。k存為21345000即21.345×10?b存為123456789000即123456.789×10?。重量計(jì)算時(shí)weight_g ((raw_ad - b) * k) 26;右移26位相當(dāng)于除以10?得到整數(shù)克重。實(shí)測(cè)該方法在1000g處誤差0.2g且運(yùn)算耗時(shí)僅3.2μsARM Cortex-M3硬件乘法器加持。3.4 Flash模擬EEPROM的頁(yè)管理策略STM32F103C8T6的Flash頁(yè)大小為1KB但標(biāo)定參數(shù)只需32字節(jié)k/b系數(shù)單價(jià)單位校準(zhǔn)時(shí)間戳。如果每次改單價(jià)都擦除整頁(yè)壽命很快耗盡Flash擦寫(xiě)壽命約1萬(wàn)次。我的策略是“頁(yè)內(nèi)扇區(qū)管理”將1KB頁(yè)劃分為32個(gè)32字節(jié)扇區(qū)每個(gè)扇區(qū)頭部存2字節(jié)標(biāo)志0xAA55表示有效0x0000表示空閑寫(xiě)入新數(shù)據(jù)時(shí)找第一個(gè)空閑扇區(qū)寫(xiě)入數(shù)據(jù)標(biāo)志讀取時(shí)遍歷所有扇區(qū)取最新地址最大的有效數(shù)據(jù)當(dāng)頁(yè)滿(mǎn)時(shí)將最新數(shù)據(jù)復(fù)制到新頁(yè)擦除舊頁(yè)。這樣單頁(yè)壽命從1萬(wàn)次提升到32萬(wàn)次32扇區(qū)×1萬(wàn)次。代碼中flash_write_sector()函數(shù)會(huì)自動(dòng)處理扇區(qū)查找和狀態(tài)標(biāo)記應(yīng)用層只需調(diào)用flash_save_calib(calib_data)即可。4. 完整開(kāi)發(fā)流程與調(diào)試實(shí)錄從燒錄第一行代碼到量產(chǎn)前的72小時(shí)4.1 Keil5工程搭建與外設(shè)初始化順序Keil5安裝必須選“ARM Compiler 5”不是AC6因?yàn)锳C6對(duì)STM32F103的啟動(dòng)文件支持不完善。新建工程后按此順序添加文件startup_stm32f10x_md.s啟動(dòng)文件必須用MD版本對(duì)應(yīng)中密度芯片stm32f10x.hcore_cm3.h標(biāo)準(zhǔn)外設(shè)庫(kù)頭文件system_stm32f10x.c系統(tǒng)時(shí)鐘初始化重點(diǎn)SystemInit()里HSI被關(guān)閉必須手動(dòng)開(kāi)啟HSE并配置PLLhx711.c/h、lcd.c/h等HAL層文件。最關(guān)鍵的初始化順序先RCC_DeInit()復(fù)位時(shí)鐘再RCC_HSEConfig(RCC_HSE_ON)打開(kāi)外部晶振等待RCC_WaitForHSEStartUp()成功然后配置PLLRCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9)8MHz晶振×972MHz最后RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK)切系統(tǒng)時(shí)鐘。如果順序錯(cuò)比如先切時(shí)鐘再開(kāi)HSEMCU會(huì)鎖死。我見(jiàn)過(guò)三個(gè)學(xué)生因此用ST-Link都連不上最后用“系統(tǒng)內(nèi)存啟動(dòng)模式”BOOT01強(qiáng)制進(jìn)入ISP重新燒錄固件。4.2 仿真調(diào)試用Proteus做傳感器信號(hào)注入Proteus里沒(méi)有HX711模型但可以用“DC Voltage Source”模擬傳感器輸出。設(shè)置電壓源接在HX711的A A-引腳間值設(shè)為0.01V對(duì)應(yīng)2g重量在Keil里勾選“Use Simulator”加載Proteus VSM DLL運(yùn)行后在Debug窗口Watch欄添加hx711_raw變量實(shí)時(shí)觀察AD值變化。這樣能驗(yàn)證標(biāo)定算法是否正確當(dāng)電壓源從0.001V調(diào)到0.02Vweight_g應(yīng)從100g線性增長(zhǎng)到2000g。比實(shí)物調(diào)試快10倍且不受環(huán)境溫度影響。4.3 實(shí)物調(diào)試七步法從現(xiàn)象到根因的排查路徑當(dāng)板子焊好第一次上電LCD不顯示、HX711無(wú)響應(yīng)、按鍵失靈——?jiǎng)e急著換芯片按此順序查測(cè)電源用萬(wàn)用表量VCC對(duì)GND是否4.95~5.05V低于4.9V說(shuō)明LDO負(fù)載過(guò)重查晶振示波器探頭接地夾接GND針尖碰OSC_IN看是否有8MHz正弦波幅值1Vpp驗(yàn)復(fù)位測(cè)NRST引腳電壓上電瞬間應(yīng)為0V然后升至3.3V并保持測(cè)HX711供電AVDD/DVDD是否分別為5.0V/3.3VDOUT引腳空閑時(shí)應(yīng)為高電平查DOUT信號(hào)示波器看DOUT在SCK時(shí)鐘下是否有24位數(shù)據(jù)脈沖高電平寬度≈1μs看LCD背光若背光亮但無(wú)字符檢查RS/EN電平是否按協(xié)議時(shí)序翻轉(zhuǎn)讀Flash用ST-Link Utility讀取0x08000000開(kāi)始的前16字節(jié)確認(rèn)程序已正確燒錄。去年幫客戶(hù)修一批故障板70%問(wèn)題出在第1步——PCB上5V電源走線太細(xì)0.15mm帶載后壓降達(dá)0.3V導(dǎo)致HX711基準(zhǔn)不穩(wěn)。改用0.3mm線寬后問(wèn)題全解決。4.4 量產(chǎn)前的72小時(shí)壓力測(cè)試清單交付前必須跑滿(mǎn)72小時(shí)模擬真實(shí)使用場(chǎng)景溫度循環(huán)-10℃→25℃→60℃每段保溫2小時(shí)全程稱(chēng)重精度偏差±0.5g電源擾動(dòng)用可編程電源模擬電網(wǎng)波動(dòng)輸入電壓在4.5V~5.5V間每10秒跳變一次LCD不花屏、數(shù)據(jù)不丟失按鍵疲勞用繼電器模擬“單價(jià)輸入”操作每秒按10次持續(xù)24小時(shí)Flash寫(xiě)入無(wú)失敗EMC摸底靠近手機(jī)通話(huà)GSM頻段、微波爐運(yùn)行2.45GHz、電動(dòng)工具啟動(dòng)寬帶噪聲稱(chēng)重?cái)?shù)據(jù)跳變±2g。其中EMC測(cè)試最易被忽略。我們發(fā)現(xiàn)當(dāng)秤放在微波爐旁1米內(nèi)HX711的DOUT引腳會(huì)感應(yīng)到100MHz諧波導(dǎo)致數(shù)據(jù)錯(cuò)位。解決方案是在DOUT線上串一個(gè)100Ω電阻并聯(lián)100pF電容到GND構(gòu)成RC低通濾波器截止頻率≈16MHz完美抑制干擾。5. 常見(jiàn)問(wèn)題與獨(dú)家避坑指南那些教程里永遠(yuǎn)不會(huì)寫(xiě)的細(xì)節(jié)5.1 “LCD顯示亂碼”的11種可能原因及速查表現(xiàn)象可能原因快速驗(yàn)證方法解決方案全屏黑塊背光亮但無(wú)字符用萬(wàn)用表測(cè)VO引腳電壓應(yīng)為0.5~1.5V調(diào)節(jié)10kΩ電位器或檢查電位器是否虛焊首行顯示正常第二行亂碼DDRAM地址錯(cuò)亂發(fā)送指令0x80設(shè)置DDRAM地址為0x00后觀察檢查EN引腳時(shí)序確保脈沖寬度450ns字符閃爍不定讀寫(xiě)時(shí)序沖突示波器看RS/EN/RW三線電平變化RW必須接地只寫(xiě)不讀禁用讀忙信號(hào)顯示數(shù)字但小數(shù)點(diǎn)錯(cuò)位浮點(diǎn)數(shù)格式化錯(cuò)誤在Debug Watch中查看float_val實(shí)際值用sprintf(buf, %.2f, weight)而非printf上電后顯示固定字符如EEFlash參數(shù)損壞用ST-Link讀取0x0800F000頁(yè)內(nèi)容執(zhí)行flash_erase_page(0x0800F000)后重標(biāo)定注意1602的DDRAM地址映射很反直覺(jué)——第一行地址是0x00~0x0F第二行是0x40~0x4F。很多代碼直接寫(xiě)lcd_write_cmd(0xC0)想跳到第二行首列但若之前沒(méi)清屏DDRAM指針可能在0x10位置導(dǎo)致顯示偏移。我的做法是每次寫(xiě)入前先發(fā)0x01清屏指令再發(fā)0x80或0xC0定位。5.2 HX711“讀數(shù)歸零”故障的深層分析現(xiàn)象空載時(shí)AD值穩(wěn)定在123456但一放物體就歸零全0。這不是傳感器壞了而是DOUT引腳被意外拉低。原因有三靜電擊穿焊接時(shí)烙鐵未接地靜電損壞HX711內(nèi)部輸出級(jí)。更換模塊即可GPIO配置錯(cuò)誤DOUT接的GPIO被設(shè)為推挽輸出應(yīng)為浮空輸入。檢查GPIO_InitTypeDef.GPIO_Mode GPIO_Mode_IN_FLOATING電源耦合HX711的DVDD與MCU共地不良形成電位差。用萬(wàn)用表測(cè)HX711 GND與STM32 GND間電壓若10mV需加粗地線或單點(diǎn)接地。我遇到過(guò)最詭異的一次客戶(hù)工廠車(chē)間地線帶30V交流電導(dǎo)致HX711 GND比MCU GND高28VDOUT被鉗位到0V。解決方案是加光耦隔離DOUT信號(hào)成本增加0.8元但徹底解決問(wèn)題。5.3 Flash寫(xiě)入失敗的“隱形殺手”現(xiàn)象標(biāo)定后重啟單價(jià)恢復(fù)默認(rèn)值。表面看是Flash沒(méi)寫(xiě)成功實(shí)則是未關(guān)中斷flash_program_word()執(zhí)行時(shí)若發(fā)生SysTick中斷可能導(dǎo)致Flash控制器狀態(tài)機(jī)紊亂。必須在寫(xiě)入前__disable_irq()寫(xiě)完后__enable_irq()未檢查Busy寫(xiě)入后立即讀取但Flash實(shí)際未完成。必須輪詢(xún)FLASH_GetFlagStatus(FLASH_FLAG_BSY) RESET跨頁(yè)寫(xiě)入試圖往0x0800F000寫(xiě)4字節(jié)但該地址在頁(yè)邊界實(shí)際擦除的是0x0800F000頁(yè)而參數(shù)存在0x0800E000頁(yè)。我的flash_save_calib()函數(shù)內(nèi)置頁(yè)邊界檢查自動(dòng)選擇安全地址。實(shí)測(cè)數(shù)據(jù)在1000次連續(xù)寫(xiě)入測(cè)試中未加__disable_irq()的失敗率達(dá)37%加了之后0失敗。5.4 量產(chǎn)BOM優(yōu)化的三個(gè)血淚教訓(xùn)電阻精度陷阱標(biāo)定電路中的分壓電阻用于HX711參考電壓必須用1%精度如RC0603FR-0710KL不能用5%的如RC0603JR-0710KL。后者溫漂達(dá)±100ppm/℃導(dǎo)致夏天和冬天標(biāo)定參數(shù)差5%。電容ESR影響AVDD濾波電容若用普通電解電容ESR1Ω在10MHz下阻抗高達(dá)10Ω濾波失效。必須用鉭電容ESR0.5Ω或固態(tài)電容。晶振負(fù)載匹配8MHz晶振配套的兩個(gè)22pF負(fù)載電容若PCB走線長(zhǎng)1cm需減小到18pF。否則起振困難冷機(jī)啟動(dòng)失敗率超20%。最后分享個(gè)小技巧在原理圖里給HX711的REFIN引腳預(yù)留0Ω電阻焊盤(pán)方便后期調(diào)試時(shí)接入精密電壓源校準(zhǔn)。這個(gè)焊盤(pán)在量產(chǎn)版里不貼件但調(diào)試階段救了我們?nèi)沃卮蠊收?。我在嘉立?chuàng)打樣第一版時(shí)因?yàn)闆](méi)加AVDD LC濾波整板稱(chēng)重誤差±50g。返工第二版加上電感和鉭電容誤差降到±0.3g。硬件設(shè)計(jì)沒(méi)有銀彈只有把每個(gè)器件的datasheet參數(shù)摳到小數(shù)點(diǎn)后三位才能讓STM32真正發(fā)揮出它的潛力。這套電子秤系統(tǒng)現(xiàn)在每天在200個(gè)社區(qū)柜子里稱(chēng)重超過(guò)1.2萬(wàn)次零返修——不是因?yàn)樗嘞冗M(jìn)而是因?yàn)槊恳粋€(gè)看似微小的細(xì)節(jié)我們都用實(shí)測(cè)數(shù)據(jù)驗(yàn)證過(guò)三遍。