传感器驱动系列之HX711称重模块

传感器驱动系列之HX711称重模块HX711 是一种高精度 低噪声的模拟前端芯片 常用于称重传感器和负载细节测量应用中

大家好,欢迎来到IT知识分享网。

目录

一、HX711称重模块简介

1.1 HX711简介

1.2 称重传感器简介

1.3 称重模块

二、工作原理简介

三、STM32驱动源码

3.1 STM32源码

3.2 代码分析

END


一、HX711称重模块简介

1.1 HX711简介

        HX711是一种高精度、低噪声的模拟前端芯片,常用于称重传感器和负载细节测量应用中。它具有内置的放大器和ADC(模数转换器),可以将称重传感器的模拟信号转换为数字信号。其实物见下图1所示。

传感器驱动系列之HX711称重模块
图1  HX711称重模块

        HX711模块通常与称重传感器(如压阻式称重传感器)配合使用,以便实现重量测量功能。在使用HX711时,通常需要将其与一个称重传感器连接,以便将传感器的模拟输出信号转换为数字信号。然后,这个数字信号可以被微控制器或其他数字系统处理和解读。

1.2 称重传感器简介

        称重传感器,也可称为负载单元,称重单元。称重传感器测量重量(或者更准确地说是方向力)通常是通过弹簧元件和应变片的组合,转换为电气输出。应变片称重传感器由固定应变片的固体金属体(或”弹簧元件)组成。应用负载时,称重传感器的主体轻微变形并偏转。见下图2示。

传感器驱动系列之HX711称重模块
图2  称重传感器

        如上图2所示,单点式称重传感器是低量程高精度的称重传感器。外形如四方体形状,测量结果准确可靠,广泛运用于电子秤,厨房秤,珠宝秤等领域,是工业和农业自动化系统中不可缺少的核心部件。

1.3 称重模块

        称重模块实物图示意见下图3所示。

传感器驱动系列之HX711称重模块
图3  HX711称重模块实物

二、工作原理简介

        HX711的串口通讯线由管脚PD_SCKSCK)和DOUTDT)组成,共同用来输出数据、选择输入通道和增益。下图4为数据手册贴出的工作时序图。

传感器驱动系列之HX711称重模块
图4  HX711工作时序

        1. 当DOUT(数据输出引脚)为高电平时,表明A/D转换器还未准备好输出数据,此时串口时钟输入信号PD_SCK应为低电平;

        2. 当DOUT从高电平变低电平后,PD_SCK应输入2527个不等的时钟脉冲(其中前24各时钟脉冲输出的是传感器测得的ADC数据,第25-27个时钟脉冲与数据无关,仅用于选择下一次传感器的输出增益和输出通道)。

需要注意的是:这里说明的DOUT和PD_SCK是针对于传感器的数据手册来说明的,即在数据手册中,传感器的DOUT引脚是作为输出,那么我们在使用MCU控制器驱动该传感器时,需要将该引脚作为输入引脚进行配置;同理,PD_SCK引脚是需要MCU向传感器输出时钟脉冲的,因此MCU控制器需要将该引脚配置为输出模式向HX711输入时钟脉冲。

        3. 在第一个时钟脉冲的上升沿会读取出输出的24位数据的最高位(即最高有效位,MSB),然后在接下来的时钟脉冲中,逐位输出这24位数据,从最高位到最低位。这个过程会一直持续,直到24位数据全部输出完成。因此传感器的数据输出是从高位到低位的,驱动编写时需注意。

        4. 数据手册中还有一个可能会被忽略的细节,见下图5所示。

传感器驱动系列之HX711称重模块
图5  时序时间分析

        由上图5可知,我们需要给定的时PD_SCK正脉冲的电平(高电平)最大时间不能超过50us,而负脉冲的电平(低电平)的时间不能小于0.2us,而由于我们一般是选择将脉冲的占空比设置为50%,因此我们可以给定高低电平的延时时间相等,后续的驱动程序中给定的是1us。

        5. PD_SCK 的输入时钟脉冲数不应少于 25 或多于 27,否则会造成串口通讯错误。 当 A/D 转换器的输入通道或增益改变时,A/D 转换器需要 4 个数据输出周期才能稳定。DOUT 在 4 个数据输出周期后才会从高电平变低电平,输出有效数据。见下图6所示。

传感器驱动系列之HX711称重模块
图6  PD_SCK脉冲数选择

        上图中,第2527个时钟脉冲用来选择下一次A/D转换的输入通道和增益。关于整体HX711的介绍就到这里,感兴趣的读者可以参考HX711的数据手册,链接如下:HX711数据手册

三、STM32驱动源码

3.1 STM32源码

        其中hx711.c驱动源码如下:

