
1. 称重项目为什么值得用 STM32HX711 这套组合来做称重看起来简单无非是把物体放上去读个数但真要做到稳定、准确、不跳变里面的门道比想象中多。我前后做过好几个称重相关的项目从最简单的电子秤到配料系统的称重反馈踩过的坑基本都集中在三个地方传感器信号太微弱、ADC 采样噪声大、显示刷新和采样节奏打架。STM32 加 HX711 加 OLED 这套组合恰好能用较低的成本把这三个问题都处理得比较干净所以它成了很多人做毕业设计、DIY 电子秤、小型配料装置的首选方案。先把这套东西的角色分工说清楚。HX711 是一颗专为高精度电子秤设计的 24 位模数转换芯片它内部集成了稳压电源、片内时钟振荡器还有专门针对桥式传感器也就是我们常说的电阻应变片称重传感器的差分输入通道。它的两个通道 A 和 B通道 A 可以设置 128 倍或 64 倍增益通道 B 固定 32 倍增益用来接一些辅助信号。STM32 在这里扮演的是大脑负责按 HX711 的时序把数据读出来、做滤波和标定运算、驱动 OLED 显示顺便还能扩展按键、串口上报、报警输出这些功能。OLED 则是人机交互的窗口把重量数值、单位、状态实时呈现出来。为什么不用 STM32 自带的 ADC 直接接传感器这是新手最容易问的问题。原因在于称重传感器输出的差分电压非常小满量程通常只有几毫伏到几十毫伏STM32 内置的 12 位 ADC 分辨率和噪声水平根本不够看直接采出来的数会跳得你怀疑人生。HX711 的 24 位分辨率配合内部低噪声放大器能把有效精度做到十几万分之一甚至更高这才是称重场景真正需要的东西。所以这套组合不是随便凑的而是各司其职。这套方案适合谁如果你正在做基于 STM32 的毕业设计、想做一个厨房电子秤、想做配料称重、想给鱼缸或者宠物喂食器加称重反馈那这套组合基本可以直接抄作业。它不需要你懂太深的模拟电路只要把 HX711 的时序搞明白剩下的都是软件活。下面我会从硬件连接、时序驱动、标定算法、OLED 显示、滤波优化几个角度把整个项目拆开讲透尽量把那些文档里不会写的经验都倒出来。2. HX711 的硬件连接与那些容易接错的引脚2.1 传感器和 HX711 之间的四线接法称重传感器一般引出四根线颜色通常是红、黑、白、绿但不同厂家的配色并不统一这一点必须先确认。标准接法是红线和黑线是传感器的激励电源正负白线和绿线是差分信号输出。接到 HX711 上时红黑接 E 和 E-白绿接 A 和 A-。这里有个非常关键的细节白绿两根线如果接反了读数会反向也就是压上去重量变成负数。很多人第一次调试发现数值是负的第一反应是程序写错了其实只是信号线接反了对调一下就好。传感器到 HX711 的连线尽量短如果实在要延长建议用屏蔽线并且屏蔽层单端接地。我见过有人用几十厘米的杜邦线随便一插结果读数一直在抖换成短一点的线立刻稳定。称重传感器的信号是毫伏级的任何一点干扰都会被放大所以走线这件事不能偷懒。2.2 HX711 和 STM32 之间的引脚分配HX711 和单片机之间只需要两根信号线SCK有时标为 PD_SCK和 DOUT有时标为 DT。这两根线是 HX711 自己定义的串行时序不是标准 I2C 也不是标准 SPI所以不能用硬件外设直接驱动必须用普通 GPIO 软件模拟时序。这一点是新手最容易误解的地方看到两根线就以为是 I2C结果怎么调都不通。我一般这样分配引脚把 DOUT 接到 STM32 的一个输入引脚SCK 接到一个输出引脚。以 STM32F103C8T6 为例可以选 PA0 做 DOUT、PA1 做 SCK这两个引脚不冲突配置起来也方便。DOUT 必须配置成输入模式SCK 配置成推挽输出。如果你用的是 HAL 库初始化的时候把这两个引脚分别设成 GPIO_MODE_INPUT 和 GPIO_MODE_OUTPUT_PP速度设成低速就够了因为 HX711 的时序并不快。注意HX711 的供电电压要和 STM32 的 IO 电平匹配。HX711 常见的工作电压是 2.7V 到 5V如果你用 5V 给 HX711 供电而 STM32 是 3.3V 系统DOUT 输出的高电平可能接近 5V长期直接接会损伤 STM32 引脚。稳妥的做法是 HX711 也用 3.3V 供电或者加电平转换。实测 3.3V 供电时 HX711 完全能正常工作精度也够用。2.3 电源和去耦电容的处理HX711 的供电质量直接影响读数稳定性。模块上一般已经带了滤波电容但如果你是自己画的板子AVDD 和 DVDD 附近一定要各放一个 0.1uF 的去耦电容电源入口再并一个 10uF 的电解电容。传感器激励电源 E 和 E- 之间的电压稳定性同样重要如果电源纹波大读数就会跟着波动。我遇到过一个很典型的案例有人用 USB 供电给整个系统电机一启动读数就乱跳。后来在 HX711 电源入口加了一个 LC 滤波问题立刻缓解。所以如果你的项目里还有电机、继电器这类负载一定要把称重部分的电源和它们隔离开至少加个磁珠或者电感。3. 把 HX711 的时序吃透24 位数据到底怎么读出来3.1 HX711 的通信时序本质HX711 的通信协议说穿了很简单但时序细节必须抠准。它的工作流程是这样的当 DOUT 为高电平时表示数据还没准备好这时候你不能去读当 DOUT 变成低电平说明一次转换完成数据可以读了。这时候你给 SCK 发 25 到 27 个时钟脉冲前 24 个脉冲把 24 位数据一位一位地移出来第 25 个脉冲用来选择下一次转换的通道和增益。具体来说第 25 个脉冲的数量决定下一次读的是哪个通道、什么增益发 25 个脉冲选通道 A 增益 128发 26 个脉冲选通道 B 增益 32发 27 个脉冲选通道 A 增益 64。这个设计很巧妙用脉冲个数来切换配置省了额外的控制线。但如果你数错了脉冲下一次读出来的数据就会来自错误的通道表现就是数值突然变得很奇怪。3.2 用 GPIO 模拟时序的代码实现下面这段是基于 HAL 库的读取函数逻辑很直白你可以直接拿去改long HX711_Read(void) { unsigned long value 0; unsigned char i; // 等待 DOUT 变低表示数据就绪 while (HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN) GPIO_PIN_SET); for (i 0; i 24; i) { HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET); value value 1; HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET); if (HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN) GPIO_PIN_SET) { value; } } // 第 25 个脉冲选择通道 A 增益 128 HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET); // 补码转换24 位有符号数 if (value 0x800000) { value | 0xFF000000; } return (long)value; }这段代码里有两个地方值得展开说。第一等待 DOUT 变低的那句 while 循环是阻塞的如果 HX711 没接好或者坏了程序会卡死在这里。实际项目里我会加一个超时计数超过一定次数就返回错误避免整个系统被一个传感器拖死。第二24 位数据是补码形式最高位是符号位所以读完之后要判断第 23 位如果是 1 就要把高 8 位补成 1转成 32 位有符号数才能正确表示负值。3.3 采样率 10Hz 还是 80Hz 的选择HX711 有两个采样率版本通过模块上的一个引脚通常标为 RATE来选择。拉低是 10Hz拉高是 80Hz。这个选择不是随便定的它直接决定了你的系统响应速度和噪声水平。10Hz 模式下芯片内部做了更多的平均噪声更低读数更稳适合静态称重比如电子秤、配料称。80Hz 模式下响应快但噪声明显增大适合需要快速跟踪重量变化的场景比如动态检重、流量称重。我个人的经验是如果你只是做一个静态电子秤老老实实用 10Hz读数稳定性会好很多滤波压力也小。如果你发现 10Hz 下响应太慢比如放上物体要等一秒才稳定那再考虑 80Hz同时把软件滤波加强。提示切换采样率之后标定参数可能需要重新做因为不同采样率下的噪声特性和零点漂移不完全一样。我一般会在确定采样率之后再开始标定避免返工。4. 从原始 ADC 值到真实重量标定和去皮怎么做才靠谱4.1 为什么要标定标定的数学本质是什么HX711 读出来的是一个 24 位的原始数值它和真实重量之间是线性关系但比例系数和零点你并不知道。标定就是把这个线性关系确定下来。数学上很简单重量 (原始值 - 零点值) / 比例系数。零点值是空载时的读数比例系数是每单位重量对应的原始值变化量。标定分两步。第一步去皮空载时读若干个值取平均作为零点。第二步放砝码放一个已知重量的物体读出稳定后的原始值用 (当前值 - 零点值) / 砝码重量 算出比例系数。这个系数就是你的标定参数存到 Flash 里下次开机直接调用。4.2 标定实操中的几个关键细节砝码的选择有讲究。尽量选接近你常用量程的砝码比如你平时称 1kg 左右的东西就用 1kg 砝码标定不要用 100g 去标一个 5kg 的量程那样误差会被放大。如果没有标准砝码可以用已知重量的物品代替比如一袋标注净含量的米但精度会差一些。读数要等稳定了再取。HX711 上电后需要一点时间稳定放上砝码后也要等读数不再漂移。我的做法是连续读 20 个值去掉最大最小各几个剩下的取平均这样得到的标定值比较可靠。标定时环境温度也会影响结果应变片对温度敏感如果标定和使用的温差很大零点会漂。要求高的场合需要做温度补偿普通项目里至少保证标定和使用在相近温度下进行。4.3 去皮功能的实现和常见误区去皮功能看起来简单但有个坑很多人踩去皮之后如果零点漂移了重量会慢慢偏。原因是去皮时记录的零点是一个瞬时值而 HX711 的零点会随温度和时间缓慢变化。解决办法是定期自动去皮或者在检测到空载且读数稳定时自动更新零点。我一般会实现一个自动零点跟踪逻辑当读数在零点附近一个小范围内波动并且持续一段时间没有明显重量变化时就认为当前是空载慢慢把零点往当前值靠。这样既能消除漂移又不会在称重过程中误更新。这个逻辑在电子秤里是标配自己写项目时加上会让体验好很多。5. OLED 显示让重量数值稳定又好看地呈现出来5.1 OLED 选型和 I2C 地址的那些事0.96 寸 OLED 是最常见的选择SSD1306 驱动芯片四针 I2C 接口接线简单。但这里有个高频问题0.9 寸和 0.96 寸的 OLED 对 I2C 的兼容性不完全一样有些 0.9 寸屏的 I2C 时序要求更严格用标准库的软件 I2C 可能点不亮。如果你遇到 OLED 不亮先检查地址SSD1306 的 I2C 地址通常是 0x78 或 0x7A7 位地址是 0x3C 或 0x3D有些模块背面有电阻可以改地址。还有一个常见现象是花屏。花屏的原因很多电源不稳、I2C 速率太高、初始化序列不对都可能。我遇到最多的是电源问题OLED 在刷新时电流会有波动如果和 HX711 共用一条电源线且没有足够去耦就会互相干扰。解决办法是在 OLED 的 VCC 和 GND 之间并一个 0.1uF 电容尽量靠近屏幕引脚。5.2 显示刷新的节奏控制称重项目里OLED 刷新和 HX711 采样如果处理不好会互相拖累。HX711 在 10Hz 模式下每 100ms 出一次数据OLED 全屏刷新一次 I2C 传输大概需要几十毫秒。如果你在主循环里既读 HX711 又刷 OLED很容易出现读数节奏被打乱的情况。我的做法是把采样和显示解耦用一个定时器或者系统滴答定时器每 100ms 触发一次 HX711 读取读到的值放进一个缓冲区做滤波OLED 则每 200ms 到 300ms 刷新一次只更新变化的数字区域不做全屏刷新。这样既保证了采样节奏稳定又不会因为显示拖慢系统。SSD1306 支持页地址模式可以只更新某几页刷新数字区域用这个模式效率很高。5.3 显示内容和单位处理显示内容上我建议至少包含这几项当前重量数值、单位g 或 kg、状态提示稳定/不稳定。数值的位数要根据量程定比如 5kg 量程、1g 精度就显示到小数点后一位或者整数克。单位切换可以在超过 1000g 时自动切到 kg这样读起来更直观。数值的稳定性显示是个加分项。当连续几次读数变化小于某个阈值时显示稳定否则显示波动。这个判断逻辑很简单但用户体验提升明显尤其是配料场景操作者需要知道什么时候读数可信。6. 滤波和抗干扰让读数不跳变的实战经验6.1 为什么原始读数会跳HX711 虽然精度高但原始读数一定会有波动这是正常的。波动来源有几个传感器本身的噪声、电源纹波、机械振动、温度变化。你不可能把所有噪声都从硬件上消除所以软件滤波是必须的。很多人第一反应是用一个很大的平均值滤波读 100 次取平均。这样做确实稳但响应会变得很慢放上物体要好几秒才显示正确值。滤波的本质是在稳定性和响应速度之间找平衡没有免费午餐。6.2 几种实用的滤波方案对比滤波方案原理优点缺点适用场景算术平均N 次采样取平均实现简单抑噪明显响应慢N 越大越慢静态称重滑动平均维护一个窗口每次替换最旧值响应比算术平均快需要缓冲区一般称重中值滤波取 N 次采样的中间值抗脉冲干扰强对连续噪声效果一般有突发干扰的场合一阶低通新值按系数加权计算量小响应可调参数需要调实时性要求高复合滤波中值滑动平均组合兼顾抗脉冲和平滑实现稍复杂推荐方案我实际项目里最常用的是中值加滑动平均的复合滤波先连续采 5 个值去掉最大最小剩下 3 个取平均再把这个结果放进一个长度为 5 的滑动窗口做二次平均。这样既有抗脉冲能力又能平滑连续噪声响应速度也还能接受。实测在 10Hz 采样率下放上物体大约 300ms 到 500ms 就能稳定显示。6.3 硬件层面的抗干扰补充软件滤波再强也架不住硬件层面的干扰。几个我踩过坑之后总结的硬件要点传感器信号线远离电源线和电机线如果必须交叉尽量垂直交叉而不是平行走线HX711 的模拟地和数字地分开走最后单点汇合整个系统如果有金属外壳外壳接地。这些看起来是老生常谈但在称重这种微弱信号场景里每一条都能实实在在减少跳变。还有一个容易被忽略的点机械安装。传感器如果安装不牢固或者受力方向不对读数会随位置变化。称重传感器有明确的受力方向安装时一定要按照它的受力轴线加载不要有侧向力。我见过有人把传感器随便用螺丝拧在亚克力板上结果不同位置放同一个物体读数都不一样这就是机械安装没做好。7. 项目整合主循环怎么组织才不卡顿7.1 用定时器驱动采样主循环只管显示和逻辑把整个项目串起来的时候最容易犯的错误是把所有事情都塞进主循环顺序执行。读 HX711 要等 DOUT刷 OLED 要等 I2C按键要消抖如果都顺序做任何一个环节慢了都会拖累其他环节。我的组织方式是用一个定时器中断每 100ms 置一个标志位主循环检测到标志位就去读一次 HX711 并做滤波OLED 刷新用另一个计数器每 3 次采样刷新一次按键扫描放在主循环里用状态机做消抖。这样各个任务的节奏是独立的互不阻塞。如果你用的是 FreeRTOS那就更简单采样、显示、按键各开一个任务用队列传递数据优先级合理安排就行。7.2 标定参数的存储和读取标定参数要存到 STM32 的 Flash 里掉电不丢。STM32F103 的 Flash 擦写需要注意写之前要先擦除整个页不能直接覆盖写。我一般会在 Flash 的最后一页划一块区域专门存参数存的时候加一个校验和读的时候校验一下如果校验失败就用默认值避免参数损坏导致系统异常。参数结构体大概长这样零点值、比例系数、校验和。存的时候把结构体按字节写入读的时候按字节读出再还原。注意 Flash 写入的地址要按半字对齐STM32F1 的 Flash 编程单位是半字16 位这一点在写代码时要留意。7.3 串口上报和扩展功能称重数据除了显示很多时候还需要上报给上位机或者传给其他模块。用串口按固定格式发送是最简单的比如每 200ms 发一帧重量:1234g\r\n。如果你要做更复杂的系统比如配料控制可以在重量达到设定值时触发继电器或者蜂鸣器这些扩展都不难核心还是把称重这部分做稳。我在一个配料项目里做过这样的逻辑设定目标重量实时显示当前重量和差值达到目标值 95% 时慢速加料达到 100% 时停止。这里称重的响应速度和稳定性直接决定了配料精度所以前面讲的滤波和采样率选择在这个场景里格外重要。8. 调试过程中最常遇到的几个问题及排查思路8.1 读数一直是 0 或者一直是最大值这种情况通常是通信没通。排查顺序先确认 DOUT 有没有在变化如果 DOUT 一直高电平说明 HX711 没有完成转换检查供电和传感器接线如果 DOUT 有变化但读出来全是 0 或全 1检查 SCK 时序特别是脉冲数量和顺序。用逻辑分析仪或者示波器看一眼 SCK 和 DOUT 的波形问题一目了然。没有仪器的话可以在代码里把原始值打印出来看变化趋势。8.2 读数跳动厉害先排除硬件传感器接线是否牢固、电源是否干净、有没有电机等干扰源。硬件没问题再调软件加大滤波窗口、降低采样率到 10Hz、检查标定是否合理。如果跳动是周期性的可能是电源纹波或者机械振动需要从根源上解决。8.3 数值线性度差小重量准大重量不准这通常是标定问题。检查标定砝码是否接近常用量程标定时读数是否稳定。如果传感器本身质量差线性度就是不行软件没法完全弥补。另外注意传感器的量程选择用一个大量程传感器称小重量精度天然就差这是物理限制。8.4 OLED 显示正常但数值不更新检查采样标志位有没有被正确置位滤波缓冲区有没有溢出显示函数有没有被调用。这种问题多半是任务调度逻辑写错了用调试器单步跟一下就能找到。9. 我在这个项目里积累的几条实在经验做称重项目这些年有几个体会是文档里不会写但特别有用的。第一先把硬件调通再写复杂软件。我见过太多人一上来就写一大堆滤波和显示代码结果硬件接线是错的调了半天以为是软件问题。正确的顺序是先用最简单的代码把原始值读出来确认能随重量变化再往上加功能。第二标定比滤波更重要。很多人把精力全花在滤波上却忽略了标定的准确性。实际上一个准确的标定能让你的读数又稳又准而滤波只是锦上添花。标定时多花十分钟后面省心很多。第三留出调试接口。项目里一定要留串口打印原始值和中间变量的能力调试阶段全靠它。等产品定型了再把调试代码去掉或者用宏关掉。第四注意温度影响。如果你的项目在不同温度环境下使用零点漂移是绕不开的。简单的做法是开机时自动去皮复杂一点可以加温度传感器做补偿。普通室内使用的项目开机预热几分钟再标定基本就够用了。这套 STM32HX711OLED 的方案硬件成本低软件难度适中只要把时序、标定、滤波这三块吃透做出来的称重系统精度和稳定性都能满足大部分需求。后面如果你想扩展成无线传输、多路称重、或者接入更复杂的控制系统这套基础框架都能直接往上搭。