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;
    
    // 缓冲区未满时返回0
    if(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

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