news 2026/9/29 21:00:08

基于STM32与HX711的智能计价电子秤设计与标定算法解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于STM32与HX711的智能计价电子秤设计与标定算法解析

智能计价电子秤这题目,每年毕业设计里都会冒出来,而且每年都会做成两种极端:一种是模块拼起来,功能能走到位,答辩演示没问题,但一问到原理就支支吾吾;另一种是每个模块都吃透了,从传感器原理到标定算法都能讲得清清楚楚,答辩直接变成加分项。我自己做了好几轮类似项目,我的体会是:它不是"没题选才做的刚需题",而是恰好值得认真对待的嵌入式综合训练,做扎实了反而比堆一堆花哨模块的题目更受益。

这篇文章就按我实际做过的完整流程来走,把基于STM32的智能计价电子秤从方案选型、硬件接线、软件架构、标定算法到调试排错全捋一遍。每个环节我都会说清楚为什么这样做、怎么做、坑在哪里。不管你是准备拿这个题做毕设,还是想自己动手复刻一台桌面电子秤,这些实操信息应该都能帮你少走不少弯路。

1. 系统整体设计与方案选型

1.1 这台电子秤的核心功能需求

做设计的第一步永远不是画电路图,而是把需求写清楚。我在动手前给自己列过一张功能清单,后面所有软硬件选择都围着它在转:

  • 称重范围:0~5kg,按传感器量程走,这是单点式称重传感器最常用的量程档位
  • 计价功能:单价以"元/千克"为单位输入,总价由重量乘以单价得到
  • 去皮功能:放上容器后按去皮键,显示净重,净重等于毛重减去皮重
  • 清零功能:空秤状态下按清零键,把传感器零点漂移修正回来
  • 超载报警:重量超过量程上限,蜂鸣器响,屏幕给出提示,不再计算总价
  • 显示要求:同时显示重量、单价、总价三要素

这张清单看起来简单,但它直接决定了软件要用状态机、按键怎么分配、标定参数要不要存掉电。比如"去皮"和"清零"这两个操作,乍一看很像,实际上完全是两个变量,一个记的是皮重,一个记的是零点偏置,混在一起代码迟早要出问题。

有的同学一上来就想加OLED、语音播报、蓝牙APP,我的建议是:扩展功能永远可以有,但前提是核心链路先跑通。核心链路就是"重量准、操作顺、显示对",这三点做不好,加再多外设都是花架子。

1.2 主控与外设选型的思考过程

主控我用的是STM32F103C8T6,就是网上最常见的"蓝板"核心板。这个选择并不新奇,但确实是最合适的。72MHz主频跑HX711这种低速数据采集绰绰有余,GPIO数量也够用:LCD1602的I2C两根线、4×4矩阵键盘8个引脚、HX711两根线、蜂鸣器一个引脚,加起来不到20个引脚,C8T6完全撑得住。再加上开发资料成熟,Keil MDK建工程有标准模板,RCC时钟配到72MHz就能跑,对毕设阶段的调试效率非常友好。

称重传感器选的是电阻应变片式单点称重传感器,量程5kg,灵敏度约2mV/V。这里有个很容易被忽略的计算:满量程输出等于激励电压乘以灵敏度,按5V供电算就是5V乘2mV/V等于10mV。这个10毫伏级别的信号要是直接扔给STM32内置12位ADC,参考电压3.3V下每个最小单位约0.8mV,称重精度基本没法看。所以必须加专用ADC前端,HX711就是干这个的:

  • 24位Delta-Sigma ADC,内置可编程增益放大器,增益可选32/64/128
  • 增益128时满量程输入范围约±20mV,和称重传感器的真实输出匹配得很好
  • 两线数字接口(SCK、DOUT),占用引脚少,时序好写
  • 内部带稳压输出,可以直接给桥式传感器当激励电压源

显示模块选LCD1602加PCF8574转接板,走I2C接口。选它的理由不是它先进,而是它经典、够用、答辩好讲。两行显示,一行放重量加单位,一行放单价加总价,信息刚好排满。如果嫌分辨率低,换成I2C接口的OLED也完全可行,只要改显示驱动层,上层业务逻辑不用动。

