资讯详情

【STM32技巧】HX711称重芯片详细说明

概述

HX711 模块 A 通道带有 128 倍信号增益,可以 5mV 的电压放大 128 倍,然后采样输 出 24bit AD 单片机通过指定的顺序转换转换值 24bit 数据读出

如何计算传感器的电压

HX711 可以在产生 VAVDD 和 AGND 电压,即 711 模块上的 E 和 E-电压。 该电压通过 :

VAVDD=VBG(R1 R2 )/R2

例如:

VBG 基准模块电压 1.25V,R1 = 20K,R2 = 8.2K,因此得出 VAVDD = 4.3V

(为了降低功耗,电压只能在采样时输出,所以用万用表读取的值可能低于 4.3v,因为万用表测量有效值。

讲解测重原理

全量程输出电压 = 激励电压 * 灵敏度 1.0mv/v 例如:

供电电压是 5V 乘以灵敏度 1.0mV/V = 满量程 5mV。 相当于有 5Kg 当产生重力时 5mV 的电压。

如何将 AD值反向转换为重力值

假设重力为 A Kg,(x<5Kg),测量出来的 AD 值为 y 传感器输出,发送给 AD 模块电压为 A Kg * 4.3mV / 5Kg = 0.86A mV 经过 128 倍增益后为 128 * 0.86A = 110.08AmV 转换为 24bit 数字信号为 110.08A mV * 224 / 4.3V = 429496.7296A 所以 y = 429496.7296A 因此得出 A = y / 429496.7296 因此,在得出程序中计算公式

Weight_Shiwu = (unsigned long)((float)Weight_Shiwu/429.5);

特别注意: 由于不同传感器的斜率特性曲线不完全相同,因此每个传感器都需要在这里纠正 429.5 只有这个除数,才能达到高精度。

安装压力传感器的方法

在这里插入图片描述

知识点:为什么官方例程要读?AD数据 异或 0x800000

count :是读出的AD数据 count :读取的数据是24位有符号,二进制补码是: 0x800000 - 0x7FFFFF (-8388607 ~ 8388607)     count = count ^ 0x800000;   这里的意思是将二进制补码换算为 0 ~ 16777214,若采集 INP-INN ≈ 0,那么 count = count ^ 0x800000 = 8388607 (16777214 / 2, 这些误差的实际值也会增加或减少)   实际测试在本例程中没有使用:count = count ^ 0x800000,直接使用AD原始数据 count >> 8 制作后的数据16位精度   

实际测试例程,STM32测试例程

注:我用1000kg拉力传感器测试,灵敏度为2mV/V

#include "includes.h"   /* ********************************************************************************************************* * 寄存器 ********************************************************************************************************* */ #define DWT_CYCCNT *(volatile unsigned int *)0xE0001004 #define DWT_CR *(volatile unsigned int *)0xE0001000 #define DEM_CR *(volatile unsigned int *)0xE000EDFC
#define DBGMCU_CR *(volatile unsigned int *)0xE0042004

#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)

#define WEIGHT_CAP_NUM 1 //重量采集数量 滤波使用

uint8_t		ucWeightCapCompleteFlag= 0;     //重量采集完成标志
uint8_t		ucWeightCapCount 			 = 0;			//重量采集计数
int32_t   ilWeightRawDataAddToal = 0;			//重量AD数据累计
int16_t		iWeightRawData = 0;							//重量AD数据


/* ********************************************************************************************************* * 函 数 名: bsp_InitDWT * 功能说明: 初始化DWT. * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
void bsp_InitDWT(void)
{ 
        
	DEM_CR         |= (unsigned int)DEM_CR_TRCENA;   /* Enable Cortex-M4's DWT CYCCNT reg. */
	DWT_CYCCNT      = (unsigned int)0u;
	DWT_CR         |= (unsigned int)DWT_CR_CYCCNTENA;
}

/* ********************************************************************************************************* * 函 数 名: DWT_DelayUS * 功能说明: 这里的延时采用CPU的内部计数实现,32位计数器 * OSSchedLock(&err); * bsp_DelayUS(5); * OSSchedUnlock(&err); 根据实际情况看看是否需要加调度或选择关中断 * 形 参: _ulDelayTime 延迟长度,单位1 us * 返 回 值: 无 * 说 明: 1. 主频168MHz的情况下,32位计数器计满是2^32/168000000 = 25.565秒 * 建议使用本函数做延迟的话,延迟在1秒以下。 * 2. 实际通过示波器测试,微妙延迟函数比实际设置实际多运行0.25us左右的时间。 * 下面数据测试条件: * (1). MDK5.15,优化等级0, 不同的MDK优化等级对其没有影响。 * (2). STM32F407IGT6 * (3). 测试方法: * GPIOI->BSRRL = GPIO_Pin_8; * bsp_DelayUS(10); * GPIOI->BSRRH = GPIO_Pin_8; * ------------------------------------------- * 测试 实际执行 * bsp_DelayUS(1) 1.2360us * bsp_DelayUS(2) 2.256us * bsp_DelayUS(3) 3.256us * bsp_DelayUS(4) 4.256us * bsp_DelayUS(5) 5.276us * bsp_DelayUS(6) 6.276us * bsp_DelayUS(7) 7.276us * bsp_DelayUS(8) 8.276us * bsp_DelayUS(9) 9.276us * bsp_DelayUS(10) 10.28us * 3. 两个32位无符号数相减,获取的结果再赋值给32位无符号数依然可以正确的获取差值。 * 假如A,B,C都是32位无符号数。 * 如果A > B 那么A - B = C,这个很好理解,完全没有问题 * 如果A < B 那么A - B = C, C的数值就是0xFFFFFFFF - B + A + 1。这一点要特别注意,正好用于本函数。 ********************************************************************************************************* */
void DWT_DelayUS(uint32_t _ulDelayTime)
{ 
        
  uint32_t tCnt, tDelayCnt;
	uint32_t tStart;
		
	tStart = DWT_CYCCNT;                                     /* 刚进入时的计数器值 */
	tCnt = 0;
	tDelayCnt = _ulDelayTime * (SystemCoreClock / 1000000);	 /* 需要的节拍数 */ 		      

	while(tCnt < tDelayCnt)
	{ 
        
		tCnt = DWT_CYCCNT - tStart; /* 求减过程中,如果发生第一次32位计数器重新计数,依然可以正确计算 */	
	}
}


