HX711是一种高精度、低成本的压力传感器信号放大器,主要用于测量重力或压力变化。它工作在 2.7V 至 5.5V 的电源范围内,支持多种传感器类型,如电桥、应变计等。HX711 提供了一种简便的数字接口来读取模拟输出信号,适用于嵌入式系统和传感器应用。
1、海芯HX711介绍手册
2、海芯HX711手册
一、HX711参数和电路
称重传感器模块有灵敏度和激励电压两个重要参数:(这两个参数是假设值,以实际设计电路为准)
灵敏度:1.0mV/V
激励电压:3~12V
满量程输出电压 = 激励电压 * 灵敏度
这样的话,假如激励电压是 3V,那么输出最大电压是 3mV。
| 引脚名称 | 描述 |
| GND | 模块地线 |
| DT | 数据输出端口 |
| SCK | 时钟输入端口 |
| VCC | 电源 |

二、工作原理介绍
HX711压力传感器的工作原理是基于全臂电桥,利用压力传感器的阻值变化,转化为电压变化,从而实现重量的测量。
应变片一般由金属丝为材料制作的应变电阻,当金属丝受外力作用时,其长度和截面积都会发生变化,进而其电阻值即会发生改变。
当金属丝受外力作用而伸长时,其长度增加,而截面积减少,电阻值便会增大。
当金属丝受外力作用而压缩时,长度减小而截面增加,电阻值则会减小。
金属应变片对电阻丝材料有较高的要求,一般要求灵敏度系数大,电阻温系数小,具有优良的机械加工和焊接性能等,康铜是目前应用最广泛的应变丝材料。

称重传感器模块上下表面各有一个应变片,每个应变片内有 2 个压力电阻。一共为 4 个压力电阻,组成全桥式电路。全桥电路可以提高所测的精度,而且电桥本身也能实现自补偿(温度补偿)。

