STM32驱动HX711 24位ADC程序

STM32驱动HX711 24位ADC程序

一、HX711简介

HX711是一款专为高精度电子秤设计的24位A/D转换器芯片,具有以下特点:

二、硬件连接

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. 校准流程

  1. 零点校准(去皮)

    • 空载状态下调用HX711_Tare()
    • 计算多次采样的平均值作为偏移量
  2. 比例系数校准

    • 放置已知重量的物体
    • 计算: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. 数据不稳定

2. 读数漂移

3. 通信失败

七、项目应用

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的完整控制,包括:

  1. 基本读写功能
  2. 校准和滤波处理
  3. 低功耗设计
  4. 温度补偿
  5. 应用示例

专注于matlab/simulink,电子电路,编程