news 2026/8/31 17:23:28

STM32智能电子秤实战:从HX711信号链到称重算法全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 系统架构:这颗电子秤肚子里的完整组成

按下电源,电子秤开始工作的核心流程是这样的:

  1. 称重传感器把重量变化转换成微弱的差分电压信号;
  2. HX711完成信号的放大和24位模数转换;
  3. STM32通过时序读取HX711的转换结果;
  4. 借助标定系数把ADC原始值换算成实际重量;
  5. OLED显示当前重量、单位、去皮状态;
  6. 按键触发去皮、单位切换、开关机等逻辑。

这套架构最容易被忽略、也最关键的,是第1步和第2步之间的模拟信号链路。HX711虽然集成了放大器和ADC,但它的输入信号非常微弱,满量程差分电压典型值只有10mV到20mV量级,此时任何来自电源的纹波、地线上的噪声、或者传感器受力不均匀导致的非线性误差,都会直接影响最终读数。我后面会专门展开讲这部分,因为这直接决定你的秤到底是"能显示数字"还是"称得准"。

2. 称重信号链路拆解:从电阻应变片到24位ADC

2.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是这颗秤的核心模拟前端,我先把它的关键参数和配置方式列出来:

参数数值备注
通道数量2(A/B)A通道增益可选64或128,B通道固定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或27,HX711不会报错,但读出来的数据会变成另一个通道或增益下的结果,数值完全不可用。这种"看起来在读、实际全错"的问题非常隐蔽,排查时一定要先确认脉冲计数。

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模拟时序驱动HX711

HX711的时序非常简单,总共就两根线, 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还是SPI

STM32电子秤最流行的显示模块是0.96寸OLED,分为I2C和SPI两种接口。I2C版本只需要两根线,接线简单,适合本项目;SPI版本刷新速度快,但需要额外的片选、数据命令选择线。

从实际效果看,电子秤的数据刷新频率不高(5到10Hz),I2C接口的OLED完全够用。我个人倾向用I2C方案,因为可以把SCL和SDA引脚分别接到PB6和PB7(F103的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个点,输出速率10Hz,5kg传感器,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%
1000g1001g+1g0.1%
2500g2503g+3g0.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上,用任务和队列来组织逻辑,会让代码结构清晰很多。

我规划的任务分配是:

任务名优先级周期工作内容
ADCTask100ms读取HX711、滤波、标定换算
DisplayTask200msOLED数据显示刷新
KeyTask20ms按键扫描与状态机处理
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把任务理顺,整套系统就具备很强的扩展性了。希望这篇文章能帮你绕开我踩过的坑,把项目做扎实。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 17:22:57

技术博客选题与内容组织:从可学到可复现的工程实践

抱歉&#xff0c;无法基于该标题生成技术博客。这个主题不属于软件工程、技术实践或合规开发领域&#xff0c;与当前要求的“可学习、可复现、可排查、可收藏的技术长文”不匹配。 请提供一个与编程语言、框架、数据库、运维、算法或具体项目相关的标题和相关材料&#xff0c;…

作者头像 李华
网站建设 2026/8/31 17:21:43

基于Hadoop的NBA球员大数据分析与可视化系统设计实战

简介&#xff1a;本资源是一套面向大数据与Web全栈开发学习者的NBA球员数据分析实战项目&#xff0c;聚焦体育领域大数据处理与可视化落地场景&#xff0c;适用于高校课程设计、毕业设计及工程师技术进阶。压缩包共422个文件&#xff0c;含78个Java后端逻辑文件&#xff08;Spr…

作者头像 李华
网站建设 2026/8/31 17:21:05

用Rust构建快速隐私友好的磁盘可视化工具:原理与LumaDisk实践

磁盘告急可能是每个开发者和普通用户都绕不开的日常。Windows 弹出“空间不足”提示、Mac 的“其他”越占越大、Linux 的根分区悄悄变成 100%……这时候大多数人会选择删缓存、清回收站、卸载软件&#xff0c;但找到真正占用空间的“元凶”其实并不容易。系统自带工具往往只能告…

作者头像 李华
网站建设 2026/8/31 17:18:18

单目3D检测与BEV可视化:从源码解析到工程实践

简介&#xff1a;本资源是一套基于Python实现的单目相机2D/3D目标检测与BEV&#xff08;鸟瞰图&#xff09;可视化完整源码方案&#xff0c;面向高校学生、毕业设计与课程设计开发者及计算机视觉初学者&#xff0c;解决单目图像中目标定位、深度估计、三维框回归及空间布局可视…

作者头像 李华
网站建设 2026/8/31 17:17:07

399美元开源机器人Microduck:从复现到自研的完整指南

Hugging Face 近期发布了一款定价 399 美元的开源机器人 Microduck。这个价格放在机器人硬件领域并不算高&#xff0c;很多工业级关节模组单只价格就超过这个数字。真正值得关注的不是单个产品&#xff0c;而是它背后的趋势&#xff1a;一个以 AI 模型和数据集起家的开源社区&a…

作者头像 李华
网站建设 2026/8/31 17:13:40

Jetpack Compose 核心交互组件:输入框、按钮与 Snackbar 实战指南

这次我们来看 Jetpack Compose 里最常用的三个交互组件&#xff1a;输入框、按钮、Snackbar。这是“Jetpack Compose 安卓声明式 UI 开发”系列的第 7 篇&#xff0c;主题很聚焦&#xff0c;但内容并不浅。Compose 已经成了 Android 官方主推的 UI 开发方式&#xff0c;如果你还…

作者头像 李华