简介这份资源面向嵌入式初学者与电子设计爱好者提供一套基于STM32微控制器的电子秤完整工程用于学习称重数据采集、处理与显示的全流程。项目以STM32为核心配合重量传感器与内置ADC完成模拟信号数字化并通过12864液晶屏实时显示重量代码中预留了精度调整空间便于自行优化标定与滤波算法。压缩包共146个文件约1.64MB以36个h头文件与33个c源文件为主体涵盖外设驱动与业务逻辑另有Keil工程文件、编译中间产物及hex固件等结构接近真实开发工程。资源已有3235人学习适合作为课程设计、毕业设计或自学练手参考读者可从中获取传感器采样、A/D转换、显示驱动、低功耗管理及工程组织等实践思路并在此基础上扩展单位切换、过载保护等功能。1. 从一颗 HX711 说起为什么 STM32 做电子秤是门“看起来简单、做起来全是细节”的活如果你手头正好有一块 STM32 最小系统板、一个 5kg 量程的电阻应变片传感器和一个 HX711 模块那你离一台能用的电子秤其实只差“把线接对、把时序写对、把滤波调对”这三步。但真正上手你会发现事情没那么线性HX711 读回来的原始码值会跳、去皮之后零点会漂、砝码放上去读数要等两三秒才稳、串口打印出来的重量小数点后两位一直在抖。这些不是玄学是 24 位 ADC 在低电平信号下的正常表现也是 STM32 电子秤这个方向最值得拆开讲的地方。这份资源围绕的就是“用 STM32 驱动 HX711 采集称重传感器完成重量计算、去皮、校准、超限报警和显示输出”这一整套链路。它适合三类人正在做课程设计或毕设、需要一份能跑通的参考实现的学生想从 51 单片机升级到 STM32、第一次接触 24 位 ADC 时序的嵌入式新手以及手上已经有硬件、但卡在“读数不稳、校准不会、代码跑不通”的从业者。下面按硬件接线、驱动时序、重量换算、滤波校准、避坑排查、进阶技巧的顺序把这份资源拆到能照着复现的程度。2. 硬件链路与 HX711 时序先把“读得到数”这件事做扎实2.1 称重传感器、HX711 与 STM32 的接线逻辑电阻应变片式称重传感器本质是一个惠斯通电桥受力后电桥失衡输出一个毫伏级的差分电压。这个信号太小STM32 自带的 12 位 ADC 直接采基本没戏所以中间必须加一级专用 24 位 ADCHX711 就是干这个的。它内部集成了稳压、 PGA 和 24 位 sigma-delta ADC输出的是串行数据STM32 只需要两根普通 GPIO 就能读。典型接线是传感器四线E、E-、A、A-接 HX711 的对应端子HX711 的 VCC/GND 接 3.3V 或 5VDT数据和 SCK时钟接 STM32 任意两个 GPIO。这里有个新手最容易翻车的点传感器线色不统一红黑绿白对应的不一定是 E/E-/A/A-接反了读数会反向或者直接饱和。常见做法是先按模块丝印接读出来是负值就把 A/A- 对调不要靠猜。// hx711.h —— 引脚宏定义按实际接线改 #define HX711_DT_PORT GPIOB #define HX711_DT_PIN GPIO_Pin_0 #define HX711_SCK_PORT GPIOB #define HX711_SCK_PIN GPIO_Pin_1 // 初始化DT 设为输入SCK 设为推挽输出 void HX711_Init(void) { GPIO_InitTypeDef gpio; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); gpio.GPIO_Pin HX711_DT_PIN; gpio.GPIO_Mode GPIO_Mode_IPU; // 上拉输入DT 空闲时为高 GPIO_Init(HX711_DT_PORT, gpio); gpio.GPIO_Pin HX711_SCK_PIN; gpio.GPIO_Mode GPIO_Mode_Out_PP; // 推挽输出 gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(HX711_SCK_PORT, gpio); GPIO_ResetBits(HX711_SCK_PORT, HX711_SCK_PIN); // SCK 默认拉低 }这段初始化的关键在 DT 用上拉输入。HX711 在数据未准备好时 DT 输出高电平准备好后拉低上拉能保证悬空时不会误判。SCK 默认拉低是因为 HX711 要求 SCK 高电平超过 60us 会进入掉电模式初始化阶段保持低电平最安全。2.2 24 位数据的读取时序与通道增益选择HX711 的读取时序不复杂但时序参数必须卡准。一次完整读取是等 DT 变低然后发 25 到 27 个 SCK 脉冲前 24 个脉冲在上升沿移出数据高位在前第 25 个脉冲决定下一次的通道和增益。脉冲数对应关系是25 个脉冲选通道 A 增益 12826 个选通道 B 增益 3227 个选通道 A 增益 64。电子秤一般用通道 A 增益 128所以发 25 个脉冲。// 读取一次原始值返回 24 位有符号数 long HX711_ReadRaw(void) { long value 0; uint8_t i; // 等待 DT 拉低超时退出防止死等 uint32_t timeout 0; while (GPIO_ReadInputDataBit(HX711_DT_PORT, HX711_DT_PIN) 1) { if (timeout 100000) return 0; // 硬件没接好时不要卡死 } for (i 0; i 24; i) { GPIO_SetBits(HX711_SCK_PORT, HX711_SCK_PIN); __nop(); __nop(); // 短延时保证高电平够宽 value value 1; if (GPIO_ReadInputDataBit(HX711_DT_PORT, HX711_DT_PIN)) value; GPIO_ResetBits(HX711_SCK_PORT, HX711_SCK_PIN); __nop(); __nop(); } // 第 25 个脉冲选通道 A 增益 128 GPIO_SetBits(HX711_SCK_PORT, HX711_SCK_PIN); __nop(); __nop(); GPIO_ResetBits(HX711_SCK_PORT, HX711_SCK_PIN); // 24 位补码转有符号数 if (value 0x800000) value | 0xFF000000; return value; }逻辑上要说明三点。第一超时退出是血泪经验传感器没接或 HX711 没供电时 DT 永远不拉低没有超时整个程序就卡死在这一句。第二__nop()延时是给 SCK 高电平留时间STM32 主频高的时候不加延时可能超过 HX711 的时序上限。第三补码转换不能省24 位数据最高位是符号位不扩展成 32 位有符号数负值会变成很大的正数去皮和校准全乱。3. 从原始码值到克校准系数、去皮与滤波的工程做法3.1 两点校准法算出比例系数HX711 读出来的是 ADC 原始码值不是重量。要变成克需要一个比例系数工程上最稳的是两点校准空载读一次记为零点放一个已知砝码读一次两者差值除以砝码重量就是“每克对应的码值”。typedef struct { long zero_offset; // 空载零点 float scale; // 每克码值 float tare; // 去皮重量 } Scale_t; Scale_t scale {0, 1.0f, 0.0f}; // 采集 N 次取平均降低随机噪声 long HX711_ReadAverage(uint8_t times) { long sum 0; for (uint8_t i 0; i times; i) sum HX711_ReadRaw(); return sum / times; } // 校准空载时调用记录零点 void Scale_CalibrateZero(void) { scale.zero_offset HX711_ReadAverage(20); } // 校准放已知砝码后调用weight_g 为砝码克数 void Scale_CalibrateWeight(float weight_g) { long raw HX711_ReadAverage(20); scale.scale (float)(raw - scale.zero_offset) / weight_g; } // 读取重量克 float Scale_GetWeight(void) { long raw HX711_ReadAverage(10); return (float)(raw - scale.zero_offset) / scale.scale - scale.tare; }参数上ReadAverage的次数不是越多越好。20 次平均能把随机噪声压下去但响应变慢10 次是响应和稳定的折中。校准砝码建议选量程的 50% 到 80%比如 5kg 量程用 2kg 或 3kg 砝码太轻的相对误差大太重的接近满量程线性度会变差。scale系数算出来一般是几百到几千码值每克如果算出来是负数说明传感器 A/A- 接反了。3.2 去皮、滑动滤波与显示刷新节奏去皮就是把当前重量记成tare之后所有读数都减掉它。但去皮有个坑如果去皮时秤上还有残留振动tare会带误差后面所有读数都偏。常见做法是去皮前先连续读几次等波动小于阈值再记录。滤波方面一阶滑动平均够用但遇到“放上去要等两三秒才稳”的问题往往是平均次数太多加上没有做变化检测。更实用的做法是稳定时用大平均次数保证精度检测到重量突变时切小平均次数快速响应。#define FILTER_LEN 8 static float buf[FILTER_LEN] {0}; static uint8_t idx 0; float Scale_GetFiltered(void) { buf[idx] Scale_GetWeight(); idx (idx 1) % FILTER_LEN; float sum 0; for (uint8_t i 0; i FILTER_LEN; i) sum buf[i]; float avg sum / FILTER_LEN; // 突变检测与均值差超过 50g 认为重量在快速变化 float diff Scale_GetWeight() - avg; if (diff 50.0f || diff -50.0f) return Scale_GetWeight(); // 快速响应不滤波 return avg; }显示刷新不要跟着采样走。HX711 默认 10Hz 或 80Hz 输出速率10Hz 时每 100ms 一个数据显示每 200 到 300ms 刷一次就够刷太快数字跳得人心慌。串口打印同理建议 500ms 一次方便观察趋势又不刷屏。4. 避坑与排查电子秤读数不稳、校准失败的五个真实原因4.1 读数一直跳最后一位停不下来现象是空载时读数在正负几十克之间波动放上砝码后小数点后两位一直变。原因通常有三个供电纹波大、HX711 的 AVDD 和 DVDD 没做退耦、或者传感器信号线太长引入了工频干扰。解决上先在 HX711 电源脚并 10uF 和 0.1uF 电容信号线尽量短并远离电机和继电器软件上把平均次数从 10 提到 20基本能压到正负 2g 以内。4.2 校准后放砝码读数差很多现象是零点校准正常放 1kg 砝码显示 800g 或 1200g。原因多半是校准砝码太轻或者校准时秤体没放平。解决是换用量程 50% 以上的砝码重新校准校准前用水平泡确认秤体水平四个角受力均匀。如果还是差检查scale系数是不是用了整数除法被截断(raw - zero)要强制转 float 再除。4.3 HX711 读出来全是 0 或全是 0xFFFFFF现象是原始码值恒定不变或者一直是最大值。原因是 DT 和 SCK 接反、HX711 没供电、或者传感器没接。排查顺序是先量 HX711 的 VCC 有没有电压再用万用表测 DT 在空闲时是不是高电平最后确认 SCK 有没有脉冲输出。接反的情况最常见DT 和 SCK 对调后立刻正常。4.4 去皮之后过一会儿零点自己漂了现象是刚去皮显示 0过几分钟变成 5g 或 -3g。原因是温漂应变片和 HX711 都有温度系数环境温度变化几度零点就会移。解决是开机预热 5 到 10 分钟再校准软件上加一个“自动零点跟踪”当读数在零点附近且持续稳定超过 5 秒缓慢把零点往当前值靠。注意跟踪范围要限制在正负 10g 内否则放小砝码会被当成漂移吃掉。4.5 超过量程后读数不线性甚至卡死现象是接近满量程时读数增长变慢或者直接停在某个值。原因是传感器弹性体进入非线性区或者 HX711 输入饱和。解决是选量程时留 20% 余量5kg 传感器实际用到 4kg 以内软件上加超限判断超过量程 90% 就报警并停止更新显示避免用户继续加载。5. 进阶技巧把电子秤做成能长期稳定跑的成品5.1 用定时器中断做采样节拍别在 while 里裸读裸读的问题是采样间隔不均匀主循环里其他任务一多HX711 读取就被拉长滤波效果变差。更稳的做法是用一个 10ms 或 100ms 的定时器中断置标志位主循环检测标志再读保证采样节拍固定。HX711 的 DT 引脚也可以配成外部中断数据准备好自动触发CPU 不用轮询。volatile uint8_t sample_flag 0; // 定时器中断里每 100ms 置一次标志 void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); sample_flag 1; } } // 主循环 while (1) { if (sample_flag) { sample_flag 0; float w Scale_GetFiltered(); if (w OVERLOAD_THRESHOLD) { Buzzer_On(); LCD_ShowString(0, 0, OVERLOAD); } else { Buzzer_Off(); LCD_ShowFloat(0, 0, w); } } }5.2 校准参数存 Flash掉电不丢每次上电重新校准不现实把zero_offset和scale存到 STM32 内部 Flash 的最后一页上电先读读不到再用默认值。写 Flash 前要解锁写完锁定注意 Flash 写入前必须先擦除整页。常见做法是存一个结构体加一个校验字校验不过就恢复默认避免半写状态导致参数错乱。参数建议存储位置说明zero_offsetFlash 末页偏移 0空载零点long 类型scaleFlash 末页偏移 4每克码值float 类型tareFlash 末页偏移 8去皮重量float 类型checksumFlash 末页偏移 12前三项异或校验5.3 验证方法用标准砝码做三点复核写完别急着收工拿标准砝码做三点复核空载、半量程、满量程各测三次看误差是否在正负 0.5% 以内。如果半量程准、满量程偏小是传感器非线性如果三点都偏同一方向是scale系数没校好。我一般还会在秤上放一个已知重量的手机或水杯做快速验证比翻砝码方便。从那以后我每次做完电子秤都会先空载预热十分钟、再校准、再三点复核最后连续跑两小时看零点漂移。这套流程走完基本不会再出现“实验室能用、拿回去就飘”的翻车。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?