1. 项目背景与需求分析
在无人售货机、工业称重等场景中,高精度称重模块是关键部件。传统方案常面临三个痛点:一是普通电阻应变片模块精度不足(20kg量程误差±5g);二是通信接口在复杂电磁环境下稳定性差;三是低温漂性能难以保证。针对这些问题,我们设计了一款基于STM32F103C8T6的高精度称重模块,主要技术指标如下:
- 核心参数:双通道0.1g精度,12-24V宽压输入,CAN通信接口
- 关键突破:采用HX712集成方案实现±2ppm/℃低温漂,通过软硬件协同设计解决干扰问题
- 成本优势:BOM成本控制在30元以内,仅为市面同类产品的1/3
提示:该设计特别适合需要多节点组网的场景,如无人售货机集群、生产线称重工位等。
2. 硬件架构设计解析
2.1 主控选型与资源配置
选择STM32F103C8T6作为主控芯片主要基于三点考量:
- 性能匹配:64KB Flash和20KB RAM空间足够运行双路ADC采样、CAN协议栈及校准算法
- 生态优势:该型号资料丰富,社区支持完善,可降低开发风险
- 成本控制:批量采购单价约5元,性价比极高
具体引脚分配:
- PB0/PB1:通道1传感器接口
- PB2/PB3:通道2传感器接口
- PA11/PA12:CAN通信接口
- PB4/PB5:HX712时钟控制
2.2 称重传感器接口设计
传统方案对比:
| 方案 | 分辨率 | 温漂 | 成本 | 稳定性 |
|---|---|---|---|---|
| HX711分立方案 | 24位 | ±10ppm/℃ | 低 | 一般 |
| ADS1230 | 24位 | ±5ppm/℃ | 高 | 好 |
| HX712集成方案 | 24位 | ±2ppm/℃ | 中 | 优 |
最终选用HX712的关键原因:
- 内部集成PGA、基准源和温度补偿电路
- 自动切换通道功能简化软件设计
- 支持128倍增益,适合小信号放大
电路设计要点:
- 传感器供电采用独立LDO(ASM1117-3.3V)
- 信号线采用双绞线+屏蔽层处理
- 每路配置0.1μF去耦电容
2.3 电源系统设计
三级电源架构确保稳定性:
- 第一级:LM2596S-5.0将12-24V输入降至5V(效率92%)
- 第二级:ASM1117-3.3V为数字电路供电
- 第三级:REF3030提供3.0V基准电压
实测纹波数据:
- 24V输入时:5V输出纹波<50mV
- 12V输入时:3.3V输出纹波<20mV
3. 软件实现关键技术
3.1 HX712驱动优化
原始数据采集流程存在两个问题:
- 直接读取会导致±3LSB抖动
- 通道切换时出现数据异常
改进方案:
c复制#define SAMPLE_TIMES 5 // 采样次数
long HX712_ReadAvgData(uint8_t ch) {
long sum = 0;
int valid_count = 0;
for(int i=0; i<SAMPLE_TIMES; i++){
long val = HX712_ReadData(ch);
if(abs(val - last_val[ch]) < 100){ // 剔除突变值
sum += val;
valid_count++;
}
last_val[ch] = val;
delay_us(100);
}
return valid_count>0 ? sum/valid_count : 0;
}
3.2 CAN通信可靠性增强
波特率配置验证过程:
- 理论计算:36MHz/(9*(1+6+1))=500kbps
- 实测方法:发送10万帧测试数据,统计误码率
- 优化结果:
- 添加120Ω终端电阻后,误码率从0.1%降至0.001%
- 增加重传机制后,通信成功率>99.99%
通信协议设计:
c复制#pragma pack(1)
typedef struct {
uint16_t id; // 帧ID
uint8_t cmd; // 指令类型
uint8_t ch; // 通道号
float value; // 重量值/校准值
uint16_t crc; // CRC校验
} WeightFrame_t;
#pragma pack()
3.3 自适应校准算法
传统校准方法的局限:
- 固定校准系数无法适应温度变化
- 人工校准效率低下
改进方案:
- 建立温度-灵敏度查找表
- 实时监测环境温度(通过MCU内置传感器)
- 动态调整校准系数
算法实现:
c复制float GetDynamicFactor(uint8_t ch, float temp) {
static const float temp_table[] = {-10,0,25,50,75};
static const float factor_table[] = {1234.5,1230.0,1225.0,1220.0,1215.0};
// 二分查找最近温度点
int left = 0, right = 4;
while(left < right){
int mid = (left+right)/2;
if(temp_table[mid] < temp) left = mid+1;
else right = mid;
}
// 线性插值
float factor = factor_table[left] +
(temp-temp_table[left])*(factor_table[left+1]-factor_table[left])/
(temp_table[left+1]-temp_table[left]);
return factor;
}
4. 生产测试方案
4.1 校准工艺流程
三步校准法:
- 零点校准:空载状态下采集100次数据取平均
- 满量程校准:加载20kg标准砝码,记录AD值
- 线性度验证:用5kg、10kg、15kg砝码验证中间点
测试数据示例:
| 测试点 | 理论值(kg) | 实测值(kg) | 误差(g) |
|---|---|---|---|
| 零点 | 0.000 | 0.002 | +2 |
| 5kg | 5.000 | 4.998 | -2 |
| 10kg | 10.000 | 10.003 | +3 |
| 15kg | 15.000 | 14.997 | -3 |
| 20kg | 20.000 | 19.999 | -1 |
4.2 老化测试方案
加速老化测试参数:
- 温度循环:-20℃~60℃,每2小时一个周期
- 振动测试:10-500Hz随机振动,3轴各30分钟
- 连续运行:满载工作7×24小时
合格标准:
- 零点漂移<±0.3g
- 满量程误差<±0.5g
- CAN通信无丢包
5. 典型问题解决方案
5.1 传感器异常检测
常见故障现象:
- 输出值恒定不变
- 数据剧烈跳动
- 与温度变化不相关
诊断算法:
c复制#define VAR_THRESHOLD 50 // 方差阈值
bool CheckSensorHealth(uint8_t ch) {
static long history[10];
long sum = 0, sum_sq = 0;
// 采集10个样本
for(int i=0; i<10; i++){
history[i] = HX712_ReadData(ch);
sum += history[i];
sum_sq += history[i]*history[i];
delay_ms(100);
}
// 计算方差
float variance = (sum_sq - sum*sum/10.0)/9.0;
// 判断条件
if(variance < 5) return false; // 数据变化太小
if(variance > VAR_THRESHOLD) return false; // 数据跳动太大
return true;
}
5.2 电源干扰处理
实测干扰案例:
- 电机启动导致重量跳变±10g
- 继电器动作引起CAN通信错误
解决方案:
- 在LM2596输入输出端增加共模扼流圈
- 数字地与模拟地采用星型单点连接
- 关键信号线走内层并包地处理
改进后测试数据:
| 干扰源 | 改进前误差(g) | 改进后误差(g) |
|---|---|---|
| 电机启动 | ±10 | ±0.2 |
| 继电器动作 | ±5 | ±0.1 |
| 变频器工作 | ±20 | ±0.5 |
6. 应用场景扩展
6.1 多节点组网方案
典型组网配置:
- 每个CAN节点设置独立ID(0x100~0x1FF)
- 主控制器发送广播指令进行同步采样
- 采用时间戳机制保证数据一致性
网络拓扑示例:
code复制[主控制器]
│
├──[称重节点1]──[称重节点2]
│
└──[称重节点3]──[称重节点4]
6.2 数据融合算法
对于需要更高精度的场景,可采用多传感器数据融合:
- 空间融合:同一位置安装多个传感器取平均
- 时间融合:滑动窗口滤波(窗口大小20)
- 频域融合:FFT分析剔除高频噪声
算法实现:
c复制#define WINDOW_SIZE 20
typedef struct {
float buffer[WINDOW_SIZE];
int index;
} Filter_t;
float MovingAverage(Filter_t* filter, float new_val) {
filter->buffer[filter->index] = new_val;
filter->index = (filter->index + 1) % WINDOW_SIZE;
float sum = 0;
for(int i=0; i<WINDOW_SIZE; i++){
sum += filter->buffer[i];
}
return sum / WINDOW_SIZE;
}
在实际部署中,我们建议将模块安装在机械振动较小的位置,传感器电缆长度不超过3米。对于需要更高防护等级的场合,可在PCB表面喷涂三防漆。经过200小时连续测试,该方案各项指标均达到设计要求,最关键的温漂指标实测为±1.5ppm/℃,优于设计值。
