拓冰建站拓冰建站
首页 / 资讯中心 / 正文

STM32电子秤计价系统完整开源:原理图、代码与Proteus仿真全解析

做嵌入式这些年经常有人问我“想找个完整的STM32项目练手从原理图到代码再到能跑起来的仿真有没有合适的推荐”问得多了我发现大家真正想要的不是某个“点亮LED”的demo而是一个能把外设、算法、交互串在一起的小系统看完能复现改完能用在自己的课设或毕设里。电子秤计价系统就是这样一个比较理想的选题。别看它名字低调里面积累了ADC采集、传感器驱动、按键处理、显示刷新、业务逻辑分层这些基本功而且代码量不大板子成本也低拿来练手特别合适。这次我把整个项目完整开源出来STM32F103C8T6主控HX711专用称重芯片配套原理图、Keil5工程、Proteus仿真一个包全部给齐。本文就把这个项目的设计思路、硬件细节、代码逻辑、仿真联调方法以及我踩过的坑一次说透。想跟着做的朋友看完这篇文章基本就能把整套系统搭起来。1. 项目概述与整体设计思路1.1 系统能做什么先说功能。这套电子秤计价系统核心就是“称重 算钱”两个动作。把货物放到秤盘上称重传感器把压力形变转成微弱电压信号经过HX711芯片放大采样后送给STM32STM32再把原始AD值换算成克数结合键盘输入的单价计算出金额最终把重量、单价、金额三样信息同时显示在LCD屏幕上。除了这三个基本量我还做了几个很实用的功能去皮Tare功能放上托盘或包装盒后一键去皮秤上直接归零不需要手动减掉皮重。清零功能切换货品批次时把当前重量清零不影响已经累计的金额。金额累加称完一件按一下累计键程序会把当前这笔金额累加到总额里适合多件商品计价的场景。超量程报警超过传感器量程或金额溢出时蜂鸣器报警防止误操作。这整套功能放在水果摊、小型商铺、快递称重这些场景里完全够用。对于学生党来说它作为课程设计或者毕业设计的选题也很合适因为“传感器采集 人机交互 显示输出”正好覆盖了嵌入式系统最常见的三大部分答辩时能讲的东西非常多。1.2 为什么选择STM32HX711这个组合主控选型上很多人第一反应是“51单片机行不行Arduino行不行”行当然行但体验完全不同。51单片机做这个项目IO口少、外设简单代码写起来憋屈Arduino虽然上手快但很多细节被封装掉了做完以后对底层还是一知半解。STM32F103C8T6这颗芯片资源适中、资料多、调试手段丰富而且最便宜的开发板十几块钱就能买到正好卡在“有难度但又不至于劝退”的位置。称重采集这一块我直接用了HX711称重专用ADC芯片而不是用STM32自带的ADC去采传感器信号。原因很简单电阻应变式称重传感器输出的差分信号只有毫伏级别直接用MCU内部ADC采分辨率根本不够还得加仪表放大器做前端调理电路复杂度一下子上去了。HX711内部集成了低噪声放大器和一个24位高精度ADC增益最大128倍直接把传感器接到芯片上就能用接口还是简单的两线串行对新手非常友好。这个选型思路在“传感器微弱信号采集”这个方向上特别典型项目中体会一次后面做其他测量类产品也能少走很多弯路。1.3 系统架构与信号流向整个系统的信号流可以用一句话概括压力变成电压电压变成数字数字变成重量重量乘以单价变成金额。从硬件模块上看系统分为六个部分称重传感器和HX711前端负责把压力转换为数字量。STM32主控负责数据读取、滤波、标定、按键扫描、金额计算和显示控制。LCD1602液晶负责显示重量、单价、金额、累计信息。独立按键负责输入单价、去皮、清零、累计。有源蜂鸣器负责按键提示音和超量程报警。电源模块USB供电或电池供电统一稳压到3.3V/5V给各个模块供电。软件架构上我采用模块化设计每个外设对应一个独立驱动文件。这样做的目的是让代码好移植、好调试后面想换显示器、换传感器只需要改对应模块不需要重新梳理业务逻辑。1.4 开源包里都有什么这个项目的开源包我整理得比较规整目录包括HARDWARE/原理图源文件提供Altium Designer和立创EDA两个版本按个人习惯打开即可。MDK-ARM/Keil5完整工程打开后直接编译就能出hex文件。SIMULATION/Proteus仿真工程包含已经接好的原理图加载hex后可以直接跑仿真。DOC/使用说明文档、引脚对照表、BOM清单、标定操作说明。文件不复杂拿到手建议先看一遍引脚对照表然后对照原理图和代码把IO口对应关系理清楚再做修改就会非常顺手。2. 硬件设计与原理图核心要点2.1 主控最小系统STM32F103C8T6属于F103系列的中低密度产品64KB Flash、20KB RAM主频最高72MHz2个SPI、2个I2C、3个USART、1个USB还有多个定时器和12位ADC。做电子秤这种项目资源绰绰有余甚至还有大量富余可以扩展蓝牙、WiFi模块。最小系统是STM32能跑起来的最基本电路包含电源电路、复位电路、时钟电路和BOOT配置。如果自己是手工焊接或者画板子这几项一个都不能省时钟电路8MHz无源晶振两端各接一个20pF左右负载电容到地。晶振尽量靠近芯片引脚摆放走线不要太长否则容易出现起振困难或者频率偏差的问题。复位电路复位引脚接10K上拉电阻到3.3V再并联一个100nF电容到地。按下复位键时引脚短暂拉低芯片复位。上电瞬间这个电容还能提供稳定的低电平脉冲保证芯片可靠启动。BOOT配置BOOT0和BOOT1都下拉到地让芯片从内部Flash启动。想要用串口下载程序时才把BOOT0拉高。很多新手焊完板子发现程序跑不起来查了半天往往是BOOT脚悬空导致启动模式不对。电源去耦每个VDD引脚旁都要放一个0.1uF陶瓷电容VDDA模拟电源脚建议串个小磁珠再接3.3V并加1uF电容。STM32的ADC参考电压来自VDDA这个脚如果不干净会直接影响后续模拟量采集的质量。2.2 称重传感器与HX711前端电路称重传感器是整个系统的“感官”选型和接线都很重要。我选的是最常见的五线制电阻应变式传感器量程5kg。这种传感器内部是四个电阻应变片组成的惠斯通电桥受力后应变片阻值发生变化电桥失去平衡在信号输出端产生一个与受力大小成正比的差分电压。它的分辨率极高5kg量程下满量程输出大约在1mV/V到2mV/V之间也就是说5V激励时满量程也就5到10毫伏极其微弱所以必须有专门的信号调理芯片来处理。HX711就是为这种传感器量身定制的。它内部包含一个低噪声可编程放大器和一个24位ADC通道A的增益可配置为128或64通道B的增益固定为32还内置了稳压电路和振荡器。主要参数大概这样参数数值ADC位数24位通道A增益128 / 64通道B增益32输出数据速率10HzRATE接地/ 80HzRATE接高工作电压2.6V ~ 5.5V接口PD_SCK和DOUT两线制HX711和传感器、MCU的典型接线方式如下传感器E和E-接HX711的E和E-作为激励电源输入HX711内部会把这路电源稳压后提供给传感器传感器A和A-接HX711的A和A-作为差分信号输入。HX711的DOUT接STM32的一个GPIO输入脚PD_SCK接另一个GPIO输出脚。有一点需要特别说明HX711的模拟电源AVDD不是直接接电源的它通过内部的稳压输出给传感器供电。AVDD的输出电压由VFB引脚外接的电阻分压网络决定公式是VAVDD VBG * (R1 R2) / R1其中VBG大约是1.25V。我在电路里用1M和220K电阻计算出来大约是6.9V但受限于VCC是5V实际输出会在VCC附近自动回落。如果想让传感器激励电压更稳定可以在AVDD和地之间加一个10uF电解电容并联0.1uF陶瓷电容。2.3 显示、按键、蜂鸣器电路显示部分我选了LCD1602十年前的经典外设现在用依然稳。接口是并行的RS、RW、E、D0-D7共11根线。为了省引脚我在设计里把RW直接接地只做写入操作不做读取。这样即使不检查忙标志只要在指令之间插入足够延时也能稳定驱动同时省下一个IO口。V0对比度引脚接一个10K电位器到地屏幕不显示或者字淡的时候调它这是很多人忽略的细节。按键电路做了4个独立按键单价加、单价减、去皮、清零/累计。设计时没有外加上拉电阻直接用STM32内部上拉。按键一端接GPIO另一端接地按下时读到低电平。这样做的好处是省元件坏处是一旦引脚配置错就检测不到。具体用哪几个引脚我在原理图里都标好了。蜂鸣器选择的是有源蜂鸣器内部自带振荡源通电就响驱动最简单。但因为蜂鸣器工作电流比较大直接接STM32 IO口会拉垮引脚所以中间加了一个NPN三极管做放大型号用的是SS8050基极串1K电阻接IO口集电极接蜂鸣器负极蜂鸣器正极接电源同时在蜂鸣器两端反向并联一个1N4148二极管吸收关断时的反向电动势防止损坏三极管。电源部分我做了两级设计外接USB 5V输入一路直接给HX711和传感器供电另一路经过AMS1117-3.3稳压给STM32和LCD供电。这里有个需要注意的地方HX711的数据输出电平在高电压供电时会超过STM32的耐压范围所以在实际使用中我会把HX711的VCC也统一接3.3V传感器激励电压虽然低了一点但秤的精度不受影响逻辑电平也安全了。想在项目里用5V供电的话就必须加电平转换电路不能直接硬连。2.4 PCB布局与抗干扰的几条经验称重信号是毫伏级的最怕干扰。电路设计上我总结了几条属于自己的经验写在这里供参考第一模拟地和数字地分开单点连接。HX711的地、传感器信号地属于模拟地STM32的GND属于数字地两者通过一个0欧电阻或者磁珠在电源入口处连接。这样能防止数字电路的高频噪声串进模拟电路。第二HX711尽量靠近传感器接口差分信号线尽量短最好做成等长的平行走线。走线两边用地线包住信号被干扰的几率会小很多。第三电源走线加宽。3.3V和5V主干线加到1mm以上传感器激励线至少0.5mm。细小电阻对微弱电流问题不大但对电源回路的压降影响明显。第四晶振下面不要走任何信号线尤其是高频信号线。STM32的8MHz晶振起振后底层走线会产生寄生耦合直接影响系统稳定性。如果你只是用面包板或者杜邦线搭电路测试上面这些规则可以打折但“电源干净”和“信号线短”这两条一定要尽量遵守。我的经验是同样的代码和传感器在面包板上数据跳变几个字很正常焊到PCB上立刻稳很多。3. 软件代码架构与核心逻辑实现3.1 代码文件划分与工程结构Keil工程里的文件划分如下main.c主函数初始化外设循环扫描按键和刷新显示。hx711.c / hx711.hHX711驱动负责数据读取。weight.c / weight.h重量计算和滤波包含零点、斜率、去皮逻辑。lcd1602.c / lcd1602.hLCD1602显示驱动。key.c / key.h按键扫描和消抖。buzzer.c / buzzer.h蜂鸣器控制。主函数的大致流程是初始化系统时钟初始化GPIO初始化LCD初始化HX711读取10次传感器数据取平均设置为零点然后进入死循环循环体里依次做按键扫描、重量采集与滤波、金额计算、显示刷新。老生常谈的一句话但真心建议写项目一定要把“硬件驱动”和“业务逻辑”分开。滤波算法是业务逻辑HX711读原始AD值是驱动计价是业务逻辑LCD显示数值是驱动。分开之后你想把1602换成OLED只需要重写一个lcd1602.c主函数一行不用动。这个习惯不管是在学校还是以后进公司都受用。3.2 HX711驱动时序与读取代码HX711的数据接口就两根线PD_SCK和DOUT读一次数据分三个阶段等待DOUT变低、移出24位数据、输出增益脉冲。当DOUT从高电平跳变到低电平时表示24位转换结果已经准备好了。此时单片机给PD_SCK发送24个高脉冲每来一个上升沿DOUT引脚就输出一位数据先高位后低位。24个脉冲结束后再给出第25个脉冲此时芯片会为下一次转换自动选择通道A、增益128。如果第25、26、27共三个脉冲则是通道B、增益32。我项目里用的是通道A增益128所以只发一个额外脉冲。对应的核心驱动代码如下// hx711.h 引脚定义可按实际接线修改 #define HX711_SCK_PORT GPIOB #define HX711_SCK_PIN GPIO_Pin_0 #define HX711_DOUT_PORT GPIOB #define HX711_DOUT_PIN GPIO_Pin_1 // hx711.c 读取一次AD值 uint32_t HX711_Read(void) { uint32_t value 0; uint8_t i; // 等待DOUT变低表示数据已经准备好 while (GPIO_ReadInputDataBit(HX711_DOUT_PORT, HX711_DOUT_PIN) 1); for (i 0; i 24; i) { GPIO_SetBits(HX711_SCK_PORT, HX711_SCK_PIN); // SCK拉高 delay_us(5); value 1; if (GPIO_ReadInputDataBit(HX711_DOUT_PORT, HX711_DOUT_PIN) 1) value | 0x01; GPIO_ResetBits(HX711_SCK_PORT, HX711_SCK_PIN); // SCK拉低 delay_us(5); } // 第25个脉冲选择通道A增益128 GPIO_SetBits(HX711_SCK_PORT, HX711_SCK_PIN); delay_us(5); GPIO_ResetBits(HX711_SCK_PORT, HX711_SCK_PIN); delay_us(5); // 24位补码转成有符号数 if (value 0x800000) value | 0xFF000000; return value; }这个代码里有几个关键点值得展开说。等待DOUT变低这一步特别关键。如果你在DOUT还没准备好的时候强行读数据读出来的数值会乱跳。很多人调这个芯片发现“数值忽大忽小、完全不受控”原因往往就在这里。24位数据是从最高位开始移出的所以每读一位进来value要先左移一位再判断当前DOUT电平。这样循环24次后value里就是完整的原始数据。HX711的输出格式是二进制补码最高位是符号位正数看起来正常负数十进制会是一个很大的数。所以代码里用if (value 0x800000) value | 0xFF000000;做符号扩展把这个24位补码变成32位有符号数后面做减法、判断负值才能用得顺手。延时5微秒是从HX711手册里查的它能保证SCK高、低电平持续时间都满足芯片要求。STM32主频72MHz下这个延时用简单的空循环就能实现不追求精确只要不低于芯片要求的几百纳秒就行。3.3 标定、重量换算与校准方法原始AD值本身没有单位把它换算成克数靠的是标定。整个标定的核心是两点确定零点空秤时的AD值确定斜率单位重量对应的AD变化量。标定步骤很简单这也是我写在DOC文档里的操作流程秤盘上空载上电等它稳定5秒记录下此时滤波后的AD值记为zero_value。在秤盘上放一个已知重量的标准砝码比如500g等数值稳定记录下此时的AD值记为ref_value。计算斜率slope (ref_value - zero_value) / 500。实际重量的计算公式weight_g (current_value - zero_value) / slope。举个例子我实测某次标定中空载滤波值是8300000放上500g砝码后是8600000那么slope就是300000/500 600也就是每克对应600个AD值。当前读数如果稳定在8420000重量就是(8420000 - 8300000) / 600 200g。这里有一个细节称重传感器严格来说不是完全线性的在量程两端误差会比中间大。如果要求的精度比较高可以做成多点分段标定比如在0、100g、500g、1000g、2000g、5000g各取一个点相邻两点之间算一个斜率称重时先判断当前AD值落在哪个区间再用该区间的斜率计算。这个做法代码量也不大但精度提升很明显。我给项目写的重量计算函数大概长这样float Get_Weight_Gram(void) { int32_t value; float weight; value HX711_Read_Filter(); // 读滤波后的AD值 if (value zero_value) // 防止去皮后出现负重量 weight 0.0f; else weight (float)(value - zero_value) / slope; return weight; }3.4 数据滤波与去皮逻辑称重传感器的AD值天生就带噪这和芯片好坏关系不大主要是环境振动和电磁干扰造成的。如果用单次读数的原始值直接显示LCD屏幕上的数字会不停跳非常影响体验。我用的方法是“去极值平均滤波”这个算法简单有效连续采集多次排序后丢掉最大值和最小值剩下的求平均。下面是代码实现#define FILTER_NUM 7 int32_t HX711_Read_Filter(void) { uint32_t buf[FILTER_NUM]; uint8_t i, j; uint32_t temp; uint32_t sum 0; // 连续采集 for (i 0; i FILTER_NUM; i) buf[i] HX711_Read(); // 冒泡排序从小到大 for (i 0; i FILTER_NUM - 1; i) { for (j 0; j FILTER_NUM - 1 - i; j) { if (buf[j] buf[j 1]) { temp buf[j]; buf[j] buf[j 1]; buf[j 1] temp; } } } // 去掉最大最小求平均 for (i 1; i FILTER_NUM - 1; i) sum buf[i]; return sum / (FILTER_NUM - 2); }为什么不用普通的算术平均因为传感器偶尔会被一个突发的尖峰脉冲干扰比如旁边有人走动、桌面被碰了一下、附近有大功率设备启动这个毛刺数值远离真实值算术平均会把整体结果拉偏而去掉最大最小值之后就安全多了。真实场景下N取5到9都行N太小滤波效果差N太大响应变慢。我最后选7是因为实测下来它既能滤掉毛刺称重响应时间也不至于让人等太久。去皮逻辑的核心不是“把读数清零”而是把当前读数更新为新的零点。比如秤上放了托盘去皮后zero_value就变为当前带托盘的AD值之后再放货物重量就是货物净重。这个操作在代码里是实时修改zero_value变量非常直接。还有一个细节值得提醒每次上电时不一定非要执行“空秤清零”这个操作。如果上电时秤盘上已经有东西系统应该等数值稳定后用此刻的读值作为初始零点否则后面会出现“没放东西却显示负数”的尴尬情况。我在代码里加了一个上电自动稳定逻辑等连续5次读数方差在允许范围内才把当前值设为零点效果很稳。3.5 计价逻辑与单价输入的实现计价逻辑本身不复杂但有几个容易算错的地方。重量单位我用克作为内部计算单位显示在LCD上时再换算成千克。单价单位是“元/千克”那么金额的计算公式就是金额 重量(kg) × 单价(元/kg)举例货物重量是1250g单价是8元/千克那么金额就是1.25 × 8 10.00元。金额计算需要做四舍五入到分因为商品结算后找零都以分为单位。C语言里浮点数直接截断会丢掉精度正确做法是uint32_t amount_fen; // 金额单位分 float weight_kg; uint32_t price_yuan; // 单价单位元/千克只支持整数 amount_fen (uint32_t)(weight_kg * price_yuan * 100 0.5);加0.5再截断是C语言里最基本的四舍五入技巧。weight_kg * price_yuan * 100可能得到一个类似1000.999999的小数如果不加0.5直接截断会少1分钱加了之后就安全了。单价输入我用的是“加1、加10、加100”这种递增方式按键上标了“单价”、“单价-”、“档位”这几个功能。每次按键当前单价按设定好的步进增减长按“单价”可以连续快进。这样虽然输入大额单价时按键次数多一点但在按键数量有限的情况下最直观也符合计价秤的常用操作习惯。累计金额的代码也很简单在每一次称重结算时把本次金额加到total_fen变量里显示时再拆成元和小数部分。超出9999元时触发蜂鸣器报警防止计算溢出。核心代码如下void Calc_Price(void) { float weight_kg Get_Weight_Gram() / 1000.0f; uint32_t amount_fen (uint32_t)(weight_kg * price_yuan * 100 0.5); if (amount_fen 999999) // 单笔金额上限防溢出 { Buzzer_Alarm(); return; } display_amount amount_fen; // 更新显示金额 if (accumulate_flag) { total_fen amount_fen; // 累计 display_total total_fen; } }3.6 按键消抖与状态机设计按键是机械结构按下和松开的瞬间触点会快速通断好几次这就是“抖动”。如果不处理一次按键可能被识别成多次单价一不小心就从1跳到11。最常见的消抖方法是检测到电平变化后延时10到20毫秒再确认一次电平。这个做法在阻塞式程序里没问题但如果在延时的10毫秒里来了重量变化就来不及响应了。所以我采用了一种非阻塞的状态机消抖方案不让程序傻等而是靠主循环的周期性扫描来判断。具体逻辑是每10ms扫描一次按键如果检测到引脚为低电平并且上一次扫描结果也是低电平就认为按键确实被按下执行一次动作。如果只有一次低电平下一次又变高了就判定是抖动忽略掉。核心判断代码void Key_Scan(void) { // key_state 记录当前按键原始电平key_last 记录上次数值 uint8_t current KEY_READ(); // 读取四个按键组合值 if (current ! key_last) // 电平发生变化可能是抖动 { key_debounce_cnt; if (key_debounce_cnt 2) // 连续两次扫描结果一致才确认 { Handle_Key_Action(current); // 执行按键逻辑 key_debounce_cnt 0; key_last current; } } else { key_debounce_cnt 0; key_last current; } }利用主循环定时调用的机制配合一个计数器就能在不阻塞其他任务的情况下完成消抖。在此基础上你还可以扩展长按功能当同一按键持续为低超过1秒就认为是长按触发连续加单价操作。对我来说这个状态机设计是这个项目里收益最高的部分之一后面做其他带按键的产品我都是直接复用这套逻辑。4. Proteus仿真环境搭建与联调4.1 仿真的价值与局限我见过不少朋友一上来就拿电烙铁焊硬件结果代码问题、接线问题混在一起排查起来特别痛苦。Proteus仿真的第一个价值就是在没拿到实物之前先把“软件逻辑”调通。LCD能不能正确显示、按键能不能正确响应、计价结果对不对这些都能在电脑上先验证一轮。第二个价值是方便做课程设计演示教室里没有硬件也能完整展示运行效果。但仿真也有明显的局限这点我必须在文章里说清楚Proteus里的HX711模型是理想化的它不会模拟真实传感器的噪声、温漂、接触电阻这些物理特性所以仿真里数值“稳如老狗”不代表真板也一样稳。仿真的作用在于验证“逻辑链路”不在于验证“硬件精度”。4.2 仿真工程搭建关键步骤Proteus版本建议用8.11以上元件库更全。打开我提供的仿真工程后应该能看到STM32F103C8T6、HX711、LCD1602、按键、蜂鸣器等元件已经连接好了。如果要从零开始搭步骤也不复杂新建工程后在元件模式点“P”搜索并放置STM32F103C8T6、HX711、LCD1602、BUTTON、BUZZER、RESISTOR等元件。按照原理图连接线路注意电源和地要接对STM32的VDD和VDDA都要接5V或3.3VHX711的AVDD按前面的分压网络接好。用Keil5打开我的工程在Options for Target里把输出勾选“Create HEX File”编译生成hex文件。回到Proteus双击STM32芯片在Program File里选择刚才生成的hex文件把Crystal Frequency设为8MHz这个一定要和代码的时钟配置一致。点击左下角运行按钮LCD会显示欢迎信息按下按键就能看到重量和金额变化。这里有个容易踩的坑Proteus搜HX711时元件名可能是“HX711”也可能带后缀不同版本显示不一样。如果搜不到可以换成用一个滑动变阻器加一个电压源来模拟传感器差分信号效果类似只是需要手动调节电压来模拟重量的变化。4.3 仿真常见联调问题仿真环境里遇到问题大多数不是代码逻辑问题而是元件连接或配置问题程序跑起来但LCD没反应先检查对比度电位器有没有接V0引脚电压是不是在1V左右然后检查RS、RW、E三根控制线的连接对不对尤其是RW如果直接接地代码里就不能再初始化这个引脚。都查完之后用万用表测一下LCD供电脚3.3V或者5V要正确。按键按下去没反应在Proteus里按键按一下后要释放仿真器默认是按“空格”或者点击按钮触发如果引脚一直被拉低程序会认为按键一直处于按下状态而忽略动作。确认按键连接是“一端接GPIO一端接地”并使用内部上拉。重量数值不动多半是HX711没有工作起来查一下AVDD有没有分压到位PD_SCK和DOUT有没有接反。HX711的DOUT没变低时程序会一直卡在等待循环里这就是仿真界面看起来“一切正常但程序不推进”的原因。4.4 从仿真到真板的注意事项仿真跑通之后做真板心态上要有所准备仿真里一切正常只代表逻辑正确真板上多出来的是电压纹波、接触电阻、电磁干扰、温度漂移这四样东西。第一要注意的是HX711的供电。真板上如果直接用USB供电电源噪声会很大我用一个10uF电解电容并联0.1uF陶瓷电容放在HX711电源脚附近效果立竿见影。第二要注意的是传感器接线。五根线一定不要接错尤其是A和A-如果反了标定斜率会变成负数重量越大读值越小。第三要注意的是逻辑电平匹配问题。文章前面提过HX711在5V供电下DOUT输出高电平接近5VSTM32的 GPIO耐压不够所以我把HX711电源直接也降到3.3V一次性解决电平匹配问题。这个点在我早期的版本里吃过亏后来统一3.3V供电之后稳定性和安全性都好了很多。5. 常见问题与排查技巧实录5.1 称重值跳字严重跳字是电子秤项目最让人头疼的问题我调试过程中也在这个问题上耗了不少时间。总结下来跳字的原因基本就这几类排查的时候按顺序来传感器信号线太长或者没有屏蔽环境里的电磁噪声直接耦合进差分信号。对策是把传感器线换成屏蔽线屏蔽层单端接地。HX711模拟电源纹波大。对策是在AVDD和地之间加大电容10uF并联0.1uF。滤波强度不够。把去极值平均滤波的N从5提高到7或9。这个改动对数字稳定性的改善非常明显只是响应时间会稍微变长。秤盘附近有气流或桌面振动。把秤放在稳固的台面上尤其是仿真转真板测试时不要拿手扶着秤盘。接地不良。STM32、HX711、传感器三者的地必须可靠接在一起不能靠信号线“顺便”接地。软件上的对策可以配合一个“稳定检测”连续多次读数间的差值小于某个阈值才认为重量稳定此时更新显示。这样即使偶尔跳一下显示也不会跟着闪。5.2 标定后称重不准标定没问题的前提下称重不准最常见的原因是传感器本身的非线性或者砝码位置不合理。传感器在受压时如果重物放得偏离中心读数会明显偏小这就是“偏载误差”。所以标定和称重时都要尽量把物体放在秤盘中央。另一个常见问题是传感器蠕变。放上重物后传感器应变片和弹性体需要一点时间才能稳定很多人刚放上去就读数自然会觉得“越称越轻”。解决方法是读数前加稳定延时比如等连续几次滤波值变化小于0.5g再锁定显示。如果要求更高的精度可以做多点标定把量程分成几段每段用独立的斜率计算。实测中这种分段线性化处理能把误差控制在0.2%以内对于这种小成本电子秤来说已经非常优秀了。5.3 LCD1602显示乱码或无显示LCD1602显示问题排在第一位的原因是对比度没调好。V0引脚需要一个负电压才能正常显示但简单做法是用电位器从地到VCC分压一般调到1V左右显示最清晰。如果不接电位器让V0悬空轻则显示深黑方块重则完全没显示。排在第二位的是初始化时序问题。LCD1602上电后需要等待一段时间才能接受命令代码里要注意在初始化时加足够延时不要一上电就猛发指令。我的初始化代码里每步之间都加了5ms以上延时实测很稳。排在第三位的是电平问题。如果你给LCD1602供5V而STM32是3.3V数据线高电平对LCD来说够用但RS、E等控制线电平略低有些液晶模块会不稳定。稳妥方案是LCD也接3.3V供电或者在关键控制线上加电平转换。项目原理图里我画的是3.3V供电版本直接照抄就行。5.4 按键不灵或连按按键不灵多数是硬件问题接线上拉电阻没焊、GPIO模式配错、引脚被复用。检查顺序是先用万用表测按下时引脚电压有没有变化再用代码读一次GPIO输入值确认不是硬件问题之后再查软件。连按则多半是软件消抖时间太短或者没有处理重复触发。我前面写的状态机消抖方案里最关键的是“确认后延时忽略一段时间”防止一次按下触发多次动作。按键动作执行和主循环扫描频率不要太快10ms扫一次足够。5.5 程序下载失败STM32F103C8T6支持ST-LinkSWD接口和串口ISP两种下载方式。如果下载失败先看芯片能不能被识别。ST-Link识别不到检查SWDIO和SWCLK有没有接反、复位电路是否正常、芯片有没有供电。串口下载的话记得先给BOOT0接3.3V让芯片进入ISP模式下载完再把BOOT0拉低复位重新运行。还有一个经常被忽视的问题下载线太长尤其是杜邦线超过20cm时SWD信号很容易出错。换短一点的线往往就好了。5.6 去皮键按下后重量为负这个问题的根源在于去皮操作把当前值设成了零点但如果当前值原本就略低于初始零点比如传感器从热机状态变到冷机状态零点漂移了去皮后差值为负显示就会出现负重量。对策有两个一个是代码里对小于0的重量统一按0处理另一个是在去皮前先确认当前读数大于某个阈值比如大于2g才允许去皮避免“负得莫名其妙”。我个人建议两者都做代码里先限制去皮条件再在显示前限制最小值为0这样用户面对的就永远是可理解的逻辑。最后再分享一个我自己的真切体会。电子秤这个项目从“能跑”到“好用”之间差的永远是稳定性而不是某个炫技功能。你会花大量时间在滤波、接地、去耦、标定这些看起来很琐碎的事情上但恰恰是这些功夫才是真正的项目经验。这套开源工程能给到你的是一条完整踩通的路原理图怎么画、代码怎么写、仿真怎么搭、标定怎么做、问题怎么查全都摆在面前照着走一遍你对嵌入式系统的理解会和只看教程完全不同。另外这个项目也很适合继续扩展加个蓝牙模块变成手机同步称重记录加个WiFi模块做成云端电子秤换上大屏做触摸版都是很自然的下一步。需要源码和仿真文件的朋友直接在评论区留言交流就行。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门