三、数据的获取与处理
HX711 芯片与单片机的通讯只需要两个引脚,时钟引脚PD_SCK及数据引脚DOUT,用来输出数据,选择输入通道和增益。
当数据输出管脚 DOUT 为高电平时,表明 A/D 转换器还未准备好输出数据,此时串口时钟输入信号 PD_SCK 应为低电平。当 DOUT 从高电平变低电平后,PD_SCK 应输入 25 至 27 个不等的时钟脉冲。
其中第一个时钟脉冲的上升沿将读出输出 24 位数据的最高位(MSB),直至第 24 个时钟脉冲完成,24 位输出数据从最高位至最低位逐位输出完成。第 25 至 27 个时钟脉冲用来决定下一次 A/D 转换的输入通道和增益。
HX711.h
#ifndef __HX711_H
#define __HX711_H
#include "stm32f10x.h" // 包含STM32F10x系列的头文件
#define HX711_DT_GPIO GPIOA
#define HX711_SCK_GPIO GPIOA
#define HX711_DT_PIN GPIO_Pin_0
#define HX711_SCK_PIN GPIO_Pin_1
// --- HX711 相关宏定义 ---
// 用于控制SCK和读取DT的引脚状态
#define W_SCK(x) GPIO_WriteBit(HX711_SCK_GPIO, HX711_SCK_PIN, (BitAction)(x))
#define R_DT GPIO_ReadInputDataBit(HX711_DT_GPIO, HX711_DT_PIN)
// 校准系数 (需要根据实际校准结果调整)
// GapValue 代表单位重量变化对应的ADC差值
extern float GapValue;
// --- 全局变量声明 ---
extern unsigned long HX711_Buffer;
extern unsigned long Weight_Maopi;
extern int32_t Weight_Zhengshu;
extern int32_t Weight_xiaoshu;
extern float Weight_tmp;
extern float Weight_filtered;
// --- 函数声明 ---
void HX711_Init(void);
unsigned long HX711_Read(void);
void Get_Maopi(void); // 获取毛皮值(去皮)
void Get_Weight(void); // 获取当前重量
#endif /* __HX711_H */
HX711.C
为了实现较高精度并且稳定数值,本代码采用以下算法:
取五次连续测量值,排序后刨除两个极值,再对剩余的三个值求平均值。
#include "HX711.h"
// --- 全局变量定义 ---
unsigned long HX711_Buffer = 0;
unsigned long Weight_Maopi = 0;
int32_t Weight_Zhengshu = 0;
int32_t Weight_xiaoshu = 0;
float Weight_tmp = 0.0f;
float Weight_filtered = 0.0f;
float GapValue = 3774.2f;
/**
* @brief 初始化HX711连接的GPIO引脚
* 针对STM32F103C8T6 (如BluePill核心板) 进行了时钟使能配置
* @param None
* @retval None
*/
void HX711_Init(void)
{
GPIO_InitTypeDef hx711_gpio_struct;
// 使能GPIO时钟
// 对于PB0, PB1,需要使能GPIOB的时钟
// STM32F103C8T6通常只挂载在APB2总线上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置SCK引脚 (PB1) - 推挽输出
hx711_gpio_struct.GPIO_Mode = GPIO_Mode_Out_PP;
hx711_gpio_struct.GPIO_Pin = HX711_SCK_PIN;
hx711_gpio_struct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(HX711_SCK_GPIO, &hx711_gpio_struct);
// 配置DT引脚 (PB0) - 上拉输入
hx711_gpio_struct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
hx711_gpio_struct.GPIO_Pin = HX711_DT_PIN;
// GPIO_Speed 对输入模式无意义,可不设置或保持上次设置
GPIO_Init(HX711_DT_GPIO, &hx711_gpio_struct);
// 初始化时将SCK拉高 (虽然注释说拉高,但函数内部是拉低,这里保持原逻辑)
// 根据HX711协议,SCK空闲时应为低电平,这里拉高是为了在初始化后确保状态
W_SCK(1);
}
/**
* @brief 从HX711读取一次A/D转换结果
* @param None
* @retval unsigned long - 24位ADC值 (已处理符号位)
*/
unsigned long HX711_Read(void)
{
unsigned long Count = 0;
unsigned char i;
W_SCK(0); // 拉低SCK,准备开始读取
// 等待HX711准备好 (DT拉低表示转换完成)
// 注意:如果HX711一直未准备好,这里可能会死等,实际应用中可能需要超时处理
while(R_DT);
// 读取24位数据 (对应128增益)
for (i = 0; i < 24; i++)
{
W_SCK(1); // SCK拉高,数据准备好
Count = Count << 1; // 数据左移一位
W_SCK(0); // SCK拉低,为下次读取做准备
if(R_DT) // 读取当前位数据
{
Count++; // 如果DT为高,则当前位为1
}
}
// 读取完24位后,需要额外的一个时钟脉冲来设置下一次转换的增益 (对于128增益)
// 这样总共是25个脉冲,对应A+通道128倍增益
W_SCK(1); // 第25个脉冲
Count = Count ^ 0x800000; // 对24位数据的最高位(符号位)进行处理
// HX711的24位数据是有符号的,最高位为符号位
// 当读数为负时,最高位为1,这里通过异或操作将其取反,
// 转换为无符号数,方便后续计算。注意这改变了负数的表示方式。
W_SCK(0); // 结束读取,拉低SCK
return Count;
}
/**
* @brief 获取当前毛皮值 (去皮值)
* @param None
* @retval None
*/
void Get_Maopi(void)
{
Weight_Maopi = HX711_Read(); // 读取当前空载状态下的ADC值作为毛皮值
}
/**
* @brief 获取当前重量
* @param None
* @retval None
*/
/**
* @brief 获取当前重量
* @param None
* @retval None
*/
void Get_Weight(void)
{
unsigned long temp_buffers[5] = {0};
float current_weights[5] = {0.0f};
float sorted_weights[5] = {0.0f};
float current_weight = 0.0f;
// 读取五次ADC值,中间添加延迟
for(int i = 0; i < 5; i++)
{
temp_buffers[i] = HX711_Read();
// delayus(60);
}
// 计算五次重量
for(int i = 0; i < 5; i++)
{
// 不再强制限制为0,保留负值
int32_t temp_diff = temp_buffers[i] - Weight_Maopi;
current_weights[i] = ((float)temp_diff / GapValue) * 10.0f / 1.082f;
}
// 复制到排序数组
for(int i = 0; i < 5; i++)
{
sorted_weights[i] = current_weights[i];
}
// 冒泡排序
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < 4 - i; j++)
{
if(sorted_weights[j] > sorted_weights[j+1])
{
float temp = sorted_weights[j];
sorted_weights[j] = sorted_weights[j+1];
sorted_weights[j+1] = temp;
}
}
}
// 去除最大最小值,取中间3个求平均
current_weight = (sorted_weights[1] + sorted_weights[2] + sorted_weights[3]) / 3.0f;
// 应用死区阈值处理
if (Weight_filtered == 0.0f)
{
// 第一次读取,直接使用当前值
Weight_filtered = current_weight;
}
else
{
// 计算当前值与上一个滤波值的差值
float diff = (current_weight > Weight_filtered) ?
(current_weight - Weight_filtered) :
(Weight_filtered - current_weight);
// 死区阈值
const float dead_zone = 0.03f; // 死区阈值,0.03g以内认为无效
if (diff >= dead_zone)
{
// 差值大于等于死区阈值,更新滤波值
Weight_filtered = current_weight;
}
// 如果差值小于死区阈值,保持原值不变
}
Weight_tmp = Weight_filtered;
// 提取整数部分
Weight_Zhengshu = (int32_t)Weight_tmp;
// 正确计算小数部分(保留符号)
float decimal_part = Weight_tmp - (float)Weight_Zhengshu;
Weight_xiaoshu = (int32_t)(decimal_part * 100);
// 保证小数部分的绝对值不超过99
if (Weight_xiaoshu >= 100) {
Weight_xiaoshu = 99;
} else if (Weight_xiaoshu <= -100) {
Weight_xiaoshu = -99;
}
}
四、实物展示







Comments | NOTHING