尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32+HX711电子秤设计:从Proteus仿真到称重算法与实物调试

STM32+HX711电子秤设计:从Proteus仿真到称重算法与实物调试 简介基于STM32与HX711的电子秤称重超重报警Proteus仿真全套资料面向嵌入式初学与电子设计开发者用来学习传感器采集、超重判断和虚拟仿真流程。压缩包共282个文件约18.44MB包含C源程序、HX711驱动、STM32工程、Proteus仿真文件以及原理图、PDF文档等覆盖从代码到仿真的完整链路。项目使用STM32作为主控通过HX711高精度ADC读取重量数据超阈值时触发报警并在Proteus中完成整体验证。内容还含有hex、axf生成文件便于直接烧录与调试。目前已有1367人学习下载适合想快速上手STM32称重项目、或需要参考完整例程的开发者。资料目录结构清晰配合源程序与仿真可自行修改阈值和报警逻辑扩展为不同量程的电子秤设计。 把HX711接到STM32上做电子秤基本是每个学嵌入式的人绕不开的一个完整项目。原因很简单它把“模拟小信号采集”这件事讲透了——应变片的微弱差分电压变化经过仪表放大器和24位ADC变成一串数字再换算成g、kg甚至带一位小数显示出来整个过程环环相扣任何一个环节没做对秤上显示的就是跳动的、完全不可信的数值。这篇就围绕这个STM32HX711电子秤项目把我从Proteus仿真搭建到称重算法调试的完整过程摊开讲包括HX711驱动时序、去皮和零点追踪、超重报警策略以及仿真和实物之间那些资料里不会明说的差异。1. 方案选型为什么电子秤项目都在用STM32HX7111.1 HX711这颗芯片到底做了什么很多人第一次见到称重传感器的时候是蒙的传感器输出只有毫伏级的差分电压STM32内部的12位ADC根本没法直接采集那么小的信号直接把传感器输出接到单片机的PA0上读出来的值要么是0要么是乱跳。HX711就是来解决这个问题的它内部集成了低噪声仪表放大器和一个24位高精度ADC能把传感器输出的微弱信号放大到ADC可分辨的范围然后以数字方式输出给MCU。这颗芯片的接口非常简洁和单片机通信只需要两根线PD_SCK时钟和DOUT数据。内部自带时钟振荡器不需要额外挂晶振供电范围也很宽典型的2.6V到5.5V都可以正常工作。它有两个差分输入通道通道A可以设置增益64或128通道B固定增益32称重场景基本都用通道A增益128因为传感器输出的信号太微弱需要足够大的放大倍数才能在ADC读数上体现出来。1.2 为什么这个项目适合先仿真再动手电子秤项目用Proteus仿真有一个很实际的好处先把逻辑跑通再花钱买硬件。仿真的重点不是让你省掉焊接这一步而是让你在没有应变片、没有砝码的情况下先把HX711的时序调对把标定算法的逻辑理清把超重报警的条件状态机写好。这些东西如果直接在实物上调试一旦接线错误或者传感器损坏排查起来非常痛苦。仿真中的“应变片”可以用四个电阻搭成惠斯通电桥来模拟其中一个电阻用可变电阻RV代替调节RV的阻值就能模拟传感器受力时的电阻变化。电桥的输出接到HX711的A和A-通过改变RV就能观察到称重读数的变化这个方式在仿真阶段完全够用。整体方案的可行性能在仿真里得到验证后面接实物时就会轻松很多。2. Proteus环境搭建那些没写进教程的接线细节2.1 元件清单与HX711仿真模型在Proteus中搭这个电路元件不算多但每个元件的参数都得设置正确。我先说元件清单后面再逐个讲容易出错的地方。元件型号/参数用途主控STM32F103C8T6数据处理、逻辑控制称重ADCHX711传感器信号放大与AD转换传感器模拟电阻桥 可变电阻RV模拟应变片受力变化显示LCD1602实时显示重量蜂鸣器有源蜂鸣器 三极管超重报警LED红色LED 限流电阻报警指示Proteus元件库里直接搜索HX711就能找到模型不同版本可能存在细微差别常见的是HX711的库文件里已经包含了完整功能。我用的版本里这个模型可以直接工作但要注意它的电源引脚VCC接5V模拟电源和数字电源最好统一供电GND共地。2.2 STM32F103C8T6在仿真里的电源设置这可能是整个Proteus仿真里最容易被忽略的一步STM32F103C8T6的VDD要接3.3VVDDA也一定要接3.3VVSSA接地。很多人只接了VDD结果程序怎么烧都跑不起来就是因为VDDA和VSSA没接。BOOT0引脚必须接GND这样芯片才会从Flash启动。NRST复位引脚在仿真电路里可以串一个10k电阻上拉到3.3V再接一个100nF电容到地虽然仿真中很多时候直接接3.3V也能跑但按照规范电路接出来更接近真实硬件后续转实物时直接复用这套电路。在Proteus里要双击单片机芯片在Program File选项中选择编译生成的.hex文件。还有一个容易被忽略的配置是外部时钟频率如果代码里用的是外部8MHz晶振这里就要把Clock设置为8MHz如果代码里用的是内部高速时钟HSI仿真里的时钟设置也要和代码一致否则串口波特率、定时器延时这些和时间相关的功能会全部对不上。2.3 电桥模拟传感器和报警电路的接法在Proteus里模拟称重传感器我习惯用四个10k电阻组成惠斯通电桥其中R1用RV可变电阻代替这样转动RV就能改变电桥的输出电压差。电桥的两个输出点分别接到HX711的A和A-电桥的供电可以直接从HX711模块的E和E-引出。调节RV的时候HX711读到的原始ADC值会往一个方向变化这就模拟了传感器受力时的输出变化。报警电路建议用三极管驱动STM32的GPIO引脚直接驱动蜂鸣器其实电流不够。工程中常用的接法是GPIO通过1k电阻接到NPN三极管基极三极管的集电极接蜂鸣器负极蜂鸣器正极接5V发射极接地。GPIO输出高电平时三极管导通蜂鸣器工作。同时在蜂鸣器两端反向并联一个二极管续流二极管防止产生反向电动势。3. HX711驱动代码两线协议读出24位称重数据3.1 时序逻辑是理解HX711的关键HX711和MCU的通信机制首先要有一个清晰的认识DOUT引脚在数据准备好之前保持高电平一旦HX711完成了模数转换DOUT就拉低告诉MCU“我来数据了”。MCU检测到DOUT拉低后开始在PD_SCK上发送一连串脉冲每一个脉冲的上升沿让HX711从最高位开始移出一位数据连续24个脉冲就把完整的24位数据全部读出来了。很多初学者会困惑为什么最后还要多送一个脉冲因为这个第25个脉冲有双重作用一是让HX711进入下一次转换二是用来选择下一次的通道和增益。我代码里使用通道A、增益128所以第25个脉冲后保持PD_SCK为低电平HX711会在内部完成通道切换然后自动开始下一次ADC转换。3.2 完整的HX711读取函数在STM32上使用标准库或者HAL库都可以关键是GPIO方向要配置正确PD_SCK配置为推挽输出DOUT配置为浮空输入因为DOUT是由HX711驱动的。下面是核心读取函数// HX711引脚定义 #define HX711_SCK_PORT GPIOB #define HX711_SCK_PIN GPIO_PIN_6 #define HX711_DOUT_PORT GPIOB #define HX711_DOUT_PIN GPIO_PIN_7 /** * brief 读取一次HX711原始数据返回24位有符号数 */ int32_t HX711_ReadOnce(void) { uint32_t raw 0; uint8_t i; uint16_t timeout 10000; // 等待DOUT拉低表示数据就绪 while (HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN) ! GPIO_PIN_RESET) { if (--timeout 0) { return 0; // 超时保护防止程序死等 } } for (i 0; i 24; i) { HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET); raw 1; if (HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN) ! GPIO_PIN_RESET) { raw; } HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET); } // 第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 (raw 0x800000) { raw | 0xFF000000; } return (int32_t)raw; }这里我特别加了一个等待超时保护。实际项目中如果HX711没有正常工作DOUT可能一直保持高电平不加超时保护的话程序就会死等在这里看起来像整个系统卡死。这个细节资料里一般不写但真机调试时特别有用。3.3 数据滤波是称重稳定的基础HX711虽然标称是24位ADC但有效精度受噪声影响很大。当数据输出速率设置为80Hz时噪声会明显增加读出来的数据最后几位一直在跳动。仿真过程中也一样直接看着LCD上的重量值会发现小数点后面一直不稳。解决办法是多次读数取平均这是最简单也最有效的办法/** * brief 多次采样取平均带去除最大值最小值的中值平均滤波 */ int32_t HX711_ReadFilter(void) { int32_t buf[8]; int32_t sum 0; uint8_t i, j; int32_t temp; for (i 0; i 8; i) { buf[i] HX711_ReadOnce(); } // 简单冒泡排序 for (i 0; i 7; i) { for (j 0; j 7 - i; j) { if (buf[j] buf[j 1]) { temp buf[j]; buf[j] buf[j 1]; buf[j 1] temp; } } } // 去掉最大和最小值中间6个取平均 for (i 1; i 7; i) { sum buf[i]; } return sum / 6; }这个中值平均滤波的思路是先把一组采样值排序去掉最大最小值防止偶然的尖峰干扰把平均值拉偏。实测下来采样8次取中间6次平均在仿真和实物上的稳定性都相当不错。4. 称重算法去皮、标定、零点追踪一个都不能少4.1 从ADC原始值到重量的换算逻辑HX711读出来的原始数值本身没有单位它和重量存在一个线性关系但具体系数取决于传感器的灵敏度、激励电压和HX711的增益。所以必须先标定再使用。标定分两步。第一步是空载标定什么都不放连续读取16次采样值取平均得到空载偏置offset。第二步是加载标定放一个已知重量的砝码比如100克读取采样值记为standard_raw然后计算出换算系数float scale (float)(standard_raw - offset) / 100.0f;之后任意时刻的重量就是float weight_g (float)(current_raw - offset) / scale;这里有一个很容易出错的点current_raw必须和offset、standard_raw来自同一个滤波函数不能一会儿用单次读取值一会儿用滤波值否则计算结果会跳变得很厉害。我的习惯是统一使用HX711_ReadFilter去拿所有参与运算的采样值。4.2 去皮的本质是修改offset去皮功能很多人一开始理解偏了以为去皮是把重量清零或者改变scale。实际上去皮是在空载状态下重新把当前采样值赋值给offset。这样即使秤盘上放了容器此时显示的也是0克后续加进去的物料才会被正确计算出来。void Tare(void) { offset HX711_ReadFilter(); }务必要理解offset一变所有后续的重量计算都会基于新的零点而scale保持不变。如果去皮时把scale一起改了就会导致整个量程全部错误。这个逻辑虽然简单但我在几次给学生看代码的时候发现有不少人确实把offset和scale搞混了。4.3 零点追踪解决重量自己漂移的问题做电子秤项目时最讨厌的故障就是秤上什么都没有显示值却从0慢慢漂到2克、3克甚至更多。这种漂移的来源有两个一是应变片的电阻值会随温度变化导致电桥平衡点缓慢偏移二是机械结构变形和应力释放带来的蠕变效应。ADC读数的绝对值在漂但秤上没有真实负重。零点追踪的处理思路是设定一个阈值如果在一段时间内当前读数与offset的差值始终小于这个阈值就判定当前变化是漂移而非真实加载于是把offset更新为当前读数。这里阈值的选择很关键太小了起不到追踪效果太大了会把真实的小重量也给吞掉。以100克的常见量程为例我会把阈值设为大约十分之一量程对应的ADC变化值。void Zero_Tracking(int32_t current_raw) { static uint8_t stable_cnt 0; int32_t diff current_raw - offset; int32_t threshold 200; // 这个值根据实际标定结果调整 if (diff 0) { diff -diff; } if (diff threshold) { stable_cnt; if (stable_cnt 10) // 连续10次稳定重置零点 { offset current_raw; stable_cnt 0; } } else { stable_cnt 0; } }我把这个函数放在主循环里每隔200毫秒调用一次实测下来零点漂移的问题能得到明显压制。要注意的是既然开启了零点追踪系统就会自动消除缓慢漂移相当于不再有严格的“绝对零点”但它换来的是用户实际体验的大幅提升。5. 超重报警策略与仿真的验证方法5.1 报警阈值与回差防临界抖动超重报警的逻辑看起来很简单超过阈值就响。但在实际编写判断条件时直接用一个阈值会导致临界点反复跳动——当秤上重量恰好卡在阈值附近比如阈值设置5000克实际重量4999克和5000克之间波动时蜂鸣器会频繁启动和停止非常烦人。解决办法是引入回差控制也就是滞回比较。当重量超过5000克时触发报警报警后只有重量降至5000克减去一定差值比如200克即4800克以下时才解除报警。这样报警状态一旦触发就不容易被临界抖动打断。#define ALARM_THRESHOLD_G 5000 #define ALARM_HYSTERESIS_G 200 uint8_t alarm_active 0; void Alarm_Control(float weight_g) { if (alarm_active) { if (weight_g (ALARM_THRESHOLD_G - ALARM_HYSTERESIS_G)) { alarm_active 0; // 下降并低于阈值解除报警 } } else { if (weight_g ALARM_THRESHOLD_G) { alarm_active 1; // 超重触发报警 } } }除了回差之外还可以加持续确认机制连续3次采样都超过阈值才触发报警这样能滤除短暂干扰。仿真里可以用一个可变电阻快速旋动模拟重量突变验证这个状态机是否正确。5.2 仿真中如何验证报警动作在Proteus里跑通整个流程后我建议按下面这几个步骤去做验证先观察空载状态。启动仿真后打开串口观察窗口或者查看LCD显示如果原始ADC读数没有稳定下来说明滤波或者接线有问题。接着调节RV模拟加载。向右旋转RV观察LCD上的重量值是否同步变化变化方向是否和预期一致。如果顺时针旋转RV时重量变大那这次调节就是“加载”方向。然后直接超载。把RV调到使重量超过5000克的阻值位置观察LED是否点亮、蜂鸣器引脚的电平是否翻转。此时报警状态应该持续保持即使轻微回调RV让重量降到4950克报警仍然不解除这个就是回差在起作用。最后验证解除报警。继续逆时针调节RV让重量降到4800克以下报警才应该解除。这几个步骤能完整验证报警逻辑的正确性。5.3 我在仿真中踩过的坑第一个坑是仿真中HX711读到的数据一直是0。排查下来发现是STM32的GPIO引脚配置错了SCK引脚没有配置为推挽输出一直在高阻态导致时钟脉冲没送到HX711。解决方法是仔细检查GPIO模式配置并且确认SCK和DOUT的引脚编号与代码定义一致。第二个坑是蜂鸣器在初始化时就一直响。原因是在主程序执行到GPIO初始化的那一刻引脚默认电平不确定三极管被误触发导通了。解决办法是在初始化阶段先把控制蜂鸣器的GPIO拉低再去配置其他外设。这个经验在实物调试中同样适用一开始蜂鸣器响不响基本能判断GPIO初始电平有没有设置好。第三个坑是LCD1602显示乱码。大多数情况下是引脚映射不一致尤其在使用Proteus仿真时LCD的数据线D0-D7分别接到了哪些GPIO必须和代码中的LCD驱动一一对应。为了减少这种问题我倾向于参考江科大那套LCD1602驱动思路直接用并口模式映射到同一个GPIO端口这样写起来和排错都比较省心。6. 资料包的完整链路与实际扩展方向6.1 这份资料包里到底有什么整套项目资料包含四个核心部分源程序工程文件、Proteus仿真文件、原理图PDF和芯片数据手册。源程序里除了HX711驱动还包含了LCD1602显示、蜂鸣器报警、按键去皮等功能的完整代码工程基于STM32标准库搭建主循环结构清晰适合对照学习。Proteus仿真文件里已经把电路搭好双击单片机加载对应的.hex文件就能直接跑。原理图PDF可以作为转实物时的接线参考数据手册是调试HX711时查官方时序和电气特性用的。这些资料放在一起基本上从仿真验证到实物搭建的链路都有覆盖。6.2 从仿真切到实物必须注意的改动点仿真和实物之间存在几个明显的差异。第一仿真里的可变电阻RV响应是线性的而真实传感器的应变片输出存在一定的迟滞和非线性所以实物标定时需要多取几个重量点至少要两点标定有条件的话做三到五点的分段标定会更准。第二实物的电源噪声远大于仿真HX711的电源引脚附近一定要加100nF和10uF的滤波电容模拟电源和数字电源要分开走线。第三蜂鸣器驱动电路在实物上务必用三极管或者MOS管驱动GPIO直接驱动有源蜂鸣器时虽然偶尔能响但长时间工作会导致单片机引脚过载。最后还有一个容易被忽略的点真实称重传感器的接线颜色并不统一拿到实物传感器后第一件事是查手册确认各个引线的功能再把电桥信号接对否则HX711读出来的可能是负值。6.3 后续可以扩展的方向这个项目的扩展空间其实很大。如果想做高精度小量程电子秤可以换用量程更匹配的传感器并把HX711的增益调整到64同时配合更严格的滤波算法。如果想做物联网电子秤可以在现有代码基础上加一个串口发送函数把重量数据通过UART发送给ESP8266或者蓝牙模块这样手机端和云平台就能实时看到重量数据。或者更进一步在报警逻辑中增加LED闪烁方式和蜂鸣器声音模式的区分让不同的报警类型能直观识别。我个人的实际体会是这个项目值得花时间从头到尾亲手调一遍。第一次跑通时可能只是照着资料搭好了电路和代码但当你真正理解了标定、去皮、零点追踪和回差这些概念之间的关系之后再去接触任何带传感器采集的项目思路都会清晰很多。做嵌入式最怕的是只会抄代码而电子秤这个项目恰好是一个把模拟前端、数字接口、数据处理和状态控制串在一起的完整链路值得每个学单片机的人亲手做一遍。本文还有配套的精品资源点击获取
返回列表