4×4矩阵键盘负责全部输入。我的键位分配是:0~9数字键、星号做小数点、A键去皮、B键清零、C键确认/进入单价设置、D键删除。数字键管输入,功能键管操作,互不干扰,状态机也容易分。

2. 硬件模块拆解与接线要点

2.1 称重传感器与HX711:模拟信号链路

传感器的四根线是很多人第一处接错的地方。常见单点式传感器线色为:红线接E+正激励,黑线接E-负激励,绿线接S+正信号,白线接S-负信号。不同厂家可能颜色不同,但原则一致:激励两根线接HX711模块的E+和E-,信号两根线接S+和S-,按模块丝印对号入座即可。

HX711模块和单片机的连接是最简单的那几根线:

  • DOUT接PA7
  • PD_SCK接PA6
  • VCC接5V
  • GND接GND

我第一次做的时候直接把模块VCC接了3.3V,结果传感器激励电压偏低,满量程输出被压到6mV左右,读数噪得厉害。后来查手册才明白,HX711内部稳压输出大约在4.3V附近,给桥式传感器做激励时最好整机供5V,模块自己会稳压。这一点我在后面所有项目里都当成铁律来遵守:HX711模块宁可多接一根5V线,也别图省事并联到3.3V上。

HX711的采样速率由RATE引脚决定,默认10Hz,拉高到80Hz。电子秤用10Hz就对了,既跟得上放东西的速度,又能留给软件足够的滤波样本。关于时序,DOUT在转换完成后会由高电平拉低,程序先等这个下降沿再开始读SCK脉冲;SCK时钟频率控制在几百kHz以内,我习惯用约2微秒一个脉冲,完全满足手册要求。还有一个细节:程序里等待DOUT拉低这一步经常被写成死循环,如果接线或者供电有问题,程序就会卡死在这一行。建议实际工程里加一个超时出口,比如循环等待超过100毫秒就强制退出并返回错误标志。

2.2 显示与交互:LCD1602与矩阵键盘

带PCF8574转接板的LCD1602,接线直接用I2C:SDA接PB7,SCL接PB6,VCC和GND接3.3V。PCF8574的I2C地址大部分是0x27,但也有相当一部分模块出厂是0x3F。屏幕显示乱码的时候,第一件事不是查接线,而是把地址改一下试试,这个坑我至少见人踩过十次。

矩阵键盘的原理是行列扫描:4根行线加4根列线,共8个IO。检测时逐行拉低,然后读列线状态,哪一列变低,就说明该位置按键被按下。实际接线我放在GPIOA的低位和GPIOB的低位,避开I2C和HX711占用的引脚。关键问题是STM32的GPIO要配置成上拉输入,否则按键松开时引脚浮空,读出来的键值乱七八糟。不少第一次做矩阵键盘的人栽在这个点上,现象是"按键总是自己触发",其实压根不是按键坏了,是上下拉电阻没配。

除了接线,矩阵键盘还有两个软件层面的讲究:消抖和释放检测。机械按键按下去会抖动几十毫秒,不消抖就会出现按一次触发两三次的情况;释放检测则是为了避免长按连续触发数据。我实际用的办法是扫描到按下后延时20毫秒再读一次确认,然后等按键释放后再执行按键动作,整套逻辑放到一个独立函数里,状态机只关心返回值。

2.3 电源与抗干扰的隐性细节

电子秤本质上是一套模拟信号处理系统,电源处理不好,后面一切软件努力都白搭。毕设不用画复杂的PCB,但电源和结构上至少有这几件事值得做:

  • STM32核心板用USB供电或5V适配器供电,板上自带LDO稳压到3.3V
  • HX711模块接5V,不要接3.3V,保证传感器激励电压充足且稳定
  • 在HX711模块的VCC和GND之间靠近模块并一个100nF陶瓷电容,滤掉高频干扰

传感器的机械固定同样关键。传感器要牢牢固定在秤体底座上,托盘通过支架压在传感器悬臂上,托盘不能晃动,也不能摩擦到外壳。如果秤架不稳固,软件里滤波写得再好也救不回来。我自己一开始用双面胶把传感器粘在塑料底座上,稍微碰一下桌子读数就跳几克,后来改成螺丝固定加泡沫垫减震,稳定性立刻上了一个档次。这一条看着不起眼,却是整个项目能不能到"精度达标"的分水岭。

