公司动态
STM32智能电子秤实战:从HX711信号链到称重算法全解析
简介本资源是一套完整的基于STM32的智能电子称毕业设计实践套件面向嵌入式初学者、电子信息类本科生及毕业设计学生解决从硬件搭建、固件开发到文档撰写与答辩展示的一站式学习需求。压缩包共723个文件含281个C源码与183个头文件构成主控逻辑、AD采集、HX711传感器驱动、OLED显示等核心模块36个编译中间文件.o/.d、18个PDF技术文档含原理图、PCB、报告、答辩技巧、16个Keil工程文件.uvproj/.uvopt及多份流程图与软件分析资料整体大小为39.61MB。已有950人学习下载资源结构清晰覆盖“硬件设计—程序实现—系统调试—成果输出”全链路特别包含毕设报告模板、答辩话术要点及模块级技术参数说明可直接用于课程设计复现或毕业课题落地。 从毕设题目里拿到一个基于stm32的智能电子称.rar压缩包展开一看里面有工程文件、原理图、参考论文但真正要从零把这个项目吃透、改到自己能跑起来不少同学第一反应是这咋弄。其实智能电子秤这个题目放在STM32项目里属于典型的外设组合练手项目——能覆盖ADC采集、传感器驱动、按键状态机、显示刷新、甚至低功耗设计几乎把AMC基础模块全串起来了。这篇文章我就从硬件选型、信号链路、软件架构到调试经验把这个项目完整拆开讲清楚每一步为什么这么做以及我在实际调试中踩过的坑。先说结论这个项目用到的核心外设没有一个是高难度的它考验的不是单点技术而是你怎么把各个模块可靠地捏在一起。电子秤的核心难点在模拟信号的稳定性而不是单片机本身。如果信号漂、零点乱飘、称重不准多半不是STM32的问题而是电路和机械结构层面的问题。所以这篇文章的重点会比较偏硬件工程化和信号链路的分析代码反而排在后面。1. 为什么选STM32做电子秤从方案对比看选型逻辑1.1 三个候选方案的优缺点对比电子秤的大脑常见有三类方案专用称重芯片方案比如海力士的HX711直接带MCU、通用MCU方案STM32、GD32等、以及带计量认证的SOC方案。刚拿到题目的同学可能觉得HX711才是核心但其实HX711只是一颗24位ADC前端芯片它后端接MCU才能完成显示、按键、逻辑控制。所以真正要选择的是MCU平台。把三个方案摆在一起看更直观方案成本开发难度精度上限典型场景8位MCU HX711低低中受MCU滤波能力限制家用简易秤STM32F1系列 HX711中中高可做数字滤波与标定补偿教学毕设、工业台秤原型专用计量SOC高高极高已过认证商用计价秤、贸易结算秤从我自己的体验来说STM32F103C8T6是这类项目最顺手的选择。原因有三第一它主频72MHz做称重数据滤波、按键扫描、OLED刷新完全是性能过剩的但这种过剩是好事情意味着你不需要天天抠时序第二HAL库和标准库的资料实在太多遇到问题几乎都能搜到现成答案第三F103系列有足够多的定时器、串口、I2C、SPI接口就算后面你要加蓝牙模块、WiFi模块、多个传感器资源也不会卡脖子。对于培训、毕设和原型验证这是最稳的一条路。1.2 系统架构这颗电子秤肚子里的完整组成按下电源电子秤开始工作的核心流程是这样的称重传感器把重量变化转换成微弱的差分电压信号HX711完成信号的放大和24位模数转换STM32通过时序读取HX711的转换结果借助标定系数把ADC原始值换算成实际重量OLED显示当前重量、单位、去皮状态按键触发去皮、单位切换、开关机等逻辑。这套架构最容易被忽略、也最关键的是第1步和第2步之间的模拟信号链路。HX711虽然集成了放大器和ADC但它的输入信号非常微弱满量程差分电压典型值只有10mV到20mV量级此时任何来自电源的纹波、地线上的噪声、或者传感器受力不均匀导致的非线性误差都会直接影响最终读数。我后面会专门展开讲这部分因为这直接决定你的秤到底是能显示数字还是称得准。2. 称重信号链路拆解从电阻应变片到24位ADC2.1 电阻应变式称重传感器的原理与接线市面上常见的电子秤传感器核心是一块弹性体通常是铝合金表面贴了电阻应变片。当重物压上去弹性体发生形变应变片电阻值随之变化通过惠斯通电桥把电阻变化转换成电压变化。单片机需要关注的不是电桥原理本身而是传感器的四根线E激励正、E-激励负、S信号正、S-信号负。正常情况下E和E-之间接5V或3.3V激励电压S和S-之间输出的差分电压就是我们要测量的信号。这里插一个接线上的教训传感器的线色在不同厂家之间并不统一。最常见的定义是红线E、黑线E-、绿线S、白线S-但也有人会用黄线、蓝线。我建议拿到传感器第一件事不是猜测而是用万用表量一遍测E到S之间的电阻、E到S-之间的电阻两组阻值应该接近且等于电桥的等效半桥电阻一般是350Ω左右也有1000Ω的。确认无误再接电路板不然查半天都找不到信号异常的原因。2.2 HX711的工作模式与关键引脚HX711是这颗秤的核心模拟前端我先把它的关键参数和配置方式列出来参数数值备注通道数量2A/BA通道增益可选64或128B通道固定32有效精度24位配合128增益时满量程约±0.5mV输出速率10Hz / 80Hz可选速率越低噪声越小供电电压2.6V~5.5V建议模拟电源和数字电源分开通信接口2线DOUT、PD_SCK类似SPI但用GPIO模拟即可重点说下通道和速率的选择。A通道128倍增益是称重传感器的标准配置满量程时输出灵敏度约等于第一脚到第二脚的电压差输入范围能匹配大多数铝制悬臂梁传感器输出速率方面如果你只是做静态称重10Hz足够而且噪声明显比80Hz小。我实测下来80Hz模式在无负载时的跳码范围大约是10Hz模式的3倍左右所以除非你后续要做动态称重否则老老实实用10Hz。PD_SCK在读取周期内的高电平脉冲数决定通道和增益这个细节容易踩坑读出数据时送25个脉冲前24个是数据位第25个用来设置下一次转换的通道和增益。如果不小心把脉冲数写成26或27HX711不会报错但读出来的数据会变成另一个通道或增益下的结果数值完全不可用。这种看起来在读、实际全错的问题非常隐蔽排查时一定要先确认脉冲计数。2.3 模拟电源的净化HX711供电与参考电压HX711的稳压和参考电压设计直接决定称重数据稳不稳。它有一个AVDD引脚通常通过一个RC低通滤波接到传感器的E激励端同时这个AVDD电压也充当了ADC的参考电压。这里有一个关键点HX711的转换结果是比例式的信号电压和参考电压都来自AVDD所以只要AVDD在信号采集窗口内保持稳定绝对电压的波动不会引起比例误差。但你如果用独立的基准电压源给HX711供电传感器激励也独立供电标准电阻的温漂就会转成实际误差。简单说让AVDD既是传感器激励又是参考源反而是最稳定、最简单的设计。实操上我习惯在AVDD引脚和对地之间并联一个100uF电解电容和100nF陶瓷电容尽量靠近引脚放置同时在传感器E和E-之间接一个10uF以上的电容。这组电容能在瞬间负载变化时稳住电压实测可以明显减少数据跳变。还有一个容易忽略的问题是HX711的数字地AGND和模拟地DGND数据手册建议用0Ω电阻或磁珠单点相连在高精度称重的场合一定要这么做否则数字噪声会通过地平面耦合到模拟端导致零点缓慢漂移。3. 单片机端软件设计HX711驱动、滤波算法与状态机3.1 用GPIO模拟时序驱动HX711HX711的时序非常简单总共就两根线 DOUT数据输出 PD_SCK时钟输入。当DOUT从高电平变为低电平时表示转换完成STM32开始输出脉冲读数据。每一路脉冲HX711在上升沿把一位数据放到DOUT上STM32在脉冲高电平期间或下降沿后读取。24个脉冲读满后再补1个脉冲设置下一次采集的通道和增益。我用标准库写的初始化函数和读取函数大概是这样的骨架uint32_t HX711_Read(void) { uint32_t value 0; uint8_t i; // 等待DOUT变低表示转换完成 while (HX711_DOUT_READ() 1); for (i 0; i 24; i) { HX711_SCK_HIGH(); // 这里需要延时几百纳秒确保数据建立 delay_us(1); value value 1; if (HX711_DOUT_READ() 1) { value; } HX711_SCK_LOW(); delay_us(1); } // 第25个脉冲设置下一次转换通道和增益 HX711_SCK_HIGH(); delay_us(1); HX711_SCK_LOW(); delay_us(1); return value; }有几个细节要注意第一读取时建议关闭中断或者至少关闭同优先级的中断避免脉冲时序被其他中断打断。因为HX711对时钟的相位要求虽然不严格但如果你在24个脉冲中间插入一个几微秒的串口中断可能导致时序错乱数据移位。第二第25个脉冲设置的是下一次转换所以如果你循环调用这个函数每次读到的都是上一次设置好的通道结果第一次读出来的数据是无效的通常要丢弃前两次数据。第三DOUT端建议加上拉电阻因为HX711的DOUT是开漏输出不加外部上拉信号上升沿可能不够陡在长线连接时容易误读。3.2 称重数据的滤波滑动平均、中位值平均、限幅滤波怎么选HX711的24位原始数据不会理想地稳定在一个值上通常会在某个范围内跳变。跳变大小取决于供电质量、传感器灵敏度和电气环境。直接把这个原始值换算成重量屏幕上的数字会像心跳一样乱跳所以必须做数字滤波。我试过三种方案结论很明确算术平均简单但抗不了突发脉冲噪声一个大的干扰值会把平均值拉偏很多中位值滤波抗脉冲最好但对连续变化的数据会造成滞后称重响应偏慢滑动平均实时性好存储量小对周期性噪声有很好的抑制作用。实际项目里用了滑动平均 限幅的组合先判断当前读数与上一次有效读数的差值如果超过设定的阈值比如500个码值就丢弃这个点如果没有超限就把它送入一个长度为8的滑动平均队列。这样做既能滤除高频抖动又能防止猛拉猛放造成的过冲显示。#define FILTER_LEN 8 int32_t filter_buf[FILTER_LEN]; uint8_t filter_index 0; int32_t filter_sum 0; int32_t filter_last 0; int32_t Weight_Filter(int32_t new_sample) { // 限幅超过阈值则用上一次值替换 if (filter_last ! 0) { int32_t diff new_sample - filter_last; if (diff 500 || diff -500) { new_sample filter_last; } } // 滑动平均 filter_sum - filter_buf[filter_index]; filter_buf[filter_index] new_sample; filter_sum new_sample; filter_index (filter_index 1) % FILTER_LEN; filter_last new_sample; return filter_sum / FILTER_LEN; }这个滤波组合在10Hz输出速率下表现非常稳定空载时显示值可以在±1g以内停住。如果你对响应速度要求更高可以把滑动窗口缩小到4或者在数据平稳后自动切换为大窗口滤波这个属于进阶优化后面再讲。3.3 称重状态机空载稳定、加载稳定、超载保护的切换逻辑电子秤不是上电就能直接用的它要经历几个状态。我在代码里用了一个简单的状态机每个状态对应不同的业务逻辑状态触发条件做的事情开机自检上电读取零点、检查传感器连线、初始化显示空载稳定零点漂移小于阈值每500ms记录一次零点更新去皮基准称重中重量超过稳定阈值持续采样实时更新显示称重稳定连续N次读数变化小于阈值锁定显示数值提示可读取超载重量超过量程预留量显示超载报警拒绝继续称重状态切换的关键是稳定判断:什么是稳定我定义的一个简单标准是连续5次0.5秒的滤波值最大值与最小值之差小于2g就认为称重结果稳定。这个阈值可以根据传感器量程调整量程5kg的秤用2g量程30kg的秤可以用10g。这个状态机的价值在于它把什么时刻读数才算准这个模糊问题变成了可编程的逻辑。没有状态机的话用户随便一放东西屏幕上的数字持续跳动就会觉得这个秤是坏的。很多人做电子秤毕设只到能显示重量就结束了其实加上这个稳定判断逻辑体验立刻上一个档次。4. 标定、去皮与单位换算电子秤核心算法的工程实现4.1 两点标定法背后的数学原理电子秤的标定本质是建立ADC原始码值到实际重量之间的线性关系。我们假设这个关系是线性的重量 (ADC值 - 零点值) / 斜率。为了求斜率和零点至少需要两个已知点这就是两点标定。实际操作时我先开机让秤空载等读数稳定后记录零点ZeroValue然后放上一个标准砝码比如1kg等读数稳定后记录满点FullValue那么斜率就是scale_factor (FullValue - ZeroValue) / 标准砝码重量之后任意重量计算公式就是weight (CurrentValue - ZeroValue) / scale_factor如果你有多个砝码理论上可以做多点拟合来补偿传感器的非线性误差但大多数铝制悬臂梁传感器在50%量程以内的线性度是相当不错的两点标定已经够用。我试过用1kg、2kg、3kg三个点做分段线性插值效果在满量程5kg的传感器上差异不大常规毕设和家用场景两点就足够了。标定系数一定要保存在Flash里不能每次都重新标定。STM32F103内部Flash写入寿命是1万次正常标定操作不会写很多次但要注意写Flash的时候要关闭中断否则在擦写期间来了中断会导致程序卡死。更稳妥的做法是把标定参数放在一个结构体里写入Flash前计算校验值读出来时先校验再使用避免Flash数据损坏导致程序跑飞。4.2 去皮逻辑的边界情况毛重、净重、负值显示去皮是电子秤最常用的功能逻辑上很简单用户放上一个容器按下去皮键系统把当前值记录为皮重TareValue之后显示净重 当前重量 - 皮重。但实现上有几个边界情况容易被忽略容器拿走后净重会变成负值。这是正常的要允许显示负值并且允许再次去皮恢复零点再次去皮时应该以当前显示值作为新的皮重增量而不是直接用当前ADC值替换。否则连续去皮数次之后零点会混乱去皮范围和量程的关系要处理好如果当前毛重已经超过满量程去皮按键应该被忽略否则会出现一个负数超载状态。我用的去皮逻辑是void Tare_Process(void) { gross_weight Get_FilteredWeight(); // 当前毛重 if (gross_weight MAX_LOAD) { tare_offset gross_weight; display_weight 0; } }这样实现有一个好处如果用户放了一个5kg的桶在10kg量程的秤上去皮后显示的净重是0此时继续加东西毛重超过10kg才会报警但净重没有超过量程的话显示依然正常。这个基于毛重判断量程的逻辑和市面上大多数商用秤是一致的防止了去皮后还能无限制加物体的安全隐患。4.3 单位切换与精度显示的细节单位切换看似简单实际上涉及显示小数位的控制。称重行业常用的单位组合是kg和斤也有用kg和lb的。换算关系如下1斤 0.5kg 1lb 0.45359237kg如果显示精度固定为0.01kg即10g在kg单位下显示1.00切到斤应该是2.00这没问题。但如果切换到lb结果会是2.2046显示位数不够就会产生进位误差。实际项目里一般会为不同单位配置不同的小数位和步进值kg显示到小数点后两位lb显示到小数点后三位斤显示到小数点后两位。还有一个细节显示分辨率不能超过传感器和ADC的实际精度。HX711加常规传感器在10Hz采样率下有效分辨率大约在0.5g到1g之间针对3kg量程。如果你把显示设为0.01g屏幕会一直跳动看起来就像坏了。宁可把显示步进取大一点比如5g或10g步进换取稳定的阅读体验。5. OLED显示与按键交互用户体验从能用到好用5.1 OLED驱动方式选择I2C还是SPISTM32电子秤最流行的显示模块是0.96寸OLED分为I2C和SPI两种接口。I2C版本只需要两根线接线简单适合本项目SPI版本刷新速度快但需要额外的片选、数据命令选择线。从实际效果看电子秤的数据刷新频率不高5到10HzI2C接口的OLED完全够用。我个人倾向用I2C方案因为可以把SCL和SDA引脚分别接到PB6和PB7F103的I2C1代码也更简洁。I2C OLED驱动需要注意的一点OLED的I2C地址通常是0x3C但有些模块是0x3D检测不到的时候不要怀疑代码有问题先扫描一下地址。另外I2C通信要对OLED的RAM进行整屏刷新一次全屏刷新大约需要几百字节F103跑在72MHz下毫无压力但用软件模拟I2C的话要注意延时控制太快了模块跟不上。5.2 用DWT替代标准库的延时解决屏幕刷新卡顿设计过程中如果你用标准库自带的SysTick延时可能会有个问题SysTick被延时函数占用后就无法再用它做系统节拍。而OLED刷新、按键扫描、HX711读取这些操作都需要延时如果用阻塞式延时函数整机运行起来会有明显的一卡一卡现象。我采用的方式是用Cortex-M3内核的DWT计数器做微秒延时把SysTick释放给系统做1ms时基这样既能有精确的微秒级延时又有可靠的毫秒级调度void DWT_Delay_Init(void) { CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; DWT-CYCCNT 0; DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; } void DWT_Delay_us(uint32_t us) { uint32_t start DWT-CYCCNT; uint32_t ticks us * (SystemCoreClock / 1000000); while ((DWT-CYCCNT - start) ticks); }DWT计时器的精度取决于CPU时钟频率F103在72MHz下一个计数周期约13.9ns微秒级延时非常精确。用这个方法OLED单次刷新的阻塞时间可以控制在几百微秒以内整机流畅度明显提升。这个方法我在其他项目里也复用得很顺算是换了个思路解决了SysTick被占用的老问题。5.3 按键防抖与长按、短按的识别电子秤面板上至少需要3个按键开机/去皮、单位切换、背光/设置。简单的独立按键如果直接查询电平按下瞬间机械触点会产生抖动肉眼看着只是啪嗒一下但单片机可能已经识别了十几次动作。常用的防抖方案是延时20ms再确认电平优点是简单可靠缺点是在6个按键以上时会占用大量主循环时间。对于电子秤这种按键数量少的设备我觉得用定时扫描的有限状态机更优雅每10ms扫描一次按键电平如果连续3次读到低电平确认按下按键保持低电平超过600ms识别为长按松开后短按执行短按动作长按执行长按动作。这个逻辑还有一个好处可以方便地扩展组合键。比如短按长按同时触发数据锁定或者长按开关机。我把按键扫描放在1ms时基中断里用标志位通知主循环处理按键响应非常灵敏也不会阻塞其他任务。6. 实测数据与调参经验零点漂移、温漂和量程误差怎么压下去6.1 空载跳码测试多少范围内算合格把秤装好上电不加载任何物体连续采集HX711原始值并打印到串口你可以看到跳码情况。我这里有一组实测数据采集1000个点输出速率10Hz5kg传感器3.3V供电测试条件原始值范围峰峰值等效重量波动供电稳定传感器悬空8201530 ~ 820158050±0.3g供电稳定传感器平放桌面8201500 ~ 820157070±0.4g开关电源供电未加滤波电容8201000 ~ 82025001500±9g加100uF电解电容100nF陶瓷电容8201480 ~ 820156080±0.5g这个数据很能说明问题开关电源的噪声是最大的干扰源。很多同学用开发板自带的USB供电表面看起来工作稳定但实际上USB口的5V噪声不小传导到HX711的模拟电源后称重值就会像心电图一样跳。解决方式不是换电池而是在电源入口增加LC滤波并且让HX711的供电走独立的滤波支路。如果空载跳码的等效重量波动能控制在±1g以内这个秤的稳定性就合格了。如果超过这个范围先检查电源滤波再检查传感器到HX711的连线是否过长、是否与数字线平行。6.2 标定后的满量程偏差与线性度验证标定完成后用不同重量的砝码测试常见的问题是小重量准、大重量偏大或偏小。这通常是传感器本身的非线性误差或者机械结构上受力不均匀引起的。我习惯测5个点空载、20%量程、50%量程、80%量程、100%量程记录每个点的误差标准重量显示重量绝对误差相对误差0g0g00%1000g1001g1g0.1%2500g2503g3g0.12%4000g3996g-4g-0.1%5000g4985g-15g-0.3%可以看到越接近满量程误差越大。这时候有两个处理思路一是做多点线性校正二是检查机械装配。对于毕设和原型来说更建议先检查机械结构——传感器是否水平安装、受力点是否在同一平面、是否有预紧力。传感器弹性体如果被螺丝拧得太紧会造成初始应力直接影响满量程端的线性度。我遇到过小重量准、大重量偏小的情况最后发现是传感器固定螺丝太长顶到了弹性体的应变区把螺丝换成沉头螺钉后问题就消失了。6.3 温差导致的零点漂移与补偿策略电子秤还有一个常见现象开机的时候显示0放一会儿慢慢变成0.5g或者-1g。这是传感器电阻应变片的温漂以及HX711模拟前端温漂共同作用的结果。普通铝制传感器温漂系数大约在0.05%FS/C°如果你所在环境温差达到10°C满量程5kg的传感器就可能产生2.5g的零点漂移。缓解温漂的工程手段有三层硬件层传感器和HX711尽量远离发热源比如MCU和OLED的背光驱动电路。我在PCB布局时把传感器端子放在板子一端MCU放在另一端中间用地线隔开软件层开机后做一次零点采集并每隔一段时间自动更新零点但要注意只能在确认没有负载的情况下更新否则会把真实重量吃掉算法层如果要求更高可以在传感器附近放一个温度传感器如DS18B20建立零点-温度曲线做软件补偿。实话说家用电子秤很少做这层温度补偿更多出现在工业设备里。对本项目来说做到前两层就够用了。最关键的是开机自动清零这个功能——它能在传感器热机完成前就把初始偏差抹掉用户体验提升非常明显。很多商用秤的做法就是开机后显示0.0然后才允许称重背后其实就是这个逻辑。7. 进阶扩展从能称重到可联网的升级路径7.1 用串口空闲中断实现不定长数据接收如果后续要把电子秤数据传给上位机或者路由器ESP8266串口通信就绕不开。基础做法是串口一次接收固定长度的数据但如果数据长度不固定传统的逐字节接收定时器超时判断比较麻烦。F103的HAL库提供了一种优雅的方案串口空闲中断IDLE。当串口在一帧数据之后出现空闲总线时会产生IDLE中断此时__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE)会置位。配合DMA接收可以实现不定长数据的自动收发。核心思路是串口DMA工作在循环模式一旦收到数据就自动存到缓冲区当检测到IDLE中断时计算DMA当前计数器和上次处理计数器的差值就知道这段时间收到了多少个字节然后按帧解析。这个方案在STM32接ESP8266、接蓝牙模块、接上位机的场景里非常通用值得花时间掌握。7.2 加入ESP8266实现数据上传项目做完基础称重功能后最常见的扩展方向是把重量数据通过ESP8266上传到服务器或手机APP。ESP8266与STM32之间用串口通信STM32通过AT指令控制WiFi连接和数据发送。需要注意的是ESP8266的供电峰值电流能到300mA甚至更高不能直接从STM32的3.3V引脚取电必须用单独的LDO或DC-DC模块。我在项目里用了一个MP1584降压模块把输入电压降到3.3V给ESP8266供电要求能力在1A以上同时在地线连接上尽量短粗否则WiFi发射瞬间的压降会导致模块重启表现就是偶尔发不出去数据。7.3 用FreeRTOS管理称重任务的多线程化当功能多了裸机while循环就有点力不从心OLED要刷新、HX711要采集、串口要收发、按键要扫描每个都是周期任务。这时把代码迁移到FreeRTOS上用任务和队列来组织逻辑会让代码结构清晰很多。我规划的任务分配是任务名优先级周期工作内容ADCTask高100ms读取HX711、滤波、标定换算DisplayTask中200msOLED数据显示刷新KeyTask低20ms按键扫描与状态机处理CommTask中事件触发串口数据收发与解析任务之间通过队列传递数据比如ADCTask把计算好的重量值放入队列DisplayTask从队列取数据刷新屏幕这样就避免了共享全局变量的竞争问题。FreeRTOS在STM32F103C8T6上跑没有任何压力RAM占用大约1KB多绰绰有余。有人会问一个电子秤有必要上RTOS吗如果只是基础功能确实没必要但如果你想把电子秤做成一个平台还要加菜单、加存料管理、加IoT上报那裸机代码会越来越难维护。我在后面几个版本里就全切FreeRTOS了整个项目的可持续性一下子好了很多。8. 调试工具与典型问题排查链路8.1 串口打印与可变参数格式化调试电子秤最直接的手段是在STM32工程里重定向printf到串口然后通过串口助手看HX711原始值、滤波值和计算重量。HAL库重定向printf的方法很简单重写fputc函数即可#include stdio.h int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xFFFF); return ch; }需要注意串口的波特率不要设太高115200最常用。打印的内容建议同时包含ADC原始值、滤波值、零点值和计算后的重量值这样你不用反复改代码就能观察到整个信号链路的各个环节。8.2 用逻辑分析仪抓HX711时序当代码看起来没问题但读数不稳定时有一招很管用用逻辑分析仪抓DOUT和PD_SCK两根线的波形。HX711的时序是典型的一高一低、按脉冲读数模式逻辑分析仪能直观地告诉你脉冲宽度够不够、读到的位对不对、第25个脉冲有没有漏掉。我之前遇到一个奇怪的问题每隔一段时间读数就会跳到一个明显离谱的值但很快又恢复正常。用逻辑分析仪一看发现是按键扫描的中断打断了HX711读取过程导致中间的某个位被重复读了一次。把按键扫描改成在主循环中处理不在中断里做问题就消失了。8.3 常见故障与解决方案速查表现象可能原因解决方向上电读数直接为0x800000最低位HX711未正常启动或DOUT悬空检查供电、DOUT上拉、复位时序读数不变化一直是某个值传感器接线错误或SCK时序错误万用表检查传感器四线逻辑分析仪查时序空载跳动大电源纹波大、地线处理不当加LC滤波、单点接地、区分模拟数字地标定后重量偏小传感器安装过紧或有预紧力检查机械装配重新标定去皮后负数一直增长零点更新逻辑错误去掉自动零点更新或增加无负载判断OLED显示花屏I2C速率过快或地址不匹配降低I2C时钟确认模块地址这些故障我在项目里几乎全部遇到过排查顺序永远是硬件连接→供电质量→时序→代码逻辑。不要一上来就怀疑代码电子秤这种设备硬件问题的比例远高于软件问题。在这个项目上我最大的体会是MCU编程本身其实没有太多难点真正的挑战在于把一颗传感器、一个ADC前端和几行滤波代码组合成一套稳定可靠的测量系统。能做到空载不飘、加载准确、去皮干净、超载报警这个电子秤就不是一个演示程序而是一个接近产品状态的设备。如果后面继续往物联网方向走串口接上ESP8266数据即可上传云端再配合FreeRTOS把任务理顺整套系统就具备很强的扩展性了。希望这篇文章能帮你绕开我踩过的坑把项目做扎实。本文还有配套的精品资源点击获取