STM32F103C8T6与HX711压力传感器全流程实战指南

1. 项目概述与硬件准备

在嵌入式开发领域,重量测量是一个常见但技术要求较高的应用场景。STM32F103C8T6作为一款性价比极高的ARM Cortex-M3内核微控制器,配合HX711这款专为电子秤设计的24位ADC芯片,能够构建稳定可靠的压力测量系统。这套组合特别适合需要精确测量小范围重量变化的场景,比如智能厨房秤、实验室测量设备或工业自动化中的重量检测环节。

硬件准备清单 :

  • STM32F103C8T6最小系统板(蓝色药丸开发板)
  • HX711模块(带焊接排针)
  • 压力传感器(常见规格:5kg/10kg量程)
  • 杜邦线若干(建议使用优质线材减少干扰)
  • USB转TTL串口模块(用于调试输出)
  • 稳压电源或手机充电器(为系统供电)

硬件连接时需特别注意:

  • HX711的VCC引脚可接3.3V或5V,但必须与STM32逻辑电平匹配
  • DOUT(数据线)连接STM32的GPIO输入引脚
  • SCK(时钟线)连接STM32的GPIO输出引脚
  • 压力传感器的四个应变片引线需正确接入HX711的A+、A-、B+、B-端子

2. CubeMX工程配置详解

2.1 时钟系统配置

启动CubeMX后,选择STM32F103C8T6型号并进入时钟配置界面。对于HX711应用,我们推荐如下配置:

  1. 在RCC配置中选择高速外部晶振(HSE)
  2. 系统时钟树设置:
    • PLL源选择HSE
    • 设置PLL倍频因子为9(8MHz晶振×9=72MHz系统时钟)
    • 配置AHB预分频器为1(72MHz)
    • APB1预分频器设为2(36MHz)
    • APB2预分频器保持1(72MHz)

提示:精确的时钟配置对HX711的时序控制至关重要,建议使用外部晶振而非内部RC振荡器。

2.2 GPIO引脚配置

根据硬件连接方案,在CubeMX中配置对应引脚:

引脚功能 引脚编号 模式配置 备注
SCK PA0 GPIO_Output 推挽输出,无上下拉
DOUT PA1 GPIO_Input 上拉输入
USART1_TX PA9 USART1_TX 异步模式
USART1_RX PA10 USART1_RX 异步模式

配置完成后生成代码前,务必检查:

  • 每个GPIO的初始状态设置是否正确
  • 是否启用了需要的时钟(如USART1)
  • 中断优先级配置(本项目暂不需要)

3. HX711驱动开发与移植

3.1 基本读写时序实现

HX711的通信协议相对简单但时序要求严格。创建hx711.c文件并实现以下核心函数:

// 读取HX711数据(增益128)
uint32_t HX711_Read(void) {
    uint32_t count = 0;
    uint8_t i;
    
    HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
    
    // 等待数据就绪
    while(HAL_GPIO_ReadPin(DOUT_GPIO_Port, DOUT_Pin) == GPIO_PIN_SET);
    
    // 读取24位数据
    for(i=0; i<24; i++) {
        HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
        delay_us(1);
        count = count << 1;
        HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
        delay_us(1);
        
        if(HAL_GPIO_ReadPin(DOUT_GPIO_Port, DOUT_Pin) == GPIO_PIN_SET) {
            count++;
        }
    }
    
    // 设置增益为128(发送第25个脉冲)
    HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
    delay_us(1);
    HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
    delay_us(1);
    
    return count ^ 0x800000; // 补码转换
}

3.2 去皮与重量计算

实际应用中需要考虑去皮(Tare)功能,即扣除容器重量:

// 全局变量定义
uint32_t tare_value = 0;
float calibration_factor = 106.5f; // 需根据传感器特性调整

void Get_Tare(void) {
    uint32_t sum = 0;
    for(uint8_t i=0; i<10; i++) {
        sum += HX711_Read();
        HAL_Delay(10);
    }
    tare_value = sum / 10;
}

float Get_Weight(void) {
    uint32_t raw_data = HX711_Read();
    if(raw_data > tare_value) {
        return (float)(raw_data - tare_value) / calibration_factor;
    }
    return 0.0f;
}

4. 数据处理与优化技巧

