HX711芯片
简介:
HX711 采用了海芯科技集成电路专利技术, 是一款专为高精度电子秤而设计的 24 位 A/D 转 换器芯片。与同类型其它芯片相比,该芯片集 成了包括稳压电源、片内时钟振荡器等其它同类型芯片所需要的外围电路,具有集成度高、 响应速度快、抗干扰性强等优点。降低了电子秤的整机成本,提高了整机的性能和可靠性。 该芯片与后端 MCU 芯片的接口和编程非常 简单,所有控制信号由管脚驱动,无需对芯片 内部的寄存器编程。输入选择开关可任意选取 通道 A 或通道 B,与其内部的低噪声可编程放 大器相连。通道 A 的可编程增益为 128 或 64,对应的满额度差分输入信号幅值分别为±20mV 或±40mV。通道 B 则为固定的 32 增益,用于系 统参数检测。芯片内提供的稳压电源可以直接 向外部传感器和芯片内的 A/D 转换器提供电源,系统板上无需另外的模拟电源。芯片内的时钟振荡器不需要任何外接器件。上电自动复位功能简化了开机的初始化过程。
特点:
• 两路可选择差分输入
• 片内低噪声可编程放大器,可选增益为 32,64 和 128 • 片内稳压电路可直接向外部传感器和芯片内 A/D 转换器提供电源
• 片内时钟振荡器无需任何外接器件,必要时 也可使用外接晶振或时钟
• 上电自动复位电路
• 简单的数字控制和串口通讯:所有控制由管 脚输入,芯片内寄存器无需编程
• 可选择 10Hz 或 80Hz 的输出数据速率
• 同步抑制 50Hz 和 60Hz 的电源干扰
• 耗电量(含稳压电源电路): 典型工作电流:< 1.6mA, 断电电流:< 1µA
• 工作电压范围:2.6 ~ 5.5V
• 工作温度范围:-40 ~ +85℃
• 16 管脚的 SOP-16 封装
本次内容讲解使用的主控芯片为stm32f1038t6,使用的是最小系统板,结构图如下:
我们主要目的是让大家快速上手使用该称重传感器,所以上述内容只作为教学开篇使用,具体内容还需大家自行深入学习。结合HX711芯片使用(这边建议大家直接购买功能板,如上图所示),只需要外接功能板的VCC(亲测5V/3.3V都可使用,毕竟电压范围是2.7-5.5V,上面框图有标注)、GND以及数据线DOUT和时钟线SCK到核心板自行设置的对应引脚。另一边的E+、E-、A+、A-、B+、B-则是连接我们对应的称重传感器。使用的是实验中常见的桥式压力传感器,称重范围(5kg、10kg等等)大家可以根据自身需求购买,在这里就不多赘述了。 见下图:
该传感器会带有四根线,颜色普遍为红黑白绿(如有例外大家自行询问商家如何连接即可),这四根线则需要连接上述的E+、E-、A+、A-即可使用,不用连接B+、B-(如果如下图连接存在不显示称重重量或为负数,可尝试将白绿两线调换位置。如果还不行,当我没说!!!偷偷跳楼即可!!!),连接顺序见下图:
程序代码:
接下来就是大家最期待的代码部分:
(为了方便大家 CV,直接为大家准备好 .C 和.H 以及main的整体代码!!!)
hx711.c文件:
代码注意事项:
1.代码亲测能用的,遇到问题别着急!!!
2.引脚配置要与hx711.h内定义相对应,换就要全部换!!!
3.如不懂hx711工作原理,自行查看芯片手册。(建议小破站搜索!!!)
#include "HX711.h" //调用hx711头文件
#include "delay.h" //调用delay延时头文件
void HX711_GPIO_Init(void) //初始化hx711
{
GPIO_InitTypeDef GPIO_InitStructure;
HX711_GPIO_APBxClkCmd(HX711_GPIO_CLK, ENABLE); //使能对应时钟
GPIO_InitStructure.GPIO_Pin = HX711_SCK_GPIO_PIN; //配置SCK引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //配置输出模式-推完输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置速度频率
GPIO_Init(HX711_SCK_GPIO_PORT, &GPIO_InitStructure); //初始化配置
GPIO_InitStructure.GPIO_Pin = HX711_DATA_GPIO_PIN; //配置DOUT引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //配置输入模式-浮空输入
GPIO_Init(HX711_DATA_GPIO_PORT, &GPIO_InitStructure); //初始化配置
}
void HX711_Data_Out(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
HX711_GPIO_APBxClkCmd(HX711_GPIO_CLK, ENABLE);
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);
}
void HX711_Data_In(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
HX711_GPIO_APBxClkCmd(HX711_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = HX711_DATA_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(HX711_DATA_GPIO_PORT, &GPIO_InitStructure);
}
u32 Read_HX711(void)
{
uint8_t i;
uint32_t value = 0;
/**
数据手册写到,当数据输出管脚 DOUT 为高电平时,表明A/D 转换器还未准备好输出数据,此时串口时
钟输入信号 PD_SCK 应为低电平,所以下面设置引脚状态。
**/
HX711_Data_Out();
HX711_DATA=1; //初始状态DT引脚为高电平
delay_us(1);
HX711_SCK=0; //初始状态SCK引脚为低电平
HX711_Data_In();
/**
等待DT引脚变为高电平
**/
while(HX711_DATA);
delay_us(1);
/**
当 DOUT 从高电平变低电平后,PD_SCK 应输入 25 至 27 个不等的时钟脉冲
25个时钟脉冲 ---> 通道A 增益128
26个时钟脉冲 ---> 通道B 增益32
27个时钟脉冲 ---> 通道A 增益64
**/
for(i=0; i<24; i++) //24位输出数据从最高位至最低位逐位输出完成
{
HX711_SCK=1;
delay_us(1);
HX711_SCK=0;
if(HX711_DATA == 0)
{
value = value << 1;
value |= 0x00;
}
if(HX711_DATA == 1)
{
value = value << 1;
value |= 0x01;
}
delay_us(1);
}
//第 25至 27 个时钟脉冲用来选择下一次 A/D 转换的输入通道和增益
HX711_SCK=1;;
value = value^0x800000;
delay_us(1);
HX711_SCK=0;
delay_us(1);
return value;
}
//最后记得空行!!!
hx711.h文件:
代码注意事项:
1.这里采用的引脚是A11、A12分别连接的是Dout和Sck,如要修改记得将全部引脚号修改!!!
2.看好修改的引脚对应的APB总线,避免无效修改(改就要全部改好)。
#ifndef __HX711_H
#define __HX711_H
#include "sys.h"
#define HX711_DATA PAin(11) //这里使用的DOUT引脚是A11
#define HX711_SCK PAout(12) //这里使用的SCK引脚是A12
// USART GPIO 引脚宏定义
#define HX711_GPIO_CLK RCC_APB2Periph_GPIOA
#define HX711_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define HX711_DATA_GPIO_PORT GPIOA
#define HX711_DATA_GPIO_PIN GPIO_Pin_11
#define HX711_SCK_GPIO_PORT GPIOA
#define HX711_SCK_GPIO_PIN GPIO_Pin_12
void HX711_GPIO_Init(void);
uint32_t Read_HX711(void);
#endif
//最后记得空行!!!
main文件:
代码注意事项:
1.使用了0.96寸OLED显示屏用作重量的显示(如不需要或尺寸不同请自行更换OLED相关代码);
2.使用了核心板串口1进行数据通信,可以连接核心板的PA9(TX)、PA10(RX)到电脑,使用串口助手查看数据输出;(如不需要,请将与usart相关的的代码全部删除,包括头文件、初始化、printf等)
3.称重传感器使用中,称重不准不是代码问题,是由于每款传感器存在差异,代码中修改修正系数可以解决问题——例如1000g砝码称出来重量是934g,则将代码中的HX711_xishu修改为原数据(指的是代码中的47785)*1000/934。假如我们称100g砝码,显示重量为98g,就用 47785*100/98得到新的修正系数为48760(这里取整了,带小数也是可以的)。建议大家多调试几次,采用不同重量砝码!!!
4.中值滤波方法简单有效,如有更好办法,可以自行尝试!
#include "sys.h"
#include "delay.h"
#include "oled_iic.h"
#include "HX711.h"
#include "usart.h"
#include "stdio.h"
#define MEDIAN_LEN 5 //中值滤波的滤波长度,一般取奇数
#define MEDIAN 3 //中值在滤波数组中的位置
u32 buffer[MEDIAN_LEN]; //中值滤波的数据缓存
int medleng = 0; //一组中值滤波数据中,进入滤波缓存的数据个数
u32 xd,xd1; //数据对比大小中间变量
u32 weight; //实际重量值
u32 pi_weight; //皮重
//u32 hx711_xishu=31706; //这是一个修正系数,例如1000g砝码称出来是934g,则HX711_xishu=原数据*1000/934;
u32 hx711_xishu=47785;
void Get_Tare(void)//获取皮重
{
u32 hx711_dat;
u8 i;
for(i=0;i<MEDIAN_LEN;i++)
{
hx711_dat=Read_HX711(); //HX711AD转换数据处理
if(medleng == 0) //缓存的第1个元素,直接放入,不需要排序
{
buffer[0] = hx711_dat; medleng = 1;
}
else //插入排序算法,按从小到大的顺序排列
{
for(i = 0; i < medleng; i ++)
{
if( buffer[i] > hx711_dat) // 轮询到的当前元素>AD值,则交换它们的值,xd为中间变量存放位置
{
xd = hx711_dat; hx711_dat = buffer[i]; buffer[i] = xd;
}
}
buffer[medleng] = hx711_dat; //把轮询出较大的数放入缓存的后面.
medleng++;
}
if(medleng >= MEDIAN_LEN) //ADC采样的数据个数达到中值滤波要求的数据个数
{
hx711_dat = buffer[MEDIAN]; //最终重量取中值滤波数组的中间值
medleng = 0;
}
}
pi_weight=(u16)(hx711_dat*0.01);
}
void Get_Weight() //获取被测物体重量
{
u32 hx711_data,a;
u32 get,aa;
hx711_data=Read_HX711(); //HX711数据采集函数
get=(u16)(hx711_data*0.01); //HX711AD转换数据处理,数据缩小100倍
if(get>pi_weight)
{
a=Read_HX711(); //重新采集HX711数据
aa=(u16)(a*0.01)-pi_weight; //测得的重量值减去皮重
weight=(u16)((float)aa*0.00001*hx711_xishu);//重量转换函数,传感器型号不同此函数要适当修改(修改HX711_xishu的大小)
}
else
weight=0;
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
delay_init();
HX711_GPIO_Init();
uart_init(115200);
Get_Tare();
OLED_Init();
OLED_Clear();
OLED_ShowCH(20,4,"重量: 0g");
while(1)
{
Get_Weight();
if(medleng == 0) //缓存的第1个元素,直接放入,不需要排序
{
buffer[0] = weight; medleng = 1;
}
else //插入排序算法,按从小到大的顺序排列
{
for(int i = 0; i < medleng; i ++)
{
if( buffer[i] > weight) // 轮询到的当前元素>AD值,则交换它们的值,xd为中间变量存放位置
{
xd = weight; weight = buffer[i]; buffer[i] = xd;
}
}
buffer[medleng] = weight; //把轮询出较大的数放入缓存的后面.
medleng++;
}
if(medleng >= MEDIAN_LEN) //ADC采样的数据个数达到中值滤波要求的数据个数
{
weight = buffer[MEDIAN]; //最终重量取中值滤波数组的中间值
medleng = 0;
OLED_ShowNum(60,4,weight,4,0);
printf("weight:%d g\r\n",weight);
delay_ms(500);
}
}
}
//最后记得空行!!!
有遇到其他问题可关注私信!!!
更新自制PCB板,开源广场:
失重-智能迷你秤 - 嘉立创EDA开源硬件平台 (oshwhub.com);
更新代码提取:
链接:https://pan.baidu.com/s/1KPyF-2T3ezOItrAhBjPTbQ
提取码:ztyy