51单片机+HX711电子秤Proteus仿真完整教程

发布时间:2026/10/5 5:53:25
51单片机+HX711电子秤Proteus仿真完整教程
电子秤项目在单片机课程设计和毕业设计里出现的频率相当高我见过太多人卡在同一道坎上实物称重电路调不通就想先在Proteus里仿真验证逻辑结果仿真也不是装上元件就能跑的光是HX711的时序、传感器模型的选择、标定公式的处理就能劝退一批人。这篇教程就把我用Proteus 8 Professional配合Keil5做51单片机HX711电子秤仿真的完整过程拆开讲清楚从硬件电路搭建、代码时序分析到常见的仿真坑全部给到能直接照做的方案源码部分也会逐段解释关键逻辑不让你对着代码发懵。1. 为什么称重首选HX711从精度、成本到Proteus仿真可行性的权衡1.1 51单片机内置ADC的局限先解决第一个问题为什么称重电路几乎不用51单片机自带的ADC模块STC89C52这类经典51芯片本身没有集成ADC即便你用STC12C5A60S2这类带8路10位ADC的增强型51直接采集称重传感器的差分毫伏信号也远远不够。称重传感器常见的悬臂梁式、平行梁式在满量程时的输出灵敏度通常是1mV/V到2mV/V配合5V激励电压满量程输出也就是5mV到10mV。10位ADC的理论分辨率是5V/1024≈4.88mV/LSB你连满量程输出都分不出几个台阶更别说称出1g以内的变化。即便用外部独立的16位ADC芯片比如ADS1115价格和驱动复杂度又上去了。HX711就是冲着这个场景来的专为高精度电子秤设计的24位Σ-Δ型ADC内部集成稳压、放大、时钟两线数字接口成本几块钱还能在Proteus里直接仿真性价比直接拉满。1.2 HX711的核心参数与工作模式HX711有两个差分输入通道通道A的可编程增益为128或64通道B固定增益32。电子秤常规接法是传感器输出接通道A增益128倍此时满量程输入范围约为±20mV刚好匹配常见的1mV/V传感器在5V供电下的输出范围。片上自带稳压电路可以直接用稳压后的AVDD给传感器供电简化了外部电路。内部时钟约10MHz数据输出速率有两个档位SDA引脚PD_SCK拉高的脉冲个数控制着读数和通道/增益切换。SDA拉低时为掉电模式这也是Proteus仿真中一个关键细节如果SCK引脚电平状态不对HX711模型可能一直处于掉电状态读回来的数据就是恒定的0x800000或乱跳。1.3 Proteus仿真HX711的独特优势很多初学者以为Proteus里的HX711只是个摆设模型仿真意义不大实际上不是这样。Proteus的HX711库模型是支持真实时序交互的——你通过SCK引脚给它发送25个脉冲24个数据位1个通道增益选择位它会按照24位二进制补码的格式把数据逐位移出。这意味着你的代码时序如果写错了仿真里同样会读出错误数据跟实物的表现几乎一致。而且仿真环境里你可以用虚拟示波器、虚拟终端、逻辑分析仪去观察DOUT引脚的电平变化这在实物上需要用万用表或示波器探头慢慢点的调试过程在仿真里可以看得一清二楚。对课程设计来说先把整套系统在Proteus里跑通再画PCB做实物成功率会高很多。2. 硬件电路搭建Proteus元件选型、传感器模型与连线细节2.1 元件清单与Proteus检索方法先给完整元件清单Proteus 8 Professional及以上版本亲测可用元件名称Proteus检索关键字说明单片机AT89C51 / AT89C52用AT89C52更合适RAM和ROM更大称重传感器LOADSENSOR库里的应变片式压力传感器模型输出差分信号HX711HX711在Analog IC或专门传感器分类里搜索液晶显示LM016L / LM044L16x2字符液晶课程设计常用晶振CRYSTAL11.0592MHz或12MHz均可电容/电阻CAP / RES按电路需求放置电位器POT-HG仅作标定模拟仿真里常用注意Proteus元件库的版本差异很大。有些老版本比如8.6以下搜不到HX711我遇到过读者用Proteus 8.0找不到HX711模型的情况。如果你用的版本没有这个元件两个解决办法一是换用Proteus 8.9以上版本库模型比较全二是在库搜索框输入HX711后如果没结果可以去Proteus官网的元件库下载页面找第三方库文件需要下载.pd4库文件放到Library目录。不要为了省事用AD620仪表放大器替代HX711那样代码和参考设计全对不上反而更麻烦。2.2 LOADSENSOR传感器模型的关键设置Proteus里的LOADSENSOR模型不是简单的电阻应变片桥它自带一个输入参数力的大小用Force属性设置单位牛顿。双击元件后你会看到一个Force参数默认可能是10N或100N仿真时它就是你的砝码你改这个参数就相当于往电子秤上放重物。这是仿真中最容易忽略的点。很多人的电路接好了、程序烧进去了LCD上数据却纹丝不动排查半天发现是Force参数设成了0传感器输出为零HX711当然读不出东西。仿真时你可以把Force设为50N然后一边运行一边改这个值观察读数变化特别直观。传感器供电接E和E-信号输出接S和S-。HX711的AVDD输出通常是4.3V到4.8V可以直接给传感器的E供电E-接地。如果你用外部5V给传感器供电注意HX711通道A的差分输入范围是±20mV增益128倍如果传感器满量程输出超过这个范围读出来的数据就会饱和这在实物上会损坏芯片仿真倒是不怕但结果也不会对。2.3 电路接线对照我给你一套可以直接照着画的接线关系HX711的E接传感器E红色线E-接传感器E-黑色线HX711的A接传感器S绿色线A-接传感器S-白色线HX711的VCC接5VGND接地HX711的DOUT接单片机P1.0PD_SCK接P1.1单片机P2.0~P2.7接LCD1602的数据口D0~D7LCD1602的RS接P3.5RW接P3.6EN接P3.4晶振电路11.0592MHz晶振两端接30pF电容到地复位电路10uF电容10K电阻经典复位电路如果你想把VCC和模拟电源分开接HX711的VCC可以单独接一个经过LC滤波的5VVFB引脚接一个0.1uF电容到地这在实物上能明显降低纹波仿真里不接也能跑。2.4 下拉电阻与上拉电阻的取舍HX711的DOUT和PD_SCK是开漏输出Proteus仿真模型里不接上拉电阻也能出结果实物上一般也不需要外部上拉因为HX711内部有弱上拉。但51单片机的P1口内部没有上拉如果你用P0口接HX711那必须外部接10K上拉电阻否则高电平读不进去数据全是0xFF。这也是一个典型的仿真能过、实物翻车陷阱原理上必须讲清楚。3. 核心代码实现24位数据读取时序、均值滤波与标定逻辑3.1 HX711数据读取时序的本质HX711的通信时序说简单也简单数据线DOUT平时为高电平当单片机准备好接收数据时DOUT会被拉低表示数据已经准备好。此时单片机给PD_SCK发送25个高电平脉冲前24个脉冲对应24位数据从最高位D23到最低位D0逐位移出第25个脉冲控制下一次转换的通道和增益。关键点DOUT必须在第25个脉冲的下降沿之后才会恢复高电平标志一次完整读数结束。如果你读完24位就停了DOUT不会再输出下一次数据。这就是为什么初始化函数里通常需要清空一次数据——上电后HX711可能处于内部状态不确定的状态连续读两次丢掉第一次的结果第二次才是稳定的。// HX711 数据读取核心函数 unsigned long HX711_Read(void) { unsigned long value 0; unsigned char i; EA 0; // 关总中断防止时序被定时器打断 DOUT 1; SCK 0; while(DOUT); // 等待DOUT变低变低表示数据准备好 for(i 0; i 24; i) { SCK 1; // 产生上升沿数据移出 value value 1; // 左移一位 SCK 0; if(DOUT) { // 读取当前位 value; } } // 第25个脉冲选择通道A增益128 SCK 1; value value ^ 0x800000; // 24位二进制补码转无符号数 SCK 0; EA 1; // 恢复中断 return value; }3.2 二进制补码转换的细节HX711输出的是24位二进制补码最高位是符号位。直接把读到的24位数据当成无符号整数用会出问题空载时读到的可能是0x800000左右约8388608加载后数据增大但如果你把负的传感器偏移量比如传感器零点输出为负读回来最高位是1数值看起来会特别大。处理方式有两种。第一种是按二进制补码转有符号数读到的24位数据如果最高位是1先减1再取反然后加负号得到有符号的int型值。第二种更常用也更简洁直接读无符号24位值然后在标定的时候把空载读数作为零点偏移基准每次读数减去这个基准就得到了相对变化量。我在代码里用了value value ^ 0x800000这一行这是把24位补码等效转成以0x800000为中心的无符号值。这样空载值大约在0x800000附近加载后值单调增加后续标定减去零点值就得到正比于重量的差值。这种方法好理解也方便串口调试观察。3.3 为什么必须加均值滤波HX711是24位高精度ADC分辨率极高也意味着它对噪声极其敏感。即使仿真环境里没有实物噪声Proteus的模型也会模拟一定的随机扰动你会发现连续读10次数据最后几位一直在跳。实物上更严重电源纹波、机械振动、温度漂移都会叠加进去。解决办法就是多次采样取平均工程上叫滑动平均滤波。// 多次读取取平均提高稳定性 unsigned long HX711_GetValue(unsigned char times) { unsigned long sum 0; unsigned char i; for(i 0; i times; i) { sum HX711_Read(); } return sum / times; }times取值多少合适我实测下来5次平均在仿真里就已经很稳了实物上如果电源质量一般建议8~10次。但注意不要贪多HX711默认输出速率10Hz读一次约100ms你取10次平均刷新一次就1秒了用户体验很差。如果需要更快响应可以把HX711的RATE引脚接高电平输出速率翻倍到20Hz或者降低平均次数。这是一个精度与实时性的取舍要根据实际场景调整没有绝对最优解。3.4 标定逻辑从原始读数到实际重量标定是电子秤的灵魂。称重传感器的输出电压与受力是线性关系所以重量 K × (当前读数 - 零点读数)K就是标定系数单位是克/每码值。标定过程分两步第一步记录零点偏移。空载时调用HX711_GetValue读到的平均值记为offset。第二步放已知重物计算标定系数。比如放一个100g的标准砝码读到的平均值为value那么100g对应的码值差值 value - offset标定系数K 100.0 / (value - offset)之后任意重量 K × (当前读数 - offset)。仿真里模拟标定很简单把LOADSENSOR的Force设成0记录offset设成1N约102g记录value然后你就能算出K。注意Proteus里Force单位是牛1N对应约102g你可以在标定时直接按1N100g处理这样后面显示的重量数值比较规整。但为了严谨建议在代码注释里写清楚单位换算关系免得换个人看代码时一头雾水。#define FILTER_TIMES 5 // 滤波次数 long offset 0; // 零点偏移 float K 0.0; // 标定系数单位g/码值 void HX711_Calibration(void) { unsigned long value; // 空载读数作为零点 offset HX711_GetValue(FILTER_TIMES); // 放100g标准重物仿真里调整Force参数 value HX711_GetValue(FILTER_TIMES); K 100.0 / (value - offset); } float HX711_GetWeight(void) { unsigned long value HX711_GetValue(FILTER_TIMES); long delta value - offset; return delta * K; }这里有个非常隐蔽的坑offset和delta都可能出现负数。一是传感器安装预压导致空载输出不为零二是你放上去的重量太小读数变化量在噪声范围内delta偶发为负。所以代码里必须判断delta小于0时按0处理否则显示负数会很奇怪。另一个坑是标定系数K丢了。很多人在开发板上调通了断电重启后发现重量不对了就是因为K和offset存在RAM里掉电丢失。课程设计要求不高可以直接写死在程序里每次上电重新标定也不是不行如果要做得正规一点建议把K和offset存储在单片机内部EEPROM里比如STC系列自带EEPROMAT89C52没有EEPROM就要外挂AT24C02。这个根据自己的开发板型号灵活处理。4. Proteus仿真调试全流程从加载程序到LCD稳定显示4.1 Keil5工程配置与HEX文件生成写代码之前先把Keil5的工程配置好这里有一个高频错误新装Keil5默认没有安装51系列芯片包如果芯片型号列表里找不到AT89C52需要先下载安装C51相关的Device Pack。Keil5和Keil4的安装逻辑不一样Keil4装完自带C51编译器Keil5需要独立安装C51的包。工程配置步骤打开Keil5点击Project → New uVision Project取好工程名在弹出的Select Device窗口里输入AT89C52选中对应芯片左侧Project栏右键Target选择Options for Target或者直接点魔法棒图标切换到Output选项卡勾选Create HEX File如果代码里用到了定时器中断需要把Interrupt的勾选保持默认用不到就不用管点击编译按钮F7生成HEX文件生成HEX文件之后打开Proteus。默认情况下Proteus不会自动加载HEX需要双击AT89C52元件在Program File一栏点击文件夹图标选择Keil输出目录下的.hex文件。这一步做完点击Proteus左下角的运行按钮仿真就开始跑了。4.2 程序烧录进Proteus仿真芯片这里说一个很多人不知道的细节Proteus仿真51单片机不需要烧录器只要加载HEX文件即可。但你加载完HEX之后如果改过代码重新编译Proteus里可能会继续运行旧程序。很多人改完代码发现仿真结果没变化就是因为Proteus没有重新加载HEX或者Proteus还开着旧的仿真进程。稳妥做法是先停止仿真重新加载HEX文件再运行仿真。Proteus默认的仿真速度是实时仿真你可以在右下角看到仿真进度条的运行时间。如果代码里有死循环等待某个引脚电平变化而外部没有触发条件仿真可能看起来像卡死了这时候按左下角的暂停按钮检查代码里有没有while(1)死循环在等待一个永远不会变的条件。4.3 观察重量变化调整传感器Force参数仿真运行后怎么模拟放重物双击LOADSENSOR元件会弹出属性对话框里面有一个Force属性。你把它改成10N大约1公斤点击确定程序下一次采样就能读到新数据LCD上的数字会跟着变化。我测试时的操作路径是先把Force设为0观察LCD显示0g然后把Force改为0.5NLCD显示约50g再改为1NLCD显示约100g。这个变化过程非常直观就像真的在秤盘上放砝码。如果你的LCD读数不变化从下面三个方向排查一是程序有没有编译成功、HEX有没有正确加载二是HX711的DOUT和PD_SCK接的是不是程序里写的引脚三是LOADSENSOR的Force是不是0。4.4 虚拟终端和变量观测技巧Proteus里最实用的调试工具是Virtual Terminal虚拟终端。在元件库搜索VIRTUAL TERMINAL放到原理图上把它的RXD接到单片机的TXD引脚P3.1TXD接到单片机的RXD引脚P3.0然后把程序里的串口初始化补上就能在虚拟终端里实时看到调试数据。我在调试HX711时序的时候习惯在关键位置加串口输出void UART_Init(void) { TMOD 0x20; // 定时器1方式28位自动重载 TH1 0xFD; // 波特率9600晶振11.0592MHz TL1 0xFD; TR1 1; SM0 0; SM1 1; // 串口方式1 REN 1; // 允许接收 }然后在HX711_Read函数里临时插入一条串口打印语句看DOUT在时序中的作用是否正常。虚拟终端的好处是数据流清晰能直观看到每次读到的原始值判断滤波器有没有生效。另外Proteus 8里的调试方法很实用在HX711的DOUT引脚放一个逻辑探针Logic Probe或者直接右键引脚选择View State就能实时看到引脚电平排查DOUT是否真的拉低了。时序代码写对没有看DOUT的电平变化频率是最直观的判断依据。5. 避坑指南我在HX711Proteus仿真中踩过的6个坑5.1 DOUT一直为高电平程序卡死在while(DOUT)这是最高频的坑。程序一运行就卡在等待DOUT变低的死循环里LCD没显示仿真像死机。绝大多数原因是SCK引脚初始状态不对。HX711的PD_SCK如果一直处于高电平芯片就一直处于掉电或复位状态DOUT永远不会拉低。解决办法确保程序初始化时把SCK赋0且SCK引脚必须接在51单片机准双向IO口上P0口需要外部上拉P1/P2/P3口直连没问题。另一个原因是Proteus模型里HX711上电后需要一定时间来稳定而你的程序在main函数开头就调用HX711_Read此时芯片还没准备好。解决在初始化代码里加一个延时比如上电后delay_ms(100)再开始读数据。5.2 读到的24位数据全是0xFFFFFF这个现象对应的数据转换有问题。0xFFFFFF是24位补码的-1通常说明你的时序没有真正读到数据或者说读到的每一位都是高电平。排查思路先用虚拟终端打印HX711_Read的返回值如果恒定0xFFFFFF基本可以断定SCK和DOUT中有一个引脚接错了或者芯片根本没工作。检查DOUT和SCK是否接反、引脚号是否和代码一致。5.3 LCD显示但数字乱跳稳定不下来仿真中数字跳动的第一原因不是噪声而是你没有做滤波读了几次原始值直接用来显示。24位ADC的末几位跳动是正常现象不做均值滤波显示结果自然会跳。第二个原因是标定系数K不合理把微小码值差异放大成很大的重量变化。检查一下标定时代码里读到的空载值和加负载值之间的差值如果差值只有几百那么K会很大比如0.2g/码值噪声引起的波动就会很明显。第三个不太容易想到的原因Proteus仿真中如果其他元件在消耗大量CPU资源比如LCD频繁刷新、复杂图形仿真速度跟不上HX711的时序就会被程序的内部延时拉开。这个可以通过把LCD刷新频率降低、减少无意义的屏幕清空操作来解决。5.4 实物和仿真数据差异过大Proteus仿真用的是理想模型传感器输出线性度非常好电源噪声也小。实物上传感器供电纹波、布线质量、稳压芯片的噪声都会叠加进测量结果。我在实物上调试时最有效的优化是给HX711的AVDD和VCC分别加一个100uF电解电容和0.1uF瓷片电容组合给传感器桥路的S和S-之间并一个0.1uF电容滤除高频干扰。另外一个容易被忽略的点是传感器外壳必须固定牢靠机械谐振会直接变成读数上的周期性波动。5.5 标定系数在断电后丢失前面提过RAM里存的标定系数断电就没了。这个问题在课程设计答辩时特别容易暴露评委让你演示你上电发现显示0g之后放上砝码数字完全不对瞬间尴尬。我建议代码里做两个标定模式长按按键进入标定模式此时显示当前读数短按确认零点再放砝码确认满量程。标定完成后把K和offset烧写到EEPROM下次上电直接读取。你如果没有硬件EEPROM至少把标定结果用十六进制写死在程序里也行。5.6 Proteus仿真速度慢刷屏明显Proteus的LCD1602模型刷新比实物慢得多如果你的主循环里频繁调用LCD写函数仿真速度会肉眼可见地掉帧。优化方案只在重量变化超过阈值比如1g时才刷新LCD显示或者把刷新频率控制在每秒3到5次。人类肉眼对重量数字的响应不需要那么高频这个频次完全够用而且CPU占用率会大幅降低。6. 从仿真到实物移植时的接线改动与代码适配6.1 实物硬件的选型建议仿真跑通之后做实物前先确认几件事。单片机建议直接用STC89C52RC或STC12C5A60S2前者是完全兼容AT89C52的程序几乎不用改后者速度快一个数量级但引脚复用要注意如果你用到的引脚恰好是ADC或PWM功能引脚初始化时要关掉复用功能。HX711模块买独立的称重模块板红板或蓝板淘宝搜HX711模块就能找到模块上自带稳压和滤波比自己搭电路稳定得多。传感器推荐5kg或10kg量程的平行梁式传感器配一个称重托盘。电源建议用USB口的5V供电不要用充电宝的5V纹波太大实验室直流稳压电源最好。6.2 与Proteus仿真的硬件差异分析实物和仿真最核心的区别是仿真里HX711是理想模型引脚时序只要逻辑对就能跑通实物上HX711的DOUT和SCK信号线要尽量短避免和电机、继电器这类大功率器件共地线。如果在实物上发现读数异常优先检查电源HX711的VCC和传感器供电是不是同一路5V如果是务必加上LC滤波串联10uH电感再并100uF电容。另外实物上因为晶振频率偏差串口波特率、定时器延时都可能和仿真不一样。这个不影响称重功能但如果你的程序里有基于延时的时间特性比如按键消抖、超时判断要注意用示波器实测校准。6.3 功能扩展键盘校准、超重报警、数据存储项目做完基础功能后建议加几个实际功能让整体更完整键盘校准两个按键一个进校准模式一个确认当前重量。校准模式实现思路第一次按键记录零点放上1kg砝码后再次按键记录满量程点自动计算K和offset。超重报警加一个蜂鸣器当重量超过设定阈值比如2kg蜂鸣器响这个用有源蜂鸣器最简单给高电平就响。数据存储外挂AT24C02存储标定参数上电时先读取如果校验失败首次上电再进入标定流程。这就解决了5.5节说的问题。串口上位机用串口把重量数据传给PC做一个简单的上位机显示曲线。HX711数据率10Hz画实时曲线完全够用。7. 完整源码我整理了一份可以直接编译运行的完整代码基于AT89C52最小系统。源码包含初始化、HX711驱动、LCD1602驱动、按键标定和主循环逻辑代码里注释写清楚了每个函数干什么。// // 51单片机 HX711 电子秤 Proteus仿真程序 // MCU: AT89C52 / 晶振: 11.0592MHz // HX711: DOUT - P1.0, PD_SCK - P1.1 // LCD1602: 数据口 P2, RS-P3.5 RW-P3.6 EN-P3.4 // #include reg52.h #include string.h #include stdio.h #define FILTER_TIMES 5 sbit HX711_DOUT P1^0; sbit HX711_SCK P1^1; sbit LCD_RS P3^5; sbit LCD_RW P3^6; sbit LCD_EN P3^4; #define LCD_DATA P2 long offset 0; float K 0.0f; unsigned char calibration_step 0; void delay_ms(unsigned int ms); // LCD1602驱动 void LCD_WriteCmd(unsigned char cmd) { LCD_RS 0; LCD_RW 0; LCD_DATA cmd; LCD_EN 1; delay_ms(1); LCD_EN 0; } void LCD_WriteData(unsigned char dat) { LCD_RS 1; LCD_RW 0; LCD_DATA dat; LCD_EN 1; delay_ms(1); LCD_EN 0; } void LCD_Init(void) { LCD_WriteCmd(0x38); // 8位数据2行5x7点阵 LCD_WriteCmd(0x0C); // 显示开光标关 LCD_WriteCmd(0x06); // 文字不动光标右移 LCD_WriteCmd(0x01); // 清屏 } void LCD_SetCursor(unsigned char row, unsigned char col) { unsigned char addr; if(row 0) { addr 0x80 col; } else { addr 0xC0 col; } LCD_WriteCmd(addr); } void LCD_ShowString(unsigned char row, unsigned char col, unsigned char *str) { LCD_SetCursor(row, col); while(*str) { LCD_WriteData(*str); } } // 显示浮点数到LCD void LCD_ShowFloat(unsigned char row, unsigned char col, float num, unsigned char decimal) { char buf[16]; sprintf(buf, %0.*f, decimal, num); LCD_ShowString(row, col, (unsigned char*)buf); } // HX711驱动 unsigned long HX711_Read(void) { unsigned long value 0; unsigned char i; EA 0; HX711_DOUT 1; HX711_SCK 0; while(HX711_DOUT); // 等待数据准备好 for(i 0; i 24; i) { HX711_SCK 1; value value 1; HX711_SCK 0; if(HX711_DOUT) { value; } } HX711_SCK 1; // 第25个脉冲通道A增益128 value value ^ 0x800000; // 补码转无符号偏移值 HX711_SCK 0; EA 1; return value; } unsigned long HX711_GetValue(unsigned char times) { unsigned long sum 0; unsigned char i; for(i 0; i times; i) { sum HX711_Read(); } return sum / times; } // 标定 void HX711_Calibration(void) { unsigned long v; LCD_ShowString(0, 0, Calibration); switch(calibration_step) { case 0: // 第一步空载采集零点 LCD_ShowString(1, 0, Zero: Remove); v HX711_GetValue(FILTER_TIMES); offset (long)v; calibration_step 1; break; case 1: // 第二步放100g标准重物 LCD_ShowString(1, 0, Load: 100g); v HX711_GetValue(FILTER_TIMES); if(v offset) { K 100.0f / (float)(v - offset); calibration_step 2; } break; case 2: // 标定完成 calibration_step 0; LCD_ShowString(1, 0, Done!); delay_ms(1000); break; } } // 主函数 void main(void) { unsigned long value; float weight; LCD_Init(); delay_ms(100); // 等待HX711上电稳定 // 上电进入标定模式如需正常称重可把下面这行注释掉 // 实际使用时可以把标定结果固化在代码里跳过每次标定 // offset 8388608; K 0.001; // 示例默认值 while(1) { value HX711_GetValue(FILTER_TIMES); weight ((long)value - offset) * K; if(weight 0) { weight 0; } LCD_ShowString(0, 0, Weight:); LCD_ShowFloat(0, 8, weight, 1); LCD_ShowString(0, 12, g); // 标定按键P3.2 if(P3_2 0) { delay_ms(20); // 按键消抖 if(P3_2 0) { HX711_Calibration(); while(P3_2 0); // 等待按键松开 } } } } void delay_ms(unsigned int ms) { unsigned int i, j; for(i 0; i ms; i) { for(j 0; j 120; j); } }这段代码在Proteus仿真里编译烧录后默认会走到标定逻辑。你第一次上电先按键进入标定空载确认零点然后放上Proteus里传感器Force1N的负载确认100g标定点之后就正常显示重量。代码里把标定步骤通过LCD提示文字展示出来操作起来很清楚。调试代码时有一个建议先注释掉标定相关代码直接写死offset和K的默认值空载读数大约0x800000K可以先给一个近似值等确认HX711能读出稳定的值时再恢复标定逻辑细调系数。这样把问题隔离先解决读不到数再解决读数不准排查效率高很多。我自己做类似项目时还有一个习惯在代码里预留一个串口调试开关用宏定义#define DEBUG_UART 1控制。调试时打开串口打印原始值功能稳定后关掉LCD显示和串口输出互不干扰。别小看这个习惯它能帮你省掉至少一半的调试时间。