☰
STM32智能体重秤实战:HX711驱动、OLED显示与Proteus仿真全解析
2026/10/19 6:43:06 网站建设 项目流程

1. 从一个厨房角落里的需求说起

去年帮朋友改造他家的旧电子秤,拆开一看,里面那颗主控芯片的型号模糊得几乎看不清,但板子上的丝印布局、晶振位置、传感器接口,一眼就能认出是典型的STM32最小系统。那一刻我意识到,体重秤这个看起来再普通不过的小家电,其实是嵌入式入门到进阶的绝佳练手项目——它同时涉及模拟信号采集、数字滤波、人机交互、低功耗管理,甚至还能延伸到物联网数据上传。市面上开源出来的智能体重秤项目不少,但真正把代码、原理图、仿真三件套凑齐,并且能让一个新手照着复现出来的,其实并不多。

这个项目的核心价值在于:它不是一个停留在PPT上的概念,而是一套完整的、可落地的工程文件集合。代码部分覆盖了从HX711称重传感器驱动、OLED显示刷新、按键交互到数据存储的完整逻辑;原理图部分给出了主控最小系统、传感器接口、电源管理和显示模块的连接关系;仿真部分则让你在没有实物硬件的情况下,也能在电脑上验证核心算法的正确性。适合谁来参考?如果你是刚学完STM32基础外设、想找一个综合项目练手的学生,或者是有一定嵌入式经验、想快速搭建一个称重类产品原型的开发者,这套东西能帮你省掉大量从零摸索的时间。

我见过太多人卡在“传感器读数跳变”“ADC采样不稳”“OLED花屏”这些看似简单实则磨人的问题上。这篇文章就把这个项目从头到尾拆一遍,把那些文档里不会写的坑和技巧都摊开来讲。

2. 整体方案设计与选型背后的逻辑

2.1 为什么是STM32而不是51或ESP32

选型这件事,很多人上来就问“哪个芯片最强”,但工程选型的核心从来不是性能天花板,而是性能够用前提下的综合成本与开发效率。这个项目选STM32F103C8T6作为主控,理由很实在:它有一颗72MHz的Cortex-M3内核,跑称重滤波算法和OLED刷新绰绰有余;片上资源包括64KB Flash、20KB SRAM,存校准参数和临时数据完全够用;最关键的是它的生态——标准外设库和HAL库资料铺天盖地,遇到问题搜索一下就有答案。

对比一下:51单片机虽然便宜,但运算能力和RAM捉襟见肘,做滑动平均滤波时稍微多开几个缓冲区就紧张;ESP32性能强且自带无线,但它的ADC线性度在称重这种需要高精度采样的场景下反而不如外挂专用ADC芯片来得稳,而且对于只想学嵌入式基础的人来说,ESP32的复杂度会分散注意力。所以STM32F103是那个“刚刚好”的选择——不浪费,也不将就。

2.2 称重传感器的信号链设计思路

体重秤的核心是把重量这个物理量转换成可处理的数字量。整个信号链是这样的:电阻应变式称重传感器(通常是一个半桥或全桥结构)受到压力后,应变片电阻发生微小变化,电桥输出一个差分电压,这个电压非常微弱,通常在毫伏级别。如果直接用STM32内部的12位ADC去采,分辨率根本不够——STM32的ADC最小分辨力大约是0.8mV,而体重秤满量程50kg对应的传感器输出可能只有十几毫伏,算下来每公斤才零点几毫伏,完全被噪声淹没。

所以必须用专用仪表放大器或集成ADC芯片。这个项目用的是HX711,一颗专门为高精度称重设计的24位模数转换芯片,内置了低噪声可编程增益放大器,增益可选128、64、32。选128增益时,它能分辨的最小电压变化是±20mV满量程下的24位精度,换算下来理论分辨率达到纳伏级别,实际有效精度也能到十几位,足够分辨几十克的重量变化。HX711通过两个普通IO口模拟串行时序与STM32通信,不需要SPI或I2C外设,接线简单,成本也低。

2.3 仿真方案的选择与取舍

仿真这部分,项目里用的是Proteus。有人会问,都2025年了为什么不用更现代的仿真工具?原因很简单:Proteus对STM32和HX711这类常见器件的模型支持最成熟,网上能找到现成的元件库和仿真案例,而且它能把原理图和代码联调——你可以在Proteus里加载编译好的hex文件,直接看到OLED上显示的数字随虚拟传感器滑动而变化。这对于没有实物硬件的初学者来说,是建立信心的重要一步。

