基于51单片机与HX711的电子秤设计与校准实战详解

发布时间:2026/9/1 22:34:44
基于51单片机与HX711的电子秤设计与校准实战详解 简介本资源是一套完整的基于51单片机的电子秤毕业设计实现方案面向电子、自动化、测控等专业本科生及课程设计/毕设实践者解决称重系统硬件搭建、信号采集、软件算法与人机交互等典型工程问题。压缩包共104个文件含Keil源程序工程.c/.h/.uvproj等、Proteus仿真工程.dsn/.pdsprj、电路原理图.sch、技术手册与论文资料.doc/.pdf/.ppt、调试过程文件.bak/.lst/.hex及实操说明.txt/.xlsx覆盖从原理设计、代码开发、仿真验证到实物调试全流程总大小17.89MB。已有195人学习下载资源结构清晰工程文件保留多版本备份如Administrator/yong双用户配置便于理解开发迭代过程配套技术文档详述HX711信号调理、数码管动态扫描、去皮校准算法及蜂鸣器反馈逻辑可直接用于毕设答辩、课程报告或二次开发参考。 电子秤这种项目几乎是每个单片机学习者绕不开的一个经典设计。但说句实话很多人照着网上的模板抄完原理图能跑程序能烧真正问起来为什么这么接、为什么这么写却答不上来。这次我基于51单片机HX711SEG4B四位共阴数码管10KG量程传感器蜂鸣器3按键的完整方案从硬件选型到软件逻辑再到Proteus仿真和实物校准把整个设计链路重新梳理了一遍。这篇文章不会只丢给你一堆代码和原理图而是会讲清楚每一部分背后的取舍逻辑、实际调试中容易踩的坑以及那些文档里基本不会写的细节。1. 方案选型与整体架构为什么是51HX711SEG4B1.1 主控芯片的选择逻辑在这个项目里我用的主控是STC89C52RC属于经典的MCS-51内核单片机。有人可能会问现在ARM Cortex-M系列这么普及STM32价格也下来了为什么还要用51来做电子秤原因有三个。第一电子秤的核心任务其实就是“采集计算显示”对主控的运算能力要求极低。HX711芯片已经把模拟信号的放大和AD转换全部做完了单片机要做的只是通过时序读取24位数据再做一个线性标定换算。这个工作量用51完全够用何必杀鸡用牛刀。第二51单片机的GPIO口是准双向口驱动能力虽然弱但配合三极管或直接驱动共阴数码管的段选正好够用电路结构简单教学意义强。第三从课程设计和毕业设计的答辩角度来说51方案更容易被评委老师理解你解释得清楚本身就加分。1.2 称重传感器与HX711搭配的合理性称重传感器选择的是10KG量程的铝制悬臂梁式传感器内部是四个电阻应变片组成的惠斯通电桥。传感器输出的差分信号幅度非常小满量程时也只有几毫伏必须经过高精度运放放大后才能被ADC采集。HX711就是专门干这个的。HX711内部集成了一个低噪声可编程增益放大器PGA增益可选32、64和128还集成了24位高精度Σ-Δ型ADC。在电子秤应用中最常见的配置是增益128此时HX711可以检测到非常微小的电压变化。配合5V供电和10KG传感器做到1克的分辨率是完全可行的。多说一句很多人纠结HX711到底是“称重专用芯片”还是“通用ADC”从数据手册看它确实是为桥式传感器量身定制的内部有专门的时钟电路和稳压输出整体方案非常成熟这也是它成为电子秤设计标配的原因。1.3 系统整体结构和信号流程整个系统的数据链路是这样的传感器受力产生微小的差分电压变化经过HX711内部仪表放大器放大再经过24位ADC转换为数字信号单片机通过模拟时序从HX711读出数据经过滤波和标定换算得到实际重量最后把重量值刷新到数码管上。按键负责去皮、校准、开关蜂鸣器等交互功能蜂鸣器在按键操作和超重时产生声音提示。这种“传感器专用ADC通用MCU”的三层架构是工业测量设备中最常见的设计范式。理解了这个架构后面看电路图和写程序时思路会清晰很多。2. 硬件电路设计与器件细节从原理图到实物2.1 电源与去耦设计这个项目可以用USB供电也可以用5V直流电源适配器供电。表面上看这只是一个电源接口的选择但实际布线时有个容易忽略的点如果直接用USB供电HX711的模拟电源AVDD和数字电源DVDD都来自同一个5V电流波动可能会耦合到模拟部分造成读数不稳定。我的做法是在电源入口放一个100uF电解电容滤低频纹波然后在HX711的AVDD引脚旁边并联一个0.1uF陶瓷电容和10uF钽电容分别滤高频和低频噪声。单片机数字部分和传感器模拟部分的地在电源入口处单点汇接。这样做之后读数的稳定性会有非常明显的改善。实测下来同样的传感器GND处理得好不好零点漂移能差到3到5倍。2.2 SEG4B数码管驱动方式SEG4B是四位共阴数码管模块。很多新手会纠结一个问题要不要用锁存器或移位寄存器来驱动我的答案是看引脚资源和刷新方式。如果直接用51单片机的P0口做段选P2口的部分引脚做位选四个位用三极管8550驱动那么一个数码管模块要占用大约12个IO口。51单片机总共就32个IO口还要留出HX711的2个口DT和SCK、按键的3个口、蜂鸣器的1个口这样算下来IO刚好够用只是余量不多了。所以没有额外加锁存器直接动态扫描驱动。刷新频率要做到至少1ms切换一位四位数码管一个完整扫描周期是4ms刷新率250Hz肉眼看不出闪烁。位选三极管必须用PNP型如8550因为共阴数码管的公共端要接地才能点亮而用PNP管时基极拉低导通导通后集电极输出高电平到公共端这个是常规驱动方式。反过来用NPN管会比较别扭容易犯错误。段选电阻我选了220欧姆实测在5V供电下数码管亮度适中长时间工作不会明显发热。2.3 HX711的接线与时钟配置HX711模块通常有8个引脚VCC、GND、SCK、DT、E、E-、A、A-。其中E和E-接传感器的激励电压正负端A和A-接传感器的信号输出正负端。SCK和DT接单片机任意两个GPIO即可。这里有个细节值得注意HX711的SCK引脚用于输出时钟脉冲来控制数据读取每次从DT引脚读取一位数据需要24个脉冲读到24位数据后再输出1到25个额外脉冲可以选择通道和增益。数据手册推荐的时序是先将SCK拉低等待DT变为低电平表示数据准备好然后连续输出24个脉冲读取数据最后再输出特定数量的脉冲来设置下一次转换的增益。标准配置下25个脉冲对应通道A增益12826个脉冲对应通道A增益6427个脉冲对应通道B增益32。在我的程序里选择的是25个脉冲也就是通道A、增益128。还有一个容易踩的坑HX711模块的供电电压会影响激励电压进而影响传感器灵敏度。有些模块上有稳压芯片可以把供电电压稳定到5V或3.3V给传感器桥路供电。如果是3.3V版本的模块传感器在5V标定下的灵敏度和实际工作电压下的输出会有差异这时候标定系数自然也会变不要照搬网上的系数一定要用砝码实际标定。2.4 按键与蜂鸣器电路设计按键部分用了三个独立按键去皮键、校准键、开关蜂鸣器键。按键电路没有做得很复杂每个按键串联一个10K上拉电阻到VCC按下时接地单片机检测到低电平即可。需要注意的是51单片机的P3口内部有弱上拉所以有些人不接外部上拉也能检测到但为了波形可靠我还是接上了外部上拉电阻。加上按键去抖动处理可以用硬件RC滤波也可以在程序里用延时或状态机消抖。程序里我用了10ms延时消抖实测稳定可靠。蜂鸣器选了有源蜂鸣器驱动方式用NPN三极管S8050。有源蜂鸣器内置振荡源只要通电就会响单片机只需要控制基极高低电平即可。这里有个容易忽略的地方蜂鸣器是感性负载关断瞬间会产生反向感应电动势可能会通过电源线干扰单片机和HX711的读数。所以务必要在蜂鸣器两端并联一个续流二极管1N4148即可方向要反接否则你可能会发现每次按键蜂鸣器响的瞬间数码管读数会跳一下。3. 核心代码实现与算法逻辑3.1 HX711读取时序的实现HX711的读取是软件模拟时序这个函数的写法有很多种但核心逻辑必须严格符合芯片手册。我的实现如下#include reg52.h sbit HX711_SCK P1^5; sbit HX711_DT P1^6; // 从HX711读取一次AD值返回24位有符号数 unsigned long HX711_Read(void) { unsigned long value 0; unsigned char i; HX711_SCK 0; // 等待DT变为低电平表示数据准备好 while(HX711_DT); for(i 0; i 24; i) { HX711_SCK 1; value value 1; HX711_SCK 0; if(HX711_DT) value; } // 25个脉冲进入通道A增益128 HX711_SCK 1; value value ^ 0x800000; // 转为有符号数 HX711_SCK 0; return value; }有些资料会在读取前先加上延时我实测下来只要SCK高低电平的维持时间不小于1us时序就是可靠的。51单片机在12MHz晶振下一个NOP约1us直接操作IO也可以满足要求。但要注意如果用的是STC系列的单片机在1T模式下速度会快很多这时候如果你不加延时实际的脉冲宽度可能太窄导致读取错误。所以我的做法是在循环里插入几个NOP确保脉冲宽度足够。3.2 均值滤波与数据平滑HX711的原始数据有波动是正常的尤其是人在秤上轻微晃动时数据会不停跳动。因此在读取到原始AD值后不能直接拿去算重量必须做滤波处理。我的做法是连续读取10次去掉最大值和最小值然后求平均。这种去极值平均滤波法在电子秤里非常常用既有中值滤波的抗脉冲干扰能力又有算术平均滤波的平滑效果。实现代码如下unsigned long HX711_Filter(void) { unsigned long buf[10]; unsigned long sum 0; unsigned long max, min; unsigned char i; for(i 0; i 10; i) { buf[i] HX711_Read(); } max buf[0]; min buf[0]; for(i 1; i 10; i) { if(buf[i] max) max buf[i]; if(buf[i] min) min buf[i]; } for(i 0; i 10; i) { sum buf[i]; } sum sum - max - min; return sum / 8; }有一个细节要注意如果每次读取都调用了延时函数那么整个滤波过程会占用不少时间可能会影响数码管动态扫描的刷新率。我的建议是HX711的读取间隔就靠芯片自身的转换时间决定不需要额外延时太多。HX711的转换速率默认是10Hz也就是说每秒可以读大约10次每次读数之间必须有足够的间隔否则读出来会是上一次的缓存数据。3.3 重量标定算法这是整个程序最核心的部分也是很多初学者最容易困惑的地方。电子秤的标定本质上是一个线性映射问题传感器受力后HX711输出的AD值和重量之间存在一个近似的线性关系所以只需要知道两个已知点就可以求出斜率和截距。我的标定思路是这样的首先在空秤状态下读取一个零点值offset然后放上一个已知重量的标准砝码比如1kg或5kg读取对应的AD值两者相减得到差值用砝码重量除以这个差值就得到了每个AD单位对应的重量值也就是标定系数。long offset 0; // 零点AD值 float scale 0.001; // 每个AD单位对应的克数初始值随便给 // 按键去皮记录当前AD值为零点 void Tare_Key(void) { offset (long)HX711_Filter(); } // 放入标准砝码weight_g后执行校准 void Calibrate_Key(unsigned int weight_g) { long current (long)HX711_Filter(); long delta current - offset; if(delta ! 0) { scale (float)weight_g / (float)delta; } } // 计算当前重量 float Get_Weight_Gram(void) { long current (long)HX711_Filter(); long delta current - offset; float weight (float)delta * scale; if(weight 0) weight 0; return weight; }这段代码看起来简单但实际使用时有个问题标定系数scale在断电后会丢失每次上电都要重新校准吗我的做法是把标定好的scale值写入EEPROMSTC系列单片机内部有EEPROM每次上电时先读出来这样只需要出厂时校准一次以后每次开机就能直接用。有些设计干脆用预设的固定系数省去校准流程但那样误差会比较大因为不同传感器的灵敏度差异可能高达百分之几。3.4 数码管动态扫描与显示处理数码管显示部分用定时器中断做动态扫描。我开了一个定时器0中断中断频率设为1ms每次中断刷新一位数码管。显示内容放在一个全局变量数组里主循环只要更新这个数组即可显示和称重逻辑互不干扰。unsigned char code digit_table[] {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; // 0-9共阴段码 unsigned char display_buf[4]; // 待显示的数字低地址对应左边第一位 void Timer0_ISR(void) interrupt 1 { static unsigned char pos 0; // 先消隐 P2 0xFF; // 位选全部关闭假设低电平有效这里根据实际电路调整 // 放置段码 P0 digit_table[display_buf[pos]]; // 选中当前位 P2 ~(0x01 pos); // 低电平选中根据实际共阴驱动调整 pos; if(pos 4) pos 0; }具体到共阴数码管的段码值0x3F对应数字0这个应该很熟。显示小数点和单位的话可以再定义一个带小数点的段码数组在需要显示小数点的那一位单独控制。这里有个容易出问题的细节动态扫描时如果位选切换和段码更新没有做到先关位选再更新段码就会出现“拖影”现象也就是一位数字轻微显示在相邻位上。正确顺序是先关闭所有位选消隐再更新段码最后打开当前位选。3.5 按键处理与功能逻辑三个按键我分别定义为去皮、校准、蜂鸣器开关。按键扫描放到主循环里用状态机的方式实现短按检测避免阻塞主循环。这里我分享一个实用的按键编程思路不需要延时消抖而是定时中断每10ms扫描一次按键连续两次检测到同一状态才认为按键有效。这种方式不阻塞CPU称重实时性更好。功能逻辑上去皮键的作用是记录当前AD值为零点这个比较直观。校准键的设计我做了个特殊处理长按3秒进入校准模式在校准模式下数码管会显示一个提示值按一下去皮键加一定的校准重量按一下校准键减一定的校准重量再次长按校准键保存退出。这个交互在实物上调试起来比较方便不用每次改代码来调整系数。4. Proteus仿真调试与常见问题排查4.1 仿真环境搭建Proteus里做这个仿真元件清单大致包括AT89C51或STC89C52、HX711Proteus库里有这个模型、称重传感器模型Graph Based Analogue Sensor或直接用两个可调电阻模拟电桥输出变化、SEG4B共阴数码管、按键、蜂鸣器、晶体管等。仿真和实物的一个主要区别在于HX711的Proteus模型是一个比较理想化的模型不会模拟实际芯片的噪声和零点漂移。所以仿真时数据会很稳定但实物上读到的数据肯定会有波动。这也是为什么一定要把滤波算法写好的原因之一。4.2 HX711模型在仿真中的连接在Proteus中HX711模型的引脚和实物模块一致。传感器部分我用了一个滑动变阻器来模拟电桥的不平衡输出把滑动变阻器跨接在E和E-之间滑动端接到A或A-的其中一个输入端另一个输入端接在E和E-的分压点上。通过改变滑动变阻器的位置可以模拟传感器受力后输出电压的变化。这样仿真时有一个好处你可以直接观察AD值是否随着输入电压变化而变化很方便验证接线和程序的正确性。如果程序能正常显示数字变化说明时序是通的再去排查硬件问题就更有针对性。4.3 仿真中常见的三大类问题第一类是数码管不亮或显示乱码。这个首先检查共阴和共阳段码是否匹配。SEG4B是共阴管用共阳的段码表结果就是乱的。其次检查位选驱动方式Proteus里如果没有加三极管直接用GPIO输出位选信号要注意电平逻辑是否和硬件一致。第二类是按键无效。Proteus里按键按下时默认是高电平还是低电平取决于按键模型和上拉/下拉电阻的设置。如果程序检测低电平触发但仿真里按下变成了高电平自然就没反应。这个排查起来很简单用虚拟示波器或电压探针看引脚电平变化即可。第三类是重量值不动。比如滑动变阻器调节后数码管显示的值始终不变。这种情况多半是HX711的时序没有通过程序卡在等待DT变低电平的while循环里。在Proteus仿真中HX711的DT信号需要SCK脉冲的配合才会变化如果程序里初始化时SCK电平状态不对DT可能一直为高或一直为低程序就死循环了。4.4 仿真和实物的关键差异如果只做仿真很多东西会被“完美”二字带过去。但实物调试时你会遇到仿真完全遇不到的问题电源纹波导致的读数漂移、传感器受力非线性、按键抖动更严重、蜂鸣器干扰、数码管亮度不均、导线接触不良导致的数据偶尔跳变。所以我的建议是先用仿真把程序逻辑跑通、把电路功能验证清楚然后再焊实物这样可以把问题范围缩小很多不至于一上来就硬件软件一起错很难定位。5. 实物调试、标定测量与误差修正5.1 上电前的检查清单实物焊接完成后先别急着烧程序。用万用表依次检查电源正负极是否短路、各芯片电源引脚电压是否正常5V、传感器E和E-两端电压是否约为供电电压、HX711的AVDD是否正常、数码管各段是否有短路。这五步检查最多花五分钟但能帮你避免烧芯片的悲剧。我见过太多人一上电数码管冒烟最后发现是段选和位选搞反了。5.2 标定步骤与数据记录上电正常后先烧录程序然后进行标定。我的标定步骤是空载状态下等待读数稳定按“去皮”键记录零点。放上标准砝码建议用5kg尽量接近满量程这样标定出来的线性更准。按“校准”键程序记录当前AD值并计算系数存入EEPROM。取下砝码检查零点是否回到0如果不是再按一次去皮。分别放上1kg、2kg、3kg、5kg砝码记录显示值画出误差曲线。这个过程中我实测到的数据大概是这样的不同传感器会有差异仅作参考标准重量(g)显示重量(g)绝对误差(g)00010001001120001999-1300030011500050022整体误差在正负2克以内对于10KG量程的家用秤来说这个精度已经可以接受。如果误差偏大往往不是程序问题而是机械结构问题比如传感器安装面不平、受力点偏离中心、螺丝没有拧紧。5.3 误差来源分析与修正方法电子秤的误差来源大致有三个传感器本身的非线性误差、ADC转换的量化误差、机械安装造成的受力不均匀。HX711的24位ADC量化误差其实非常小基本可以忽略。真正影响大的是传感器非线性。悬臂梁式传感器在满载时非线性误差一般在0.02%到0.05%之间对应10KG也就是2到5克。如果你发现满载时误差明显增大可以考虑使用分段标定在0-2kg、2-5kg、5-10kg各取一个标定点然后程序里根据重量区间选择不同的标定系数。这个方法在很多工业仪表里叫“多点校正”能有效降低非线性误差。机械安装方面传感器的一端固定另一端受力一定要保证受力方向垂直于传感器表面不能有侧向力。安装螺丝不要拧得太紧导致传感器变形也不要太松导致晃动。这个在实物的稳定性测试里表现得非常明显。5.4 关于HX711的速率和稳定性进一步优化如果你觉得默认10Hz的采样速率不够用可以修改HX711的速率选择引脚RATE。当RATE接VCC时输出速率10Hz接GND时输出速率80Hz。很多模块上这个引脚是悬空或通过跳线帽配置的。需要指出的是提高采样速率会略微增加噪声但不一定能提高精度。对于静态称重来说10Hz完全够用80Hz更多用于动态称重或峰值捕捉场景。稳定性方面除了滤波算法还可以做软件上的零点跟踪当重量值在一段时间内小于某个阈值比如5克时自动把它归零。这个功能在实物上体验很好可以避免零点温漂导致的微小读数变化。但如果要做合法计量器具这个功能允许与否就要看计量标准的要求了作为学习设计加上它有助于理解自动归零的原理。6. 实际使用体验与代码维护心得整套系统调试完成后我把它放在办公室用了一个多星期每天称一些小物件。体会最深的有三个点第一个是去皮功能的使用频率远高于校准功能。凡是称容器、称包装物都会用到去皮。所以去皮键一定要好用按下去响应要快反馈要清晰。我在程序里加了按键触发时的短暂蜂鸣提示这个细节在体验上非常加分。第二个是长期运行后传感器会有一点零漂但幅度不大一般几克以内。所以设计成每次上电自动去皮是个很实用的功能。我在上电初始化时会自动等待传感器稳定然后将当前值置为零点这样用户不用每次开机都手动按去皮。第三个是显示器上的单位标注。因为SEG4B只有四位数字无法显示“kg”或“g”的字母我用了两个LED灯来指示单位一个绿LED亮表示克一个红LED亮表示千克。按一下单位切换键可以在克和千克之间切换显示LED随之变化。这个小功能虽然简单但让整个作品完成度提升了一个档次。代码维护方面的一个心得是一定要把标定参数零点、系数和程序逻辑分离。所有需要根据实际硬件调整的参数集中放在一个config.h头文件里传感器换了、量程换了只需要改这个文件和重新校准一次程序主体完全不用动。这样在多版本迭代时省了很多事。最后再分享一个可能会帮到你的小技巧在调试阶段把HX711读到的原始AD值通过串口打印到电脑上观察它的变化比只看数码管上的数字高效得多。你可以直观地看到在静止状态下的噪声幅度、在加载瞬间的跳变过程、按键按下时是否对AD值产生了干扰。用串口调试助手配合波形显示工具很快就能定位问题到底出在传感器、电路还是程序上。我在前几次做类似项目时靠着这个方法省了大量排查时间强烈建议你也试试。本文还有配套的精品资源点击获取