STM32F103C8T6称重传感器HX711模块压力传感器称重的使用方法和代码驱动
STM32F103C8T6称重传感器HX711模块压力传感器称重的使用方法和代码驱动
文档结尾有代码下载链接
🎯 实现效果
🌟 传感器用途
称重传感器的核心价值是“将重量信息数字化、可量化”,结合HX711和单片机后,能实现从“单纯称重”到“智能监测与控制”的延伸,覆盖民用、工业、智能硬件、医疗等多个领域。
1.民用消费场景
- 家庭日常称重:家用电子体重秤(通过4个分布式传感器测量体重、体脂率,HX711负责同步采集各传感器信号)、厨房秤(称量食材克数,精度达1g,满足烘焙、辅食制作的精准配比需求)、宠物秤(监测宠物体重变化,辅助判断健康状况)。
- 便携称重工具:行李秤(最大量程50kg,通过挂钩式传感器测量行李重量,避免航空托运超重)、钓鱼秤(称量渔获重量,带背光显示屏,适配户外使用)、珠宝秤(高精度达0.01g,采用小型应变式传感器,搭配HX711实现微量称重)。
- 消费电子附件:智能水杯(内置微型传感器,监测饮水量变化,通过APP提醒补水)、快递打包秤(小型桌面秤,方便电商卖家快速称重计价)。
2. 工业生产场景
- 生产线上的重量管控:食品饮料行业(瓶装饮料灌装后称重,检测是否漏灌、少灌,不合格产品自动剔除)、制药行业(药片/胶囊重量检测,确保每粒药量符合标准,避免药效不足或过量)、五金加工(零部件重量筛选,剔除材质不均的次品)。
- 仓储物流与物料管理:仓库货架称重(在货架横梁安装传感器,实时监测货物重量,实现库存动态管理)、传送带物料流量监测(通过传感器连续称重传送带上的物料,换算单位时间内的输送量,优化生产节奏)、叉车称重(在叉车货叉上安装传感器,叉取货物时直接显示重量,无需额外过磅)。
- 工业设备状态监测:机械臂抓取力检测(在机械臂末端安装小型传感器,通过抓取重量判断是否成功抓取物体,避免空抓或抓取过紧损坏工件)、机床切削负载监测(在机床主轴或工作台安装传感器,监测切削过程中的重量变化,间接判断切削力,防止过载损坏设备)。
3. 智能硬件与物联网场景
- 智能家居与农业:智能花盆(传感器监测盆土+植物总重量,结合湿度传感器判断是否缺水,自动启动浇水装置)、智能垃圾桶(通过重量变化判断垃圾是否装满,满桶后推送提醒至用户手机)、温室大棚(监测作物生长过程中的重量变化,分析生长速率,优化水肥管理)。
- 医疗健康设备:婴儿培养箱体重监测(内置高精度传感器,实时监测新生儿体重变化,数据同步至医护系统)、康复训练设备(如肌力训练器,通过传感器测量患者发力时的重量/压力,制定个性化康复方案)、输液重量监测(通过传感器监测输液袋重量,计算输液速度,快输完时报警提醒护士)。
- 创意DIY与创客项目:自制自动喂料机(传感器检测料仓重量,低于阈值时启动电机补料)、智能快递柜称重模块(用户存件时自动称重,根据重量收取费用)、重量感应式台灯(放置物体在底座上时自动开灯,移开后关灯,实现无接触控制)。
🌟 传感器的介绍
称重传感器是将物体重量信号转换成可测量电信号的核心器件,也是 HX711 的前端信号来源,其设计和性能直接决定称重系统的精度。
1.主流类型与核心原理
- 目前与 HX711 搭配最广的是电阻应变式称重传感器,原理可拆解为 3 步:
- 传感器内部含 “应变片”(一种受力后电阻会变化的特殊材料),应变片粘贴在金属弹性体上。
- 当物体压在传感器上时,弹性体发生微小形变,带动应变片同步形变,使其电阻值改变。
- 应变片组成 “惠斯通电桥” 电路,电阻变化会转化为微弱的差分电压信号(通常仅几毫伏),该信号需经 HX711 放大、AD 转换后,才能被单片机读取。
2.关键技术参数
- 量程:传感器能测量的最大重量,常见规格有 1kg、5kg、10kg、50kg 等,需根据实际称重需求选择。
- 灵敏度:单位重量对应的输出电压,通常标注为 “mV/V”(如 2mV/V),表示给传感器加 1V 电源时,每承受 1kg 重量会输出 2mV 电压。
- 精度:测量值与真实重量的偏差程度,民用场景(如电子秤)选 0.1% 精度即可,工业检测可能需 0.01% 高精度。
🎯 单片机连接硬件图
🌟 驱动思路
步骤 1:硬件初始化
- 将 SCK 配置为输出引脚,DOUT 配置为输入引脚
- SCK 引脚:推挽输出(GPIO_Mode_Out_PP),初始电平为低(HX711 规定:DOUT 为高时,SCK 必须为低)。
- DOUT 引脚:浮空输入(GPIO_Mode_IN_FLOATING)或上拉输入(避免悬空干扰)。
- 使能对应 GPIO 端口的时钟(通过 RCC 寄存器)。
步骤 2:传感器数据读取
- HX711 的数据读取依赖严格的时序控制,核心流程:等待数据就绪→读取 24 位数据→发送通道 / 增益选择脉冲。
- (1)等待数据就绪
HX711 完成 AD 转换后,DOUT 会从高电平变为低电平(表示数据就绪)。需循环检测 DOUT 电平,直到变为低。 - (2)读取 24 位数据(高位先出)
通过 SCK 发送 24 个时钟脉冲,每发一个脉冲(高→低),从 DOUT 读取 1 位数据(24 位补码):
第 1 个脉冲:读取最高位(bit23),第 24 个脉冲:读取最低位(bit0)。
每次 SCK 从低→高时,HX711 准备好下一位数据;SCK 从高→低时,读取当前位。 - (3)通道 / 增益选择(第 25-27 个脉冲)
读取 24 位数据后,需额外发送 1-3 个 SCK 脉冲,选择下一次转换的通道和增益:
25 个脉冲:通道 A,增益 128(最常用)。
26 个脉冲:通道 B,增益 32。
27 个脉冲:通道 A,增益 64。
步骤 3:数据处理与显示
- HX711 输出的 24 位数据是补码形式,需转换为实际物理量(重量):
补码转原码:24 位补码的最高位为符号位,若为 1(负数),需转换为正数(rawData ^= 0x800000)。
滤波处理:称重数据易受噪声干扰,需通过中值滤波、滑动平均等算法平滑(如取 5 次数据的中值)。
重量转换:通过校准系数将 AD 值转换为实际重量(单位:g),公式:重量 = (AD值 - 皮重AD值) × 校准系数。
4.数据显示: 接提取出来的数据通过串口一打印以及OLED显示数据
🎯 单片机程序代码
main.c
#include "stm32f10x.h"
#include "string.h"
#include "stdio.h"
#include "delay.h"
#include "bsp_usart.h"
#include "oled.h"
#include "HX7111.h"int weight=0;
char OledBuff[52];
int main(void)
{NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2);SysTick_Init(72); //系统时钟初始化 usart1_init(115200);//串口1初始化printf("USART1 OK!\r\n");usart2_init(9600);//串口1初始化usart3_init(115200);//串口3初始化 OLED_Init();OLED_ShowString(36,0,"HX711");HX711_Init();OLED_ShowString(0,2,"去皮");HX711_CalibrateTare();delay_ms(100);OLED_ShowString(0,2,"去皮成功");delay_ms(100);OLED_ShowString(0,2," ");while(1){weight=HX711_GetWeight();sprintf(OledBuff,"重量:%d g ",weight);OLED_ShowString(0,2,OledBuff);}
}
HX7111.c
#include "HX7111.h"
#include "delay.h"
#include "bsp_usart.h"// 静态变量 - 仅在本模块内有效,避免全局变量冲突
static uint32_t tareWeight = 0; // 皮重值
static const uint32_t calibrationFactor = 25499; // 校准系数
static uint32_t filterBuffer[MEDIAN_FILTER_LEN]; // 滤波缓冲区
static uint8_t filterIndex = 0; // 滤波数据计数/*** @brief 配置HX711数据引脚为输出模式*/
static void HX711_SetDataOutput(void)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = HX711_DATA_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(HX711_DATA_GPIO_PORT, &GPIO_InitStructure);
}/*** @brief 配置HX711数据引脚为输入模式*/
static void HX711_SetDataInput(void)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = HX711_DATA_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(HX711_DATA_GPIO_PORT, &GPIO_InitStructure);
}/*** @brief HX711初始化函数*/
void HX711_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 使能GPIO时钟(仅需初始化一次)HX711_GPIO_APBxClkCmd(HX711_GPIO_CLK, ENABLE);// 配置SCK引脚为推挽输出GPIO_InitStructure.GPIO_Pin = HX711_SCK_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(HX711_SCK_GPIO_PORT, &GPIO_InitStructure);// 初始化为输入模式HX711_SetDataInput();// 初始状态设置HX711_SCK_LOW;
}/*** @brief 读取HX711原始AD数据* @return 24位AD转换结果*/
uint32_t HX711_ReadRawData(void)
{uint8_t i;uint32_t rawData = 0;// 等待数据就绪HX711_SetDataOutput();HX711_DATA_HIGH;delay_us(HX711_DELAY_US);HX711_SCK_LOW;HX711_SetDataInput();// 等待DOUT变为低电平(数据就绪)while(HX711_DATA_READ);delay_us(HX711_DELAY_US);// 读取24位数据(高位先出)for(i = 0; i < 24; i++){HX711_SCK_HIGH;delay_us(HX711_DELAY_US);rawData <<= 1; // 左移一位if(HX711_DATA_READ) // 读取当前位rawData |= 0x01;HX711_SCK_LOW;delay_us(HX711_DELAY_US);}// 第25个时钟脉冲(选择通道A,增益128)HX711_SCK_HIGH;rawData ^= 0x800000; // 转换为补码delay_us(HX711_DELAY_US);HX711_SCK_LOW;delay_us(HX711_DELAY_US);return rawData;
}/*** @brief 中值滤波处理* @param newData 新采集的数据* @return 滤波后的值(当缓冲区满时)*/
static uint32_t medianFilter(uint32_t newData)
{uint8_t i, j;uint32_t temp;// 存入新数据filterBuffer[filterIndex++] = newData;// 缓冲区未满时返回0if(filterIndex < MEDIAN_FILTER_LEN)return 0;// 缓冲区满,进行排序(插入排序)for(i = 0; i < MEDIAN_FILTER_LEN - 1; i++){for(j = i + 1; j < MEDIAN_FILTER_LEN; j++){if(filterBuffer[i] > filterBuffer[j]){temp = filterBuffer[i];filterBuffer[i] = filterBuffer[j];filterBuffer[j] = temp;}}}// 重置缓冲区索引filterIndex = 0;// 返回中值return filterBuffer[MEDIAN_POSITION];
}/*** @brief 校准皮重(获取空载重量)*/
void HX711_CalibrateTare(void)
{uint32_t rawData;uint32_t filteredData = 0;// 采集一组数据进行中值滤波filterIndex = 0; // 重置滤波缓冲区while(filteredData == 0){rawData = HX711_ReadRawData();filteredData = medianFilter(rawData);}// 计算皮重(缩小100倍处理)tareWeight = (uint16_t)(filteredData * 0.01f);
}/*** @brief 获取当前重量(已扣除皮重)* @return 重量值(g)*/
uint32_t HX711_GetWeight(void)
{uint32_t rawData, processedData;uint32_t weight = 0;uint32_t filteredData = 0;// 读取原始数据并进行滤波while(filteredData == 0){rawData = HX711_ReadRawData();processedData = (uint16_t)(rawData * 0.01f); // 数据预处理filteredData = medianFilter(processedData);}// 计算净重(扣除皮重)if(filteredData > tareWeight){// 应用校准系数转换为实际重量weight = (uint16_t)(((float)(filteredData - tareWeight) * calibrationFactor) * 0.00001f);}else{weight = 0; // 小于皮重时视为0}// 打印重量信息(调试用)printf("重量: %d g\r\n", weight);delay_ms(500);return weight;
}
🎯 代码下载链接
https://download.csdn.net/download/qq_41954594/92130073