资讯动态

HX711与51单片机电子秤代码实战:从时序到校准的避坑指南

发布时间:2026/10/15 1:53:35 来源:尧图企业网站定制
简介这份资源是面向51单片机初学者与电子制作爱好者的hx711压力传感器驱动代码包用于搭建电子秤、配料称重等需要高精度重量检测的小型项目。包内共12个文件约18KB以C语言源码与Keil工程文件为主包含hx711驱动头文件与实现、main主程序以及uvproj工程、hex可烧录文件、lst与m51编译中间文件等覆盖从源码到烧录的完整链路。资源已有4298人学习下载说明其在入门称重项目中有一定参考价值。读者可从中获得51单片机与hx711通信的初始化配置、时钟脉冲读取、滑动平均或低通滤波处理等实现思路并对照工程结构理解数据采集到显示输出的整体流程同时留意电源接地、抗干扰与传感器校准等实际调试要点适合作为称重计课程设计或DIY项目的起步参考。1. 称重不准别急着换传感器先看懂 HX711 与 51 单片机的这套代码很多人第一次用 HX711 配 51 单片机做电子秤都会遇到同一个场景硬件接好了程序烧进去了串口打印出来的数值却像心电图一样乱跳放上砝码数值也不线性。第一反应往往是“传感器坏了”或者“HX711 模块是假货”于是换模块、换传感器折腾一圈问题依旧。实际上绝大多数翻车都出在代码的时序、通道选择和校准逻辑上而不是硬件本身。HX711 是一颗 24 位模数转换芯片专门为桥式压力传感器设计内置增益可编程放大器通过两根线SCK 和 DOUT与单片机通信。51 单片机没有硬件 SPI必须用普通 IO 口模拟时序这就对延时和电平判断提出了要求。这套代码要解决的核心问题只有三个稳定读出 24 位原始值、把原始值换算成克数、让读数不跳。适合正在做电子秤、配料机、压力检测类小项目的嵌入式新手也适合想从 STM32 转回 51 平台验证算法的熟手。2. HX711 的通信时序与 51 单片机 IO 模拟为什么你的读数总在跳2.1 先搞懂 HX711 到底怎么把 24 位数据吐出来HX711 的通信协议不复杂但细节很要命。DOUT 引脚在数据准备好时会拉低单片机检测到低电平后开始给 SCK 引脚发送 25 到 27 个时钟脉冲。前 24 个脉冲对应 24 位数据第 25 个脉冲用来选择下一次转换的通道和增益。数据是最高位先出在 SCK 上升沿之后DOUT 上的电平就是当前位。这里有一个容易被忽略的点HX711 的输出码是二进制补码形式最高位是符号位。当传感器受力为负或者零点漂移时读出来的 24 位值可能是一个很大的正数直接当无符号数处理就会得到荒谬的结果。常见做法是先把 24 位拼成一个 32 位有符号整数再做后续运算。51 单片机的 IO 口是准双向口作为输入使用时必须先写 1。很多新手在读取 DOUT 之前忘了把 P1.0 置 1导致读到的永远是 0 或者随机值。另外51 的机器周期与晶振频率相关11.0592MHz 晶振下一个机器周期约 1.085 微秒。HX711 要求 SCK 高电平持续时间至少 0.2 微秒低电平至少 0.2 微秒这个速度对 51 来说完全跟得上但前提是不要在时序中间插入串口打印或者长延时。我一般会在 SCK 翻转之间加一个_nop_()既满足时序又不会拖慢整体速度。2.2 用普通 IO 口模拟 HX711 时序的完整代码下面这段代码是 51 单片机读取 HX711 原始值的核心函数晶振按 11.0592MHz 写其他频率需要调整延时。#include reg52.h #include intrins.h sbit HX711_DOUT P1^0; // 数据输出引脚 sbit HX711_SCK P1^1; // 时钟引脚 // 读取 HX711 的 24 位原始值返回有符号长整型 long HX711_ReadRaw(void) { unsigned char i; unsigned long raw 0; unsigned char timeout 0; HX711_SCK 0; HX711_DOUT 1; // 51 作为输入前必须先写 1 // 等待 DOUT 变低超时退出防止死循环 while (HX711_DOUT 1) { timeout; if (timeout 200) // 约 200 次循环后超时 return 0x80000000; // 返回一个明显错误的值 } // 读取 24 位数据最高位先出 for (i 0; i 24; i) { HX711_SCK 1; _nop_(); _nop_(); raw raw 1; // 左移一位准备接收新位 if (HX711_DOUT) raw; // DOUT 为高则当前位为 1 HX711_SCK 0; _nop_(); _nop_(); } // 第 25 个脉冲选择下一次通道 A 增益 128 HX711_SCK 1; _nop_(); _nop_(); HX711_SCK 0; _nop_(); _nop_(); // 补码转有符号数如果第 23 位是 1说明是负数 if (raw 0x800000) raw | 0xFF000000; // 符号扩展 return (long)raw; }这段代码的逻辑说明等待 DOUT 拉低是同步的关键超时机制防止传感器未接时程序卡死。24 次循环中每次先拉高 SCK延时两个空指令然后左移 raw 并读取 DOUT 电平再拉低 SCK。第 25 个脉冲固定为通道 A 增益 128这是最常用的配置。符号扩展那一步很多人会漏掉导致负值被当成大正数。参数说明timeout的阈值 200 是经验值实际项目中如果传感器响应慢可以适当加大但不要超过 1000否则会影响采样率。_nop_()的数量与晶振有关如果换到 12MHz 晶振可以保持两个不变因为 HX711 的时序余量足够。2.3 通道和增益怎么选A 通道 128 不是唯一答案HX711 有两个通道通道 A 可编程增益为 128 或 64通道 B 固定增益 32。第 25 个脉冲的数量决定下一次转换用哪个通道25 个脉冲选通道 A 增益 12826 个脉冲选通道 B 增益 3227 个脉冲选通道 A 增益 64。很多电子秤代码默认用通道 A 增益 128因为桥式传感器的满量程输出通常在 1mV 到 20mV 之间128 倍增益能把信号放大到接近 HX711 的输入范围充分利用 24 位分辨率。但如果你的传感器输出信号较大比如某些压力变送器输出 0 到 50mV用 128 倍增益会导致 HX711 输入饱和读数卡在最大值附近。这时候应该换到通道 A 增益 64或者用通道 B 增益 32。判断方法很简单空载时读原始值加载额定重量后再读如果两次读数差值很小或者直接跳到 0x7FFFFF就是饱和了。我一般会在代码里留一个宏定义方便切换通道和增益。#define HX711_CHANNEL_A_128 25 #define HX711_CHANNEL_B_32 26 #define HX711_CHANNEL_A_64 27 // 在读取函数最后根据宏定义发送对应数量的脉冲 void HX711_SetNextChannel(unsigned char pulses) { unsigned char i; for (i 0; i pulses; i) { HX711_SCK 1; _nop_(); _nop_(); HX711_SCK 0; _nop_(); _nop_(); } }这个函数可以替换掉前面代码里固定的第 25 个脉冲部分让通道选择更灵活。参数说明pulses只能取 25、26、27其他值会导致 HX711 进入未知状态需要重新上电才能恢复。3. 从原始值到克数校准、去皮与滑动滤波的代码实现3.1 两点校准法为什么你的秤线性度差HX711 读出来的原始值本身没有物理意义必须通过校准建立原始值与实际重量的对应关系。最常见的是两点校准空载时读一个值叫零点放上已知重量的砝码读一个值叫满量程点然后计算斜率。公式是重量 (原始值 - 零点) / 斜率。斜率 (满量程原始值 - 零点) / 砝码重量。这里有一个坑很多人只做一次空载校准然后直接用一个理论系数去乘结果小重量准、大重量偏。原因是传感器的输出并不是完美线性而且 HX711 内部放大器在不同增益下的失调也不同。两点校准能抵消掉大部分线性误差如果要求更高可以做三点或多点分段校准。long zero_offset 0; // 零点原始值 float scale_factor 1.0; // 斜率单位原始值/克 // 获取一次稳定读数用于校准 long HX711_GetStableValue(unsigned char times) { long sum 0; unsigned char i; for (i 0; i times; i) { sum HX711_ReadRaw(); } return sum / times; } // 校准函数空载时调用传入砝码重量 void HX711_Calibrate(float weight) { long raw_empty, raw_weight; raw_empty HX711_GetStableValue(10); // 空载读 10 次取平均 // 提示用户放上砝码这里用延时代替按键 delay_ms(5000); raw_weight HX711_GetStableValue(10); zero_offset raw_empty; scale_factor (float)(raw_weight - raw_empty) / weight; } // 获取重量单位克 float HX711_GetWeight(void) { long raw HX711_GetStableValue(5); return (float)(raw - zero_offset) / scale_factor; }逻辑说明HX711_GetStableValue做多次采样取平均能有效抑制随机噪声。校准函数里空载和加载各读 10 次取平均后计算斜率和零点。HX711_GetWeight每次读 5 次取平均然后套用公式。参数说明采样次数越多越稳定但响应越慢。电子秤一般 5 到 10 次比较合适配料机可以降到 3 次。delay_ms需要自己实现可以用定时器也可以用简单的循环延时。3.2 去皮和滑动滤波让读数不再像心电图去皮功能是电子秤的标配实现很简单把当前重量对应的原始值设为新的零点。但要注意去皮之后如果传感器漂移零点会慢慢偏移所以需要定期重新去皮或者加入自动跟踪。滑动滤波是另一个关键HX711 的原始值本身有几十到几百个字的跳动直接换算成重量会看到末位不停跳。滑动滤波维护一个数组每次新数据进来就替换最旧的数据然后求平均。窗口大小取 5 到 10 比较合适太小滤波效果差太大响应迟钝。#define FILTER_SIZE 8 long filter_buf[FILTER_SIZE]; unsigned char filter_index 0; // 滑动滤波返回滤波后的原始值 long HX711_Filter(long new_raw) { long sum 0; unsigned char i; filter_buf[filter_index] new_raw; filter_index (filter_index 1) % FILTER_SIZE; for (i 0; i FILTER_SIZE; i) { sum filter_buf[i]; } return sum / FILTER_SIZE; } // 去皮把当前滤波后的原始值设为零点 void HX711_Tare(void) { long raw HX711_GetStableValue(10); zero_offset raw; }逻辑说明filter_buf是一个环形缓冲区filter_index指向下一个要替换的位置。每次新数据覆盖最旧的数据然后求整个缓冲区的平均。去皮函数读 10 次取平均后直接覆盖zero_offset。参数说明FILTER_SIZE建议取 8这是响应速度和稳定性的折中。如果发现重量变化后读数要好几秒才跟上就把窗口调小到 4 或 5。3.3 串口输出与上位机观察调参时别靠猜调参阶段最忌讳盲调一定要把原始值和重量都打印出来看。51 单片机的串口配置比较简单用定时器 1 做波特率发生器11.0592MHz 晶振下配 9600 波特率误差为 0。下面是一个简单的串口打印函数把原始值和重量一起输出方便观察跳动范围和线性度。#include stdio.h void UART_Init(void) { TMOD 0x0F; TMOD | 0x20; // 定时器1模式28位自动重装 TH1 0xFD; // 9600 波特率 11.0592MHz TL1 0xFD; TR1 1; SM0 0; SM1 1; // 串口模式18位UART REN 1; // 允许接收 EA 1; ES 1; } void UART_SendByte(unsigned char dat) { SBUF dat; while (!TI); TI 0; } void UART_SendString(char *str) { while (*str) { UART_SendByte(*str); } } // 在主循环中调用打印原始值和重量 void Print_Weight(void) { long raw HX711_ReadRaw(); float weight (float)(raw - zero_offset) / scale_factor; char buf[32]; sprintf(buf, raw%ld, weight%.1f g\r\n, raw, weight); UART_SendString(buf); }逻辑说明串口初始化把定时器 1 设为模式 2自动重装波特率 9600。UART_SendByte等待发送完成标志 TI然后清零。Print_Weight用sprintf格式化字符串把原始值和重量一起输出。参数说明sprintf在 51 上比较耗资源如果代码空间紧张可以自己写一个简单的整数转字符串函数。打印频率不要太高建议 200ms 一次否则串口会成为瓶颈影响采样时序。4. 避坑与排查HX711 配 51 单片机最常见的 5 个翻车现场4.1 读数一直是 0 或者 0xFFFFFF现象程序烧进去后串口打印的原始值始终是 0 或者 16777215放不放东西都不变。原因DOUT 引脚没有正确配置为输入或者 SCK 和 DOUT 接反了。51 单片机作为输入前必须写 1如果忘了这一步DOUT 会被内部下拉管脚拉低读到的永远是 0。另外有些 HX711 模块的丝印和实际引脚顺序不一致SCK 和 DOUT 接反的情况很常见。解决先用万用表确认模块引脚定义然后在代码里检查HX711_DOUT 1这一句是否在读取前执行。如果接反了交换两个sbit定义即可。4.2 数值随电源波动手一碰就跳几百个字现象空载时读数还算稳定但手靠近或者电源电压稍微变化数值就跳几百甚至上千。原因HX711 的模拟电源和数字电源没有分开滤波或者地线走线太长形成环路。51 单片机开发板上的 5V 电源通常带有很多数字噪声直接给 HX711 供电会耦合进模拟部分。解决给 HX711 的电源引脚并联一个 10uF 电解电容和一个 0.1uF 陶瓷电容地线单独走一根到电源入口。如果条件允许用独立的 3.3V 或者 5V 线性稳压器给 HX711 供电。软件上可以把采样次数从 5 次提高到 10 次但治标不治本。4.3 校准后小重量准大重量偏差越来越大现象用 100g 砝码校准后称 100g 很准但称 500g 时显示 480g称 1000g 时显示 950g。原因传感器本身非线性或者 HX711 在大量程时进入了非线性区。另一个常见原因是机械结构问题比如秤台和传感器连接处有摩擦或者预紧力。解决先排除机械问题确保传感器只受垂直力。如果机械没问题改用三点校准空载、半量程、满量程各读一次然后做分段线性插值。代码上可以维护两个斜率和两个零点根据原始值范围选择对应的参数。4.4 程序跑一会儿就死机复位后才能恢复现象上电后正常工作几分钟然后串口不再输出数码管也不刷新按复位键又能恢复。原因HX711_ReadRaw里的等待循环没有超时机制当传感器接触不良或者 DOUT 被干扰拉高时程序会一直卡在while (HX711_DOUT 1)里。另外51 单片机的看门狗如果没有开启程序跑飞后无法自动恢复。解决在等待循环里加入超时计数超过阈值就返回错误值并跳过本次采样。同时开启看门狗在主循环里定期喂狗。如果用的是 STC 系列 51看门狗寄存器是 WDT_CONTR具体配置查数据手册。4.5 串口打印正常但重量始终为负现象原始值看起来正常但换算出来的重量一直是负数去皮后更负。原因符号扩展写错了或者零点校准的时候传感器上还放着东西。HX711 的 24 位数据是补码如果第 23 位是 1 而没有做符号扩展raw会被当成一个很大的正数减去零点后变成负数。解决检查if (raw 0x800000) raw | 0xFF000000;这一句是否执行。另外去皮之前确保秤台上没有东西如果用的是HX711_Tare函数调用前先清空秤台。5. 把采样率提到 80HzHX711 高速模式与 51 单片机的配合技巧HX711 默认输出速率是 10Hz 或 80Hz由模块上的 RATE 引脚决定。很多模块默认是 10Hz对于静态称重够用但如果你要做动态力检测或者快速配料10Hz 就太慢了。把 RATE 引脚接高电平可以切换到 80Hz但这时候 51 单片机的读取速度必须跟上。80Hz 意味着每 12.5ms 就要完成一次 24 位读取而 51 在 11.0592MHz 下执行一次HX711_ReadRaw大约需要 1 到 2ms看起来余量很大但实际上串口打印、滤波计算和显示刷新都会占用时间。我一般会把串口打印降到 500ms 一次滤波窗口从 8 降到 4确保主循环能在 12.5ms 内完成一轮。高速模式下还有一个细节HX711 在 80Hz 时内部振荡器频率会变化时序参数略有不同SCK 高电平时间建议不小于 0.5 微秒。前面代码里的两个_nop_()在 11.0592MHz 下大约 2 微秒完全满足。如果你用的是 12MHz 晶振机器周期是 1 微秒两个_nop_()也是 2 微秒同样没问题。但如果你为了省电把晶振降到 6MHz就需要增加_nop_()数量到 4 个。验证高速模式是否生效可以看原始值的刷新频率。在串口里连续打印原始值数一下每秒出现多少个不同的数值。10Hz 模式下每秒大约 10 个80Hz 模式下每秒大约 80 个。如果发现数值重复率高说明主循环太慢需要优化代码。一个实用的技巧是把滤波和重量计算放到定时器中断里主循环只负责串口发送和按键扫描。定时器中断频率设为 80Hz每次中断读取一次 HX711 并更新滤波缓冲区这样能保证采样间隔均匀不会因为串口发送而抖动。最后说一个我自己的习惯每次调试 HX711 相关代码我都会先用一个 100g 的砝码做单点验证确认原始值变化在合理范围内再去做多点校准。如果单点都不对后面所有校准都是白费功夫。另外51 单片机的 RAM 很小滤波数组不要开太大FILTER_SIZE超过 16 就可能挤爆内存导致其他变量被覆盖这种问题排查起来非常痛苦。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