1. 项目概述
在工业称重、物流计量和家用称重等场景中,高精度电子秤的需求日益增长。传统10位或12位ADC的分辨率往往难以满足精确称重的要求,而24位ADC则能提供更高的精度和稳定性。本项目基于STM32F103C8T6微控制器和HX711 24位ADC芯片,设计并实现了一个高精度电子秤系统。
这个项目最吸引我的地方在于它完美结合了硬件设计和软件算法的优势。HX711作为一款专为称重传感器设计的ADC芯片,内置低噪声放大器,支持可编程增益(128/64/32),仅需两根GPIO线即可与STM32通信。而STM32F103C8T6作为一款性价比极高的ARM Cortex-M3内核微控制器,提供了足够的处理能力来实现各种软件滤波算法。
2. 硬件设计与准备
2.1 核心器件选型
在设计高精度电子秤时,器件选型直接影响最终的性能表现。经过多次测试和比较,我确定了以下核心器件清单:
| 器件名称 | 数量 | 选型理由 |
|---|---|---|
| STM32F103C8T6开发板 | 1块 | 72MHz主频,64KB Flash,20KB RAM,性价比高,资源丰富 |
| HX711模块 | 1块 | 24位高精度ADC,内置低噪声放大器,专为称重传感器设计 |
| 桥式称重传感器(5kg量程) | 1个 | 5kg量程适合大多数应用场景,灵敏度2.0mV/V,非线性度±0.03%FS |
| USB-TTL模块(CH340) | 1块 | 用于程序下载和串口调试,稳定性好 |
| 杜邦线 | 若干 | 建议使用优质镀金杜邦线,减少接触电阻 |
| 5V稳压电源 | 1个 | 建议使用线性稳压电源,纹波小于10mV,确保ADC参考电压稳定 |
提示:称重传感器的选择尤为关键。在实际项目中,我发现5kg量程的传感器在1-4kg范围内线性度最好,精度最高。如果测量范围较小,可以考虑选择2kg量程的传感器以获得更好的分辨率。
2.2 硬件原理详解
2.2.1 称重传感器工作原理
桥式称重传感器的核心是惠斯通电桥结构,由四个应变片电阻组成。当受到外力作用时,弹性体发生形变,导致应变片的电阻值发生变化:
- 两个电阻值增加(R+ΔR)
- 两个电阻值减小(R-ΔR)
这种变化打破了电桥的平衡,在输出端产生一个与外力成正比的差分电压信号。典型值为1-2mV/V,也就是说,对于一个5V激励电压,满量程输出仅为5-10mV。
HX711芯片内置的可编程增益放大器(PGA)将这个微小信号放大128/64/32倍后,再由24位Δ-Σ ADC转换为数字信号。这种架构的优势在于:
- 高共模抑制比(CMRR),有效抑制干扰
- 积分型ADC具有优异的噪声性能
- 可编程增益适应不同灵敏度的传感器
2.2.2 HX711与STM32通信机制
HX711采用简单的二线制串行接口:
- PD_SCK:时钟输入,由STM32控制
- DOUT:数据输出,连接到STM32的GPIO
通信时序分为三个阶段:
- 等待阶段:STM32持续检测DOUT引脚,当DOUT变低表示数据就绪
- 数据采集阶段:STM32产生24个时钟脉冲,在每个脉冲的上升沿读取DOUT状态
- 增益选择阶段:额外的1-3个脉冲选择下次转换的增益和通道
这种设计巧妙地将数据采集和配置结合在一起,减少了IO占用。在实际调试中,我发现时钟脉冲的宽度至少需要0.2μs,对应STM32的72MHz主频下,延时函数需要精心设计。
2.3 硬件连接实战
2.3.1 电源系统设计
稳定的电源是高精度测量的基础。我采用了以下电源方案:
- 使用LM7805线性稳压器提供5V主电源
- 在每个IC的电源引脚就近放置0.1μF去耦电容
- 模拟部分(称重传感器)和数字部分(STM32)的电源通过磁珠隔离
注意:共地处理至关重要!必须确保STM32、HX711和称重传感器的GND可靠连接。我曾遇到因接地不良导致数据跳变±50g的情况,后来通过星型接地解决了问题。
2.3.2 信号线连接细节
称重传感器通常有四根线:
- 激励正(红) → HX711 E+
- 激励负(黑) → HX711 E-
- 信号正(白) → HX711 A+
- 信号负(绿) → HX711 A-
如果发现输出信号异常,可以尝试交换A+/A-或E+/E-的连接。在我的项目中,曾遇到传感器线序与模块标注不符的情况,通过交换线序解决了问题。
3. 软件设计与实现
3.1 开发环境配置
推荐使用以下工具链组合:
- STM32CubeMX v6.5.0:图形化配置工具,自动生成初始化代码
- Keil MDK-ARM v5.36:功能强大的ARM开发环境
- ST-Link V2:调试和程序下载
- Tera Term或Putty:串口调试工具
安装时需要注意:
- STM32CubeMX需要安装对应的STM32F1系列HAL库
- Keil需要安装STM32F1的Device Family Pack
- 确保USB转串口驱动正确安装
3.2 STM32CubeMX关键配置
3.2.1 时钟树配置
精确的时钟对时序敏感的HX711驱动至关重要。我的配置如下:
- HSE(外部高速时钟):8MHz晶体振荡器
- PLL倍频:9倍
- 系统时钟(SYSCLK):72MHz
- AHB总线时钟:72MHz
- APB1总线时钟:36MHz
- APB2总线时钟:72MHz
这样配置可以确保:
- GPIO操作速度最大化
- USART波特率计算精确
- 延时函数精度高
3.2.2 GPIO配置
HX711只需要两个GPIO:
- PB0(PD_SCK):推挽输出,无上拉/下拉
- PB1(DOUT):输入模式,上拉电阻使能
USART1配置:
- 波特率:115200
- 数据位:8
- 停止位:1
- 无校验
- 无硬件流控
3.3 HX711驱动开发
3.3.1 精确延时实现
HX711的时序要求严格,需要微秒级延时。在72MHz系统时钟下,我实现的延时函数如下:
c复制void HX711_Delay_us(uint32_t us)
{
uint32_t delay = (72 * us) / 8;
while(delay--) {
__NOP();
}
}
这个函数通过计算CPU周期数实现精确延时。实测误差小于5%,完全满足HX711的时序要求。
3.3.2 数据采集核心代码
HX711数据采集的关键是正确处理24位补码数据:
c复制int32_t HX711_Read_RawData(void)
{
int32_t raw_data = 0;
// 等待数据就绪
while(HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN));
// 读取24位数据
for(uint8_t i=0; i<24; i++) {
HAL_GPIO_WritePin(HX711_PD_SCK_PORT, HX711_PD_SCK_PIN, GPIO_PIN_SET);
HX711_Delay_us(1);
raw_data <<= 1;
if(HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN)) {
raw_data++;
}
HAL_GPIO_WritePin(HX711_PD_SCK_PORT, HX711_PD_SCK_PIN, GPIO_PIN_RESET);
HX711_Delay_us(1);
}
// 选择128增益
HAL_GPIO_WritePin(HX711_PD_SCK_PORT, HX711_PD_SCK_PIN, GPIO_PIN_SET);
HX711_Delay_us(1);
HAL_GPIO_WritePin(HX711_PD_SCK_PORT, HX711_PD_SCK_PIN, GPIO_PIN_RESET);
// 处理24位补码
if(raw_data & 0x800000) {
raw_data |= 0xFF000000;
}
return raw_data;
}
这段代码实现了完整的HX711数据采集过程,包括:
- 等待数据就绪
- 24位数据读取
- 增益选择
- 补码转换
3.4 软件滤波算法实现
3.4.1 中值滤波
中值滤波能有效去除脉冲干扰:
c复制int32_t HX711_Filter_Median(int32_t *buf, uint8_t len)
{
// 冒泡排序
for(uint8_t i=0; i<len-1; i++) {
for(uint8_t j=0; j<len-i-1; j++) {
if(buf[j] > buf[j+1]) {
int32_t temp = buf[j];
buf[j] = buf[j+1];
buf[j+1] = temp;
}
}
}
return buf[len/2];
}
3.4.2 滑动平均滤波
滑动平均滤波使数据更平滑:
c复制int32_t HX711_Filter_MovingAvg(int32_t new_data, int32_t *buf, uint8_t len, uint8_t *index)
{
buf[*index] = new_data;
*index = (*index + 1) % len;
int32_t sum = 0;
for(uint8_t i=0; i<len; i++) {
sum += buf[i];
}
return sum / len;
}
3.4.3 中值平均滤波
结合中值和平均滤波的优点:
c复制int32_t HX711_Filter_MedianAvg(int32_t *buf, uint8_t len)
{
int32_t temp_buf[10];
memcpy(temp_buf, buf, len*sizeof(int32_t));
// 先中值滤波
HX711_Filter_Median(temp_buf, len);
// 去掉首尾极值后平均
int32_t sum = 0;
for(uint8_t i=1; i<len-1; i++) {
sum += temp_buf[i];
}
return sum / (len-2);
}
在实际测试中,中值平均滤波表现最佳,既能有效抑制突发干扰,又能保持数据的平滑性。
4. 系统校准与测试
4.1 校准原理与方法
校准是高精度称重的关键步骤,需要两个参数:
- 零点偏移(offset):空载时的ADC原始值
- 校准系数(calib_factor):单位重量对应的ADC变化量
校准过程分为两步:
- 空载校准:获取零点偏移
- 加载已知重量校准:获取校准系数
4.2 校准代码实现
c复制void HX711_Calibrate(float *calib_factor, int32_t *offset)
{
int32_t raw_buf[10];
// 零点校准
printf("空载校准中...\r\n");
for(uint8_t i=0; i<10; i++) {
raw_buf[i] = HX711_Read_RawData();
HAL_Delay(100);
}
*offset = HX711_Filter_MedianAvg(raw_buf, 10);
// 加载校准
printf("请放置1000g砝码...\r\n");
HAL_Delay(5000);
for(uint8_t i=0; i<10; i++) {
raw_buf[i] = HX711_Read_RawData();
HAL_Delay(100);
}
int32_t calib_raw = HX711_Filter_MedianAvg(raw_buf, 10);
*calib_factor = (calib_raw - *offset) / 1000.0;
printf("校准完成: offset=%ld, calib_factor=%.2f\r\n", *offset, *calib_factor);
}
4.3 重量转换
将ADC原始值转换为重量值:
c复制float HX711_Convert_Weight(int32_t filtered_data, int32_t offset, float calib_factor)
{
float weight = (filtered_data - offset) / calib_factor;
return (weight < 0.1 && weight > -0.1) ? 0.0 : weight;
}
5. 系统集成与优化
5.1 主程序架构
c复制int main(void)
{
// 初始化
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
// 校准(首次运行需要)
float calib_factor = 1234.56f; // 替换为实际校准值
int32_t offset = -123456; // 替换为实际偏移值
// HX711_Calibrate(&calib_factor, &offset);
// 数据缓冲区
int32_t raw_buf[10];
uint8_t avg_index = 0;
while(1) {
// 采集数据
for(uint8_t i=0; i<10; i++) {
raw_buf[i] = HX711_Read_RawData();
HAL_Delay(50);
}
// 滤波处理
int32_t filtered_data = HX711_Filter_MedianAvg(raw_buf, 10);
// 转换为重量
float weight = HX711_Convert_Weight(filtered_data, offset, calib_factor);
// 输出结果
printf("重量: %.2f g\r\n", weight);
HAL_Delay(200);
}
}
5.2 性能优化技巧
-
采样率优化:HX711的数据输出速率与增益设置有关。在128增益下,最高速率为10SPS;在32增益下可达80SPS。根据应用需求权衡精度和速度。
-
滤波参数调整:
- 对于静态称重(如厨房秤),可使用较大的滤波窗口(15-20个样本)
- 对于动态称重(如生产线),应减小窗口(5-10个样本)以提高响应速度
-
温度补偿:在精度要求极高的场合,可以增加温度传感器,根据温度变化调整校准参数。
-
低功耗设计:通过HX711的待机模式(发送≥25个时钟脉冲)和STM32的低功耗模式,可大幅降低系统功耗。
6. 常见问题排查
6.1 数据不稳定问题
现象:重量显示不断跳动,幅度超过±1g
可能原因:
- 电源噪声过大
- 接地不良
- 机械振动影响
- 电磁干扰
解决方案:
- 使用线性稳压电源
- 检查所有接地连接,确保单点接地
- 增加机械减震措施
- 远离电机、变频器等干扰源
6.2 校准失败问题
现象:校准后测量结果偏差大
可能原因:
- 校准砝码不准确
- 校准过程中有外力干扰
- 传感器线性度差
解决方案:
- 使用经过认证的标准砝码
- 确保校准环境稳定,无振动、气流
- 选择更高精度的称重传感器
6.3 通信失败问题
现象:DOUT始终为高电平,无法读取数据
可能原因:
- HX711供电异常
- 传感器连接错误
- HX711模块损坏
解决方案:
- 检查HX711的VCC和GND连接
- 确认传感器线序正确
- 更换HX711模块测试
7. 项目扩展与进阶
7.1 多传感器应用
通过多路复用器(如CD4051)可以实现多个称重传感器的测量。典型应用包括:
- 多点称重平台
- 重心测量系统
- 对称结构受力分析
7.2 无线传输功能
增加蓝牙(HC-05)或WiFi(ESP8266)模块,实现:
- 无线数据显示
- 手机APP监控
- 云端数据记录
7.3 商业级产品开发
若要将此设计产品化,需要考虑:
- 外壳设计与机械保护
- 防潮防尘处理
- 计量认证(如OIML)
- 用户界面设计(按键、LCD等)
在实际项目中,我发现称重系统的精度不仅取决于电路设计,机械结构的影响同样重要。特别是传感器的安装方式、受力点的位置、平台的刚性等,都会显著影响测量结果。建议在机械设计阶段就考虑这些因素,避免后期调试困难。