4.1 数字滤波实现

压力传感器读数常伴有噪声,采用合适的滤波算法可显著提升稳定性:

移动平均滤波实现 :

#define FILTER_WINDOW_SIZE 5

float moving_average_filter(float new_sample) {
    static float buffer[FILTER_WINDOW_SIZE] = {0};
    static uint8_t index = 0;
    static float sum = 0;
    
    sum -= buffer[index];
    buffer[index] = new_sample;
    sum += buffer[index];
    index = (index + 1) % FILTER_WINDOW_SIZE;
    
    return sum / FILTER_WINDOW_SIZE;
}

卡尔曼滤波简化版 :

float simple_kalman_filter(float new_value) {
    static float last_value = 0;
    static float p = 1.0f;
    const float q = 0.01f; // 过程噪声
    const float r = 0.1f;  // 观测噪声
    
    // 预测
    p = p + q;
    
    // 更新
    float kg = p / (p + r);
    float current_value = last_value + kg * (new_value - last_value);
    p = (1 - kg) * p;
    last_value = current_value;
    
    return current_value;
}

4.2 校准与误差补偿

精确测量需要进行系统校准:

  1. 零点校准 :

    • 空载状态下执行Get_Tare()函数
    • 确保传感器不受外力作用
  2. 满量程校准 :

    • 放置已知重量的标准砝码
    • 调整calibration_factor直到显示重量与实际一致
    • 计算公式: 新校准系数 = (当前系数 × 显示重量) / 实际重量

常见问题排查:

  • 读数不稳定:检查电源质量,确保传感器供电充足
  • 数值漂移:检查机械结构是否稳固,避免温度剧烈变化
  • 线性度差:考虑分段校准或非线性补偿算法

5. 系统集成与调试

5.1 主程序逻辑实现

在main.c中构建完整应用流程:

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    
    // 初始化延时函数
    delay_init(72);
    
    printf("系统启动...\r\n");
    printf("执行去皮操作,请确保空载...\r\n");
    Get_Tare();
    printf("去皮完成,当前零点值:%lu\r\n", tare_value);
    
    while(1) {
        float weight = Get_Weight();
        weight = moving_average_filter(weight); // 应用滤波
        
        printf("当前重量: %.2f g\r\n", weight);
        HAL_Delay(200); // 控制输出频率
    }
}

5.2 串口调试技巧

利用串口输出调试信息时,推荐以下实践:

  1. 格式化输出 :

    printf("重量: %.1fg 原始值: %lu 校准系数: %.2f\r\n", 
           weight, raw_data, calibration_factor);
    
  2. 调试命令接口 :

    if(serial_data_available()) {
        char cmd = getchar();
        switch(cmd) {
            case 't': Get_Tare(); break;
            case '+': calibration_factor *= 1.01f; break;
            case '-': calibration_factor *= 0.99f; break;
        }
    }
    
  3. 数据可视化 :

    • 使用串口绘图工具(如SerialPlot)实时显示重量曲线
    • 通过Excel分析采集的历史数据

6. 进阶优化方向

6.1 低功耗设计

对于电池供电的应用,可实施以下优化:

  1. 配置STM32进入睡眠模式,定时唤醒采样
  2. 动态调整HX711的采样速率
  3. 关闭不必要的外设时钟
void enter_low_power_mode(void) {
    // 配置唤醒源(如外部中断)
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}

6.2 多传感器融合

结合其他传感器提升系统可靠性:

  • 温度传感器补偿热漂移
  • 加速度计检测机械振动干扰
  • 湿度传感器监测环境变化

6.3 用户界面增强

提升终端用户体验:

  1. 添加按键控制去皮/校准功能
  2. 设计OLED显示界面
  3. 实现蓝牙/Wi-Fi无线数据传输
  4. 开发手机APP可视化数据
void update_display(float weight) {
    char buf[16];
    sprintf(buf, "%.1f g", weight);
    OLED_ShowString(0, 0, (uint8_t *)buf, 16);
}

在实际项目中,我发现机械结构的稳定性往往比电路设计更能影响测量精度。一个常见的错误是过度关注软件滤波而忽视了传感器的物理安装。使用3D打印的传感器支架配合适当的预紧力调节,能让系统性能提升显著。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