STM32读取HX711(AD)模块数据——压力传感器
背景:在无人机动力系统的选型时,为了测试无人机的动力系统所能提供的最大拉力,使用压力传感装置测量拉力。
链接:
压力传感器tb链接:
HX711模块是一个24位精度的AD模块。
(1)https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-21223910208.20.6c496a4bdA2Bew&id=522572281513
(2)https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-21223910208.14.6c496a4bdA2Bew&id=569898995913
另外还有一个固定压力传感器的支架,通过机械方式将螺旋桨产生的拉力加到拉力传感器上。暂时找不到链接。
代码github连接:
https://github.com/W-yt/YuTian_Pro/tree/master/press_measure
程序说明:
使用STM32F103C8T6最小系统板连接HX711模块和一个OLED12864显示屏,读取HX7111模块的数据,经过处理后通过显示屏显示实际的拉力大小。
程序的初始化写在main.c文件中
程序的主循环写在control.h文件中(包括读取拉力数据和液晶显示)
代码:
读取AD芯片数据,一般有两种方式,直接利用GPIO读写操作读取数据和使用STM32的SPI读取数据。
这里由于模块自带的资料中提供了使用51单片机读取HX711数据的例程,使用的直接操作IO口的方式,我直接根据例程移植到了STM32下。
GPIO配置:
void Sensor_Init(void)
{
GPIO_InitTypeDef gpio;
RCC_APB2PeriphClockCmd(Sensor_Clock,ENABLE);
//时钟线推挽输出
gpio.GPIO_Pin = CLK;
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(Sensor_Gpio,&gpio);
//数据线浮空输入
gpio.GPIO_Pin = DATA;
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(Sensor_Gpio,&gpio);
}
HX711数据读取函数(程序主要内容):
unsigned long Sensor_Read(void)
{
unsigned long value;
unsigned char i;
//每次读取数据前保证数据线电平稳定
//此处只是为了稳定电平 拉高或拉低效果相同
// GPIO_ResetBits(Sensor_Gpio,DATA);
GPIO_SetBits(Sensor_Gpio,DATA);
//为了等待输出电平稳定
//在每次一操作电平时加微小延时
delay_us(2);
//时钟线拉低 空闲时时钟线保持低电位
GPIO_ResetBits(Sensor_Gpio,CLK);
delay_us(2);
//等待AD转换结束
while(GPIO_ReadInputDataBit(Sensor_Gpio,DATA));
for(i=0;i<24;i++)
{
//时钟线拉高 开始发送时钟脉冲
GPIO_SetBits(Sensor_Gpio,CLK);
delay_us(2);
//左移位 右侧补零 等待接收数据
value = value << 1;
//时钟线拉低
GPIO_ResetBits(Sensor_Gpio,CLK);
delay_us(2);
//读取一位数据
if(GPIO_ReadInputDataBit(Sensor_Gpio,DATA))
value ++;
}
//第25个脉冲
GPIO_SetBits(Sensor_Gpio,CLK);
delay_us(2);
//第25个脉冲下降沿到来时 转换数据
//此处说明:
// HX711是一款24位的AD转换芯片
// 最高位是符号位 其余为有效位
// 输出数组最小值0x800000
// 最大值0x7FFFFF
//异或运算:
// 相同为0
// 不同为1
//数据处理说明:
// 之所以会发生 INPA-INNA < 0mv 的情况
// 是因为发生了零点漂移
// 例如上面的数据就是初始状态INPA-INNA = -0.5mv
// 然后随着重量的增加会发生过零点
// 这时如果直接使用读取到的数据就会发生错误
// 因为读取到的是小于0的二进制补码
// 是不能直接使用的 需要转换成其原码
// 比较简单的处理方法就是读到的数据直接和0x800000进行异或
// 这时最高位可以看做是有效位
// 不代表符号位而代表的下一位的进位
// 这样数据会一直往上增长
// 我们可以直接拿来进行使用
value = value^0x800000;
// value = value&0x7FFFFF;
//第25个脉冲结束
GPIO_ResetBits(Sensor_Gpio,CLK);
delay_us(2);
return value;
}
关于读取数据操作的说明都在以上代码中有详细注释。
获取拉力:
void Get_Weight(void)
{
HX711_Buffer = Sensor_Read();
Weight_Lode = HX711_Buffer;
//判断非空载
if(Weight_Lode > Weight_No_Lode)
{
Weight_Real = (Weight_Lode - Weight_No_Lode)/Kp_Weight;
}
else if(Weight_Lode <= Weight_No_Lode)
Weight_Real = 0.0f;
//拉力达到一定阈值 则串口显示
// if(Weight_Real>100.0f)
// printf("当前拉力%u\r\n\r\n",Weight_Real);
}
粗略直线拟合:(确定上面代码段中的系数)
//比例系数确定数据:
// 42500 --> 160g --> 265.65
// 80000 --> 285g --> 280.7
// 115000 --> 405g --> 283.95
// 405000 --> 1400g --> 289.29
//拟合直线:
// y = 291.92x-3580.2 (忽略截距)
这里只是用电子秤称量了几个重物作为样本,大致拟合,为了获得更高精度,可以改进样本和拟合方式。
如有问题,欢迎交流。
——cloud over sky
——2019/10/31