
1. 项目背景与整体设计思路1.1 为什么选择STM32做智能计价电子秤计价电子秤这个东西看起来简单——不就是称重然后乘单价嘛。但真正动手做过的人都知道里面涉及的东西比想象中多得多高精度ADC采样、数字滤波、键盘输入、LCD显示、单价计算、超载报警如果要加上数据上传功能还得跑通信协议。用51单片机当然也能做但当你需要同时处理称重采样、按键扫描、显示刷新和串口通信的时候51的资源和主频就开始捉襟见肘了。STM32F103系列是我认为这个项目最合适的选型。原因很直接Cortex-M3内核72MHz主频内置多通道12位ADC硬件SPI接口多个USART定时器资源丰富Flash和RAM对于这种量级的项目绰绰有余。更重要的是STM32的生态非常成熟HAL库和标准库都有大量参考代码社区里踩过的坑基本都能搜到解决方案。价格上F103C8T6这种最小系统板十几块钱就能拿下做毕设或者练手项目成本极低。这个项目的核心目标很明确做一台能实际用的计价秤称重范围0-5kg精度到1g支持单价输入、总价计算、超载提示并且预留物联网数据上传的接口。适合有C语言基础、学过STM32基本外设操作的同学也适合想找一个完整嵌入式项目练手的开发者。1.2 系统整体架构拆解整个系统我把它分成四个模块来设计每个模块各司其职称重采集模块核心是HX711这颗24位ADC芯片配合电阻应变式称重传感器。HX711内部集成了稳压电源和时钟振荡器外围电路极其简单只需要两个普通IO口就能读数据。它负责把传感器输出的微弱差分电压信号放大并转换成数字量STM32再通过时序读取。主控与计算模块STM32F103负责整个系统的调度。它要定时读取HX711的数据做滤波处理把原始ADC值转换成重量再根据键盘输入的单价计算总价最后驱动LCD显示。同时它还要管理按键扫描、超载判断、蜂鸣器报警等逻辑。人机交互模块显示用0.96寸或1.3寸的OLEDSSD1306驱动或者LCD1602。我倾向于OLED因为I2C接口只占两个引脚显示内容丰富不需要背光电路。按键用矩阵键盘或者独立按键至少需要数字键0-9、小数点、去皮、清零、确认这几个功能键。通信扩展模块ESP8266通过UART和STM32连接用AT指令或者直接烧写固件做透传把称重数据上传到云平台。这部分是可选的但加上之后项目的完整度会高很多也更符合“智能”的定位。四个模块之间的关系是这样的HX711采集重量数据给STM32STM32处理后一方面驱动显示另一方面通过ESP8266上传。按键输入单价和操作指令STM32根据这些输入完成计价逻辑。1.3 关键器件的选型考量选型这件事我的原则是够用就好但关键器件不能省。称重传感器选5kg量程的电阻应变式传感器精度等级C3输出灵敏度1mV/V左右。这种传感器价格便宜十几到几十块线性度好配合HX711完全能满足1g精度的要求。注意传感器的量程要略大于实际最大称重留20%余量否则长期满量程工作会影响寿命和精度。HX711模块市面上常见的HX711模块自带PCB和滤波电容直接能用。它的采样率可选10Hz或80Hz通过RATE引脚控制。10Hz模式下噪声更低适合静态称重80Hz响应更快但噪声略大。计价秤场景下我建议用10Hz因为称重是静态过程精度优先。STM32主控F103C8T6最小系统板72MHz64KB Flash20KB RAM。这个配置跑裸机程序绰绰有余即使加上FreeRTOS也够用。如果后续要加更多功能可以升级到F103RCT6或者F407系列。ESP8266用ESP-01S模块体积小价格便宜支持AT指令固件。通过UART和STM32通信STM32发AT指令控制它连接WiFi和上传数据。注意ESP8266是3.3V供电峰值电流可能到300mA所以电源要单独处理不能直接从STM32的3.3V稳压器取电。显示模块0.96寸OLEDSSD1306驱动I2C接口。分辨率128x64显示重量、单价、总价、状态信息完全够用。I2C地址通常是0x78或0x7A具体看模块背面的标注。2. 硬件电路设计与核心细节2.1 HX711与称重传感器的接线要点HX711和传感器的连接是整个项目精度成败的关键。传感器一般有四根线红E、黑E-、白A、绿A-。红黑是激励电压白白绿是差分信号输出。接线的时候一定要注意传感器的E接HX711的EE-接E-A接AA-接A-。不同厂家的传感器线色可能不同一定要看说明书或者用万用表测。传感器信号线要尽量短最好不超过20cm而且要用屏蔽线。如果线太长容易引入干扰读数会跳。HX711的B通道一般不用悬空即可。如果要用B通道接第二个传感器需要修改代码里的通道选择。HX711和STM32的连接就简单了VCC接3.3VGND接GNDDT数据和SCK时钟接任意两个GPIO。我一般用PA0接DTPA1接SCK。注意这两个引脚在代码里要配置成推挽输出SCK和浮空输入或上拉输入DT。注意HX711的供电电压会影响零点漂移。如果用3.3V供电零点可能会随温度变化。建议在初始化时做一次去皮校准并且在实际使用中定期重新去皮。2.2 STM32最小系统与外围接口分配我用的引脚分配方案如下你可以根据自己手头的板子调整功能引脚说明HX711 DTPA0数据输入HX711 SCKPA1时钟输出OLED SCLPB6I2C1时钟OLED SDAPB7I2C1数据按键行PB0-PB3矩阵键盘行线按键列PB4-PB7矩阵键盘列线ESP8266 TXPA9USART1 TXESP8266 RXPA10USART1 RX蜂鸣器PC13报警输出这个分配方案的好处是I2C和UART都是硬件外设不占CPU时间按键用矩阵方式4x4可以接16个键足够用蜂鸣器用普通IO控制三极管驱动。电源部分要注意STM32和HX711都用3.3VESP8266也用3.3V但电流较大。建议用AMS1117-3.3提供3.3V输入用5V USB供电。ESP8266的电源引脚旁边要并一个100uF电解电容和一个0.1uF陶瓷电容防止WiFi发射时的电流冲击导致复位。2.3 电源与抗干扰设计电子秤的精度很大程度上取决于电源质量和抗干扰能力。我踩过的坑包括读数跳动大、零点漂移、按键时读数突变。后来总结了几条经验HX711的模拟电源和数字电源要分开滤波。AVDD和DVDD之间用磁珠隔离各自并10uF和0.1uF电容。传感器的激励电压最好用独立的LDO供电不要和STM32共用一路。如果条件允许用REF3033之类的基准源给传感器供电稳定性会好很多。PCB布局时模拟部分和数字部分要分开地线单点接地。如果用的是模块而不是自己画板至少要把HX711模块远离WiFi天线和电机等干扰源。软件上做数字滤波后面会详细讲。3. 软件架构与核心算法实现3.1 HX711驱动时序与数据读取HX711的通信协议是自定义的串行时序不是标准SPI需要手动模拟。时序是这样的当DT为低电平时表示数据准备好然后SCK给25到27个时钟脉冲前24个脉冲读出24位数据补码格式第25个脉冲选择下一次的通道和增益。// HX711读取原始值的简化代码 long HX711_Read(void) { long value 0; unsigned char i; // 等待DT变低 while(HX711_DT_READ() 1); // 读取24位数据 for(i 0; i 24; i) { HX711_SCK_HIGH(); delay_us(1); value value 1; HX711_SCK_LOW(); delay_us(1); if(HX711_DT_READ()) value; } // 第25个脉冲选择A通道增益128 HX711_SCK_HIGH(); delay_us(1); HX711_SCK_LOW(); delay_us(1); // 补码转换 if(value 0x800000) value | 0xFF000000; return value; }这段代码里几个关键点延时不能太短HX711的时序要求SCK高电平至少0.2us低电平至少0.2us实际用1us很安全第25个脉冲不能少否则下次读的是B通道补码转换必须做否则负值会出错。3.2 数字滤波与重量计算HX711读出来的原始值跳动是正常的因为24位ADC的分辨率远高于传感器的实际精度。直接显示原始值会看到最后几位一直在变。我的做法是第一步滑动平均滤波。连续读10次去掉最大和最小值剩下8个取平均。这样能有效抑制随机噪声。第二步一阶低通滤波。把滤波后的值再经过一个低通滤波器进一步平滑。公式是filtered filtered * 0.9 new_value * 0.1。系数0.1决定了响应速度和平滑度的平衡太小响应慢太大滤波效果差。第三步重量换算。先用已知砝码做校准得到两个参数零点偏移量offset和比例系数scale。重量 (原始值 - offset) / scale。校准的时候用两个点空载和标准砝码比如500g分别记录原始值算出scale。float Get_Weight(void) { long raw HX711_Read_Filtered(); float weight (float)(raw - offset) / scale; if(weight 0) weight 0; return weight; }实操心得校准的时候一定要等传感器稳定空载读数要连续读几十次取平均。砝码要放在秤盘正中央避免偏载误差。如果条件允许用多个砝码点做线性拟合精度会更高。3.3 计价逻辑与键盘输入处理计价逻辑本身不复杂总价 重量 × 单价。但实际使用中有几个细节要处理重量单位是kg还是g我建议内部统一用g做整数运算显示的时候再转成kg。这样可以避免浮点数精度问题。单价输入支持小数点后两位用整数存储比如12.50元存成1250计算时再除以100。去皮功能按去皮键把当前重量设为新的零点offset更新为当前原始值。超载判断如果重量超过最大量程比如5kg显示“超载”并蜂鸣器报警。键盘扫描我用的是定时器中断状态机的方式每10ms扫描一次带20ms消抖。这样主循环不用一直等着按键可以腾出时间做其他事情。// 按键扫描状态机简化版 void Key_Scan(void) { static unsigned char key_state 0; unsigned char key Read_Key_Matrix(); switch(key_state) { case 0: // 空闲 if(key ! 0xFF) { key_state 1; key_temp key; } break; case 1: // 消抖 if(key key_temp) { key_state 2; key_press key_temp; } else key_state 0; break; case 2: // 等待释放 if(key 0xFF) key_state 0; break; } }3.4 OLED显示驱动与界面布局OLED用SSD1306驱动I2C接口。初始化序列比较长但都是固定的网上能找到现成的。显示界面我分成三行第一行重量大字体显示比如“1.234 kg”第二行单价比如“12.50 元/kg”第三行总价比如“15.43 元”刷新策略上不要每次循环都全屏刷新那样会闪。我的做法是重量变化超过1g才刷新重量区域单价变化才刷新单价区域总价变化才刷新总价区域。这样既流畅又不闪。I2C通信速率建议用400kHz太快了OLED可能不响应。如果显示花屏先检查I2C地址对不对再检查上拉电阻有没有接一般模块自带4.7k上拉。4. 物联网功能扩展与ESP8266接入4.1 ESP8266的AT指令配置流程ESP8266用AT指令固件是最简单的接入方式。STM32通过UART发AT指令ESP8266执行后返回结果。基本流程是发送AT确认模块响应。发送ATCWMODE1设置为Station模式。发送ATCWJAPSSID,password连接WiFi。这一步可能需要几秒钟要等返回OK。发送ATCIPSTARTTCP,服务器地址,端口建立TCP连接。发送ATCIPSEND长度然后发送数据。数据发送完成后等待返回SEND OK。// 发送AT指令的简化函数 void ESP8266_SendCmd(char *cmd, char *expect, u16 timeout) { USART1_SendString(cmd); USART1_SendString(\r\n); // 等待期望的响应超时返回 while(timeout--) { if(USART1_CheckResponse(expect)) return; delay_ms(10); } }注意ESP8266的AT指令对大小写敏感必须大写。每条指令后面要加\r\n。WiFi密码如果有特殊字符要注意转义。4.2 数据上传协议设计上传的数据格式我用的是简单的JSON因为可读性好云平台也容易解析{weight:1234,price:1250,total:1543,unit:g}发送频率不用太高每5秒发一次就够了。如果重量变化超过10g立即发送一次。这样既能实时反映称重变化又不会产生太多流量。如果云平台支持MQTT也可以用MQTT协议但AT指令固件对MQTT的支持有限需要先连TCP再手动组包。对于这个项目来说HTTP POST或者TCP透传就够用了。4.3 通信稳定性与异常处理ESP8266在实际使用中会遇到各种问题WiFi断连、TCP超时、模块死机。我的处理策略是每条AT指令都有超时机制超时后重试重试3次还失败就复位ESP8266。定期发送AT心跳检测模块是否在线。如果连续3次无响应硬件复位。数据发送失败时先把数据存到本地缓冲区等连接恢复后补发。电源一定要稳ESP8266发射瞬间电流很大电源不稳会导致重启。我实测下来加了100uF电容和独立LDO之后ESP8266的稳定性提升非常明显。之前用STM32的3.3V直接供电WiFi一连接就复位换了独立供电后再没出现过。5. 常见问题与排查技巧实录5.1 称重读数跳动大怎么办这是最常见的问题原因可能有以下几种现象可能原因解决方法读数最后几位一直跳正常噪声加滑动平均滤波读数跳几十克电源干扰检查HX711供电加滤波电容手靠近就跳电磁干扰传感器线用屏蔽线远离WiFi天线按键时跳电源波动按键和HX711分开供电温度变化后漂移温漂定期去皮或用温度补偿我的经验是先排除硬件问题再调软件滤波。硬件上HX711的AVDD和DVDD一定要分开滤波传感器线尽量短。软件上滑动平均低通滤波组合基本能解决90%的跳动问题。5.2 HX711读数一直是0或最大值这种情况通常是接线问题或者时序问题。排查步骤用万用表测HX711的VCC和GND之间是不是3.3V。测传感器的E和E-之间是不是有电压一般是2.5V到4V左右。检查DT和SCK有没有接反。用示波器看SCK有没有脉冲输出。如果以上都正常可能是HX711模块坏了换一个试试。还有一种情况是读数一直是0x7FFFFF或0x800000这是ADC饱和了。可能是传感器接反了或者增益设置不对。检查A和A-有没有接反第25个脉冲有没有发。5.3 ESP8266连接WiFi失败ESP8266连不上WiFi的原因很多我整理了一个排查顺序先确认WiFi是2.4G的ESP8266不支持5G。确认SSID和密码正确注意大小写和特殊字符。确认模块供电充足电压在3.0-3.6V之间电流能到300mA。发送ATCWJAP?查询连接状态。如果返回ERROR尝试先ATRST复位再重连。如果一直超时可能是固件版本太老重新烧写AT固件。实操心得ESP8266的AT固件版本很多不同版本指令略有差异。建议用安信可官方的AT固件版本1.7以上兼容性最好。烧写的时候注意选对Flash大小和晶振频率。5.4 OLED显示花屏或乱码OLED花屏一般是I2C通信问题。检查以下几点I2C地址对不对0x78还是0x7A用扫描程序确认。上拉电阻有没有一般4.7k到10k。通信速率是不是太快降到100kHz试试。初始化序列是不是完整特别是对比度设置和显示模式设置。电源是不是稳定OLED对电源波动比较敏感。如果显示内容乱码检查字库有没有取对中文字库和英文字库的偏移量不一样。用取模软件生成字库时注意设置正确的扫描方式和数据格式。6. 项目扩展与个人经验总结这个项目做完之后还可以往几个方向扩展。一个是加蓝牙模块用手机APP显示称重数据适合做零售场景。另一个是加SD卡存储记录每笔交易方便对账。还可以加打印机模块直接打印小票。如果要做成产品还需要考虑外壳设计、防水防尘、电磁兼容认证等。我个人在实际操作中的体会是电子秤这个项目看起来简单但精度和稳定性是最难调的部分。硬件设计占70%的功夫软件滤波占30%。很多人一开始把精力放在代码上结果发现读数怎么都调不稳最后发现是电源或者布线的问题。所以我的建议是先把硬件做扎实电源滤波、传感器接线、PCB布局这些基础工作做到位软件部分反而简单。另外HX711的采样率选择要根据实际场景来。10Hz适合静态称重80Hz适合动态称重比如传送带上称重。计价秤是静态场景用10Hz就够了噪声更低。如果发现响应太慢可以适当提高滤波器的截止频率但不要直接切到80Hz那样噪声会明显增大。最后分享一个小技巧校准的时候除了空载和满量程两点校准最好在中间加一个点比如2kg做线性度检查。如果中间点误差大说明传感器线性度不好或者HX711的增益设置有问题。这时候可以尝试用多点拟合精度会更高。