当然仿真有它的局限。Proteus里的HX711模型是理想化的,不会模拟真实的温漂和噪声,所以仿真通过不代表实物一定稳。我的建议是:用仿真验证逻辑和时序,用实物验证精度和稳定性,两者不可偏废。

3. 核心细节解析与实操要点

3.1 HX711驱动时序:别被“简单”两个字骗了

HX711的通信协议看起来很简单:时钟线PD_SCK给脉冲,数据线DOUT在时钟上升沿输出一位数据,24位数据加1位通道选择,一共25个脉冲。但实际操作中有几个细节如果没注意,读数就会乱跳甚至完全读不出来。

第一个坑是时序延时。HX711的数据手册里写了,PD_SCK高电平持续时间不能超过50微秒,否则芯片会进入掉电模式。很多人在写驱动时用HAL_GPIO_WritePin加HAL_Delay,但HAL_Delay的最小分辨率是1毫秒,远远超过50微秒,一拉高就掉电了。正确的做法是用__NOP()或者简单的for循环做微秒级延时,或者用定时器产生精确的微秒延时。

第二个坑是数据就绪判断。DOUT引脚在数据准备好时会变低,但如果你在它还没准备好的时候就开始给时钟,读到的就是上一次的残留数据或者全0。稳妥的做法是在读数据前先等待DOUT变低,加一个超时机制防止死等。

第三个坑是符号位处理。HX711输出的是24位二进制补码,最高位是符号位。如果你直接把它当无符号数处理,负重量(比如传感器装反了)就会变成一个巨大的正数。正确的做法是先判断最高位,如果是1,说明是负数,需要取反加一还原成有符号整数。

// HX711读一个字节的典型实现 uint8_t HX711_ReadByte(void) { uint8_t i, data = 0; for (i = 0; i < 8; i++) { HX711_SCK_HIGH(); __NOP(); __NOP(); __NOP(); // 微秒级延时 data <<= 1; if (HX711_DOUT_READ()) data++; HX711_SCK_LOW(); __NOP(); __NOP(); __NOP(); } return data; }

注意:不同批次的HX711模块,DOUT和SCK的上拉电阻配置可能不同。有些模块DOUT需要外部上拉,有些内部已经有了。如果读出来一直是0或一直是1,先检查硬件上拉。

3.2 称重校准:从原始值到公斤数的数学转换

HX711读出来的原始值是一个24位有符号整数,它和实际重量之间是线性关系,但需要两个参数才能换算:零点偏移和比例系数。零点偏移就是空秤时的读数,比例系数是每单位重量对应的读数变化量。

校准的标准流程是:先放空秤,读若干次取平均得到零点值;然后放一个已知重量的物体(比如5kg砝码或者一袋标称5kg的大米),读若干次取平均得到满量程值;比例系数 = (满量程值 - 零点值) / 已知重量。之后每次读数减去零点值再除以比例系数,就是重量。

听起来简单,但实际操作中有几个经验点。第一,取平均的次数要够。HX711单次转换时间在10Hz模式下是100毫秒,80Hz模式下是12.5毫秒。建议在10Hz模式下连续读20次取平均,这样能有效抑制随机噪声。第二,校准时的环境要稳定。别在风扇旁边或者有人走动的桌子上校准,振动会让读数波动。第三,比例系数要存到Flash里。每次上电重新校准太麻烦,把零点和系数存到STM32的Flash模拟EEPROM区,开机直接读取。

// 重量换算的核心逻辑 float Get_Weight(void) { int32_t raw = HX711_ReadAverage(20); // 读20次取平均 float weight = (float)(raw - zero_offset) / scale_factor; if (weight < 0.05f) weight = 0.0f; // 死区处理,避免空秤显示负数 return weight; }

3.3 OLED显示刷新:别让屏幕拖慢整个系统

项目里用的是0.96寸SSD1306 OLED,I2C接口。这个屏幕本身不复杂,但刷新策略如果没设计好,会严重影响称重响应速度。我见过有人在主循环里每读一次重量就全屏刷新一次,结果屏幕闪烁不说,称重响应也变慢了。

正确的做法是局部刷新加定时刷新。重量数值变化时才更新对应的显示区域,其他静态内容(比如单位“kg”、标题文字)只在初始化时写一次。刷新频率控制在5到10Hz就够了,人的视觉暂留效应会让它看起来是连续的。另外,I2C的速率建议设到400kHz快速模式,标准100kHz在刷新较多内容时会感觉到明显延迟。

还有一个细节:OLED的I2C地址通常是0x78或0x7A,取决于模块上的电阻配置。如果屏幕完全不亮,先用I2C扫描程序确认地址。

3.4 电源管理:电池供电时的关键考量

