ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32+HX711+OLED称重系统实战:从选型到滤波避坑

STM32+HX711+OLED称重系统实战:从选型到滤波避坑 1. 为什么选择STM32HX711这套组合做称重1.1 从需求倒推方案称重项目到底需要什么做称重类项目核心需求其实就三条第一能稳定读取重量传感器的微弱信号第二能把重量数值实时显示出来第三整体成本可控、便于二次开发。围绕这三条市面上常见的方案有几种直接用带ADC的单片机采集应变片桥式信号、用专用称重芯片比如HX711做前端采集再交给主控、或者买现成的称重变送器模块。我选STM32HX711OLED这套组合理由很直接。HX711内部集成了24位ADC和可编程增益放大器专门为桥式传感器设计能直接把应变片输出的毫伏级差分信号放大并数字化省去了自己搭仪表放大器的麻烦。STM32F103C8T6这类芯片资源足够、资料多、价格便宜配合OLED做本地显示整套下来成本能压到很低。OLED用0.96寸I2C接口的SSD1306接线简单显示效果比LCD1602好太多还能显示汉字和图形。这套方案适合谁适合做电子秤、配料秤、压力监测、厨房秤、快递称重、教学实验、毕业设计这类场景。不管你是刚接触STM32的新手还是想快速搭一个称重原型的开发者这套组合都能让你在半天到一天内跑通基本功能。1.2 核心器件选型背后的逻辑先说HX711。它有两个通道通道A增益可选128或64通道B固定32。称重传感器一般用通道A、增益128因为这样能获得最小的可检测信号。HX711的输出速率可选10Hz或80Hz这个参数很关键。10Hz模式下噪声更低、读数更稳适合静态称重80Hz模式响应快但噪声会大一些适合动态称重或者需要快速刷新的场景。很多人纠结选哪个我的经验是如果你做的是电子秤10Hz足够因为人放上去到稳定也就一两秒如果你要做动态检重或者振动监测那就上80Hz但软件上必须做滤波。再说STM32。F103C8T6是经典款72MHz主频、64KB Flash、20KB RAM跑称重OLED显示绰绰有余。它的GPIO、定时器、I2C、SPI资源都够用。如果你手头有F401、G030之类的也行HAL库基本通用。注意一点HX711是2线同步串行接口不是标准I2C也不是SPI需要自己用GPIO模拟时序。所以选型时不用纠结硬件I2C够不够HX711占两个普通IO就行。OLED选0.96寸SSD1306I2C接口四针VCC、GND、SCL、SDA。这里有个坑市面上有些0.9寸OLED对I2C兼容性不好上电后不亮或者花屏。我实测下来0.96寸SSD1306兼容性最好驱动库也最成熟。如果你手头只有0.9寸的先确认驱动芯片是不是SSD1306有些是SH1106初始化命令不一样直接套用SSD1306代码会花屏。1.3 整体数据流与模块划分整个系统的数据流很清晰称重传感器应变片桥式输出差分毫伏信号→HX711做24位ADC采集和增益放大→STM32通过GPIO模拟时序读取HX711的24位数据→STM32做去皮、校准、滤波、单位换算→OLED显示重量数值和状态。模块划分上我习惯分成四层硬件层传感器、HX711、STM32、OLED的电路连接、驱动层HX711时序驱动、OLED驱动、业务层称重逻辑、校准算法、滤波算法、应用层显示刷新、按键交互、串口输出。这样分层的好处是换传感器或者换屏幕时只需要改驱动层业务逻辑不用动。2. 硬件连接与电路设计要点2.1 HX711与称重传感器的接线细节称重传感器一般是四线制红E、黑E-、白A、绿A-对应HX711的E、E-、A、A-。有些传感器线色不一样比如黄、蓝、红、黑这时候必须查传感器手册不能凭感觉接。接反了不会烧但读数会反向或者漂移。HX711的VCC和GND接STM32的3.3V或5V都行但要注意如果HX711模块供电是5V而STM32是3.3V那么HX711的DT和SCK引脚输出高电平是5V直接接STM32的IO可能会损坏芯片。稳妥做法是HX711也用3.3V供电或者加电平转换。我实测HX711在3.3V下工作正常精度也够所以直接统一3.3V最省事。HX711的DT数据和SCK时钟接STM32任意两个GPIO。我一般用PA0和PA1方便记忆。注意DT是HX711的输出STM32要配置成输入SCK是STM32的输出配置成推挽输出。上电后SCK要拉低否则HX711会一直处于掉电模式。2.2 OLED的I2C连接与上拉电阻OLED四针模块一般自带4.7k上拉电阻直接接STM32的I2C引脚或者普通GPIO模拟I2C都行。如果用硬件I2CSTM32F103的I2C1是PB6SCL、PB7SDAI2C2是PB10、PB11。但硬件I2C在F103上有个老毛病容易卡死尤其是总线被拉低的时候。所以我更推荐用GPIO模拟I2C稳定可控换引脚也方便。模拟I2C的引脚我习惯用PB8SCL、PB9SDA这两个脚不冲突接线也顺手。上拉电阻如果模块自带就不用外加如果自己画板子记得在SCL和SDA上各接一个4.7k到3.3V。没有上拉电阻的话I2C通信会时好时坏甚至完全不亮。2.3 电源与抗干扰处理称重系统对电源噪声很敏感。HX711的模拟供电和数字供电最好分开滤波模块上一般有电容但如果你自己画板建议在HX711的VCC和GND之间并一个10uF电解加一个0.1uF陶瓷电容。STM32的电源也要干净尤其是ADC参考电压虽然HX711不依赖STM32的ADC但电源波动会影响HX711的基准。传感器信号线要远离电机、继电器、无线模块这些干扰源。如果传感器线比较长建议用屏蔽线屏蔽层单端接地。我踩过的坑有一次传感器线和电机线捆在一起读数跳得厉害分开走线后立刻稳定。3. HX711驱动与采样时序实现3.1 HX711的24位数据读取时序HX711的通信协议很简单当DT为低电平时表示数据准备好然后SCK给24个脉冲每个脉冲上升沿读出一位数据MSB先出第25个脉冲用来选择下一次的通道和增益。具体来说第25个脉冲的个数决定下次通道1个脉冲选通道A增益1282个脉冲选通道B增益323个脉冲选通道A增益64。读到的24位数据是二进制补码最高位是符号位。如果读到0x800000表示负满量程0x7FFFFF表示正满量程。实际使用时要先判断符号再转成有符号整数。很多新手直接当无符号数处理结果负数重量显示成巨大正数这就是没处理补码。long HX711_Read(void) { unsigned long data 0; unsigned char i; while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) 1); // 等待DT变低 for(i 0; i 24; i) { GPIO_SetBits(GPIOA, GPIO_Pin_1); // SCK拉高 delay_us(1); data data 1; GPIO_ResetBits(GPIOA, GPIO_Pin_1); // SCK拉低 delay_us(1); if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) data; } // 第25个脉冲选择通道A增益128 GPIO_SetBits(GPIOA, GPIO_Pin_1); delay_us(1); GPIO_ResetBits(GPIOA, GPIO_Pin_1); delay_us(1); // 补码转换 if(data 0x800000) data | 0xFF000000; return (long)data; }这段代码里delay_us(1)是关键。HX711的SCK高电平持续时间最小0.2us低电平最小0.2us1us足够。但如果你用HAL库的HAL_Delay那是毫秒级完全不行。必须用微秒延时可以用定时器或者空循环实现。3.2 采样率10Hz与80Hz的选择与配置HX711的RATE引脚决定输出速率接低电平是10Hz接高电平是80Hz。模块上一般有个焊盘或者跳线默认是10Hz。如果你需要80Hz把RATE接到VCC即可。但注意80Hz模式下每次读取间隔要大于12.5ms否则会读到重复数据或者出错。10Hz模式下间隔要大于100ms。我一般用定时器每100ms读一次这样既稳定又不会丢数据。如果你用80Hz定时器设12.5ms或者15ms。实际项目中10Hz的稳定性明显好于80Hz。我做过对比同一个传感器10Hz下读数波动在±5个计数以内80Hz下波动能到±30个计数。所以除非你要做动态称重否则老老实实用10Hz。3.3 去皮与校准的算法实现去皮就是记录当前读数作为零点偏移后续读数减去这个偏移。校准需要两个步骤先放一个已知重量的砝码记录读数然后计算比例系数。具体算法假设空载读数为offset放上100g砝码后读数为raw那么比例系数scale (raw - offset) / 100。之后每次读到的数据减去offset再除以scale就是实际重量单位g。float weight (float)(HX711_Read() - offset) / scale;这里有个细节offset和scale要保存到Flash或者EEPROM否则每次上电都要重新校准。STM32F103没有内置EEPROM可以用Flash模拟或者外挂一个24C02。我一般用Flash最后一页存这两个参数简单可靠。校准的时候砝码越接近量程上限校准越准。比如你量程5kg就用4kg或5kg砝码校准不要用100g校准完去称5kg那样误差会放大。4. OLED显示驱动与界面设计4.1 SSD1306初始化与I2C通信SSD1306的初始化命令有一长串包括设置对比度、显示模式、扫描方向、时钟分频、电荷泵等。网上有很多现成的初始化数组直接拿来用就行。但要注意不同尺寸的OLED初始化命令里的多路复用比和显示偏移不一样。0.96寸是128x64多路复用比是0x3F0.91寸是128x32多路复用比是0x1F。用错了会显示不全或者花屏。I2C通信时SSD1306的从机地址一般是0x78写或0x79读。有些模块是0x7A这个用I2C扫描工具扫一下就知道。发送数据时先发控制字节0x00表示命令0x40表示数据然后发具体内容。void OLED_WriteCmd(uint8_t cmd) { I2C_Start(); I2C_SendByte(0x78); I2C_SendByte(0x00); I2C_SendByte(cmd); I2C_Stop(); } void OLED_WriteData(uint8_t data) { I2C_Start(); I2C_SendByte(0x78); I2C_SendByte(0x40); I2C_SendByte(data); I2C_Stop(); }如果你用硬件I2C把I2C_Start这些换成HAL_I2C_Master_Transmit就行。但再次提醒F103的硬件I2C容易卡模拟的更稳。4.2 显示汉字与自定义图形OLED显示汉字需要取模。常用软件是PCtoLCD2002设置模式为阴码、逐列式、顺向然后生成字模数组。比如“重量”两个字取模后得到32字节的数组调用显示函数写到对应位置。显示图形也是类似把图片转成单色位图取模后写入。比如你想显示一个秤的图标先画好黑白图取模成数组然后写到OLED的指定区域。这里有个技巧如果汉字显示乱码先检查取模软件的设置是否和驱动代码匹配。阴码/阳码、逐行/逐列、顺向/逆向这四个参数必须和代码一致。我见过太多人取模设置错了然后怪驱动有问题。4.3 界面布局与刷新策略称重界面我一般分三行第一行显示“Weight:”第二行显示重量数值和单位第三行显示状态比如“Stable”或“Unstable”。数值用大字体状态用小字体。刷新策略上不要每次读完HX711就全屏刷新那样会闪。正确做法是只刷新数值区域或者用局部刷新。SSD1306支持页地址和列地址设置你可以只更新某几页的内容。我一般每200ms刷新一次数值状态变化时才刷新状态行。如果OLED不亮先查三件事供电有没有、I2C地址对不对、初始化命令有没有发。花屏的话查多路复用比和显示偏移。密码门锁OLED屏花屏很多时候就是初始化参数不对或者电源不稳。5. 滤波算法与稳定性优化5.1 常用滤波算法对比与选择称重读数难免有噪声必须滤波。常见的有均值滤波、中值滤波、滑动平均、一阶低通滤波、卡尔曼滤波。均值滤波简单但响应慢中值滤波能去脉冲噪声但对连续噪声无效滑动平均兼顾响应和稳定一阶低通参数好调卡尔曼适合动态系统但计算量大。我一般用“中值滑动平均”组合先连续读5次去掉最大最小剩下3个取平均再把这个结果送入滑动平均队列。这样既能去脉冲又能平滑。滑动平均队列长度取10效果就不错了。#define FILTER_LEN 10 float filter_buf[FILTER_LEN]; int filter_idx 0; float Filter_Weight(float new_val) { filter_buf[filter_idx] new_val; filter_idx (filter_idx 1) % FILTER_LEN; float sum 0; for(int i 0; i FILTER_LEN; i) sum filter_buf[i]; return sum / FILTER_LEN; }5.2 零点跟踪与漂移处理长时间运行时HX711的零点会缓慢漂移尤其是温度变化时。解决办法是零点跟踪当读数在零点附近且稳定一段时间后自动更新offset。比如连续2秒读数都在±2g以内就把当前读数设为新的offset。但要注意零点跟踪不能在称重时进行否则会把小重量当成零点。所以要先判断是否稳定再判断是否接近零点。我一般设一个阈值比如小于5g且波动小于1g才触发零点跟踪。5.3 温度漂移与长期稳定性HX711的基准电压和传感器应变片都会随温度变化。如果项目要求高精度可以加一个DS3231或者热敏电阻做温度补偿。但大多数场景下只要电源稳定、传感器质量过关漂移在可接受范围内。我实测过在空调房里连续运行8小时漂移不超过3g量程5kg。如果漂移大先查电源和传感器再考虑温度补偿。6. 常见问题排查与实操避坑6.1 HX711读数异常排查表现象可能原因解决方法读数一直是0或满量程传感器接线错误或损坏检查四线连接用万用表测桥臂电阻读数跳变严重电源噪声或地线干扰加滤波电容传感器线远离干扰源读数反向A和A-接反交换白绿线读数不变化SCK或DT接触不良检查连线确认DT能变低80Hz下读数错乱读取间隔太短增加间隔到15ms以上6.2 OLED不亮或花屏的排查思路OLED不亮先量VCC和GND之间是不是3.3V。然后看I2C地址用扫描程序扫一下。如果地址对但还不亮检查初始化命令里的电荷泵有没有开0x8D, 0x14。花屏的话查多路复用比0xA8和显示偏移0xD3。0.96寸用0x3F和0x000.91寸用0x1F和0x00。还有一个坑有些OLED模块的I2C上拉电阻没焊或者阻值太大。如果你用模拟I2C可以适当降低SCL频率比如延时2us能提高兼容性。6.3 STM32开发环境与烧录问题Keil5装STM32包时注意装对应系列的DFP。F103装F1系列包。如果编译报错“flash download failed”检查调试器配置和芯片型号。用ST-Link的话SWD模式勾选Reset and Run。VSCode配置STM32开发环境也可以用Cortex-Debug插件launch.json里配好svd文件路径能看寄存器。但新手还是建议先用Keil或者STM32CubeIDE少踩环境坑。6.4 实操心得与避坑清单HX711的RATE引脚不要悬空悬空可能不稳定明确接VCC或GND。校准砝码要放在传感器正中心偏了会有力矩误差。OLED刷新不要用全屏清屏再写会闪用局部刷新。称重数值显示要加单位不然用户不知道是g还是kg。如果做产品记得加过载保护传感器超量程会永久损坏。代码里delay_us不要用HAL_Delay那个是毫秒HX711时序会全乱。如果读数偶尔跳一下先查是不是有人碰了桌子或者传感器再查电源。7. 项目扩展与功能升级方向7.1 加入按键实现去皮与校准加两个按键一个去皮一个校准。去皮键按下时把当前读数设为offset。校准键按下时进入校准模式提示放砝码然后计算scale。按键用外部中断或者定时器扫描都行注意消抖。7.2 串口输出与上位机通信把重量数据通过串口发到电脑可以用串口助手看也可以自己写上位机画曲线。STM32的USART配置很简单波特率1152008N1。发送格式可以自定义比如“W:123.4g\r\n”。7.3 数据记录与报警功能加一个SD卡或者Flash记录每次称重数据。再加一个蜂鸣器超过设定阈值就报警。这些扩展都不难核心还是先把基础称重跑稳。7.4 低功耗设计与电池供电如果用电池供电可以让STM32在两次采样之间进入Stop模式HX711也掉电。但HX711上电后需要稳定时间所以低功耗模式下采样率会降低。这个适合做便携秤但精度会受一点影响。我个人在实际操作中的体会是这套STM32HX711OLED的方案最难的不是写代码而是把硬件连接和校准做扎实。代码网上到处都是但接线错了、电源脏了、校准不准再好的代码也白搭。先把硬件跑通再调软件顺序不能反。另外称重项目对细节要求高一个虚焊或者一根线接错就能让你调一整天。所以每次接线后先用万用表量一遍再上电。这个习惯帮我省了很多时间。
返回列表