从传感器到LCD:手把手教你用51单片机和HX711打造一个高精度电子秤(附完整代码)
从传感器到LCD:51单片机与HX711构建高精度电子秤全流程实战
在创客圈和电子设计课堂中,电子秤项目一直是最能体现硬件与软件结合能力的经典案例。不同于市面上成熟的商业产品,自己动手搭建电子秤不仅能深入理解传感器原理、信号调理电路和嵌入式编程的精髓,更能根据需求灵活调整功能。本文将用最通俗的语言,带你从零开始完成一个量程2kg、精度±2g的实用电子秤,所有代码和电路都可直接复现。
1. 硬件选型与电路搭建
1.1 核心器件选型指南
称重传感器的选择直接影响系统精度。对于0-2kg量程,推荐使用铝合金悬臂梁结构的应变式传感器,其典型参数如下:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 额定载荷 | 2kg | 最大承重能力 |
| 灵敏度 | 1.0±0.15mV/V | 每伏激励电压对应的输出毫伏 |
| 非线性度 | ≤0.03%F.S. | 全量程范围内的线性误差 |
| 重复性 | ≤0.03%F.S. | 多次测量的稳定性 |
| 输入阻抗 | 405±10Ω | 电桥输入电阻 |
HX711模块作为ADC核心,其优势在于:
- 24位高精度AD转换
- 内置可编程增益放大器(PGA)
- 集成稳压电源(可直接给传感器供电)
- 典型电路仅需4个外围元件
1.2 电路连接详解
完整的系统连接示意图如下:
[传感器] │ ├── E+ (红) → HX711 E+ ├── E- (黑) → HX711 E- ├── S+ (绿) → HX711 A+ └── S- (白) → HX711 A- [HX711] │ ├── DT → 单片机P3^2 ├── SCK → 单片机P3^3 └── VCC → 5V [LCD1602] │ ├── RS → P2^0 ├── RW → GND ├── EN → P2^1 └── D4-D7 → P0^4-P0^7注意:传感器线色可能因厂家不同而异,务必以说明书为准。若出现读数反向(加载时数值减小),只需交换S+和S-接线。
2. HX711驱动开发
2.1 底层通信协议实现
HX711采用特殊的同步串行协议,其时序要求严格:
// 引脚定义 sbit HX711_DOUT = P3^2; sbit HX711_SCK = P3^3; // 读取32位原始数据(实际使用24位) long HX711_Read() { long count = 0; while(HX711_DOUT); // 等待数据就绪 for(char i=0; i<24; i++) { HX711_SCK = 1; count <<= 1; HX711_SCK = 0; if(HX711_DOUT) count++; } // 设置下次转换的通道和增益 HX711_SCK = 1; _nop_(); HX711_SCK = 0; return count ^ 0x800000; // 补码转换 }2.2 数据处理与滤波算法
原始AD值需要经过多重处理:
移动平均滤波:消除瞬时干扰
#define FILTER_SIZE 5 long filter_buf[FILTER_SIZE]; long Get_Filtered_Value() { static char index = 0; filter_buf[index++] = HX711_Read(); if(index >= FILTER_SIZE) index = 0; long sum = 0; for(char i=0; i<FILTER_SIZE; i++) { sum += filter_buf[i]; } return sum / FILTER_SIZE; }校准参数计算:
- 空载时读取AD值(offset)
- 放置已知重量(如500g砝码)读取AD值
- 计算比例系数:scale = (AD_with_weight - AD_zero) / weight
3. 称重核心算法实现
3.1 重量计算公式优化
实际应用中需考虑非线性补偿,推荐使用分段线性化处理:
float Calculate_Weight(long ad_value) { static float scale = 0.00025f; // 校准获得 static long offset = 80000L; // 空载AD值 float weight = (ad_value - offset) * scale; // 分段补偿(根据实测数据调整) if(weight > 1000) { weight *= 0.998; } else if(weight > 500) { weight *= 0.999; } return weight > 0 ? weight : 0; }3.2 高级功能实现
去皮功能:
long tare_offset = 0; void Tare() { tare_offset = Get_Filtered_Value(); } float Get_Net_Weight() { return Calculate_Weight(Get_Filtered_Value() - tare_offset); }单位价格计算:
float price_per_kg = 10.0f; // 示例单价 float Calculate_Price(float weight) { return weight * price_per_kg / 1000; }4. LCD显示与用户交互
4.1 1602液晶驱动优化
采用4位数据模式节省IO口,关键显示函数:
void LCD_ShowWeight(float w) { char buf[16]; sprintf(buf, "Weight:%6.1fg", w); LCD_Write_String(0, 0, buf); sprintf(buf, "Price: $%5.2f", Calculate_Price(w)); LCD_Write_String(0, 1, buf); }4.2 按键功能设计
典型矩阵按键布局与扫描逻辑:
[ 去皮 ] [ 单价+ ] [ 单价- ] [ 累计 ] [ 单位 ] [ 清零 ]void Key_Scan() { static char last_key = 0; char key = Get_Key(); if(key && (key != last_key)) { switch(key) { case 1: Tare(); break; case 2: price_per_kg += 0.5; break; case 3: price_per_kg -= 0.5; break; // 其他功能键... } } last_key = key; }5. 系统校准与调试技巧
5.1 三步校准法
- 零点校准:空载时长按"去皮"键3秒
- 线性校准:
- 放置500g标准砝码
- 通过按键输入实际重量值
- 满量程验证:用2kg砝码检查读数
5.2 常见问题排查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 读数不稳定 | 电源干扰/机械振动 | 增加滤波电容/加固结构 |
| 加载无变化 | 传感器接线错误 | 检查电桥连接 |
| 显示值漂移 | 温度影响 | 预热5分钟后再校准 |
| 负值 | 传感器受力方向反 | 调整安装方向或交换S+/S- |
6. 完整工程代码架构
项目采用模块化设计,主要文件结构:
/main.c // 主循环与调度 /hx711.c // 称重驱动 /lcd1602.c // 显示驱动 /key.c // 按键处理 /scale.c // 称重算法 /config.h // 参数配置主程序框架示例:
void main() { LCD_Init(); HX711_Init(); while(1) { float weight = Get_Net_Weight(); LCD_ShowWeight(weight); Key_Scan(); DelayMs(200); } }在调试过程中发现,HX711的采样速率设置为10Hz时抗干扰性更好,可通过在初始化后发送额外的时钟脉冲来配置:
void HX711_Set_Rate(char rate) { // rate: 0=10Hz, 1=80Hz HX711_Read(); // 丢弃第一次读数 for(char i=0; i<rate+24; i++) { HX711_SCK = 1; _nop_(); HX711_SCK = 0; } }对于需要更高精度的场合,建议:
- 使用独立稳压电源给传感器供电
- 在程序中增加温度补偿算法
- 采用三点校准法(空载、半量程、满量程)
