STM32--HX711称重传感器


目录

前言

一、工作原理

二、接线方式

三、软件程序

关键说明(避坑重点)!!!!

[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。首次使用时需执行校准流程(空载校准和已知重量标定),后续即可循环读取重量数据并通过串口输出。该方案适用于需要高精度称重的嵌入式应用场景。

相关推荐
richxu202510011 小时前
嵌入式学习之路>单片机核心原理>(3)定时器
单片机·嵌入式硬件·学习
Geek__19921 小时前
记录FreeRtos消息调试问题
c语言·stm32·mcu
小琦QI1 小时前
STM32F407VET6+CCE4503学习笔记---IOLINK server
笔记·stm32·学习
Darken031 小时前
基于单片机STM32中的OLED显示屏
stm32·单片机·oled·显示屏
Bona Sun2 小时前
单片机手搓掌上游戏机(十九)—pico运行doom之硬件连接
c语言·c++·单片机·游戏机
Darken032 小时前
什么是SPI协议?
单片机·spi
努力小周2 小时前
基于STM32物联网智能老年人防摔系统
stm32·单片机·嵌入式硬件·物联网·c#·课程设计
brave and determined2 小时前
传感器学习(day02)毫米波雷达:重塑人机交互新维度
单片机·嵌入式硬件·嵌入式·人机交互·传感器·毫米波·嵌入式设计
Bona Sun2 小时前
单片机手搓掌上游戏机(二十二)—pico运行doom之固件和rom上传
c语言·c++·单片机·游戏机