在电子秤和压力测量项目中,HX711作为一款24位高精度模数转换芯片,因其性价比高、接口简单而广受欢迎。但许多开发者在使用过程中都会遇到一个共同难题——读数不稳定。数据跳变不仅影响测量精度,更会直接导致最终产品无法通过验收。本文将深入分析问题根源,提供一套经过工业验证的完整解决方案。
电源噪声是影响HX711性能的首要因素。许多初学者习惯使用手机充电头或开发板上的USB电源为HX711供电,这恰恰是数据不稳定的罪魁祸首。手机充电头设计目标是快速充电而非精密测量,其输出纹波可能高达200mV以上,远超HX711的容忍范围。
我们实测了四种常见供电方案下的HX711输出波动情况:
| 供电方案 | 纹波电压(mV) | 数据波动范围(LSB) | 成本 | 适用场景 |
|---|---|---|---|---|
| 手机充电头 | 150-300 | ±500 | 低 | 不推荐 |
| 7805线性稳压 | 50-100 | ±200 | 低 | 低精度临时测试 |
| LM1117-3.3V | 10-30 | ±50 | 中 | 一般精度应用 |
| LT3042超低噪声 | <3 | ±10 | 高 | 高精度测量系统 |
从测试数据可见,专为低噪声设计的LDO如LT3042能提供最佳性能,但成本较高。对于大多数应用,采用普通LDO如AMS1117-3.3V配合适当的滤波电路即可满足要求。
提示:即使使用优质LDO,也务必检查其PSRR(电源抑制比)参数。在100Hz时PSRR应大于60dB才能有效抑制低频噪声。
HX711的数据读取时序看似简单,实则暗藏玄机。原始文章中提到的"查询式读取"是稳定工作的关键,但实际实现中还有更多优化空间。
HX711的数据输出速率典型值为10Hz(100ms一次),但这个值会受温度、电源质量等因素影响而变化。如果固件采用固定延时方式读取,极可能遇到以下情况:
c复制// 错误示例:定时读取方式
void HX711_Read(void) {
delay_ms(100); // 固定延时不可靠
// 读取数据代码...
}
以下为经过生产验证的读取函数,增加了超时处理和错误重试机制:
c复制#define HX711_TIMEOUT 100 // 100ms超时
int32_t HX711_ReadData(void) {
uint32_t count = 0;
uint32_t timeout = 0;
// 等待数据就绪
while (HX711_DOUT_IS_HIGH()) {
if (++timeout >= HX711_TIMEOUT)
return HX711_ERROR_TIMEOUT;
delay_ms(1);
}
// 读取24位数据
for (uint8_t i = 0; i < 24; i++) {
HX711_SCK_HIGH();
delay_us(1);
count <<= 1;
if (HX711_DOUT_IS_HIGH()) count++;
HX711_SCK_LOW();
delay_us(1);
}
// 设置下次转换的增益和通道
for (uint8_t i = 0; i < 1; i++) {
HX711_SCK_HIGH();
delay_us(1);
HX711_SCK_LOW();
delay_us(1);
}
// 符号扩展转换
if (count & 0x800000) count |= 0xFF000000;
return (int32_t)count;
}
这段代码改进包括:
在实际应用中,建议采用以下错误处理策略:
c复制typedef enum {
HX711_OK = 0,
HX711_ERROR_TIMEOUT,
HX711_ERROR_INVALID_DATA,
HX711_ERROR_HARDWARE
} HX711_Status;
HX711_Status HX711_GetWeight(int32_t* weight) {
static int32_t last_valid = 0;
int32_t raw = HX711_ReadData();
if (raw == HX711_ERROR_TIMEOUT) {
HX711_Reset();
return HX711_ERROR_TIMEOUT;
}
// 数据合理性检查
if (abs(raw - last_valid) > MAX_ALLOWED_DELTA) {
return HX711_ERROR_INVALID_DATA;
}
*weight = raw;
last_valid = raw;
return HX711_OK;
}
获得稳定的原始数据只是第一步,如何将其转换为精确的物理量同样关键。原始文章中提到的线性关系(y=kx+b)是理论基础,但实际应用需要考虑更多因素。
两点校准(空载和满量程)是最基本方法,但对于高精度应用远远不够。推荐采用五点校准法:
通过最小二乘法计算最佳拟合直线,公式为:
code复制weight = (raw - offset) * scale
其中offset和scale通过以下矩阵运算得到:
code复制| n Σx | | offset | | Σy |
| | | | = | |
| Σx Σx² | | scale | | Σxy |
即使电源和读取都很稳定,环境噪声仍会导致数据微小波动。常用数字滤波算法效果对比:
| 算法 | 响应速度 | 内存占用 | 滤波效果 | 适用场景 |
|---|---|---|---|---|
| 移动平均 | 慢 | 中 | 一般 | 低频变化信号 |
| 一阶低通 | 可调 | 低 | 较好 | 大多数应用 |
| 中值滤波 | 快 | 高 | 好 | 脉冲噪声环境 |
| 卡尔曼滤波 | 可调 | 中 | 极好 | 动态测量系统 |
推荐实现简单高效的一阶低通滤波器:
c复制float HX711_LowPassFilter(float new_sample, float last_output, float alpha) {
return alpha * new_sample + (1.0 - alpha) * last_output;
}
// 使用示例
float filtered_weight = 0;
float alpha = 0.1; // 取值0.01-0.3,越小滤波越强
void main_loop() {
int32_t raw;
if (HX711_GetWeight(&raw) == HX711_OK) {
float weight = (raw - calib_offset) * calib_scale;
filtered_weight = HX711_LowPassFilter(weight, filtered_weight, alpha);
display_weight(filtered_weight);
}
}
应变片灵敏度会随温度变化,高精度应用需考虑温度补偿。常用方法包括:
以下是一个简单的温度补偿实现框架:
c复制typedef struct {
float scale;
float offset;
float temp_comp_coeff;
float reference_temp;
} HX711_Calibration;
float HX711_ApplyTempCompensation(HX711_Calibration* calib,
float raw_weight,
float current_temp) {
float temp_delta = current_temp - calib->reference_temp;
return raw_weight * (1.0 + calib->temp_comp_coeff * temp_delta);
}
将前述技术整合到一个实际项目中,才能真正检验方案的可靠性。下面分享一个工业电子秤项目的关键设计。
电源子系统:
信号链设计:
code复制应变片 → 仪表放大器(INA128) → 二阶低通滤波(截止频率10Hz) → HX711 → STM32
PCB布局要点:
采用分层架构,模块化设计:
code复制应用层:用户界面、业务逻辑
|
服务层:滤波算法、校准管理、故障诊断
|
驱动层:HX711读写、温度传感器、EEPROM
|
硬件层:STM32 HAL库、RTOS
关键服务实现示例:
c复制typedef struct {
float weight;
HX711_Status status;
float temperature;
uint32_t timestamp;
} WeightMeasurement;
void WeightService_Task(void const* arg) {
HX711_Init();
TempSensor_Init();
while (1) {
WeightMeasurement meas;
meas.status = HX711_GetWeight(&meas.weight);
meas.temperature = TempSensor_Read();
meas.timestamp = HAL_GetTick();
if (meas.status == HX711_OK) {
meas.weight = Filter_Apply(meas.weight);
meas.weight = Calibration_Apply(meas.weight, meas.temperature);
MessageQueue_Send(&meas);
} else {
ErrorHandler_Process(meas.status);
}
osDelay(10);
}
}
为确保每台设备性能一致,建议建立以下测试流程:
电源测试:
基本功能测试:
环境适应性测试:
长期稳定性测试:
注意:生产测试中发现的异常数据应记录详细日志,包括环境参数、电源质量、原始ADC数据等,便于后续分析改进。