news 2026/10/21 4:46:14

基于STM32与HX711的电子秤设计:从称重传感器选型到标定算法落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于STM32与HX711的电子秤设计:从称重传感器选型到标定算法落地

简介:面向嵌入式开发者的基于STM32单片机电子秤设计资源包,覆盖从称重传感器信号采集、HX711高精度AD转换到液晶显示与电源管理的完整开发流程。资源共225个文件,压缩包18.89MB,包含STM32工程源码(C/H文件)、Keil工程配置(uvprojx/uvoptx)、原理图与PCB设计(sch/pcbdoc)、物料表(xls)以及设计报告(doc/pdf)等,可直接对应电路连接、代码烧录与硬件制作。源码中可见HX711传感器驱动、ADC采集、平均值滤波、定时器中断与LCD显示等模块,思路适合课程设计、毕业设计或入门STM32实战的嵌入式学习者参考。设计报告包含硬件选型、电路设计说明与测试数据,物料表列出具体元件型号,方便按清单采购与焊接。已有3093人浏览学习,目录结构按功能模块划分,便于快速定位和复现项目。

1. 基于STM32单片机的电子秤设计:从称重传感器选型到标定算法落地

做电子秤类设计时,最常被问的一句话是“STM32做电子秤是不是大材小用”。实际接过项目就明白,问题的核心从来不是单片机性能过剩,而是称重传感器输出的微弱模拟信号怎么变成稳定、准确、可重复的重量读数。HX711配合电阻应变式传感器是这套设计里最成熟的组合,STM32F103C8T6作为主控,负责数据采集、滤波、校准和显示交互。这篇方案面向正在做单片机课设或毕设的人,也适合想快速搭一台可验收样机的开发者。整套设计从传感器选型、硬件电路、软件滤波、标定算法到异常排查都给了可落地的做法,照着搭就能出活。

2. 系统总体架构设计:称重模块、主控模块与人机交互三部分划分

2.1 系统组成与技术选型依据

电子秤的完整链路包含四个环节:重力转换为电信号、模拟信号放大与数字化、数字信号处理与标定、结果展示与人机交互。对应到硬件上就是电阻应变式称重传感器、HX711 24位ADC模块、STM32F103C8T6主控、OLED显示屏和按键矩阵。

选型上有几个关键考量。传感器选用量程5kg的铝制悬臂梁式电阻应变传感器,适合做小型电子秤,精度可达±0.1%F.S.,灵敏度1.0±0.1mV/V。HX711之所以被广泛采用,是因为它内部集成了低噪声可编程增益放大器(PGA,增益128或64)和24位高精度ADC,能够直接读取传感器输出的差分毫伏信号,无需额外搭建仪表放大器。STM32F103C8T6主频72MHz,自带12位ADC、I2C、USART等外设,对电子秤这类低速采集场景完全够用,而且资料丰富、调试难度低。显示端用0.96寸I2C接口OLED,四线制(VCC、GND、SCL、SDA)连接,占两个GPIO即可。

系统级的数据流向是:传感器将重量变化转换为微伏级电压差,HX711以128倍增益放大后由内部24位ADC量化为数字码值,STM32通过模拟时序读取该码值,经过滑动平均滤波与标定系数换算后得到实际重量,最终刷新到OLED并通过按键完成去皮、校准、单位切换等功能。

2.2 STM32端资源分配与引脚规划

主控资源分配遵循一个原则:模拟信号采集引脚固定、I2C总线固定、剩余按键与状态指示引脚灵活配置。表1给出了一套可直接参考的引脚分配方案。

功能模块STM32引脚说明
HX711_SCKPB0时钟输出,由STM32产生
HX711_DOUTPB1数据输入,下降沿触发读取
OLED_SCLPB6I2C时钟线
OLED_SDAPB7I2C数据线
按键1(去皮)PA0外部中断或扫描方式
按键2(校准)PA1进入校准模式
按键3(单位切换)PA2g/kg切换
蜂鸣器PA3超重或按键提示