/* ********************************************************************************************************* * 函 数 名: HX711_GPIOInit * 功能说明: 重量芯片HX711 GPIO初始化 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
void  HX711_GPIOInit(void)
{ 
        

	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//使能PORTA

 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;				      //PA7 推挽输出 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		  //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;				      //PA6 推挽输出 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		  	//上拉输入
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
}


/* ********************************************************************************************************* * 函 数 名: HX711_Init * 功能说明: 重量芯片HX711初始化 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */

void HX711_Init(void)
{ 
        
	CH376_SPI_SCS = 1;					//CH376 片选失能 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, DISABLE);	
	SPI_Cmd(SPI1, DISABLE);			//禁止SPI
	HX711_GPIOInit();						//初始化IO
}


/* ********************************************************************************************************* * 函 数 名: Task_WeightCap * 功能说明: 重量采集任务 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
void Task_WeightCap(void)
{ 
        
	uint32_t	count = 0;
	int16_t		raw_data = 0;
	uint8_t		i;	
	HX711_Init();						//HX711重新初始化
	
	
	ADSK = 0;
	count= 0;
	while(ADDO);
	
	for(i=0; i<24; i++)
	{ 
        	
		ADSK = 1;
		DWT_DelayUS(1);
		count = count << 1;
		ADSK = 0;
		DWT_DelayUS(1);

		if(ADDO) 
		{ 
        
			count++;		
		}
	}
	
	//第25个时钟信号
	ADSK=1;
	DWT_DelayUS(1);
	ADSK=0;
	DWT_DelayUS(1);
	
	
	/* count :读出的数据是24位有符号,二进制补码是: 0x800000 - 0x7FFFFF (-8388607 ~ 8388607) count = count ^ 0x800000; 这里的意思是将二进制补码换算为 0 ~ 16777214,如果采集到的 INP-INN ≈ 0,那么 count = count ^ 0x800000 = 8388607 (16777214 / 2, 误差的大小实际值也会在这数增大减少) 这里不用 count = count ^ 0x800000; 这么换算,直接使用 count >> 8 后的数据,做成16位精度 1. 拉力传感器灵敏度S 2mV/V, 实际供电电源Uin 5.08V,满负载输出电压:Uout = S * Uin ≈ 10.16mV 2. 这里是128倍放大 10.16mV * 128 = 1300.48mV 3. 16位精度最小分辨率 Uin / 2^16 ≈ 0.00007751V,满量程输出AD值:1300.48 mV / 0.00007751V ≈ 16778 4. 1g 对应的电压值是:10.16mV / 100kg = 0.0000001016V 换算实际的AD值:0.0000001016V * 128(放大倍数)/ 0.00007752V ≈ 0.16778 5. 满量程AD值 16778 / 0.16778(1gAD值) = 实际的重量 6. 注意:使用前要去皮 */
	
	
	//count = count ^ 0x800000;
	
	raw_data = count >> 8;
	
	ilWeightRawDataAddToal = raw_data + ilWeightRawDataAddToal;
	ucWeightCapCount++;
	
	if(ucWeightCapCount == WEIGHT_CAP_NUM)
	{ 
        
		ucWeightCapCount 				= 0;
		iWeightRawData = ilWeightRawDataAddToal / WEIGHT_CAP_NUM;
		ilWeightRawDataAddToal  = 0;
		ucWeightCapCompleteFlag = 1;
	}
	//raw_data = raw_data ^ 0x8000;
// if(raw_data < 0)
// { 
        
// raw_data = -raw_data;
// }
	
// printf("count %d raw_data %d %f %f kg\r\n", count, raw_data, (((double)raw_data) * 0.00007751) / 128, (float)(raw_data / 0.16778) / 1000); //数据打印出来 
}

/* ********************************************************************************************************* * 函 数 名: GetWeightRawData * 功能说明: 得到重量的原始值 * 形 参: iRawData 原始值 * 返 回 值: 1 已经得到 0 没有得到 ********************************************************************************************************* */
uint8_t  GetWeightRawData(int16_t *iRawData)
{ 
        
		if(ucWeightCapCompleteFlag == 1)
		{ 
        
			*iRawData = iWeightRawData;
			ucWeightCapCompleteFlag = 0;
			return 1;
		}
		
		return 0;
}




两点直线方程校准算法,用于校准实际数据

	注意: 使用直线方程的首要条件是 重量传感器的线性度要好,可以使用标准砝码测试

/* ********************************************************************************************************* * 函 数 名: CaculTwoPoint * 功能说明: 根据2点直线方程,计算Y值 * 形 参: 2个点的坐标和x输入量,x1: 最小千克的AD值,y1:最小千克值,x2: 最大千克的AD值, * y2: 最大千克值, x:输入的当前AD值 * 返 回 值: x对应的y值 返回实际的重量 ********************************************************************************************************* */
static float  CaculTwoPoint(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x)
{ 
        
  float value;
  value = y1 + (float)((int64_t)(y2 - y1) * (x - x1)) / (x2 - x1);
	return value;
}

标签: igt202传感器rohm光电传感器透射型rpi

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台