如果这个体重秤要做成电池供电的便携版本,电源管理就不能忽视。STM32F103在72MHz全速运行时的电流大约30到50毫安,加上HX711和OLED,整体功耗在60毫安左右。用两节5号电池供电的话,连续工作也就十几个小时。

降低功耗的几个手段:第一,用STM32的睡眠模式。称重不是每时每刻都需要,可以设计成按键唤醒或者定时唤醒,醒来后快速采样几次然后继续睡。第二,HX711支持掉电模式。不采样的时候把PD_SCK拉高超过60微秒,HX711就进入掉电,电流从1.5毫安降到不到1微安。第三,OLED可以关闭显示。SSD1306支持睡眠命令,关闭后电流从十几毫安降到微安级。

提示:如果要做低功耗版本,建议把HX711的采样率设成10Hz而不是80Hz,虽然响应慢一点,但每次转换的功耗更低,整体平均功耗反而更优。

4. 实操过程与核心环节实现

4.1 硬件搭建:从原理图到面包板

拿到原理图之后,第一步是理解各个模块的连接关系。主控STM32F103C8T6的最小系统包括:8MHz晶振加两个22pF电容构成外部高速时钟,复位电路用一个10k电阻加100nF电容,BOOT0和BOOT1通过跳线或电阻接地选择从Flash启动。这些是STM32能跑起来的基础,缺一不可。

HX711模块与STM32的连接:VCC和GND供电,DT接STM32的某个GPIO(比如PA0),SCK接另一个GPIO(比如PA1)。注意HX711的供电电压建议用3.3V而不是5V,虽然它支持5V,但3.3V下与STM32的IO电平匹配更好,不需要电平转换。

OLED的I2C连接:SCL接STM32的I2C时钟线(比如PB6),SDA接数据线(比如PB7),VCC和GND供电。I2C总线上需要两个4.7k的上拉电阻,有些OLED模块自带上拉,有些没有,如果屏幕不亮先检查这个。

称重传感器的接线是最容易出错的地方。四线制传感器的线色通常是:红=激励正,黑=激励负,白=信号正,绿=信号负。但不同厂家的线色定义可能不同,务必用万用表测一下:激励正和激励负之间的电阻通常在1kΩ左右,信号正和信号负之间的电阻也是1kΩ左右,激励和信号之间的电阻应该在1kΩ以上。如果测出来不符合,说明线序判断错了。

4.2 代码框架搭建:模块化是王道

这个项目的代码结构建议按功能模块划分,不要把所有东西塞进main.c。我的习惯是分成这几个文件:hx711.c/h负责传感器驱动和重量换算,oled.c/h负责显示驱动,key.c/h负责按键扫描,flash.c/h负责参数存储,main.c只负责初始化和主循环调度。

主循环的逻辑可以这样设计:每隔100毫秒读一次重量,如果重量变化超过阈值就更新显示;同时扫描按键,短按去皮(把当前重量设为零点),长按进入校准模式。校准模式下,先提示放空秤,按确认后采集零点;再提示放砝码,输入砝码重量后采集满量程值,计算比例系数并存入Flash。

// 主循环的简化框架 while (1) { if (timer_100ms_flag) { timer_100ms_flag = 0; float w = Get_Weight(); if (fabs(w - last_weight) > 0.05f) { OLED_ShowWeight(w); last_weight = w; } } Key_Scan(); if (key_event == KEY_SHORT_PRESS) { Tare(); // 去皮 } else if (key_event == KEY_LONG_PRESS) { Enter_Calibration(); // 进入校准 } }

4.3 Proteus仿真:没有硬件也能跑起来

Proteus仿真的搭建步骤:新建工程,从元件库中搜索STM32F103C8、HX711、SSD1306、BUTTON等元件放置到原理图编辑区,按照实际电路连接好。然后双击STM32元件,在Program File一栏加载Keil编译生成的hex文件,设置晶振频率为8MHz。HX711在Proteus里可能没有现成模型,可以用一个电位器模拟传感器输出,或者用ADC元件替代。

仿真运行时,你可以通过调节电位器来模拟重量变化,观察OLED上的数字是否跟着变。如果数字不变或者显示乱码,先检查hex文件是否加载正确,再检查I2C地址和引脚定义是否和代码一致。

注意:Proteus的STM32仿真速度受电脑性能影响较大,如果仿真跑起来很卡,可以把系统时钟设低一点,或者减少OLED的刷新内容。

4.4 实物调试:从能读到读得准

