
简介基于51单片机的电子秤设计是一个面向电子初学者的完整实战项目以51单片机为核心配合应变式压力传感器和LCD1602液晶显示模块实现05公斤称重、实时显示与去皮功能。压缩包共100个文件包含C语言源码、头文件、十六进制烧录文件、Proteus仿真工程、Keil工程文件及备份文件等全部资料仅733KB目录结构清晰便于按模块对照学习。目前已有790人浏览学习适合通过实际案例掌握单片机编程、传感器信号采集、模数转换以及液晶显示驱动的开发流程。资源提供完整源代码与可运行仿真可从电路搭建、程序调试到软硬件联调逐步复现整个电子秤设计深入理解重量传感器数据处理和去皮算法的软件实现是一份高效实用的嵌入式入门资料特别适合课程设计与毕业设计参考。1. 基于51单片机的电子秤设计从 Proteus 仿真到实物上秤的完整路线做基于51单片机的电子秤设计真正卡人的往往不是单片机本身而是那个“称得准”。网上搜“51单片机电子秤”十有八九是 STC89C52 HX711 1602 液晶这套组合再配一个 Proteus 仿真文件和 Keil5 工程。这套方案之所以成了默认选项是因为 HX711 把传感器模拟前端最难办的差分放大和 24 位 ADC 全干了留给单片机的只是读时序和算数。这篇文章按我实际拆过的流程走一遍器件选型、原理图、驱动代码、仿真与实物调试以及五条花了钱才记牢的避坑记录适合刚入手 51 想复现完整项目的人也适合要交课程设计却不想只交一堆空理论的读者。2. 选型与原理图传感器、ADC 和 Proteus 仿真三板斧2.1 应变式称重传感器与量程选择电子秤的核心是力传感器常见的是铝制单点式应变传感器四根线出来红E激励正、黑E-激励负、白IN、绿IN-内部就是一个惠斯通电桥。受压时电桥失衡差分电压变化。以量程 5kg 的传感器为例灵敏度普遍在 1mV/V 左右5V 激励下满量程输出大约 5mV——这个信号直接进单片机的 ADC 根本不现实必须差分放大。量程选择上有个容易被忽略的规矩标称量程要留 1.5 到 2 倍余量。你要称的常见物体是 3kg就买 5kg 传感器而不是 3kg。因为传感器在接近满量程区间时线性度下降而且称重时经常会顺手压一下超过量程会永久损伤弹性体。选型参数可以按这张表对参数建议值说明量程5kg / 10kg按实际称重上限的 1.5 倍选灵敏度1mV/V5V 激励下满量程约 5mV激励电压3V 或 5VHX711 的 AVDD 可输出输出线数4 线 / 6 线6 线带反馈长线场景更稳2.2 HX711 为什么是民用电子的最优 ADC如果十年前做电子秤一般是用仪表放大器 AD620 加 ADC0804电路板上一堆电阻增益全靠手工调温度一变又飘了。HX711 一颗芯片解决了全部问题内置可编程增益放大器通道 A 可选 64 倍或 128 倍增益内置 24 位 Sigma-Delta ADC还带稳压输出可以给传感器供电。外部几乎不需要模拟电路成本几块钱这决定了它在 51 电子秤项目里的统治地位。HX711 的工作电压范围是 2.6V 到 5.5V供电直接用单片机同一路 5V 即可。数据速率可选 10Hz 或 80Hz通过芯片上 RATE 引脚电平控制接低电平是 10Hz推荐抗混叠更好接高是 80Hz。我一般接低。关键参数如下参数数值使用注意通道A 和 B通道 A 带 64/128 倍增益接传感器增益64 / 1285kg 传感器配 128 倍ADC 位数24 位补码输出符号位在最高位数据速率10Hz / 80HzRATE 脚拉低选 10Hz输出格式串行 DOUT SCK只需两根 IO注意 AVDD 是传感器激励电源HX711 芯片内部带稳压AVDD 与 DVDD 之间的电容布局要靠近引脚放后面避坑部分会展开讲。2.3 原理图要点与 Proteus 里的替代方案单片机最小系统、按键、1602 显示这些常规部分不展开重点说 HX711 和传感器的接法。在原理图里传感器四线接 HX711 的 E、E-、A、A-DOUT 和 SCK 分别接 P1.0 和 P1.1。1602 的数据口接 P0 口时必须加 10K 上拉排阻P0 是开漏输出不上拉就是白屏或乱码。初期在 Proteus 里仿真时会发现一个现实问题Proteus 自带元件库没有 HX711。常见做法有三种我按实际踩过的顺序列一下一是用库里自带的应变传感器加 AD620 和 ADC0832 自己搭模拟链路费时间但最接近实物二是直接用滑动变阻器分压模拟传感器差分输出走一个量值进去只验证软件逻辑三是加载网上的第三方 HX711 模型能用但版本兼容看运气。我一般选第二种因为我们的目的是调程序逻辑传感器模拟前端的正确性最终要靠实物验证。3. 把原始值变成克HX711 驱动、单位换算与数字滤波3.1 HX711 时序驱动25 个脉冲是硬规矩HX711 的串行协议不复杂但时序上有硬规矩。DOUT 在高电平表示忙直到转换完成会拉低主控检测到 DOUT 拉低后在 SCK 上产生 25 个脉冲前 24 个把 24 位数据一位一位移出来第 25 个脉冲决定下一次转换的通道和增益。下面这段是能直接编译的读取函数#include reg52.h #include intrins.h sbit HX711_DOUT P1^0; sbit HX711_SCK P1^1; // 读取一次 24 位原始值返回无符号左对齐值 unsigned long HX711_Read(void) { unsigned long value 0; unsigned char i; HX711_SCK 0; // DOUT 由高变低表示数据已就绪等待它拉低 while (HX711_DOUT); for (i 0; i 24; i) { HX711_SCK 1; // 上升沿移出一位 value value 1; HX711_SCK 0; if (HX711_DOUT) value | 0x01; } // 第 25 个脉冲选择通道 A 增益 128 HX711_SCK 1; _nop_(); HX711_SCK 0; return value; }逻辑说明while (HX711_DOUT);是等待数据就绪DOUT 不拉低说明芯片还在转换中这个循环必须卡住否则移出来的数据全是错的。24 个脉冲里每个 SCK 上升沿对应一位数据读出value左移一位后再根据 DOUT 电平置低位的 0 或 1。第 25 个脉冲不是数据位它是给芯片内部状态机用的选通信号。参数说明这里把增益设为 128是因为 5kg 传感器满量程输出 5mVHX711 在 128 倍增益下输入范围约 ±20mV正好落在合理区间。如果换成 10kg 传感器满量程差分电压接近 10mV128 倍依然合适。只用 64 倍增益的话小重量段的分辨率会砍半不划算。还要注意一个补码问题HX711 输出的是 24 位补码value拼出来是无符号视角的 0 到 0xFFFFFF。最高位是符号位要转成有符号数才能算重量。最简单的方式是读完后减去 0x800000这个操作后面统一处理。3.2 校准系数计算空载偏移与标准砝码两点标定读出来的原始值是 ADC 码不是克。从 ADC 码到克需要一个线性映射做法是两点标定先记录空载偏移量再放一个已知重量的标准砝码算出每一克对应的原始值增量。long zero_offset; // 空载偏移量去皮基准 float scale_factor; // 每克对应的原始值增量 // 把 HX711_Read 结果转成有符号数 long HX711_Read_Signed(void) { return (long)HX711_Read() - 0x800000L; } // 标定流程空载取零再放标准砝码 void Calibrate(void) { delay_ms(200); zero_offset HX711_Read_Signed(); // 1. 空载时读零点 // 2. 提示放砝码这里假设放 500g 标准砝码 delay_ms(800); long raw_with_weight HX711_Read_Signed(); // 3. scale_factor (有载raw - 空载raw) / 砝码克数 scale_factor (float)(raw_with_weight - zero_offset) / 500.0f; } // 计算当前重量克 float GetWeightGram(void) { long raw HX711_Read_Signed(); float gram (float)(raw - zero_offset) / scale_factor; return gram; }逻辑说明HX711_Read_Signed()把无符号结果减 0x800000把零点挪到 -2^23这样正负重量都能表达。标定时分三步先读空载偏移再读带砝码的原始值两者做差除以砝码克数得到scale_factor。实际称重时用当前原始值减偏移量除以每克原始值就得到克数。参数说明这里的 500g 只是示例如果你手里的标准砝码是 200g 或 1kg把除数改成对应值即可。scale_factor的类型必须用 float两个原始值相减动辄几十万整数除法会直接舍成 0。另外标定前让传感器上电预热 1 到 2 分钟冷机状态下零点漂移明显直接标定出来的系数用起来会越来越偏。3.3 去掉毛刺的数据滤波去极值平均的取舍称重时人站在秤上、手放上去、东西丢上去都有冲击和振动ADC 读出来会带毛刺。最朴素的滑动平均不够用因为单个异常尖峰会把平均结果拉偏。我一般用去极值平均连续采样 N 次去掉最大值最小值对剩下的做平均。这样既压制了随机噪声又不会因为一次突变导致屏幕跳字。#define SAMPLE_N 5 unsigned long GetFilteredRaw(void) { unsigned long buf[SAMPLE_N]; unsigned long sum 0; unsigned char i, j; unsigned long tmp; for (i 0; i SAMPLE_N; i) buf[i] HX711_Read(); // 冒泡排序把最大值和最小值挤到两头只取中间 N-2 个 for (i 0; i SAMPLE_N - 1; i) for (j 0; j SAMPLE_N - 1 - i; j) if (buf[j] buf[j 1]) { tmp buf[j]; buf[j] buf[j 1]; buf[j 1] tmp; } for (i 1; i SAMPLE_N - 1; i) sum buf[i]; return sum / (SAMPLE_N - 2); }逻辑说明先采 5 次存进数组冒泡一趟把数据排好序掐头去尾后取中间 3 次平均。排序本身的开销在 51 上可以忽略因为每次只有 5 个元素而 HX711 在 10Hz 速率下每次读取本身要等 0.1 秒真正吃时间的不是排序而是等转换。参数说明SAMPLE_N取 5 是均衡值称重响应大约 0.5 秒体感不拖沓。取 3 则抗脉冲能力弱取 9 以上读数会明显“粘滞”放上东西要等一秒钟才稳下来适合对实时性不敏感的场景。如果做的是厨房秤这种静态称重我建议用 5如果是人体秤可以提到 7但代价是每跳一次数字都要刷新一两秒用户会觉得反应慢。4. 从 Keil5 到实物调试串口打印与量程对齐4.1 Keil5 工程的三个关键配置很多人在 Proteus 里仿真通过一转到 Keil5 建工程就翻车问题不在代码而在三个忽略项。第一是芯片型号Proteus 里选了 AT89C52实物用的是 STC89C52在 Keil5 的 Device 列表里选 STC 系需要提前装 STC 的数据库补丁没装就先用 AT89C52 型号代码区别不大只是下载方式不同。第二是 Output 选项卡里必须勾选 Create HEX File否则编译出来的东西没法烧。第三是晶振频率要和原理图一致。我用串口调试所以晶振选 11.0592MHz这样波特率误差为 0。如果只是跑纯逻辑不用串口用 12MHz 更方便做时间计算。注意这里说的是 Keil5 工程里虚拟的晶振设置它只影响编译期的时间计算真正决定运行速度的还是板子上那颗物理晶振。// 串口初始化模式19600波特率11.0592MHz void Uart_Init(void) { TMOD | 0x20; // 定时器1设为模式2自动重装 TH1 0xFD; // 9600 波特率重装值 TL1 0xFD; SCON 0x50; // 串口模式1允许接收 TR1 1; // 启动定时器1 }逻辑说明TMOD | 0x20而不是直接赋值 0x20是为了不动定时器 0 的配置位。如果定时器 0 已经在做毫秒延时直接把 TMOD 覆写等于把 T0 的工作模式改掉延时会全面跑偏这是常见低级血泪。参数说明9600 波特率下TH1 和 TL1 都要是 0xFD这是 11.0592MHz 晶振的唯一正确配法。换了 12MHz 晶振这个值要改成 0xF3否则串口出来全是乱码。实测中我把这个现象碰到了至少三次每次都是换板子忘改晶振。4.2 串口打印让原始值开口说话实物排错最核心的手段就是串口打印。LED 闪烁能确认程序跑到哪但没法回答“ADC 值到底是多少”“标定系数是不是合理”这类问题。把原始值、偏移量、计算后的克数通过串口发到电脑用串口助手盯着看比任何仿真都直观。#include stdio.h char putchar(char c) { SBUF c; while (!TI); // 等待发送完成 TI 0; return c; } void Debug_Print(long raw, long offset, float gram) { printf(raw%ld offset%ld gram%.2f\r\n, raw, offset, gram); }逻辑说明重定向 putchar 之后printf才能在 51 上工作。while (!TI);是等发送中断标志置位确保当前字符发完再发下一个不然一字节还没发完就被下一个字节冲掉。TI清完才能再次发送否则第一次 printf 之后串口永久卡住。参数说明%.2f在 Keil 里默认不开启浮点打印支持如果连接头文件 勾选浮点选项后还打印乱码检查两点一是 printf 目标格式字符串里保留浮点优化选项二是 51 的 printf 默认不支持浮点需要在 C51 编译选项里把 Floating Point 的 printf 支持勾上。这是 Keil 环境最坑的配置之一我以前被这个卡了一整个下午。4.3 仿真通过但实物翻车差别在哪仿真通过只说明逻辑正确实物跑不起来通常是硬件问题。常见差别是这三处一是晶振电路Proteus 里双击单片机设个频率就算完事实物必须真实接 22pF 到 33pF 电容有些开发板晶振起振慢一上电单片机根本没跑二是复位电路STC 系列上电后要等几十毫秒复位完成如果复位电容太便宜或者漏电程序会反复复位表现为数码管闪一下灭一下三是 EA 引脚STC89C52 的 EA 必须接 VCC接错直接执行外部程序空间板子毫无反应这个我在帮人排错时见过太多次。5. 电子秤项目避坑实录五条值得写进笔记的经验5.1 读回 0x800000SCK 时序被中断打断现象上电后 HX711 读数固定在 0x800000 附近不管放不放大砝码都没反应。原因读时序第 25 个脉冲之前被打断了。我当时的代码在读取 HX711 前开了定时器中断中断里做了延时操作恰好把 SCK 的高电平时间拉长芯片把第 25 个脉冲误判成了下一个读取周期的数据脉冲。数据错位之后读出来的东西固定是符号位。解决读取 HX711 期间临时关中断读完整包数据再开。代码里用EA 0; ... EA 1;包住HX711_Read()或者把第 25 个脉冲的延时控制好确保 SCK 的脉冲宽度落在 1us 到 60us 之间别被中断拖出界。5.2 重量跳变五个字供电纹波在捣乱现象空载时读数在零点附近每秒跳好几个字用手摸一下传感器或者动一下供电线跳动幅度更大。原因HX711 对 AVDD 供电要求高电源纹波直接影响 ADC 精度。我那块面包板的电源是从 USB 转串口模块上取的纹波大AVDD 输入毛刺被 128 倍增益放大表现在读数上就是持续低频抖动。传感器激励线又长直接当起了天线。解决把 HX711 的 AVDD 和 DVDD 用一颗 100uF 电解电容 一颗 104 陶瓷电容并联去耦电容尽量贴近芯片引脚。传感器信号线越短越好避免和电源线平行走线。如果是面包板验证阶段临时用两节电池供电对比测试能快速确认是不是电源问题。5.3 1602 白屏P0 口上拉电阻不能省现象1602 上电后白屏有时候亮第一行方块调节对比度电位器没用。原因P0 口是开漏结构默认高电平要靠外部上拉。Proteus 里仿真是默认逻辑高看不出来实物没有上拉电阻时高电平信号浮空指令数据根本送不进 1602。解决P0 口外接 10K 上拉排阻这是最基本要求。另外 RS、RW、EN 控制线接 P2 口P2 是准双向不需要上拉。如果还白屏查 VO 引脚对地电压调到 0.4V 到 0.8V 之间对比度才合适。5.4 校准系数越来越偏蠕变与零点漂移现象标定完当天很准第二天同一块砝码称出来偏了 1 到 2g三天后偏更多。原因应变传感器存在蠕变和温度漂移。蠕变是恒定载荷下应变片输出随时间缓慢变化温度漂移则是弹性体受环境影响导致零点移动。标定只是把某一时刻的零点固化了温度一变零点就搬家了。解决每次开机时自动做一次去皮校准把当前空载值定为操作零点。再有一个习惯是上电后先预热 1 分钟再进入称重界面让传感器到达热平衡。标定系数存下来但偏移量一定要每次上电刷新。5.5 Proteus 里能跑实物一上电就飞仿真替代元件的边界现象Proteus 仿真文件里重量显示完全正常烧到实物上不是乱码就是读数恒零。原因Proteus 里没有 HX711用滑动变阻器模拟了传感器差分电压这就掩盖了一个事实实物的 HX711 需要正确的时序和供电环境。仿真里你会把标定系数调得很完美因为电位器分压是理想线性的而真实的应变传感器有噪声、温漂和接触电阻。解决仿真只用来验证主逻辑接进实物前先跑串口监视把原始的raw值打出来确认空载值、轻压值、满载值三个点的数量级。如果空载值和砝码值差值不稳先别动算法回头排查硬件。从那以后我每次做这类项目都强制走一遍“串口看原始值→三点标定→断电上电复测”的流程不再凭感觉调系数。希望帮到你。本文还有配套的精品资源点击获取