做嵌入式这些年经手的称重类项目不少但真正从称重传感器一路做到量产文件齐套的还是最近这套基于STM32的智能计价电子秤。很多朋友问我嵌入式项目怎么练手我觉得计价电子秤就是一个特别典型的综合项目它要有模拟前端、有滤波算法、有按键状态机、有标定流程还要考虑实际使用的可靠性和用户操作体验。这篇文章就把这套方案完整拆开讲清楚从需求分析、硬件选型、软件实现到标定排障整个过程一步不落。想做毕业设计、想入门嵌入式、或者想给产品做原型验证的同学都可以直接参考。1. 项目需求分析与整体方案设计1.1 需求拆解智能计价电子秤到底要解决什么问题计价电子秤和普通体重秤最大的区别是它要同时完成“称重”和“算钱”两件事并且要在几秒钟内给出准确结果。商用场景里的典型流程是商品放上秤盘 → 操作员输入单价 → 系统显示净重和应付金额整个过程要快、要准、要直观。所以核心功能可以拆成五个实时重量显示、去皮重、单价输入与修改、金额自动计算、累计金额管理。精度是这类项目的灵魂。家用秤精度做到1g已经够用但商用计价秤通常要把精度控制在量程的1/3000以上。我做的这台设计量程是10kg最小分度1g目标是在整段量程内误差不超过正负1.5g。这意味着从传感器到ADC到软件滤波每一环都不能掉链子。如果哪个环节偷懒最后显示出来的数字就会飘、会跳、会忽大忽小用户一用就会投诉。另外一个容易被忽略的需求是“易用性”。电子秤的操作者可能是菜市场摊主、生鲜店员不会像咱们工程师一样调参数。所以界面必须简单清晰按键反馈必须明确操作出错时要有声音或文字提示。我在设计时反复提醒自己这个项目不是在实验室里跑通就完事而是要让人一天按几百次都不会烦。1.2 为什么选STM32算力、外设与成本的平衡点选主控这件事我见过不少争论。有人说51单片机便宜够用有人觉得随便上个Cortex-M都行。但真正做过类似产品的人会告诉你计价秤需要的不是“跑得多快”而是“外设顺手、资源不紧、开发效率高”。以市面最常见的STM32F103C8T6为例72MHz主频64KB Flash20KB RAM片上有I2C、SPI、UART、定时器、ADC一片批发价几块钱。称重信号采集用外部HX711显示用I2C的OLED按键扫描用GPIO资源刚好够用而且还有余量。对比一下其它方案就明白了。51单片机外设太基础一个I2C都要软件模拟做显示、按键、传感器三件事时代码和主循环会变得很难维护。树莓派那种Linux方案虽然图形界面方便但成本高、启动慢、实时性受系统调度影响商用电子秤完全不需要这么重。STM32卡在中间这个位置性能和成本最匹配加上HAL库和CubeMX的加持你会发现几行代码就能把一个外设配置起来前两周的进度能赶上别的方案一个月。1.3 系统架构四个模块组成一台完整的秤整体思路我习惯从上往下拆物理上一台智能计价电子秤可以分成四个部分称重传感器负责把重力变成微弱的电信号HX711放大并数字化这个信号STM32作为大脑读取数据、滤波标定、计算金额最后通过OLED显示和按键完成人机交互。电源部分则给所有模块提供稳定的电压。数据流是单方向的重力 → 电桥输出差分电压 → HX711内部PGA放大 → 24位ADC转换 → STM32读取原始值 → 数字滤波与标定 → 重量数据 → 业务逻辑计算金额 → 显示刷新。理解这条链路很重要后面所有调试都是沿着这条链找问题。如果你看到读数不对先不要急着怀疑算法从传感器开始一级一级排查往往能快速定位。2. 硬件设计传感器、模拟前端与最小系统2.1 称重传感器的选型与原理计价秤用得最多的是电阻应变式称重传感器核心结构是惠斯通电桥。简单说传感器内部贴了四片应变电阻受力时电桥失去平衡输出一对差分电压信号。这个电压非常小常见灵敏度是1mV/V到2mV/V也就是说如果给传感器加5V供电满量程时输出也只有5到10mV。这种毫伏级的信号普通单片机内置ADC根本没法直接分辨所以必须外接高分辨率ADC或者仪表放大器。选型时要重点看三个参数量程、灵敏度、综合精度。量程选多少取决于使用场景我做的是10kg秤选的是10kg量程的传感器留了10%过载余量。如果硬要拿5kg传感器去称10kg的东西时间一长弹性体就会永久变形精度报废。灵敏度决定了信号大小1mV/V还是2mV/V会直接影响后级电路的噪声表现。综合精度一般写着0.02%F.S.意思是满量程误差大概是2g这个数值基本决定了一台秤的精度上限。实际项目里还有一个很多人会踩的坑传感器的机械安装。传感器要通过螺栓固定在结构件上受力方向必须垂直且均匀。拧螺栓的力度不同、秤盘的支点分布不均匀都会造成“偏载误差”也就是同样重量放在秤盘不同位置读数不一样。这属于结构设计问题纯软件无法解决只能在安装时反复调整到四角误差合格。2.2 HX711专为电子秤设计的24位ADCHX711是仪表类项目里的常客一颗芯片就把放大和AD转换全包了。片内集成了可编程增益放大器增益可设为32、64、128还集成了稳压电源和振荡器外围电路只需要几个电容电阻就能跑起来。它和主控之间只有两根线PD_SCK是时钟输入DOUT是数据输出属于典型的串行通信。这里必须解释一下为什么不用STM32自带的12位ADC。其实思路很简单12位ADC在5V参考电压下理论分辨率就是5V除以4096大约1.22mV。而传感器满量程输出才5mV即便放大一百倍也只能勉强分辨零点几克想要稳定到1g精度太难了。HX711的有效分辨率可以做到20位以上配合PGA放大能把微伏级的信号变化清晰分辨出来。用一个芯片的外围电路换整体精度这笔账非常划算。HX711和使用者之间的物理接口在实际项目里我推荐这样接PD_SCK接STM32的一个普通输出引脚DOUT接一个输入引脚。DOUT是开漏输出所以外部要接上拉电阻否则读不到正确电平。上拉我选4.7kΩ。另外HX711的模拟电源和数字电源要分开退耦模拟电源引脚处至少放一个10uF钽电容加一个100nF陶瓷电容这能显著减少读数跳变。2.3 STM32最小系统与HX711的连接细节STM32最小系统没什么神秘常规六件套8MHz晶振、两个20pF负载电容、复位电路、BOOT0和BOOT1引脚配置、每个电源引脚的100nF去耦电容、和一个1uF左右的 bulk 电容。很多人画板子时为了省事把去耦电容省了短期没问题但遇到强干扰或电磁兼容测试就会莫名其妙复位。这类问题最难查所以在原理图阶段就要守规矩。具体引脚分配以STM32F103C8T6为例我这样安排PA0接HX711的PD_SCKPA1接HX711的DOUTI2C1的PB6和PB7接OLED按键用PB0到PB5蜂鸣器用PB8。把传感器相关引脚独立放在一组按键和显示放在另外一组布局上尽量避免数字信号和模拟信号交叉。开发阶段用杜邦线飞线没问题但一旦要做PCB模拟区域和数字区域的地要单点连接避免数字地噪声窜进HX711的参考地。还有一个小细节容易被新手忽略HX711的DOUT在每次上电后会有一个自检过程需要等待它稳定不要在刚上电时反复读取。我的处理方式是在初始化函数里延时200ms然后连续丢弃前几次读取结果等到DOUT开始正常出数据再进入工作循环。这个习惯现在保留在每一个用到HX711的项目里。2.4 显示、按键与提示电路的设计显示器件我强烈推荐I2C接口的OLED驱动芯片是SSD1306尺寸0.96寸或1.3寸都行。I2C只占两个IO代码库也很成熟而且OLED可以自由分区显示不像LCD1602那样只能显示固定位置的ASCII字符。在128x64的分辨率下我通常把上半部分用来大字显示重量中间显示单价下半部分显示金额和累计状态一眼就能看清当前核心信息。按键这块计价秤的数字键和功能键加起来至少十二三个。全用独立GPIO太浪费IO所以我用矩阵键盘结构4行4列可以挂16个键。行线配置成推挽输出列线配置成带上拉的输入扫描时逐行拉低读取列的状态。如果没有硬件上拉STM32内部也可以开上拉但为了稳定我还是在列线上外接了一排10k排阻。按键消抖放在软件里做检测到电平变化后延时10ms再确认实测很稳。再说蜂鸣器。计价秤按键应该有声音反馈输入金额后也有确认提示。蜂鸣器我用NPN三极管驱动GPIO输出高电平通过电阻驱动基极集电极接蜂鸣器发射极接地。注意蜂鸣器需要并联一个续流二极管不然关断时会产生反向电动势轻则影响电源重则损坏IO口。这个细节在原理图阶段就要画进去。2.5 电源设计稳定是称重精度的前提电子秤对电源纹波非常敏感。HX711的参考电压由内部稳压提供但如果前级电源噪声大这些噪声会通过电源引脚耦合进模拟前端造成读数漂移。我在实际测试中对比过用一个质量差的12V适配器供电空载读数每分钟会上下跳2到3克换成线性电源或者加了滤波电路之后尾数纹丝不动。这个差别比任何软件滤波算法都明显。成熟的方案是外接12V适配器先经过一个开关电源模块降到5V再给传感器和HX711供电。STM32这路单独用AMS1117-3.3线性稳压。传感器供电和数字部分供电尽量不要从同一段线上走PCB上可以用0欧电阻做模拟地和数字地单点连接。如果产品需要电池供电还要在输入端加防反接和过压保护比如一个肖特基二极管加一个TVS管。这些设计看起来增加成本但能避免后续一大堆可靠性问题。3. 软件设计从驱动到业务逻辑的完整实现3.1 开发工具链与工程搭建流程现在做STM32开发我推荐STM32CubeMX加Keil MDK这套组合。CubeMX负责图形化配置时钟、引脚和外设Keil负责写代码和调试。新建工程时在CubeMX里选择STM32F103C8Tx配置RCC为外部晶振设置时钟树让主频跑到72MHz。然后把需要用到的引脚都选好HX711的两个引脚设为GPIOOLED的I2C引脚设为开漏输出按键引脚设为输入模式。工程生成之后我通常按模块划分代码目录。HX711驱动单独成一个hx711.c和hx711.h里面提供读原始值、去皮、获取稳定重量几个接口OLED用网上成熟的开源库改一下I2C地址就能用按键扫描和状态机放在key.c业务逻辑放在main.c或独立的app.c。这样后续调试时思路清晰哪一块出问题就直接进哪个文件。一个实操上的建议从最开始就打开Keil的微库MicroLIB并把堆栈设置到足够大。OLED显示需要不少栈空间状态机里也有局部变量。我在早期测试时遇到过莫名死机最后查到是栈溢出把变量冲掉了把栈从默认值调到0x1000之后问题消失。这类问题一旦发生非常隐蔽所以宁可一开始留足余量。3.2 HX711数据读取与滤波算法详解HX711的读取时序逻辑不复杂但细节容易出错。正确流程先把PD_SCK拉低然后等待DOUT变低DOUT变低表示一次转换完成。接着产生25个正的时钟脉冲前24个用于读出24位数据采样规则是在每个SCK上升沿读取DOUT的电平。第25个脉冲用于选择下一次转换的通道和增益脉冲个数不同对应的增益也不同。如果只需要默认配置通道A增益128每次读完后补一个脉冲即可。读出来的24位数据是二进制补码格式最高位是符号位。代码里我会用一个int32_t变量接收它然后左移8位再算术右移8位完成符号扩展。很多新手在这里直接赋值给unsigned long结果就是负重量显示成巨大的正数清零后读数不对。这个问题在电子秤上特别致命因为去皮和负值显示都依赖正确的符号。单纯的单个读数没有意义必须做滤波。我用的是“中位值平均滤波法”连续采集15个原始值去掉一个最大值和一个最小值剩下13个取平均。这个算法对付瞬间冲击特别有效比如商品放上秤盘那一下传感器会产生明显抖动取平均后重量能在0.5秒内收敛。比起简单滑动平均它不会让干扰值一直滞留在窗口里稳定性好很多。3.3 重量标定与换算逻辑从ADC值到克数原始ADC值不是重量两者之间必须建立线性换算关系。理论上传感器是线性的所以在理想情况下两个点就能标定先空载采样得到零点对应的ADC值ZERO再放一个已知重量的标准砝码得到满量程对应的ADC值FULL。那么比例系数K就等于“ADC变化量除以重量变化量”未知重量就可以通过“当前ADC减ZERO再除以K”算出来。实际标定中我建议至少做三个点校验20%量程、50%量程、80%量程。如果这三个点的误差都在允许范围内说明传感器线性度不错如果中间偏差很大说明安装有应力或者传感器本身非线性这时候只靠两点标定就不够准得考虑分段线性插值。分段标定的做法是把量程切成几段每段用各自的斜率和截距软件里多存几组参数。对于商用计价秤这种分段方案能有效弥补机械和传感器的系统误差。标定参数一定要掉电保存。我放在STM32内部Flash的某个扇区用结构体存ZERO、K以及校验用的CRC。每次开机时读出参数并校验如果CRC不对就进入“未标定”状态界面提示重新标定。这个机制在量产时特别重要因为每一台秤的传感器特性都不完全一样必须在校验台上逐台标定并写入参数否则产品没法出厂。3.4 计价逻辑与按键状态机稳定精确的核心电子秤的金额计算要做好细节全在数据格式里。我强烈建议避免用浮点数做业务计算而是全部用整数。金额以“分”为单位重量以“克”为单位。比如单价15.8元/斤其实是15.8元每500克那么每克的价格就是1580分除以500等于3.16分。金额的计算公式就是“重量克乘以每克单价分再除以100转换成元分”。全程用整数乘除不会出现浮点误差代码也更简洁。按键状态机是另一块容易写乱的地方。我按场景定义了四态空闲态、单价输入态、称重计价态、累计显示态。每次按键扫描周期为10ms读取矩阵键盘后经过消抖确认生成一个按键事件主循环里的状态机根据当前状态决定事件如何处理。比如在单价输入态数字键输入数字、确认键保存并回到称重态在称重计价态去皮键清零、累计键累加金额。状态机的好处是逻辑清晰不会再出现“按键响应混乱”这种问题。我早期用标志位方式写得这段逻辑功能也能跑但一旦按键连按、长按就会进入奇怪的状态。改成状态机后每个状态都有明确的入口和出口边界情况全部有定义。这才是产品代码该有的样子。3.5 显示界面与用户体验优化显示分区要按照人的阅读习惯来重量最重要放最上面字号最大单价在中间金额和累计在最下面。我用OLED的SSD1306驱动库在内存里画好整个显示缓冲再一次性刷到屏幕避免刷新闪烁。每次重量变化时不要全屏刷新而是只更新对应区域OLED虽然有缓冲不闪烁但频繁全刷还是会拖慢主循环。体验上有一个关键点重量稳定之后才算钱。因为顾客刚把商品放上去时重量一直在变如果每时每刻都把当前重量乘以单价金额会跟着跳非常不专业。我的做法是连续500ms内重量采样差值小于2g才判定为“稳定”稳定后锁定当前重量并计算金额。如果之后重量又发生较大变化说明商品被移动或加减则重新回到“不稳定”状态。此外从用户使用角度我还在界面上加了状态提示稳定后用一个小圆点或文字标识去皮后显示净重标志累计有总金额时在底部显示。OLED能显示中文这些提示对实际使用者帮助很大。项目做到这个阶段才算真正从“能运行”走向“好用”这也是我反复和硬件搭档强调的一层价值。4. 标定、测试与实战排障记录4.1 标定流程实录从裸数据到准确重量标定不是把砝码放上去就完事它有严格的操作顺序。我参考了计量器具校准的通用做法结合嵌入式设备的实际情况整理出四步流程第一步把秤放在水平、无震动的台面上通电预热5分钟。预热这一步特别重要传感器弹性体和内部电阻需要时间达到热平衡否则零点会持续漂移。第二步清空秤盘执行零点采样记录50次滤波后的平均ADC值写入ZERO。第三步放上满量程标准砝码我用的10kg但建议用标称砝码或经过认证的重量块同样采样并记录算出比例系数K。第四步用50%量程的砝码回验如果误差在允许范围标定结束否则检查机械结构和传感器安装。实际操作中标准砝码的分级决定了标定精度。如果只是做课程项目用几瓶矿泉水凑个大概重量也可以但严谨的产品标定必须使用M1级以上砝码。我在工作室备了一套500g、1kg、2kg、5kg的标准砝码几百块的成本换来的是每次标定都能复现的安心。最后把ZERO和K写入Flash断电重启后自动加载这一步做完秤的基本功能就闭环了。4.2 读数跳变、漂移与干扰的排查思路如果你发现读数持续跳变第一反应别去改滤波代码先看硬件。用示波器量HX711电源引脚的纹波如果超过几十毫伏那就是电源问题。我在测试中遇到过一次很典型的情况适配器供电下重量值有规律地跟着负载电流波动最后查到是传感器供电和蜂鸣器供电共用了一段线路蜂鸣器一响ADC值就跳。后来把传感器供电单独接LC滤波问题立即消失。零点漂移则多半是温度造成的。传感器弹性体对温度非常敏感早上开机和运行两小时后的零底值能差好几克。处理办法有两个层面硬件上PCB布局时让HX711尽量远离发热元件软件上加零点跟踪功能。零点跟踪的思路是当检测到连续一段时间内重量读数接近零点并且变化非常小时自动微调零底值。但阈值要设得足够小比如小于2g才触发否则秤上放了轻东西会被误判成“零”给忽略掉。还有一类隐藏问题是机械蠕变。称重后把东西一直放秤上读数会随时间缓慢变化这是传感器弹性体的特性。解决它最有效的办法是缩短“重量读取到金额锁定”的时间不要让系统一直盯着重量计算商品放上去后尽快锁定数值。这又在另一个角度印证了“稳定判定”逻辑的必要性。4.3 常见异常现象与解决方案速查我在调试这套基于STM32的智能计价电子秤时把高频问题整理成了一个速查表后来给几个做类似项目的朋友参考大家反馈排查效率提升明显现象可能原因排查与处理方式读数一直为零HX711DOUT上拉缺失检查外部上拉电阻确认引脚配置为输入读数跳变剧烈电源纹波、模拟地处理不当独立供电加LC滤波单点接地读数负值异常符号扩展错误用int32_t接收并做算术右移标定后称重不准砝码不标准、量程不匹配换标准砝码核对传感器量程OLED白屏或花屏I2C地址错误、上拉电阻过小扫描I2C地址更换上拉值按键偶尔没反应缺少消抖、行列扫描太快增加10ms消抖扫描周期设为10ms蜂鸣器干扰称重感性负载反向电动势蜂鸣器并联续流二极管分开供电掉电后标定丢失Flash写入未完成或无校验写完后读取校验CRC错误自动提示重标定这张表里的问题我基本都亲手踩过。尤其是“蜂鸣器干扰称重”这一条如果不做测量很多人根本想不到秤值会跟着声音跳。嵌入式系统里所谓“软硬不分家”就是在这些细节里体现出来的。4.4 工程化可靠性与量产经验功能跑通之后如果这个方案要真正交付或量产还得补几道工序。首先是看门狗我用STM32内部独立看门狗喂狗周期1秒程序异常卡死时能自动复位。其次是Flash参数的自愈机制每次开机先检查标定参数CRC如果发现被改写就恢复默认值并进入待标定状态避免产品带着错误参数运行。量产测试阶段要做的检查项很多静态电流是否超标、每个按键是否灵敏、OLED显示是否有坏点、满量程回零误差是否在允许范围、以及连续通电老化48小时后数据是否稳定。我在这个项目里吃过一个亏一批屏在老化时偶尔白屏最后定位到是I2C上拉电阻偏大信号上升沿太慢。换成4.7kΩ之后连续老化一周再没出现过问题。这类问题只有靠老化测试才能暴露所以量产前一定要留足测试时间。我个人的习惯是每一块板子在出厂前都跑一遍“自动测试脚本”通过串口打印每个模块的检测结果。这个脚本不用太复杂但能大幅降低售后返修率。测量数据、标定参数、测试日期全部记录在Flash里后续如果出现品质问题可以很快筛选出对应的批次排查方向非常清晰。做这个智能计价电子秤项目最大的体会是“产品级的东西功夫都在细节里”。传感器、ADC、单片机这些大方向选型谁都清楚但最后拉开差距的是电源走线、滤波处理、零点跟踪、按键消抖这些容易被忽略的环节。我自己沉淀下来的几个习惯一是硬件和软件并行设计先用模块验证算法再定PCB二是标定流程一定要规范化否则后面查问题非常痛苦三是任何交互都要从使用者角度多问一句“这样会不会难受”。这套方案整体难度适中又覆盖了嵌入式开发的大半知识点非常适合用来建立完整的项目思维。后续如果时间允许我还会把PCB布局、结构件安装和量产检测的更多细节整理出来到时候再和大家继续聊。