实物调试分两个阶段。第一阶段是能读到数:烧录程序后,用串口打印HX711的原始值,看看有没有输出。如果一直是0或者一直是最大值,检查接线和时序。第二阶段是读得准:放上已知重量的物体,看显示值是否接近。如果偏差大,重新校准;如果读数跳动大,增加滤波次数或者检查电源纹波。

我自己的经验是,HX711的原始值在空秤时也会有几十到几百的波动,这是正常的。经过20次平均后,波动能降到个位数。如果波动仍然很大,可能是传感器质量不行,或者供电纹波太大,可以在HX711的VCC和GND之间并一个100uF电解电容加一个100nF陶瓷电容。

5. 常见问题与排查技巧实录

5.1 读数一直为零或满量程

这是最常遇到的问题。排查顺序:先用万用表测HX711的VCC是否有3.3V,再测DOUT引脚在空闲时是否为高电平。如果DOUT一直是低,说明HX711没有正常上电或者芯片坏了。如果DOUT是高但读出来全是0,检查SCK引脚是否有脉冲输出,用示波器或者逻辑分析仪看最直观。如果SCK有脉冲但数据不对,检查时序延时是否满足要求。

还有一种情况是传感器接线错误。四线制传感器如果激励线和信号线接反,HX711读出来的值会固定在某个极端值附近。用万用表测电阻是最快的判断方法。

5.2 重量显示跳动超过预期

跳动的原因通常有三个:机械振动、电源噪声、滤波不足。机械振动可以通过把秤体放在平稳表面、增加橡胶垫来缓解。电源噪声可以在HX711供电脚加滤波电容,或者改用线性稳压器供电。滤波不足就增加平均次数,但要注意响应速度的权衡——平均20次在10Hz模式下是2秒的延迟,对于体重秤来说可以接受,但如果要做动态称重就不行了。

5.3 OLED不亮或花屏

不亮先查供电和I2C地址。用I2C扫描程序确认STM32能否找到设备。如果找到了但屏幕不亮,可能是初始化序列不对,不同批次的SSD1306初始化命令略有差异。花屏通常是I2C速率太高或者上拉电阻不合适,把速率降到100kHz试试,或者把上拉电阻换成2.2k。

5.4 校准后精度仍然不够

校准后的误差来源可能是传感器的非线性。电阻应变式传感器在满量程的20%到80%之间线性度最好,两端会有非线性误差。如果对精度要求高,可以做多点校准——在0%、25%、50%、75%、100%五个点分别采集,然后用分段线性插值或者最小二乘法拟合曲线。不过对于体重秤来说,单点校准通常就够了,因为人体重量基本都落在满量程的30%到90%之间。

问题现象可能原因排查方法解决措施
读数恒为0传感器未接好万用表测传感器电阻重新接线
读数恒为满量程激励线接反检查线色定义交换激励线
读数跳动大电源纹波大示波器看VCC加滤波电容
OLED不亮I2C地址错误I2C扫描修改地址
校准后偏差大传感器非线性多点测量分段校准

5.5 仿真通过但实物不行

这是最让人头疼的情况。仿真里的HX711是理想模型,没有噪声、没有温漂、时序要求也不严格。实物上这些问题全都会暴露出来。我的建议是:仿真只用来验证逻辑流程和显示效果,时序和精度问题必须在实物上解决。如果仿真通过实物不行,重点检查时序延时和电源质量,这两个是仿真里最容易被忽略的。

6. 项目扩展与个人经验分享

这套东西跑通之后,其实还有很多可以玩的方向。比如加一个HC-05蓝牙模块,把重量数据传到手机App上记录体重变化曲线;或者加一个RTC时钟芯片,实现带时间戳的体重记录;再或者把STM32换成带无线功能的型号,直接上传数据到云平台。硬件上也可以升级,把HX711换成CS1237或者ADS1232,精度更高,但驱动逻辑类似,迁移成本不高。

我个人在实际操作中的体会是,称重类项目最考验的不是代码能力,而是对模拟信号链的理解。数字部分出问题通常有明确的报错或者现象,但模拟部分的毛病往往是“看起来能跑但就是不准”,需要耐心地一步步排查。另外,校准参数一定要存Flash,而且建议存两份互为备份,防止Flash写入过程中断电导致参数丢失。

最后分享一个小技巧:在HX711的电源引脚上并一个0.1uF的陶瓷电容和一个10uF的钽电容,能显著改善读数的稳定性。这个改动成本不到一块钱,但效果立竿见影。还有就是,如果你用的是淘宝上那种几块钱的HX711模块,上面的晶振质量参差不齐,如果发现读数周期性跳动,可以试着把晶振换成质量好一点的,或者直接用STM32的定时器给HX711提供时钟信号,绕过模块上的晶振。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询