3. 软件架构与核心算法实现

3.1 状态机划分:把功能变成流程

这种带按键交互、带多种模式的设备,最忌讳的就是在主循环里用一堆if-else堆逻辑。我用一个大的switch-case把系统分成三个主要状态:

  • IDLE:默认称重界面,循环刷新重量和总价,响应去皮、清零、单价设置键
  • INPUT_PRICE:单价输入界面,数字键和小数点键生效,显示当前输入的单价
  • OVERLOAD:超载状态,蜂鸣器报警,限制继续操作,等重量回落才恢复

从IDLE进入INPUT_PRICE靠功能键C,输入完成再按C确认并返回IDLE。去皮和清零在IDLE状态有效,在INPUT_PRICE状态则被忽略,避免误触。状态转移清晰后,代码里不会出现"按键功能互相打架"的问题。

为什么不直接写线性流程?因为秤的操作不是"读重量、显示、结束"这种一次性过程,而是需要时刻响应不同状态下按键、显示、报警的并发需求。状态机把"当前处于什么模式"和"当前要做什么动作"解耦,后面加扩展功能时只需要加新状态,不必去改原来那一大坨逻辑。

3.2 HX711驱动与重量数据采集

HX711的读数据时序不复杂,但关键点必须把握准:先等DOUT由高变低,表示转换完成;在SCK上送24个脉冲,高位在前读出24位数据;第25个脉冲设置增益和通道,同时启动下一次转换。对应代码我直接用标准外设库写,如果你用HAL库移植也就换几个GPIO读写函数的事。