这里HX711的数据读取协议比较特殊,与普通SPI或I2C不同,它采用自定义的25脉冲时序——前24个脉冲读取24位数据,第25个脉冲用于设置下一次转换的增益。这种时序用GPIO模拟比用硬件SPI更稳,因为HX711对时钟频率上限有要求(典型值100kHz),模拟时序容易控制速度。

2.3 模块间协作流程与状态机设计

主程序结构不采用裸机轮询加延时这种松散写法,而是用一个简单的状态机管理整个称重流程。状态包括:初始化态、称重态、校准态、去皮态、超重报警态。每次循环检查按键状态并触发对应状态迁移,HX711数据更新通过DOUT引脚的电平变化来感知——当DOUT为低电平时表示转换完成,可读取数据;为高电平时继续等待。这种设计避免了“读一次睡一会儿”的盲等,也方便后续扩展蓝牙或WiFi模块时保持主循环响应。

3. 称重数据采集实现:HX711驱动、滤波算法与重量换算

3.1 HX711驱动代码实现与时钟说明

HX711的驱动核心是时序控制。读取一次数据的流程是:等待DOUT拉低,然后依次输出24个SCK脉冲,每个脉冲的下降沿锁存一位数据,数据为二进制补码格式。实现代码如下:

uint32_t HX711_Read(void) { uint32_t value = 0; uint8_t i; // 等待DOUT拉低,表示转换完成 while (HX711_DOUT_READ()); for (i = 0; i < 24; i++) { HX711_SCK_HIGH(); delay_us(2); // SCK高电平维持至少1us HX711_SCK_LOW(); delay_us(2); value = value << 1; // 先左移一位 if (HX711_DOUT_READ()) // 在SCK下降沿后读取数据位 { value++; } } // 第25个脉冲,设置下一次转换为增益128 HX711_SCK_HIGH(); delay_us(2); HX711_SCK_LOW(); delay_us(2); // 数据为24位有符号数,符号扩展 if (value & 0x800000) { value |= 0xFF000000; } return (uint32_t)((int32_t)value); }

代码里的delay_us(2)是关键参数。HX711数据手册要求SCK高电平时间不小于1us,低电平时间不小于1us,而STM32F103C8T6在72MHz主频下,一条GPIO置位语句的执行时间约0.1us左右,如果不加延时,SCK频率可能飙到数MHz,HX711会来不及稳定输出数据,导致读出的码值跳动剧烈。这里设定2us比较保守但稳妥,实际项目中曾试过把延时压到1us,短时工作没问题,连续运行半小时后偶尔出现读数跳变,改回2us就稳定了。

3.2 称重数据滤波:滑动平均与中值滤波结合

HX711的24位ADC虽然分辨率高,但应变式传感器本身存在机械震动、温度漂移和电磁干扰,原始码值在静止称重时也常常有±3到±5的波动。解决思路是软件滤波替代硬件上复杂的RC滤波电路。

具体做法是双级滤波:第一级做中值滤波,连续采样5次,去掉最大值和最小值后取平均,用于抑制偶发脉冲干扰;第二级做滑动平均,维护一个长度为10的循环缓冲区,每次新数据进入后计算窗口内平均值。代码如下:

#define FILTER_BUFFER_SIZE 10 int32_t filter_buffer[FILTER_BUFFER_SIZE]; uint8_t filter_index = 0; uint32_t filter_sum = 0; uint8_t filter_count = 0; int32_t Weight_Filter(int32_t new_value) { // 中值滤波:取3次采样中间值,排除突变 int32_t raw[3]; int32_t temp; uint8_t i, j; for (i = 0; i < 3; i++) { raw[i] = (int32_t)HX711_Read(); } for (i = 0; i < 2; i++) { for (j = i + 1; j < 3; j++) { if (raw[i] > raw[j]) { temp = raw[i]; raw[i] = raw[j]; raw[j] = temp; } } } new_value = raw[1]; // 取中值 // 滑动平均 if (filter_count < FILTER_BUFFER_SIZE) { filter_buffer[filter_index] = new_value; filter_sum += new_value; filter_count++; } else { filter_sum -= filter_buffer[filter_index]; filter_buffer[filter_index] = new_value; filter_sum += new_value; } filter_index = (filter_index + 1) % FILTER_BUFFER_SIZE; return filter_sum / filter_count; }

需要注意滑动平均窗口长度与响应速度的权衡。窗口越长,读数越稳定,但称重响应越慢。对电子秤这种静态称重场景,10个窗口的数据刷新率约10次/秒,重量稳定时间在1秒左右,体验尚可。如果做动态称重或分拣场景,窗口长度要缩短到4到5,且要配合更快的采样频率。另外滤波缓冲区在系统启动和去皮操作后需要清零,否则旧数据会影响新读数。

3.3 重量换算与标定系数计算

HX711输出的码值与重量的关系是线性的:重量 = (读数值 - 零点值) / 标定系数。零点值指空秤状态下的稳定读数,标定系数表示每克重量对应的码值变化量。

标定系数获取的准确方法是:先记录空秤零点值zero_offset,然后放上已知重量的标准砝码(例如500g),记录稳定后的码值known_value,则每克对应码值 = (known_value - zero_offset) / 500。实际计算时为了保留整数精度,通常把系数放大。如下是标定流程实现:

#define CALIBRATION_WEIGHT_GRAM 500.0f float weight_calib_coeff; // 单位:码值/g int32_t weight_zero_offset; void Weight_Calibrate(void) { int32_t value_without_load; int32_t value_with_load; // 第一步:空秤校零 printf("Remove all loads, press key to calibrate zero\r\n"); while (KEY_CALIBRATE == 0); // 等待按键 value_without_load = Weight_Filter(0); weight_zero_offset = value_without_load; // 第二步:加载标准砝码 printf("Put standard weight on scale\r\n"); while (KEY_CALIBRATE == 0); // 等待再次按键确认 value_with_load = Weight_Filter(0); weight_calib_coeff = (float)(value_with_load - weight_zero_offset) / CALIBRATION_WEIGHT_GRAM; }

标定系数在批量生产中如果只取一个砝码点,会存在线性误差。严谨的方案是三点标定:空秤、半量程、满量程,用最小二乘法拟合直线。但对于课设和一般商用场景,两点标定(零点+满量程)已经足够把误差控制在±2g以内。这里有个血泪经验:标定时砝码必须放在秤盘中心位置,四个角受力不均会导致同一重量的码值差出十几甚至几十个码值,标定系数失准。

4. 功能模块实现:按键去皮、单位切换与超重报警逻辑

4.1 去皮功能的实现细节

去皮操作的业务逻辑是:当秤盘上有容器时,按下去皮键,当前重量被记为皮重tar_weight,后续显示的净重 = 毛重 - 皮重。实现时需处理好边界条件。

去皮状态机

去皮状态可以划分为四个阶段:去皮空闲、去皮置零、去皮保持、去皮清除。去皮置零表示当前重量作为皮重存入静态变量;去皮保持阶段每次显示都用毛重减去皮重;去皮清除在再次按下去皮键且当前毛重减去皮重后接近0时触发,将皮重清零。判断“接近0”的标准是净重绝对值小于2g,即处于空杯状态,防止误清除。

int32_t tare_weight = 0; uint8_t tare_enabled = 0; void Weight_TareProcess(int32_t raw_value) { if (KEY_TARE_PRESSED) { if (!tare_enabled) { tare_weight = raw_value; tare_enabled = 1; } else if (ABS(raw_value - tare_weight) < 2) { // 空载状态下去皮,清除皮重 tare_weight = 0; tare_enabled = 0; } KEY_TARE_PRESSED = 0; } int32_t net_weight = tare_enabled ? (raw_value - tare_weight) : raw_value; // net_weight 用于后续显示处理 }

有一个细节值得注意:去皮后的净重计算用原始码值进行,而不是先用标定系数换算成克再相减。原因是标定系数本身存在浮点误差,先相减再换算只引入一次浮点运算,精度损失更小。另外去皮操作后需要清空滑动平均滤波器的缓冲区,避免皮重切换瞬间的旧数据污染显示。

4.2 单位切换与OLED显示驱动

单位切换涉及克(g)、千克(kg)两种显示模式。转换关系简单,但显示格式需要仔细处理:克模式保留一位小数,例如123.4g;千克模式保留三位小数,例如0.123kg。不合理的格式会导致OLED刷新时闪烁不均匀,视觉效果差。

OLED显示驱动采用U8g2库裁剪版本,重点关注两个问题。第一是刷新频率,OLED的I2C接口理论速率400kHz,显示一帧完整字符串约需30ms,如果每100ms刷新一次,加上HX711采样时间,主循环占用过高。解决办法是只在重量变化超过0.5g时才刷新显示,静止时维持旧显示,这样既省时间又避免抖动闪烁。第二是显示缓冲,0.96寸OLED共8页,每页128字节,总共1024字节,在STM32F103C8T6的20KB RAM中完全足够,但注意不要为多页数据分配多个独立数组,直接用连续数组管理更简单。

void OLED_ShowWeight(float weight_gram) { char buf[16]; if (display_unit == UNIT_GRAM) { sprintf(buf, "%.1f g", weight_gram); } else { sprintf(buf, "%.3f kg", weight_gram / 1000.0f); } // 仅在变化超过阈值时更新 if (ABS(weight_gram - last_display_weight) > 0.5f) { OLED_ClearLine(2); OLED_ShowString(2, 0, buf); last_display_weight = weight_gram; } }

4.3 超重报警与蜂鸣器控制

超重保护是电子秤容易被忽视的设计点。传感器量程5kg,HX711的ADC输出范围有限,超过量程后输出码值会进入非线性区甚至饱和,显示的重量会失真。合理的做法是:重量大于等于量程的105%时触发报警,蜂鸣器鸣叫并停止重量更新,直到重量回落。这里留5%余量是为了防止传感器长时间过载损坏,如果是高精度天平应用,余量应提高到10%。

蜂鸣器驱动用有源蜂鸣器,一个GPIO加三极管驱动即可,不用PWM。按键提示音、校准完成提示音、超重报警音分开三种节奏,通过延时控制鸣叫次数和间隔。报警后的重量显示固定为“0.0g”不是好选择,最好显示“oL”提示过载,方便用户区分空秤与故障状态。

5. 常见问题排查与设计避坑指南

5.1 读数跳变,静止时重量来回波动

现象:空秤状态下读数在±5g范围内来回跳动,放上砝码后波动范围更大。原因是HX711供电不稳定,或传感器激励电压纹波过大。STM32的3.3V LDO输出能力有限,当OLED刷新、蜂鸣器鸣叫等负载变化时,VCC纹波会达到几十毫伏,直接耦合到传感器桥臂输出。

解决:将HX711的AVDD供电独立,用一颗10uF钽电容加0.1uF瓷片电容并联在AVDD与GND之间;传感器激励电压(E+和E-)之间也要加去耦电容。软件上把采样时刻避开OLED刷新瞬间,在读数据前先等待系统电压稳定。

5.2 按键去抖处理不当导致误触

现象:按键偶尔一次按压触发两次动作,去皮变清除,校准直接跳过。原因是按键扫描没有做去抖处理,机械触点弹跳时间约5~10ms,程序在弹跳期间多次检测到有效电平。

解决:在按键检测函数中加入20ms延时去抖,同时检测释放状态。不能用简单延时替代完整去抖逻辑。代码示例如下:

uint8_t KEY_Scan(void) { static uint8_t key_up = 1; if (key_up && (KEY_PRESSED())) { delay_ms(20); // 去抖 if (KEY_PRESSED()) { key_up = 0; return KEY_VALUE; // 返回有效按键 } } if (!KEY_PRESSED()) { key_up = 1; } return KEY_NONE; }

5.3 标定系数是负数或异常大

现象:放入砝码后计算出的标定系数为负值,或数值超过每克码值变化范围的不合理区间。原因是传感器信号线接反,或HX711增益配置错误。应变式传感器的输出电压方向由受力方向决定,信号线接反时受力增加码值反而减小。

解决:检查传感器E+、E-与HX711对应引脚是否接对,检查信号线S+、S-是否交叉。正常接法下,悬空施加压力时码值应增大,如果减小就交换信号线。另外增益128对应的满量程输入差分电压约±20mV,如果传感器激励电压异常导致输出超过该范围,也会产生非线性结果。

5.4 OLED白屏或显示乱码

现象:上电后OLED无显示或显示方块乱码。最常见原因不是硬件损坏,而是I2C时序不正确或地址错误。0.96寸OLED常见地址为0x3C,但部分厂商使用0x3D。

解决:编写I2C地址扫描函数,遍历0x3C和0x3D两个地址读取ACK响应。另外检查OLED的复位引脚——部分模块的RESET引脚悬空会导致初始化失败,应将其连接到MCU的GPIO并在初始化时拉低再拉高。软件开发中先用通用的I2C扫描代码验证物理链路,再跑显示驱动,能快速定位问题。

5.5 系统低功耗优化时掉称重功能

现象:采用STM32的STOP模式降低功耗后,唤醒后称重读数长时间为0。原因是HX711在MCU进入STOP模式后失去SCK时钟,DOUT引脚状态不确定,唤醒后时序同步丢失。

解决:从STOP模式唤醒后先执行一次HX711的复位时序(持续拉高SCK超过60us再释放),让模块重新进入正常转换状态,再读取第一次有效数据并丢弃,从第二次数据开始参与滤波。这里容易翻车的点是漏掉复位时序直接读,结果读到的是残留在移位寄存器里的旧数据。

6. 项目验收与答辩准备:从测试项到演示流程设计

6.1 分模块测试方法与通过标准

验收环节通常分三个层次。第一层是模块级测试:HX711读取码值是否随负载单调递增,OLED显示是否清晰无残影,按键功能是否正确切换。第二层是系统级测试:在空秤、500g、1000g、2000g量程点进行称重,记录显示值与实际值的偏差。第三层是稳定性测试:连续运行1小时,每隔10分钟记录一次零点漂移情况。

表2是一份可参考的验收记录表,实际交付时填好数据即可作为测试报告。

测试载荷(g)显示值(g)偏差(g)重复性(g)结论
00.00.00.1通过
100100.2+0.20.2通过
500499.8-0.20.3通过
10001001.3+1.30.4通过
20002001.8+1.80.5通过

这里的重复性指标指同一载荷下多次测量结果的最大差值,反映了滤波效果和传感器的一致性。如果重复性偏差超过1g,优先检查机械结构——秤盘固定螺丝是否松动、防震垫是否均匀受力。

6.2 答辩演示脚本:从开机到标定的完整流程

答辩演示中最容易翻车的不是功能缺失,而是演示流程设计不合理,现场花大量时间做标定导致评审失去耐心。我通常建议准备一套“直通脚本”:提前完成标定并将标定参数固化在Flash中,演示时先开机展示初始化画面,然后直接放砝码称重。标定作为备用演示项,只有问到“怎么标定”时才展示。

演示顺序建议按以下步骤排:插电开机(展示产品名称和版本号)、空秤回零(强调零点跟踪功能)、放置500g砝码(展示稳定读数)、按键去皮(演示容器称重场景)、放置少量物品累计称重、单位切换展示、最后演示超重报警。整个流程控制在3分钟以内。每个操作之前口头说明“接下来演示某某功能”,给评审明确的观看点。

6.3 答辩高频问题与应答要点

答辩时最常被追问的是精度和误差来源。对应答逻辑建议是:先说明精度的定义(满量程的百分比),再解释误差来源的三个部分——传感器精度、ADC量化误差、标定残余误差,最后给出实测数据支撑。这样的三层结构比单纯背参数更有说服力。

另一个常见问法是“为什么选STM32F103C8T6而不是51单片机”。回答思路是:51单片机的ADC精度和GPIO翻转速度不足以稳定读取HX711,且后续扩展蓝牙或WiFi时51的资源会非常紧张,STM32在成本和性能之间更平衡。这里千万不要贬低51,客观说差异即可。

还有一个高频问法是“如何提高称重精度”。回答分两级:硬件上使用更高精度的传感器(如0.02%F.S.的德国进口传感器)和独立模拟电源供电;软件上增加标定点数量,用分段线性插值替代单系数线性换算。可以补充一句:如果精度要求到±0.1g,需要改用更高位数的ADC方案或加温度补偿,涉及的问题就复杂了。

6.4 验收前的最终检查清单

演示前一天强制走一遍完整流程:检查电源接线是否牢固、传感器四角受力是否均匀、标定参数是否已固化、OLED对比度是否合适、按键是否灵敏。我把这些列成一个checklist贴在工作台上,每次验收前逐项打勾。从那以后每次做类似设计,我都强制自己在交付前先按用户视角操作一遍,而不是按开发者习惯操作。希望帮到你。

本文还有配套的精品资源,点击获取

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

人形机器人开源数据库 Atlas:成本、BOM 与供应链实操指南

做机器人这些年&#xff0c;我最烦的一件事就是信息差。想评估一款人形机器人的方案&#xff0c;要翻官网、找论文、找供应链朋友打听价格&#xff0c;最后凑出来的数据口径还不一致&#xff0c;根本没法横向比。所以当“全球人形机器人数据库Atlas”在Github开源的消息传出来时…

作者头像 李华
网站建设 2026/10/21 4:44:36

个人技能管理实战指南:盘点、差距分析与提升路径

我是在一次年底复盘的时候&#xff0c;才真正把“skills”&#xff08;技能&#xff09;这件事当成一个正经课题来对待的。以前我一直觉得&#xff0c;技能是长在身上的东西&#xff0c;平时干活自然会用到&#xff0c;没必要专门抽时间去梳理。直到有一次帮团队搭建能力模型&a…

作者头像 李华
网站建设 2026/10/21 4:44:23

从根因事件分析法(REA)看线上故障排查与系统性复盘实践

项目标题所揭示的真相&#xff1a;一次“缩写”引发的系统性复盘说实话&#xff0c;第一次看到“REA”这三个字母时&#xff0c;我脑子里闪过了无数个可能性——是某个内部系统的代号&#xff1f;是某个流程的英文缩写&#xff1f;还是某个新框架的名称&#xff1f;直到我坐下来…

作者头像 李华
网站建设 2026/10/21 4:43:52

DeepSeek调优指令与检测工具实测:如何将AIGC率从85%降到10%

先说个实际场景&#xff1a;我把一篇自己参考大量文献写好的初稿丢进学校常用的AIGC检测工具&#xff0c;红字直接标出“疑似AI生成占比85%”。当时整个人是懵的&#xff0c;因为稿子确实是自己一个个字敲的&#xff0c;只是中期用了 DeepSeek 帮忙顺过逻辑、润过几个过渡段落。…

作者头像 李华
网站建设 2026/10/21 4:43:47

React核心原理与工程实践:从组件设计到Hooks性能优化全解析

1. 核心思路拆解&#xff1a;为什么React是前端绕不开的那道坎很多人第一次听到"rea"这个缩写&#xff0c;第一反应是"读"&#xff0c;但放在前端圈子里&#xff0c;它基本就是React的简称——那个由某公司开源、后来被全球开发者捧上神坛的JavaScript库。…

作者头像 李华
网站建设 2026/10/21 4:43:26

HTTP协议全解析:从报文结构、缓存机制到调试实战

浏览器里敲下网址、按下回车&#xff0c;页面刷新出来的那一刻&#xff0c;背后至少发生了一次完整的HTTP请求和响应交互。作为一名常年跟网页打交道的从业者&#xff0c;我可以坦白地讲&#xff1a;很多开发者在日常工作中能熟练操作接口调试工具、能看懂浏览器开发者工具里的…

作者头像 李华