ARTICLE DETAIL

资讯详情

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

STM32电子秤设计实战:HX711高精度称重与滤波标定全解析

STM32电子秤设计实战:HX711高精度称重与滤波标定全解析 电子秤这东西看起来简单真动手做一遍才知道坑有多密。称重不准、数值乱跳、开机漂移、换个体重又得重新标定——这些问题几乎每个做过的人都遇到过。我前前后后做过三四个版本的电子秤从最开始的51单片机配HX711到后来换成STM32F103中间踩的坑足够写一篇长文了。这篇就把基于STM32单片机的电子秤设计从头到尾讲清楚包括为什么选HX711而不是自己搭仪表放大器、采样率到底该选10Hz还是80Hz、标定怎么做才靠谱、数值滤波怎么处理才不肉以及那些只有真正焊过板子、调过代码的人才会知道的细节。不管你是刚接触单片机的新手还是正在做毕业设计、课程设计的老手这篇内容都能让你少走至少两星期的弯路。1. 为什么电子秤项目值得用STM32而不是51单片机1.1 从51到STM32的真实体验差异很多人做电子秤的第一反应是用51单片机毕竟便宜、资料多、上手快。我最早那版也是51做的STC89C52配HX711能跑但问题不少。最直接的就是51的运算能力和RAM太紧张做滑动平均滤波的时候数组一开大就捉襟见肘浮点运算更是慢得让人着急。你要做去皮、标定、多级菜单、串口上传数据这些功能51很快就撑不住了。换成STM32F103C8T6之后情况完全不一样。72MHz的主频20KB的RAM64KB的Flash做滤波、标定、显示刷新、串口通信全都游刃有余。而且STM32的定时器资源丰富可以很轻松地给HX711提供精确的时钟也能用定时器做周期采样不用像51那样靠延时函数死等。更关键的是STM32的ADC、SPI、I2C、UART这些外设都是硬件实现的配置好之后基本不占CPU你可以把精力放在业务逻辑上。当然STM32也不是没有代价。它的开发环境配置比51复杂寄存器多、时钟树绕新手第一次配RCC可能就卡住了。但这些都是前期成本一旦跑通后面的开发效率是51没法比的。我的建议是如果你只是做个能称重的玩具51够用但如果你要做带显示、带标定、带通信的完整电子秤直接上STM32别在51上浪费时间。1.2 STM32F103C8T6的选型理由与资源分配具体到型号我推荐STM32F103C8T6也就是常说的蓝板或最小系统板。这颗芯片在电子秤项目里几乎是黄金选择原因有几个。第一价格便宜国产替代品多成本可控。第二资源刚好够用两个SPI、三个USART、多个定时器接HX711、接OLED或LCD、接串口模块都不冲突。第三资料极其丰富不管是标准库还是HAL库网上能找到的例程一抓一大把遇到问题好查。资源分配上我一般这样规划PA0接HX711的DOUTPA1接HX711的SCK用GPIO模拟时序就够了不需要占用硬件SPI。I2C1的PB6、PB7接OLED显示屏用来显示重量和状态。USART1的PA9、PA10留给串口调试和上位机通信。再留几个GPIO给按键做去皮、标定、单位切换。定时器用TIM2做1ms系统滴答TIM3做周期采样触发。这样分配下来引脚还有富余后续想加蓝牙、加存储都方便。注意STM32F103的PA0同时也是WKUP引脚如果做低功耗唤醒要注意。另外PA13、PA14是SWD调试口别占用否则下载一次就得用串口ISP救回来很麻烦。1.3 系统整体架构的搭建思路整个电子秤的系统架构其实很清晰分成四层传感层、采集层、处理层、交互层。传感层就是压力传感器加HX711负责把重量转换成数字信号。采集层是STM32的GPIO时序驱动负责从HX711读原始数据。处理层是核心做滤波、标定、去皮、单位换算。交互层是显示屏和按键负责人机对话。这个分层的好处是每层职责明确调试的时候可以逐层验证。比如称重不准先看传感层——传感器有没有装好、HX711供电稳不稳再看采集层——时序对不对、读数有没有跳变最后看处理层——标定系数对不对、滤波参数合不合适。很多新手一上来就怀疑代码其实问题往往出在硬件连接或者机械结构上。分层排查能帮你快速定位问题所在。2. HX711与压力传感器的硬件设计细节2.1 HX711到底解决了什么问题HX711是一颗专为高精度电子秤设计的24位模数转换芯片内置了低噪声可编程增益放大器。压力传感器通常是电阻应变片式的称重传感器输出的信号非常微弱满量程也就几毫伏直接接STM32的ADC根本分辨不出来。STM32自带的12位ADC参考电压3.3V最小分辨约0.8mV而传感器输出变化可能只有零点几毫伏完全被噪声淹没。HX711的作用就是把这点微弱信号放大128倍A通道再做24位ADC转换等效分辨率能达到很高的水平。它内部集成了稳压电路和振荡器外围只需要几个电容和电阻就能工作比自己搭仪表放大器加高精度ADC简单太多。这也是为什么几乎所有电子秤方案都用HX711的原因——它把最难做的模拟前端部分全部集成好了。2.2 称重传感器的接线与桥式电路原理称重传感器一般是四线制红、黑、白、绿不同厂家颜色可能不同以 datasheet 为准。红线接E激励正黑线接E-激励负白线接A信号正绿线接A-信号负。传感器内部是一个惠斯通电桥四个应变片贴在弹性体上受力时弹性体变形应变片阻值变化电桥失去平衡输出一个与重量成正比的差分电压。这里有个关键点传感器的输出灵敏度和量程要匹配。常见的5kg传感器灵敏度是1mV/V激励电压5V满量程输出就是5mV。HX711的A通道增益128倍输入范围是±20mV刚好覆盖。如果你用的是更大或更小的传感器要算一下满量程输出是否在HX711的输入范围内超了就得降低激励电压或换增益通道。接线的时候传感器信号线要尽量短最好用屏蔽线远离电源线和电机线。我遇到过一次称重数值疯狂跳动查了半天发现是传感器线跟电机线捆在一起走线干扰串进来了。分开走线之后立刻稳定。这个坑很典型硬件问题往往比软件问题更隐蔽。2.3 HX711的供电与PCB布局注意事项HX711的供电质量直接决定称重精度。它有两路供电AVDD模拟电源和DVDD数字电源。虽然datasheet说可以共用但实测下来模拟电源最好单独用LDO稳压并且加足够的滤波电容。我在AVDD上并了一个10uF钽电容加一个0.1uF陶瓷电容噪声明显降低。PCB布局上HX711要尽量靠近传感器接口模拟地和数字地分开走最后单点接地。晶振和数字信号线远离模拟输入。如果板子上有电机、继电器这类大电流器件HX711的模拟部分要远离它们必要时加屏蔽罩。这些细节听起来繁琐但电子秤是微伏级信号处理任何一点干扰都会体现在读数上。提示HX711的通道B增益是32一般不用。通道A增益可选128或64电子秤用128。切换增益后第一次读数要丢弃因为内部放大器需要稳定时间。2.4 采样率10Hz还是80Hz的选择依据这是被问得最多的问题之一。HX711的采样率由RATE引脚决定拉低是10Hz拉高是80Hz。很多人纠结选哪个其实要看你的应用场景。10Hz意味着每秒输出10个数据每个数据是多次内部转换的平均噪声更低稳定性更好。80Hz速度快但噪声明显增大读数跳动更厉害。对于静态称重比如厨房秤、人体秤10Hz完全够用而且更准。对于动态称重比如流水线上的分拣秤需要快速响应才考虑80Hz但必须配合更强的数字滤波。我的建议是默认用10Hz。如果你发现响应太慢再考虑80Hz同时把滤波窗口调大。实测下来10Hz配16次滑动平均读数又稳又准响应也够快。80Hz如果不做滤波读数能跳到几十克根本没法用。3. STM32驱动HX711的时序与代码实现3.1 HX711的通信时序拆解HX711用的是类似SPI的两线时序但不是标准SPI得用GPIO模拟。时序很简单DOUT是数据输出SCK是时钟输入。当DOUT为高时表示数据还没准备好要等当DOUT变低表示数据就绪可以开始读。读的时候给SCK发25到27个脉冲前24个脉冲在每个上升沿输出一位数据高位在前第25个脉冲用来选择下一次的通道和增益。具体来说第25个脉冲的数量决定下次转换的通道25个脉冲选通道A增益12826个选通道B增益3227个选通道A增益64。电子秤一般固定用通道A增益128所以每次发25个脉冲就行。读出来的24位数据是二进制补码最高位是符号位需要做符号扩展转成32位有符号整数。这里有个容易出错的地方SCK的高电平时间要小于50微秒否则HX711会复位。STM32跑72MHz一个GPIO翻转就是纳秒级所以要在SCK操作之间加短延时保证高电平时间在合理范围。我一般用1微秒左右的延时既安全又不影响速度。3.2 GPIO模拟时序的代码实现下面是我常用的HX711读取函数基于HAL库用微秒延时。这段代码实测稳定可以直接用。// HX711引脚定义 #define HX711_DOUT_PIN GPIO_PIN_0 #define HX711_DOUT_PORT GPIOA #define HX711_SCK_PIN GPIO_PIN_1 #define HX711_SCK_PORT GPIOA // 微秒延时函数基于DWT或定时器 void delay_us(uint32_t us) { uint32_t start DWT-CYCCNT; uint32_t ticks us * (SystemCoreClock / 1000000); while ((DWT-CYCCNT - start) ticks); } // 读取HX711原始数据 int32_t HX711_Read(void) { int32_t value 0; uint8_t i; // 等待DOUT变低表示数据就绪 uint32_t timeout 0; while (HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN) GPIO_PIN_SET) { if (timeout 100000) return 0; // 超时保护 } // 读取24位数据 for (i 0; i 24; i) { HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET); delay_us(1); value value 1; HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET); delay_us(1); 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); delay_us(1); HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET); delay_us(1); // 符号扩展24位补码转32位 if (value 0x800000) { value | 0xFF000000; } return value; }这段代码有几个细节值得说。第一等待DOUT变低加了超时保护否则传感器没接好时程序会死循环。第二读数据时先拉高SCK再读DOUT因为HX711是在SCK上升沿之后输出数据顺序不能反。第三符号扩展必须做否则负重量比如去皮后的反向值会变成很大的正数。3.3 采样周期与中断的配合读HX711不能太频繁因为它10Hz的话每100ms才更新一次数据。如果你在主循环里不停读大部分时间读到的都是同一个值浪费CPU。更好的做法是用定时器中断每100ms触发一次读取读到的数据放进缓冲区主循环处理。我一般用TIM3配置成100ms中断在中断里调用HX711_Read把结果存入一个环形缓冲区。主循环从缓冲区取数据做滤波和显示。这样采样节奏稳定不会因为显示刷新或串口打印而影响采样周期。注意中断里不要做太耗时的操作读HX711大概几十微秒可以接受但滤波和浮点运算要放到主循环。注意如果HX711配置成80Hz定时器周期要改成12.5ms。但80Hz下建议在中断里只做读取滤波窗口要相应加大否则数据跳得厉害。3.4 常见时序问题与排查方法调试HX711时序时最常见的问题是读出来全是0或者全是0xFFFFFF。全是0通常是DOUT一直为低可能是传感器没接、HX711没供电、或者SCK时序不对导致芯片复位。全是0xFFFFFF则是DOUT一直为高可能是等待超时返回了默认值。排查的时候先用万用表量HX711的供电AVDD和DVDD都应该在4.8V到5.2V之间如果用5V供电。然后量传感器的激励电压E和E-之间应该有稳定的电压。再用示波器看SCK和DOUT的波形正常情况DOUT应该在数据就绪时变低SCK应该有25个干净的脉冲。没有示波器的话可以用逻辑分析仪几十块钱的那种就够用能省很多调试时间。还有一个隐蔽的坑STM32的GPIO速度配置。如果配置成低速SCK的上升沿可能不够陡HX711识别不了。我一般把SCK和DOUT都配置成高速模式GPIO_SPEED_FREQ_HIGH确保边沿干净。4. 称重数据的滤波、标定与去皮处理4.1 原始数据的噪声来源分析HX711读出来的原始值即使传感器上什么都没放也会有几十到几百个数的波动。这些噪声来自几个方面传感器本身的热噪声、HX711的量化噪声、电源纹波、机械振动、还有环境电磁干扰。理解噪声来源才能对症下药。热噪声和量化噪声是固有的只能靠滤波和平均来压制。电源纹波可以通过改善供电解决。机械振动要靠减震结构比如在传感器和底座之间加橡胶垫。电磁干扰靠屏蔽和走线。软件滤波能解决一部分但硬件问题软件是补不回来的。我见过有人传感器没固定好读数一直跳加再多滤波都没用最后拧紧螺丝就好了。4.2 滑动平均、中值滤波与卡尔曼滤波的取舍滤波方案有好几种各有适用场景。滑动平均最简单把最近N个采样值求平均N越大越稳但响应越慢。中值滤波对脉冲干扰特别有效把N个值排序取中间那个能干掉突发的跳变。卡尔曼滤波理论上最优但参数难调对电子秤这种场景有点杀鸡用牛刀。我的经验是滑动平均加中值滤波组合使用效果最好。先用中值滤波去掉明显的异常值比如有人碰了一下秤再做滑动平均平滑。窗口大小取16左右10Hz采样下响应时间约1.6秒对于静态称重完全够用。如果要求快速响应窗口取8但稳定性会差一些。具体实现上维护一个长度为N的环形缓冲区每次新数据进来先做中值滤波可以用简单的冒泡排序取中值再把中值结果放进滑动平均窗口。这样两级滤波下来读数非常稳放上砝码后一两秒内就能稳定显示。4.3 两点标定法的完整操作流程标定是电子秤精度的关键。HX711读的是原始AD值要转换成重量需要一个线性关系重量 (原始值 - 零点值) / 刻度系数。零点值是空秤时的读数刻度系数是每克重量对应的AD值变化。两点标定法就是测两个点空秤0g和一个已知砝码比如500g。先记录空秤时的原始值zero再放上500g砝码记录原始值raw500那么刻度系数scale (raw500 - zero) / 500。之后任何重量 (raw - zero) / scale。操作流程上我一般这样做开机后先空秤采样100次求平均得到zero然后提示用户放上标准砝码采样100次求平均得到raw500算出scale存入Flash。下次开机直接从Flash读zero和scale不用重新标定。但要注意传感器有温漂长时间使用后零点会变所以最好加一个开机自动去皮功能每次开机重新测零点。提示标定用的砝码越接近满量程越好比如5kg的秤用4kg或5kg砝码标定比用500g标定精度高。因为两点距离越远斜率计算越准。4.4 去皮、清零与单位切换的实现去皮功能就是记录当前重量作为皮重之后显示重量减去皮重。实现很简单按去皮键时把当前稳定重量存入tare变量显示时用weight - tare。清零则是把当前重量直接设为零点相当于重新标定零点适合空秤时使用。单位切换涉及克、千克、盎司、磅的换算。建议内部统一用克存储显示时再换算。换算系数1千克1000克1盎司≈28.3495克1磅≈453.592克。注意浮点显示时小数位数要合理克显示整数千克显示三位小数盎司和磅显示两位小数。按键处理要做消抖我一般用20ms的软件消抖或者用定时器扫描。长按和短按要区分比如短按去皮长按进入标定模式。这些交互细节虽然小但直接影响使用体验。5. 显示、交互与系统稳定性优化5.1 OLED与LCD显示的选型对比显示部分常见的有OLED和LCD两种。OLED比如0.96寸SSD1306体积小、对比度高、功耗低I2C接口只占两个引脚适合小型电子秤。LCD比如LCD1602或TFT显示内容多但占引脚多、功耗大。我一般推荐OLED128x64的分辨率足够显示重量、单位、状态图标。驱动OLED用I2CSTM32的硬件I2C有时候会卡死我一般用软件I2C稳定可控。显示刷新不用太快10Hz就够了跟采样率同步。刷新太快反而闪眼也浪费CPU。显示内容布局上重量用大字体居中单位和状态用小字体放角落去皮标志用图标表示。5.2 按键交互与菜单设计按键最少要三个去皮/清零、单位切换、标定/模式。如果要做完整菜单可以加两个方向键。按键电路用上拉电阻加按键到地STM32内部上拉也能用但外部上拉更稳。消抖用定时器每10ms扫描一次连续两次相同状态才确认。菜单设计要简单电子秤不需要复杂菜单。我一般做两级主界面显示重量长按标定键进入标定模式标定模式下按提示放砝码。标定完成后自动返回主界面。模式状态用状态机管理避免逻辑混乱。5.3 电源管理与低功耗考虑如果用电池供电低功耗就很重要。STM32F103本身功耗不算低但可以通过降低主频、关闭不用外设、使用睡眠模式来省电。HX711也有省电模式不采样时可以拉高SCK超过60微秒让它进入掉电模式。不过电子秤一般用USB或适配器供电低功耗需求不强。如果要做便携式建议用锂电池加LDOSTM32跑在8MHz或16MHz就够了采样和显示都不需要72MHz。实测下来优化后待机电流能降到几毫安用2000mAh电池能撑好几天。5.4 长期运行的数据漂移与温漂补偿电子秤长时间运行后零点会慢慢漂移主要是温度变化引起的。传感器和HX711都有温漂。补偿方法有两种一是定期自动去皮比如每10分钟如果重量没变化就重新校准零点二是加温度传感器做温度补偿曲线。第一种方法简单有效我一般用这个。判断重量没变化可以用连续N次采样值波动小于阈值。第二种方法精度更高但复杂适合工业级应用。对于普通电子秤定期自动去皮就够了。注意自动去皮不能在称重过程中触发否则会把真实重量当零点去掉。6. 调试过程中那些让人抓狂的坑6.1 读数一直跳的排查链路读数跳动是最常见的问题排查要按顺序来。第一步确认传感器机械安装是否牢固有没有悬空或受力不均。第二步量HX711供电是否稳定纹波大不大。第三步看传感器信号线有没有和电源线、电机线捆在一起。第四步检查代码里滤波是否生效窗口大小是否合适。第五步看采样周期是否稳定有没有被其他中断打断。我遇到过一次读数跳得厉害查了硬件都没问题最后发现是定时器中断优先级配置错了串口中断把采样中断打断了导致采样周期忽长忽短。调整中断优先级后就好了。所以软件问题也会表现为硬件现象排查要有耐心。6.2 标定后换个体重就不准的原因标定后换重量不准通常是线性度问题。传感器本身有非线性尤其在量程两端。如果标定点选得不好中间段误差就大。解决办法是增加标定点做多点标定加分段线性拟合。比如0g、1kg、2kg、3kg、4kg、5kg各标一次用查表加插值计算重量。另一个原因是零点漂移。标定时的零点和实际使用时的零点不一致。所以标定前要确保秤台空载且稳定标定后如果换了环境温度最好重新去皮。6.3 HX711初始化失败的几种情况HX711初始化失败表现为读不到数据或数据全为固定值。常见原因供电不足低于2.7V或高于5.5V、SCK时序太快导致复位、DOUT引脚配置错误应该配置为输入、传感器没接好导致电桥不平衡。排查时先用万用表量电压再用示波器看时序。如果都没有换一片HX711试试有可能是芯片坏了。HX711虽然皮实但静电打坏的情况也有。6.4 从能用到好用的最后10%优化能称重和称得准是两回事。最后10%的优化包括加开机自检、加超量程报警、加稳定标志读数稳定后才显示、加背光自动熄灭、加蜂鸣器提示。这些功能不影响核心精度但大幅提升使用体验。稳定标志的实现是判断连续N次采样值的极差小于阈值就认为稳定显示锁定。这个功能在称重时特别有用避免读数还在跳的时候用户就读数。阈值根据量程定一般取满量程的0.1%左右。7. 写在最后的一些个人体会做电子秤这几年最大的感受是模拟电路比数字电路难搞硬件比软件难调。代码写错了可以改硬件设计错了可能要重新打板。所以前期选型和布局一定要慎重HX711和传感器的供电、走线、屏蔽这些看起来不起眼的细节往往决定最终精度。另外不要迷信高精度。24位ADC不代表24位有效精度实际能做到16位有效位就很不错了。电子秤的精度受限于传感器、机械结构、温度、电源等一堆因素软件只是其中一环。把能控制的都控制好剩下的交给时间和经验。如果你正在做这个项目遇到问题别急着换方案先把现有方案的每个环节都验证一遍。大部分问题都能在细节里找到答案。
返回列表