/ * 文件名称: hx711.c * 作 者: JJ-KING * 版 本 号: V1.0.0 * 创建日期: 2023-02-09 * 模块描述: 压力传感器配置 * 其他说明: * 修改记录: <作者> <时间> <版本号> <描述> / /*---------------------------------------------------------------------------- 更新日志: 2023-02-09 V1.0.0: 修改引脚为宏定义声明 2024-01-04 V1.0.0: 重新定义获取重量的外部接口函数 ----------------------------------------------------------------------------*/ /* 包含的头文件 --------------------------------------------------------------*/ #include "hx711.h" #include "delay.h" #define HX711_DOUT(x) GPIO_WriteBit(HX711_DOUT_GPIO_PORT, HX711_DOUT_GPIO_PIN, (BitAction)x) #define HX711_SCK(x) GPIO_WriteBit(HX711_SCK_GPIO_PORT, HX711_SCK_GPIO_PIN, (BitAction)x) #define HX711_SCK_STATE GPIO_ReadOutputDataBit(HX711_SCK_GPIO_PORT, HX711_SCK_GPIO_PIN) #define HX711_DOUT_STATE GPIO_ReadInputDataBit(HX711_DOUT_GPIO_PORT, HX711_DOUT_GPIO_PIN) static STRUCT_HX711_TYPEDEF hx711; /* 传感器 gpio引脚配置 */ static void hx711_gpio_config(void) { RCC_APB2PeriphClockCmd(HX711_DOUT_GPIO_CLK | HX711_SCK_GPIO_CLK, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; /* IO口速度为2MHz */ GPIO_InitStructure.GPIO_Pin = HX711_SCK_GPIO_PIN; /* 端口配置 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* 推挽输出 */ GPIO_Init(HX711_SCK_GPIO_PORT, &GPIO_InitStructure);/* 根据设定参数初始化 */ GPIO_InitStructure.GPIO_Pin = HX711_DOUT_GPIO_PIN; /* 端口配置 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; /* 上拉输入 */ GPIO_Init(HX711_DOUT_GPIO_PORT, &GPIO_InitStructure);/* 根据设定参数初始化 */ HX711_SCK(0); HX711_DOUT(1); } /* 传感器结构体参数初始化 */ static void hx711_struct_config(void) { hx711.gain = GAIN_128; /* 当前增益 128 */ hx711.isTare = true; /* 默认第一次称重为皮重 */ hx711.k = 0.004757f; /* 传感器转换系数 */ hx711.b = 0.f; /* 传感器误差校正/补偿值 */ hx711.tare = 0.f; /* 保存皮重数据 */ hx711.actual = 0.f; /* 保存净重数据 */ } /* 读取传感器返回的ADC数据值(数字量) 假定为一阶线性关系 y=kx+b */ static unsigned long hx711_readCount(void) { unsigned long count = 0; /* 需要读取25-27个0/1数据 */ unsigned char timeOut_cnt = 0; /* 检测超时计数值 */ HX711_SCK(0); /* 添加超时检测 防止一直未识别到传感器导致程序卡死在这里 */ while(HX711_DOUT_STATE) { /* 等待DOUT从高电平到低电平跳变 */ timeOut_cnt ++; delay_ms(1); if(timeOut_cnt > 100) return 0; } /* 读取24位的ADC数字量数据 */ for(unsigned char i=0; i<24; i++) { HX711_SCK(1); delay_us(1); HX711_SCK(0); count |= (HX711_DOUT_STATE) << (24-i); /* 上升沿读取数据 */ delay_us(1); } /* 用于设置输出增益和输出通道 */ for(unsigned char j=0; j<hx711.gain; j++) { HX711_SCK(1); delay_us(1); HX711_SCK(0); delay_us(1); } return (count ^ 0x); } /* ----------------------------- 接口函数 ---------------------- */ /* 传感器 初始化 */ void hx711_init(void) { hx711_gpio_config(); hx711_struct_config(); } /* 传感器断电 */ void hx711_power_off(void) { HX711_SCK(0); delay_us(1); HX711_SCK(1); delay_us(100); } /* 传感器上电 */ void hx711_reset(void) { if(HX711_SCK_STATE == 1) { HX711_SCK(0); } } /* 设置传感器转换系数 */ void hx711_set_convert_ratio(float ratio) { hx711.k = ratio; } /* 设置传感器误差校正/补偿值 */ void hx711_set_offset_value(float offset) { hx711.b = offset; } /* 设置传感器增益 */ void hx711_set_gain(ENUM_HX711_GAIN_TYPEDEF gain) { hx711.gain = gain; } /* 获取传感器皮重数据 */ float hx711_get_tare_weight(void) { hx711.isTare = true; /* 获取皮重的时候 将该标志位置位 */ if(hx711.isTare == true) { hx711.isTare = false; hx711.tare = (float)hx711_readCount() * hx711.k + hx711.b; /* 此时获取到的重量为皮重 */ } return (hx711.tare); } /* 获取传感器实际重量 */ float hx711_get_actual_weight(void) { float weight = 0.f; if(hx711.isTare == false) { /* 当该标志位复位 代表此时应计算净重 */ weight = (float)hx711_readCount() * hx711.k + hx711.b; hx711.actual = weight - hx711.tare; } return (hx711.actual); } 

      hx711.h文件如下:

