
目录
[1. 时序是核心!](#1. 时序是核心!)
[2. 校准流程不能少!](#2. 校准流程不能少!)
[3. 抗干扰措施](#3. 抗干扰措施)
[4. 常见问题排查](#4. 常见问题排查)
前言
最近用到了STM32驱动HX711称重传感器模块,我这里用的STM32是STM32F407IGT6,这个模块的精度能达到0.01g,所以记录一下
一、工作原理
HX711 是一款专为称重传感器(桥式压力传感器)设计的 24 位高精度 AD 转换器,核心作用是把传感器输出的微弱模拟信号,转换成 STM32 能读取的数字信号。
信号放大与 AD 转换:HX711 内部的仪表放大器将微弱信号放大(128 倍增益下放大效果最佳),再通过 24 位 AD 转换器转换成数字信号
二、接线方式
|------|-----|
| VIN | 5V |
| GND | GND |
| CLK | PB1 |
| DATA | PB2 |
三、软件程序
hx711.h
#ifndef __HX711_H
#define __HX711_H
#include "stm32f1xx_hal.h"
// #################### 引脚定义(根据你的硬件修改!)####################
#define HX711_SCK_GPIO_Port GPIOA
#define HX711_SCK_Pin GPIO_PIN_0
#define HX711_DOUT_GPIO_Port GPIOA
#define HX711_DOUT_Pin GPIO_PIN_1
// 增益选择(默认用通道A+128倍增益)
#define HX711_GAIN_128 1 // 通道A,128倍增益(推荐)
#define HX711_GAIN_64 2 // 通道A,64倍增益
#define HX711_GAIN_32 3 // 通道B,32倍增益
// 函数声明
void HX711_Init(void); // 初始化(引脚配置)
int32_t HX711_ReadData(uint8_t gain); // 读取原始AD数据
void HX711_CalibrateZero(void); // 校准零点(空载时调用)
void HX711_CalibrateScale(float weight); // 标定量程(放已知重量时调用)
float HX711_GetWeight(uint8_t sample_num); // 获取平均重量(sample_num:采样次数)
#endif
hx711.c
#include "hx711.h"
#include "delay.h" // 需自行实现delay_us函数(或用HAL_Delay替代,精度略低)
// 全局变量(零点偏移值、标定系数)
static int32_t hx711_zero_offset = 0; // 零点偏移(空载时的AD值)
static float hx711_scale = 1.0f; // 标定系数(重量/AD差值)
// #################### 基础函数 ####################
// 初始化HX711引脚(SCK输出,DOUT输入)
void HX711_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能GPIOA时钟(根据你的引脚修改时钟总线)
__HAL_RCC_GPIOA_CLK_ENABLE();
// SCK引脚:推挽输出
GPIO_InitStruct.Pin = HX711_SCK_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(HX711_SCK_GPIO_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET); // 初始低电平
// DOUT引脚:浮空输入(或上拉输入,根据模块调整)
GPIO_InitStruct.Pin = HX711_DOUT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT_FLOATING;
HAL_GPIO_Init(HX711_DOUT_GPIO_Port, &GPIO_InitStruct);
}
// 读取单次AD原始数据(gain:增益选择)
int32_t HX711_ReadData(uint8_t gain) {
int32_t data = 0;
uint8_t i = 0;
// 等待数据就绪(DOUT变低)
while (HAL_GPIO_ReadPin(HX711_DOUT_GPIO_Port, HX711_DOUT_Pin) == GPIO_PIN_SET);
// 读取24位数据(先MSB后LSB)
for (i = 0; i < 24; i++) {
// 发送时钟脉冲(SCK高电平)
HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_SET);
delay_us(1); // 延时1us,保证时序稳定(关键!)
// 移位读取数据(DOUT为当前位)
data |= (HAL_GPIO_ReadPin(HX711_DOUT_GPIO_Port, HX711_DOUT_Pin) << (23 - i));
// 时钟脉冲拉低
HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET);
delay_us(1);
}
// 发送增益选择脉冲(1~3个)
for (i = 0; i < gain; i++) {
HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_SET);
delay_us(1);
HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET);
delay_us(1);
}
// 处理24位有符号数据(HX711输出为二进制补码)
if (data & 0x800000) { // 最高位为1表示负数,转换为十进制
data |= ~0xFFFFFF; // 扩展符号位到32位(int32_t)
}
return data;
}
// #################### 校准与重量计算 ####################
// 校准零点(空载时调用,消除传感器自重误差)
void HX711_CalibrateZero(void) {
uint8_t i = 0;
int32_t temp = 0;
hx711_zero_offset = 0;
// 采样10次取平均值(提高零点精度)
for (i = 0; i < 10; i++) {
temp += HX711_ReadData(HX711_GAIN_128);
HAL_Delay(10); // 采样间隔
}
hx711_zero_offset = temp / 10; // 零点偏移值 = 空载平均AD值
}
// 标定量程(放已知重量的物体后调用,计算AD值与重量的比例)
void HX711_CalibrateScale(float weight) {
uint8_t i = 0;
int32_t temp = 0;
int32_t ad_diff = 0;
// 采样10次取平均AD值
for (i = 0; i < 10; i++) {
temp += HX711_ReadData(HX711_GAIN_128);
HAL_Delay(10);
}
temp = temp / 10;
// 计算AD差值(加载后AD值 - 零点AD值)
ad_diff = temp - hx711_zero_offset;
if (ad_diff <= 0) {
hx711_scale = 1.0f; // 异常情况,避免除零
return;
}
// 标定系数 = 已知重量 / AD差值(后续通过AD差值计算重量)
hx711_scale = weight / (float)ad_diff;
}
// 获取重量(sample_num:采样次数,次数越多精度越高,推荐10~20次)
float HX711_GetWeight(uint8_t sample_num) {
uint8_t i = 0;
int32_t temp = 0;
float weight = 0.0f;
if (sample_num == 0) sample_num = 1; // 避免采样次数为0
// 多次采样取平均
for (i = 0; i < sample_num; i++) {
temp += HX711_ReadData(HX711_GAIN_128);
HAL_Delay(5);
}
temp = temp / sample_num; // 平均AD值
// 计算重量 = (当前AD值 - 零点偏移) * 标定系数
weight = (temp - hx711_zero_offset) * hx711_scale;
return weight;
}
main.c
#include "stm32f1xx_hal.h"
#include "hx711.h"
#include "usart.h" // 用于串口打印重量(需自行配置USART)
int main(void) {
HAL_Init();
SystemClock_Config(); // 系统时钟配置(72MHz)
MX_GPIO_Init();
MX_USART1_UART_Init(); // 串口初始化(115200波特率)
HX711_Init(); // HX711初始化
// #################### 校准流程(首次使用必须执行!)####################
HAL_Delay(1000); // 上电稳定
printf("开始校准零点...\n");
HX711_CalibrateZero(); // 空载时调用(传感器上不放任何东西)
printf("零点校准完成!零点AD值:%d\n", hx711_zero_offset);
HAL_Delay(1000);
printf("请在传感器上放置已知重量的物体,3秒后开始标定...\n");
HAL_Delay(3000);
HX711_CalibrateScale(100.0f); // 放置100g的物体(根据实际重量修改)
printf("量程标定完成!标定系数:%.6f\n", hx711_scale);
// #################### 循环读取重量 ####################
while (1) {
float weight = HX711_GetWeight(10); // 采样10次取平均
printf("当前重量:%.2f g\n", weight);
HAL_Delay(500); // 每隔500ms读取一次
}
}
关键说明(避坑重点)!!!!
1. 时序是核心!
HX711 的 SCK 和 DOUT 时序必须严格遵守:
- 时钟脉冲宽度≥0.2us(代码中
delay_us(1)完全满足); - 数据就绪后必须在 10ms 内读取(否则数据会失效,重新转换);
- 禁止在读取过程中改变 SCK 电平(会导致数据错误)。
2. 校准流程不能少!
- 零点校准:传感器上不放任何东西 时调用
HX711_CalibrateZero(),消除传感器自重误差; - 量程标定:放已知重量 (如 100g、500g)的物体,调用
HX711_CalibrateScale(已知重量),计算 AD 值与重量的比例; - 若更换传感器或硬件,需重新校准。
3. 抗干扰措施
- 电源滤波:HX711 的 VCC 引脚并联 104 电容(0.1μF),减少电源噪声;
- 布线:SCK 和 DOUT 引脚尽量短,远离电机、继电器等强干扰设备;
- 共地:STM32、HX711、称重传感器必须共地(否则数据乱码)。
4. 常见问题排查
- 数据一直为 0 或固定值:检查 DOUT 和 SCK 引脚是否接反;
- 数据波动大:增加采样次数(如 20 次)、检查电源滤波、减少环境振动;
- 重量计算错误:标定时光标重量输入错误,或校准顺序颠倒(先零点后量程)。
总结
本文介绍了使用STM32F407IGT6驱动HX711称重传感器模块的实现方法。HX711是一款24位高精度AD转换器,可将称重传感器的模拟信号转换为数字信号。文章详细说明了硬件接线方式(VIN-5V、GND-GND、CLK-PB1、DATA-PB2)和软件实现,包括初始化、数据读取、零点校准和量程标定等关键功能。通过HX711_GetWeight()函数可获取平均重量值,精度可达0.01g。首次使用时需执行校准流程(空载校准和已知重量标定),后续即可循环读取重量数据并通过串口输出。该方案适用于需要高精度称重的嵌入式应用场景。