STM32F103C8T6 · HAL库 · 24位高精度ADC称重方案
HX711 是一款专为高精度电子秤设计的24位ADC芯片,搭配电阻应变片压力传感器实现重量测量。
HX711 是一款面向高精度称重应用设计的24位专用ADC(模数转换器)芯片。其核心检测原理基于电阻应变片效应:
压力传感器(称重传感器)内部由4片电阻应变片组成惠斯通电桥。当外力施加于传感器弹性体上时,应变片产生微小形变,导致电阻值发生微小变化,打破电桥平衡,输出一个与受力成正比的微弱差分电压信号(通常为毫伏级)。
HX711 芯片内部集成了可编程增益放大器(PGA)和24位Σ-Δ ADC,将该差分信号放大128倍后进行数字化转换,输出24位补码数据。STM32通过两线串行接口(SCK + DIO)读取该数据,经过校准计算后得到实际重量值。
信号链路:受力 → 应变片形变 → 电桥失衡 → 差分电压 → HX711 PGA放大(128x) → 24位ADC数字化 → SCK/DIO串行读取 → STM32校准计算 → OLED显示
24位ADC分辨率,可检测微小的电阻变化,实现克级甚至更小单位的精确重量测量,满足电子秤精度需求。
内置PGA支持Channel A可编程增益128或64倍,Channel B固定增益32倍,适配不同灵敏度的传感器,默认使用Channel A增益128倍。
支持空载时获取毛皮基准值,测量时自动减去基准计算净重。校准系数可根据实际传感器特性灵活调整。
仅需SCK(时钟)和DIO(数据)两根线即可完成数据读取,通信协议简洁高效,占用STM32极少的GPIO资源。
HX711模块共有8个引脚端子,左侧4个连接STM32,右侧4个连接压力传感器(称重传感器):
| 引脚号 | 名称 | 功能 | 连接 | 类型 |
|---|---|---|---|---|
| 1 | VCC | 电源正极(2.6V-5.5V) | 5V | 电源 |
| 2 | GND | 电源地 | GND | 地 |
| 3 | SCK | 串行时钟输入(STM32输出) | PB4(推挽输出) | 信号 |
| 4 | DIO | 串行数据输出(STM32读取) | PB3(上拉输入) | 信号 |
| 5 | E+ | 激励电压正(给传感器供电) | 称重传感器红线 | 外部 |
| 6 | E- | 激励电压负(给传感器供电) | 称重传感器黑线 | 外部 |
| 7 | A+ | Channel A 信号正(差分输入+) | 称重传感器绿线 | 外部 |
| 8 | A- | Channel A 信号负(差分输入-) | 称重传感器白线 | 外部 |
HX711压力传感器模块及称重传感器实物外观展示。
HX711压力传感器模块的电路原理图与PCB封装设计。
基于STM32 HAL库开发,分析HX711驱动程序、GPIO配置及主循环逻辑。
系统初始化流程:HAL_Init → 系统时钟配置(72MHz) → GPIO初始化 → OLED初始化 → HX711初始化 → 获取毛皮基准值。主循环每500ms读取一次重量数据并在OLED上居中显示。
/* USER CODE BEGIN Includes */ #include "./HAL/OLED/OLED.h" #include "./HAL/HX711/hx711.h" /* USER CODE END Includes */ /* USER CODE BEGIN PV */ uint32_t Time_Now; uint32_t Maopi; // 毛皮基准值 uint16_t weight; // 实际重量(g) /* USER CODE END PV */ int main(void) { HAL_Init(); SystemClock_Config(); /* 初始化所有已配置的外设 */ MX_GPIO_Init(); /* USER CODE BEGIN 2 */ OLED_Init(); // OLED显示屏初始化 Hx711_Init(); // HX711初始化(含GPIO配置+获取毛皮) Maopi = Hx711_Get_Maopi(); // 获取空载毛皮基准值 /* USER CODE END 2 */ /* USER CODE BEGIN WHILE */ while (1) { if(HAL_GetTick() - Time_Now >= 500) // 500ms更新一次 { weight = Hx711_Get_Weight(Maopi); // 获取实际重量 OLED_Clear(); // 清屏 OLED_CenterPrintf(24, "%dg", weight); // 居中显示重量 OLED_Update(); // 更新显示 Time_Now = HAL_GetTick(); // 更新时间戳 } /* USER CODE END WHILE */ } }
定义了HX711的硬件引脚连接(SCK→PB4, DIO→PB3)、校准系数(474.0)、最大量程(5000g)以及引脚操作宏。校准系数是称重精度的核心参数,需根据实际传感器校准。
/* 称重校准系数(关键参数) * 重量偏大:增大该数值;重量偏小:减小该数值 * 校准方法:用已知重量物体测试,调整至测量值与实际值一致 */ #define HX711_CALIBRATION_FACTOR 474.0f // 称重最大量程限制(单位:g,5kg) #define HX711_MAX_WEIGHT 5000u /* HX711 硬件引脚定义(STM32 GPIOB) */ // DIO引脚(数据输入)- GPIOB Pin3 #define HX711_DIO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define HX711_DIO_PORT GPIOB #define HX711_DIO_PIN GPIO_PIN_3 // SCK引脚(时钟输出)- GPIOB Pin4 #define HX711_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define HX711_SCK_PORT GPIOB #define HX711_SCK_PIN GPIO_PIN_4 /* 引脚操作宏定义 */ #define HX711_SCK_LOW() HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET) #define HX711_SCK_HIGH() HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET) #define HX711_DIO_READ() HAL_GPIO_ReadPin(HX711_DIO_PORT, HX711_DIO_PIN)
SCK配置为推挽输出模式(STM32主动输出时钟信号),DIO配置为上拉输入模式(读取HX711返回的数据)。SCK初始状态为低电平(HX711空闲状态)。
void Hx711_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 1. 使能DIO和SCK引脚对应的GPIO时钟 HX711_DIO_GPIO_CLK_ENABLE(); HX711_SCK_GPIO_CLK_ENABLE(); /* 2. 配置SCK引脚(推挽输出、高速、无上下拉) */ GPIO_InitStruct.Pin = HX711_SCK_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速输出 GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(HX711_SCK_PORT, &GPIO_InitStruct); /* 3. 配置DIO引脚(上拉输入、检测外部数据) */ GPIO_InitStruct.Pin = HX711_DIO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式 GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉输入 HAL_GPIO_Init(HX711_DIO_PORT, &GPIO_InitStruct); // 4. 初始化SCK为低电平(HX711默认空闲状态) HX711_SCK_LOW(); }
核心通信函数。等待DIO拉低(数据就绪)后,发送24个SCK时钟脉冲逐位读取24位数据(MSB先行),第25个脉冲选择下次转换的增益(128x)。最后对数据进行XOR 0x800000校正,将补码转换为无符号整数。
static uint32_t HX711_Read_Raw(void) { uint32_t raw_count = 0; uint8_t i = 0; // 1. 等待数据准备完成(DIO拉低表示数据就绪) while(HX711_DIO_READ() == GPIO_PIN_SET); // 2. 逐位读取24位数据(高位先行 MSB First) for(i = 0; i < 24; i++) { HX711_SCK_HIGH(); // 时钟高,触发输出下一位 raw_count <<= 1; // 左移一位,预留最低位 HX711_SCK_LOW(); // 时钟低,准备读取 if(HX711_DIO_READ() == GPIO_PIN_SET) { raw_count++; // DIO为高则最低位置1 } } // 3. 第25个时钟脉冲:完成读取并选择增益128 HX711_SCK_HIGH(); raw_count ^= 0x800000; // 补码转无符号(翻转最高位) delay_us(1); HX711_SCK_LOW(); return raw_count; }
读取当前ADC原始值,减去空载时的毛皮基准值得到净重计数值,再除以校准系数(474.0)转换为实际重量(克)。净重为负值时返回0,超过5000g时返回最大量程。
uint32_t Hx711_Get_Weight(uint32_t Weight_Maopi) { int32_t weight_net_count = 0; uint32_t actual_weight = 0; // 1. 当前原始值 - 去皮基准 = 净重计数值 weight_net_count = HX711_Read_Raw() - Weight_Maopi; // 2. 计算实际重量(仅当净重为正时有效) if(weight_net_count > 0) { // 除以校准系数,转换为实际重量(g) actual_weight = (uint32_t)((float)weight_net_count / HX711_CALIBRATION_FACTOR); // 3. 量程限制 if(actual_weight > HX711_MAX_WEIGHT) { actual_weight = HX711_MAX_WEIGHT; } } else { actual_weight = 0; // 空载或负偏差 } return actual_weight; }
重量计算的核心公式为:weight = (raw - tare) / 474.0,其中raw为当前24位ADC读数,tare为空载基准值,474.0为校准系数。
| 状态 | 原始值(raw) | 净重计数(raw-tare) | 计算重量(g) | OLED显示 |
|---|---|---|---|---|
| 空载 | 8388608 (0x800000) | 0 | 0 | 0g |
| 轻载(100g) | 8388608 + 47400 | 47400 | 100 | 100g |
| 中载(1000g) | 8388608 + 474000 | 474000 | 1000 | 1000g |
| 满载(5000g) | 8388608 + 2370000 | 2370000 | 5000 | 5000g |
| 超量程(>5000g) | > 8388608 + 2370000 | > 2370000 | 5000(限幅) | 5000g |
使能GPIOD和GPIOA时钟。HX711的GPIOB引脚配置在Hx711_GPIO_Init()中独立完成,OLED的GPIOB引脚配置在OLED_Init()中完成。
void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // 注:GPIOB时钟在Hx711_GPIO_Init()和OLED_Init()中使能 }
STM32主程序执行流程,包含系统初始化、外设初始化和while(1)主循环。
模拟压力传感器称重过程:放置砝码 → 应变片形变 → HX711读取ADC → OLED显示重量。
操作说明:点击按钮放置砝码到称重传感器上,观察应变片梁的形变、HX711的SCK/DIO数据传输过程,以及右侧OLED显示和ADC数据变化。点击"去皮"可重置基准值。
数据链路:受力 → 应变片电桥输出差分电压 → HX711 PGA放大128倍 → 24位ADC转换 → SCK/DIO串行读取 → 减去毛皮基准 → 除以校准系数474.0 → 重量显示