/ * 文件名称: hx711.h * 作 者: JJ-KING * 版 本 号: V1.0.0 * 创建日期: 2023-02-09 * 模块描述: 压力传感器配置 * 其他说明: * 修改记录: <作者> <时间> <版本号> <描述> / /*---------------------------------------------------------------------------- 更新日志: 2023-02-09 V1.0.0: 修改引脚为宏定义声明 2024-01-04 V1.0.0: 重新定义获取重量的外部接口函数 ----------------------------------------------------------------------------*/ #ifndef __HX711_H #define __HX711_H #include "stm32f10x.h" #include "stdbool.h" /* 用于保存HX711的增益 */ typedef enum { GAIN_128 = 1, GAIN_32, GAIN_64, } ENUM_HX711_GAIN_TYPEDEF; /* 结构体 用于实现HX711本身的属性 */ typedef struct { ENUM_HX711_GAIN_TYPEDEF gain; /* 增益 */ bool isTare; /* 判断传感器数据是否是皮重 true-是 false-否 */ float k; /* 比例系数 */ float b; /* 补偿值 */ float tare; /* 皮重 */ float actual; /* 实重 */ } STRUCT_HX711_TYPEDEF; /* HX711传感器引脚定义 */ #define HX711_DOUT_GPIO_CLK RCC_APB2Periph_GPIOC #define HX711_DOUT_GPIO_PORT GPIOC #define HX711_DOUT_GPIO_PIN GPIO_Pin_0 #define HX711_SCK_GPIO_CLK RCC_APB2Periph_GPIOC #define HX711_SCK_GPIO_PORT GPIOC #define HX711_SCK_GPIO_PIN GPIO_Pin_1 /* ---------------- 函数清单 --------------- */ void hx711_init(void); /* HX711初始化 */ void hx711_power_off(void); /* HX711断电 */ void hx711_reset(void); /* HX711断电后复位 */ void hx711_set_convert_ratio(float ratio); /* 设置HX711重量比例系数 */ void hx711_set_offset_value(float offset); /* 设置HX711重量补偿值 */ void hx711_set_gain(ENUM_HX711_GAIN_TYPEDEF gain); /* 设置HX711增益系数 */ float hx711_get_tare_weight(void); /* 获取皮重 */ float hx711_get_actual_weight(void); /* 获取实重 */ #endif 

3.2 代码分析

        上述代码中设置了结构体STRUCT_HX711_TYPEDEF用于配置传感器的自有属性:

/* 结构体 用于实现HX711本身的属性 */ typedef struct { ENUM_HX711_GAIN_TYPEDEF gain; /* 增益 */ bool isTare; /* 判断传感器数据是否是皮重 true-是 false-否 */ float k; /* 比例系数 */ float b; /* 补偿值 */ float tare; /* 皮重 */ float actual; /* 实重 */ } STRUCT_HX711_TYPEDEF;

        其中结构体成员变量k,用于配置传感器与实际重量之间的比例关系,即传感器系数。根据传感器数据手册的时序图得到的传感器数据,其实质上是一个24位的ADC数据值,与实际的物体重量其本质上并没有关联,我们可以认为的让他们之间存在一个一阶线性相关,即:

y = kx + b

        因此我们可以得到如下的公式:

实际重量(w)= 比例系数(k)* 读取的传感器adc数据 + 补偿值(b)

        那么如何计算这个参数k呢?

        1. 首先我们可以在hx711.c中将结构体初始化中的成员变量(k)初始化为1,然后我们不在称重传感器上放置任何物体,那么我们通过hx711_get_tare_weight()函数得到的皮重数据其本质上为传感器本身的adc值。

        2. 然后找到一个可以确定重量的物体,比如我们的手机(在官网上可以查到手机的参考重量),然后放置在称重传感器上,此时通过hx711_get_actual_weight()函数得到的实际重量数据为传感器本身的adc值(k值为1,即此时调用该函数得到的重量数据为ADC模数转换值,并不是具体重量)。

        3. 我们可以通过如下公式将得到的两个传感器数据值相减,算出参数k的值。公式如下:

比例系数(k)=(手机实际重量(w1) – 电子秤皮重(w0)) / (手机传感器adc数值 – 皮重adc值)

        4. 这样得到的比例系数(k)值就是适配与当前传感器模块的参数了,我们叫它传感器系数。

        5. 补偿值(b)的确定可以由物体在测量过程中的实际表现酌情设置。

        注意:测重的adc数据值可能会跳变的比较快,这是由于读取的传感器精度决定的,由于传感器是24位高精度,因此细小的变动都会导致传感器数据值发生改变。所以我们只需要取跳变中的任意一个时刻的数据值即可。

四、测试实例

        1. 首先需要调用hx711_init()函数用于初始化引脚及结构体;

        2. 然后需要先调用获取皮重函数hx711_get_tare_weight()获取一次物体的皮重

        3. 接着就可以使用hx711_get_actual_weight函数获取物体的实时重量了

END

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/137345.html

(0)
上一篇 2025-06-21 14:15
下一篇 2025-06-21 14:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信