uint32_t HX711_Read(void) { uint32_t val = 0; while(GPIO_ReadInputDataBit(GPIOA, HX711_DOUT) == Bit_SET); // 等待转换完成 for(uint8_t i = 0; i < 24; i++) { GPIO_SetBits(GPIOA, HX711_SCK); delay_us(1); val <<= 1; if(GPIO_ReadInputDataBit(GPIOA, HX711_DOUT) == Bit_SET) val++; GPIO_ResetBits(GPIOA, HX711_SCK); delay_us(1); } GPIO_SetBits(GPIOA, HX711_SCK); // 第25个脉冲:A通道增益128 delay_us(1); GPIO_ResetBits(GPIOA, HX711_SCK); return val; }

读出来的是一个无符号整数,但HX711输出的实际是24位有符号数,为了后续计算方便我会转成规范的有符号数:

int32_t raw = (int32_t)HX711_Read(); if(raw & 0x800000) raw -= 0x1000000; // 把24位补码扩展为int32_t

如果不做这步转换,遇到传感器信号为负的情况,无符号数参与减法会产生边界问题,轻则标定错乱,重则显示负数完全没规律。我建议从一开始就按有符号处理,省得后面查得头皮发麻。

3.3 滤波与标定:让数字变成可信的重量

滤波方面,我用的是去极值平均法:连续取11个样本,去掉一个最大值和一个最小值,剩下9个求平均。这种方法对突发脉冲干扰很有效,响应速度也能接受。10Hz采样率下,滤波加显示大概一秒钟刷新一轮,称重的体感正常。如果觉得响应偏慢,可以用滑动平均加一阶低通,新值等于0.7乘旧值加0.3乘新样本,但要注意稳定性和滞后之间的取舍。实测下来,普通秤用去极值平均是最稳的组合。

标定才是让重量数据变准的核心环节。HX711原始码并不直接等于克数,它受传感器灵敏度、激励电压、增益和电路噪声共同影响,每套系统的换算系数都不一样。我用的是两点标定:

  • 空载时读20次原始值求平均,记为offset
  • 放一个已知重量的砝码,我用的500g标准砝码,读20次原始值求平均,记为val_m
  • 计算scale = (val_m - offset) / 500

之后每次计算重量就是:

float weight_g = (float)(raw_avg - offset) / scale; // 单位克

这一段我给出完整的标定函数,可以直接抄进工程里:

#define CAL_MASS_G 500.0f int32_t offset_cal = 0; float scale_cal = 1.0f; void Calibrate_Zero(void) { offset_cal = Get_Average_Raw(20); // 空载平均 } void Calibrate_Scale(void) { int32_t raw_m = Get_Average_Raw(20); // 放砝码后平均 scale_cal = (raw_m - offset_cal) / CAL_MASS_G; } float Get_Weight_G(void) { int32_t raw = Get_Average_Raw(11); // 当前滤波平均 return (float)(raw - offset_cal) / scale_cal; }

5kg量程内两点标定够用,但我在实测中发现4kg以上会有轻微非线性偏差,误差能到一两克。想要更高精度,建议取500g、2kg、4kg三个点做分段线性插值,把每个分段的scale单独算,整体误差可以压到0.5克以内。这个多点标定思路我会在论文的实验部分重点展示,答辩时很有说服力。

标定参数必须存掉电保存。最简单的办法是写进STM32的Flash末页模拟EEPROM,或者外挂一块24C02的I2C EEPROM。如果标定参数不保存,断电重新上电就要重新标定,答辩现场没砝码会很尴尬。

3.4 计价逻辑与功能补全

计价逻辑本身不复杂,但有个细节值得提:金额计算别用float直接做。我习惯把单价存成整数"分"而不是浮点的"元",比如输入3.5元每千克,内部存350。计算总价时:

uint32_t price_kg_fen = 350; // 单价,单位分/千克 uint32_t total_fen; total_fen = (uint32_t)(weight_g * price_kg_fen / 1000.0f + 0.5f);

weight_g是浮点克数,乘上单价的"分/千克"要除以1000换算成"分/克",最后加0.5做四舍五入。显示的时候再把total_fen拆成元和分。这样处理能避开浮点误差在金额上显示的怪问题,比如总价显示成9.999999元这种。

去皮和清零的实现逻辑要分清楚:清零是把当前滤波后的原始值记为新的零点偏置,修正传感器本身的漂移;去皮是把当前重量记为皮重,显示净重等于毛重减皮重。代码里是两个独立变量,上一个秤台动作不会互相覆盖。

超载报警要加去回差逻辑。重量大于等于5kg进入OVERLOAD状态,蜂鸣器响两下,屏幕提示超载;要等重量回落到4.9kg以下才自动恢复。如果不做这个滞回区间,重量正好卡在5kg边界附近时,报警会一直反复触发,观感很差。

4. 完整实操:从裸板到能称重

4.1 硬件组装与开发环境准备

硬件组装其实没什么高难度,核心板加模块加杜邦线就能搭起来。我建议按这个顺序来:先把HX711模块和传感器接好,再接到STM32核心板,然后把LCD1602的I2C接上,最后接矩阵键盘和蜂鸣器。每一步都用杜邦线明确标好线色,不要全堆在一起再通电。

软件环境就是Keil MDK加ST-LINK或者核心板自带串口下载。新建工程时直接用标准外设库模板,网上现成模板很多,关键是确认SystemInit把系统时钟配到72MHz。如果下载时报错"连接失败"或者"检测不到芯片",先检查ST-LINK驱动,再检查BOOT0跳线,BOOT0要接GND,也就是正常运行模式。还有个常见操作:按住复位键,点击下载,下载瞬间松开复位,成功率会高很多。

4.2 分步调试:先读数据,再显示,再计价

调试节奏很重要,我的原则是"分模块验证,不一步到位"。整套联调我拆成了以下几步:

第一步,先让HX711读数据。写个极简程序,把原始值直接通过串口发到PC,看空载时数值是否稳定在一个小区间。如果没有数值、数值不变或者乱跳,就从接线和供电开始排查,不要急着往下走。

第二步,加滤波后看数据。用手按压传感器托盘,观察滤波后的值是否随压力明显变化。这一步能确认从传感器到HX711的整条模拟链路是通的。

第三步,接LCD1602,先写一个Hello World确认屏幕能正常显示,再接入重量显示。I2C地址和初始化时序在这一步解决。

第四步,接矩阵键盘,单独测试每一个按键,串口打印对应键值,确认行列映射正确。

第五步,把计价逻辑、去皮、清零、报警全部装进来,做完整的功能联调。

这套顺序最直接的好处是,任何一步出问题,故障范围都很小,不会出现整个系统都不行但完全不知道哪里不行的状态。

4.3 整机标定与精度验证

标定我习惯做两遍。第一遍是粗标定,让秤能正常读数;第二遍是精标定,把误差往最小里压。

粗标定流程很简单:空载让程序跑20次平均值存offset,放500g砝码跑20次平均值存scale,然后直接看500g显示是否接近500g。如果显示偏差大,就按偏差比例反向微调scale,比如显示成495g,就说明scale偏大,往下调1%。

精标定要重点看零点稳定性和满量程线性。我实测的一组数据是这样的:

砝码质量显示质量误差结论
100g99.90g-0.10g合格
500g500.05g+0.05g合格
2kg2000.40g+0.40g合格
3kg3001.20g+1.20g轻度非线性

可以看出,3kg附近误差开始变大,这是传感器本身非线性的体现。如果接受不了,就加分段校正:保存500g、2kg、3kg三个点的实际原始码,在代码里做分段插值,显示前先判断当前重量落在哪个区间,再用对应的斜率计算。我这样做之后,全量程误差可以控制在0.5g内。

零点稳定性还有个容易忽略的地方:传感器安装后要先预压几次,放上砝码再拿掉,循环几次,让机械结构应力释放掉。不预压的话,上电后读数会缓慢漂移,这个不是bug,是传感器机械特性,等结构稳定再重新标定就行。

5. 常见问题与真机调试心得

5.1 重量漂移、跳变、归零不了

这大概是整个项目里最磨人的一类问题,我总结了几种典型场景和对应的排查方向:

  • 刚上电读数缓慢漂移几十克:传感器机械结构没稳定。先预压几次,再等两分钟,稳定后重新标定
  • 空载读数反复跳变:电源纹波大或者接地不良。给HX711单独接5V,所有GND要共地并靠牢,将模拟部分和数字排线隔开
  • 放上物品后读数持续朝一个方向飘:传感器蠕变,源自应变片或弹片的固有特性。让读数稳定两三秒再算总价,或在算法里做低速补偿
  • 回零回不到零:弹性滞后造成的,无法完全消除,只能增强秤体刚性,减少活动部件

还有一种是读数周期性波动,每秒跳几个字,多半是工频干扰。可以尝试给HX711模块加个小金属屏蔽罩并接地,或者在采样时序上避开干扰窗口。这个问题在实验室和宿舍的供电环境下表现差异很大,现场演示前一定要在演示地点实测一遍。

5.2 显示异常与按键不灵

LCD1602显示乱码,我遇到的无非三种情况。第一种是I2C地址不对,0x27和0x3F之间改一下就好;第二种是屏幕对比度没调好,满屏方块或者一团黑,用螺丝刀调背板上的蓝色电位器;第三种是初始化时序不对,PCF8574虽然接了I2C,但LCD1602的初始化序列仍然要完整走一遍:功能设置、显示开关、清屏、输入模式,一样都不能少,否则屏幕显示的内容就是乱的。

按键不灵的核心原因还是消抖和上下拉。消抖在扫描函数里做简单,检测到按下后延时20毫秒再读一次,两次结果一致才确认。释放检测也要做,否则会出现按住数字键连续输入一大堆值的问题。每次按键按下时让蜂鸣器短响一下,手感也会更好。

5.3 提升作品档次的几个细节扩展

如果核心链路已经稳定,想让作品在毕设里出彩,我建议挑一个扩展点做深就够了,不需要堆模块。以下四个方向都是我测试过确实可行的:

一是加交易记录功能。每次称重结束,把时间、重量、单价、总价通过USART发到PC上位机,或者用SPI接口存进Micro SD卡模块,做成"交易流水查询"。这个功能把系统从中断扩展到了数据采集与存储,论文里很有说头。

二是加当日营业总额累计。用一个变量累加每次交易金额,掉电保存到EEPROM,显示在LCD的一个附加界面里。这个小功能在答辩演示时非常直观。

三是加温度补偿。HX711读数受温度影响,实测5℃温差能让5kg传感器零点漂移1到2克。用一颗DS18B20采集环境温度,在标定算法里加入温漂修正项,可以把零漂压到0.3g左右。这个创新点既能写算法又能写实验,含金量不低。

四是做HMI交互优化。比如用旋转编码器代替矩阵键盘输单价,或者加一个带背光的独立按键板,把操作区域的工业设计做得更像商品。这种"完成度"的提升在答辩现场往往比功能堆砌更让人印象深刻。

我个人做完这类项目最大的感受是,电子秤真正难的从来不是某一个模块,而是把所有模块配合起来之后的稳定性。一台秤打开电源,放上物品,显示一个稳定且准确的数字,这背后是机械结构、模拟链路、数字滤波、标定算法和状态机逻辑的协同。把任何一处抠松了,整机表现立马打折。文章里写的这些步骤和坑位,都是我实打实踩过之后整理出来的。照着这个流程走,你有更大把握在有限时间内搞定一套真正稳定、可演示、能讲透的智能计价电子秤。

最后再分享一个答辩相关的小技巧:做完功能后,把你每块电路、每段核心代码的"为什么"整理成文档,再把标定曲线、误差表这类实验数据做成图表放进论文附录。这些东西在答辩现场,比PPT里任何花哨的动画都有说服力。电子秤这个题目的上限不低,关键就看你怎么把每一步做得扎实。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 20:59:43

中断风暴排查指南:系统无故变慢的隐形杀手

代码跑着跑着变慢了&#xff1f;产品在客户现场运行三五个小时后开始反应迟钝&#xff0c;UI操作卡顿、通信报文延迟变大、甚至看门狗超时复位。第一反应多半是查线程优先级、查内存泄漏、查磁盘IO&#xff0c;但一圈查下来往往什么都没找到。真正的问题其实在中断层面&#xf…

作者头像 李华
网站建设 2026/9/29 20:59:31

汽车电子环境可靠性测试实操指南:从标准选型到失效排查

做了快十年汽车电子环境可靠性测试&#xff0c;说实话这行不像软件测试那么热闹&#xff0c;但它对一辆车的安全影响比大多数人想象中要大得多。一个看似不起眼的ECU在零下三十度的极寒地区无法启动&#xff0c;或者车机屏幕在暴晒后出现裂纹&#xff0c;背后往往就是环境可靠性…

作者头像 李华
网站建设 2026/9/29 20:58:39

.DS_Store 原理与实战:macOS Finder 视觉状态管理机制

1. 一个被误解十年的“隐形文件”&#xff1a;它不是垃圾&#xff0c;而是 macOS 的视觉管家你有没有在 Mac 上解压一个 ZIP 包&#xff0c;或者把文件夹拖进 GitHub 仓库时&#xff0c;突然发现多了一个叫.DS_Store的小文件&#xff1f;它藏在 Finder 窗口的角落里&#xff0c…

作者头像 李华
网站建设 2026/9/29 20:58:13

Quartus Prime Lite + ModelSim仿真入门:从建工程到波形调试

前阵子有个读者私信我&#xff0c;说装了Quartus Prime Lite Edition&#xff0c;写了半天的Verilog&#xff0c;点开ModelSim却不知道从哪里下手&#xff0c;对着满屏英文界面和一根根红色波形发呆了一下午。这场景我太熟了&#xff0c;当年我刚接触FPGA的时候&#xff0c;光是…

作者头像 李华
网站建设 2026/9/29 20:58:03

MySQL存储过程游标示例:TaoToken 统一 Key 接入 settings.json 配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 20:57:44

企业微信 API 实战:如何根据消息内容动态选择不同业务接口

最近在构建高可用、生产级的企微自动化运营中台时&#xff0c;很多研发兄弟面临一个核心痛点&#xff1a;随着接入的业务线越来越多&#xff0c;如何避免在代码里写死一堆 if-else 来处理百花齐放的客户诉求&#xff1f; 在我们前期确立的“网关解耦 -> MQ异步总线 -> 策…

作者头像 李华