STM32驱动HX711 24位ADC程序
一、HX711简介
HX711是一款专为高精度电子秤设计的24位A/D转换器芯片,具有以下特点:
- 两路可选差分输入通道
- 片内低噪声放大器,可选增益128/64/32
- 片内稳压电路,可直接向传感器供电
- 上电自动复位电路
- 简单的数字接口,仅需SCK和DOUT两根线
二、硬件连接
| HX711引脚 | STM32引脚 | 功能说明 |
|---|---|---|
| VCC | 3.3V | 电源(2.6-5.5V) |
| GND | GND | 地 |
| DT (DOUT) | PA0 | 数据输出 |
| SCK | PA1 | 时钟信号 |
| XO | 不接 | 晶振(内部) |
| XI | GND | 晶振(内部) |
三、驱动程序实现
1. 头文件 (hx711.h)
#ifndef __HX711_H
#define __HX711_H
#include "stm32f1xx_hal.h"
// 定义HX711引脚
#define HX711_DT_PIN GPIO_PIN_0
#define HX711_DT_PORT GPIOA
#define HX711_SCK_PIN GPIO_PIN_1
#define HX711_SCK_PORT GPIOA
// 增益选择
typedef enum {
CHANNEL_A_128 = 1, // 通道A,增益128
CHANNEL_B_32 = 2, // 通道B,增益32
CHANNEL_A_64 = 3 // 通道A,增益64
} HX711Gain;
// 函数声明
void HX711_Init(void);
int32_t HX711_Read(HX711Gain gain);
void HX711_Tare(uint8_t times);
float HX711_GetWeight(uint8_t times);
void HX711_SetOffset(long offset);
void HX711_SetScale(float scale);
#endif
2. 源文件 (hx711.c)
#include "hx711.h"
#include "main.h"
// 全局变量
static long offset = 0;
static float scale = 1.0f;
// 初始化HX711
void HX711_Init(void) {
// 配置GPIO
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_LOW;
HAL_GPIO_Init(HX711_SCK_PORT, &GPIO_InitStruct);
// 配置DT为输入
GPIO_InitStruct.Pin = HX711_DT_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(HX711_DT_PORT, &GPIO_InitStruct);
// 初始状态:SCK低电平
HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET);
// 等待HX711稳定
HAL_Delay(100);
}
// 读取HX711数据
int32_t HX711_Read(HX711Gain gain) {
uint32_t count = 0;
uint8_t i;
// 等待数据准备好(DT变低)
while (HAL_GPIO_ReadPin(HX711_DT_PORT, HX711_DT_PIN) == GPIO_PIN_SET);
// 读取24位数据
for (i = 0; i < 24; i++) {
// 产生一个时钟脉冲
HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET);
HAL_Delay(1); // 短暂延时
// 读取数据位
count = count << 1;
if (HAL_GPIO_ReadPin(HX711_DT_PORT, HX711_DT_PIN) == GPIO_PIN_SET) {
count++;
}
// 下降沿
HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET);
HAL_Delay(1);
}
// 设置下一次的增益和通道
for (i = 0; i < (uint8_t)gain; i++) {
HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET);
HAL_Delay(1);
}
// 符号扩展:将24位有符号数转换为32位
if (count & 0x800000) {
count |= 0xFF000000;
}
return (int32_t)count;
}
// 去皮校准
void HX711_Tare(uint8_t times) {
long sum = 0;
for (uint8_t i = 0; i < times; i++) {
sum += HX711_Read(CHANNEL_A_128);
HAL_Delay(10);
}
offset = sum / times;
}
// 设置偏移量
void HX711_SetOffset(long offset_val) {
offset = offset_val;
}
// 设置比例系数
void HX711_SetScale(float scale_val) {
scale = scale_val;
}
// 获取重量
float HX711_GetWeight(uint8_t times) {
long sum = 0;
for (uint8_t i = 0; i < times; i++) {
sum += HX711_Read(CHANNEL_A_128);
HAL_Delay(10);
}
// 计算平均原始值
long avg = sum / times;
// 减去皮重并计算重量
return (float)(avg - offset) / scale;
}
3. 使用示例 (main.c)
#include "stm32f1xx_hal.h"
#include "hx711.h"
int main(void) {
HAL_Init();
SystemClock_Config();
// 初始化HX711
HX711_Init();
// 设置校准参数(需要根据实际传感器调整)
HX711_SetScale(2280.0f); // 比例系数
HX711_Tare(10); // 去皮,取10次平均值
while (1) {
// 获取重量(取5次平均)
float weight = HX711_GetWeight(5);
// 显示或处理重量值
printf("Weight: %.2f g\n", weight);
HAL_Delay(500);
}
}
四、关键功能详解
1. 数据读取流程
int32_t HX711_Read(HX711Gain gain) {
// 1. 等待数据准备好(DT变低)
while (HAL_GPIO_ReadPin(DT_PORT, DT_PIN) == SET);
// 2. 读取24位数据
for (i=0; i<24; i++) {
SCK_HIGH(); // 上升沿
count = (count << 1) | READ_DT();
SCK_LOW(); // 下降沿
}
// 3. 设置下一次的增益和通道
for (i=0; i<(uint8_t)gain; i++) {
SCK_HIGH();
SCK_LOW();
}
// 4. 符号扩展
if (count & 0x800000) count |= 0xFF000000;
return (int32_t)count;
}
2. 校准流程
-
零点校准(去皮):
- 空载状态下调用
HX711_Tare() - 计算多次采样的平均值作为偏移量
- 空载状态下调用
-
比例系数校准:
- 放置已知重量的物体
- 计算:
scale = (raw_value - offset) / known_weight - 调用
HX711_SetScale(scale)
3. 滤波处理
// 中值滤波+均值滤波
#define SAMPLE_SIZE 5
long HX711_FilteredRead(HX711Gain gain) {
long samples[SAMPLE_SIZE];
// 采集样本
for (int i=0; i<SAMPLE_SIZE; i++) {
samples[i] = HX711_Read(gain);
HAL_Delay(10);
}
// 中值滤波
for (int i=0; i<SAMPLE_SIZE-1; i++) {
for (int j=i+1; j<SAMPLE_SIZE; j++) {
if (samples[i] > samples[j]) {
long temp = samples[i];
samples[i] = samples[j];
samples[j] = temp;
}
}
}
// 取中间3个值的平均
return (samples[1] + samples[2] + samples[3]) / 3;
}
五、应用优化
1. 低功耗设计
// 进入低功耗模式
void HX711_Sleep(void) {
// 根据数据手册,拉低SCK至少60μs进入休眠
HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET);
HAL_Delay(1); // 1ms足够
}
// 唤醒
void HX711_Wakeup(void) {
// 拉高SCK再拉低,唤醒HX711
HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET);
HAL_Delay(1);
}
2. DMA方式读取(高级)
// 使用定时器触发DMA读取
void HX711_DMA_Read(void) {
// 配置TIM2为1MHz时钟
TIM_HandleTypeDef htim2;
htim2.Instance = TIM2;
htim2.Init.Prescaler = 72-1; // 72MHz/72=1MHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1-1; // 1MHz频率
HAL_TIM_Base_Init(&htim2);
// 配置DMA
DMA_HandleTypeDef hdma_tim2_up;
hdma_tim2_up.Instance = DMA1_Channel2;
hdma_tim2_up.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim2_up.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim2_up.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim2_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tim2_up.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tim2_up.Init.Mode = DMA_NORMAL;
hdma_tim2_up.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_tim2_up);
// 关联定时器和DMA
__HAL_LINKDMA(&htim2, hdma[TIM_DMA_ID_UPDATE], hdma_tim2_up);
// 启动定时器和DMA
HAL_TIM_Base_Start(&htim2);
HAL_DMA_Start(&hdma_tim2_up, (uint32_t)&HX711_Read, (uint32_t)&GPIOA->ODR, 24);
}
3. 温度补偿
// 获取温度(需要外接温度传感器)
float HX711_GetTemperature(void) {
// 读取温度传感器
float temp = read_temperature_sensor();
// 温度补偿系数(根据传感器特性调整)
const float temp_coeff = 0.02f; // 每摄氏度变化0.02%
// 应用补偿
scale = scale * (1.0f - temp_coeff * (temp - 25.0f));
return temp;
}
参考代码 嵌入式系统STM32对24位AD hx711的驱动程序,语言采用C语言 www.youwenfan.com/contentcss/182625.html
六、常见问题解决
1. 数据不稳定
-
原因:电源波动、机械振动、电磁干扰
-
解决:
- 添加0.1μF去耦电容
- 使用屏蔽电缆
- 软件滤波(中值+均值)
- 增加机械减震
2. 读数漂移
-
原因:温度变化、传感器蠕变
-
解决:
- 定期自动校准
- 温度补偿算法
- 使用更稳定的传感器
3. 通信失败
-
原因:时序不匹配、线路过长
-
解决:
- 检查SCK和DT连接
- 增加上拉电阻(4.7kΩ)
- 降低通信速度
- 使用短而粗的导线
七、项目应用
1. 电子秤系统
// 电子秤主程序
int main(void) {
// 初始化
HX711_Init();
LCD_Init();
Keypad_Init();
// 校准
HX711_Tare(20); // 20次平均去皮
HX711_SetScale(calibrate_scale()); // 校准程序
while (1) {
// 读取重量
float weight = HX711_GetWeight(5);
// 显示
LCD_DisplayWeight(weight);
// 按键处理
if (KEY_PRESSED(KEY_TARE)) {
HX711_Tare(10);
}
// 单位切换
if (KEY_PRESSED(KEY_UNIT)) {
unit = (unit + 1) % 3; // g, kg, lb
}
HAL_Delay(200);
}
}
2. 力控制系统
// 恒力控制
#define TARGET_FORCE 10.0f // 10N
void ForceControlLoop(void) {
while (1) {
// 读取当前力
float force = HX711_GetWeight(3) * 0.01f; // 转换为牛顿
// PID控制
float error = TARGET_FORCE - force;
integral += error;
derivative = error - prev_error;
float output = Kp * error + Ki * integral + Kd * derivative;
// 执行器控制
SetActuator(output);
// 更新状态
prev_error = error;
HAL_Delay(10);
}
}
八、总结
本驱动程序实现了STM32对HX711 24位ADC的完整控制,包括:
- 基本读写功能
- 校准和滤波处理
- 低功耗设计
- 温度补偿
- 应用示例