概述
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测试例程
注意:本人使用100kg的拉力传感器测试,灵敏度是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;
int16_t iWeightRawData = 0;
void bsp_InitDWT(void)
{
DEM_CR |= (unsigned int)DEM_CR_TRCENA;
DWT_CYCCNT = (unsigned int)0u;
DWT_CR |= (unsigned int)DWT_CR_CYCCNTENA;
}
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;
}
}
void HX711_GPIOInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
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;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void HX711_Init(void)
{
CH376_SPI_SCS = 1;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, DISABLE);
SPI_Cmd(SPI1, DISABLE);
HX711_GPIOInit();
}
void Task_WeightCap(void)
{
uint32_t count = 0;
int16_t raw_data = 0;
uint8_t i;
HX711_Init();
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++;
}
}
ADSK=1;
DWT_DelayUS(1);
ADSK=0;
DWT_DelayUS(1);
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;
}
}
uint8_t GetWeightRawData(int16_t *iRawData)
{
if(ucWeightCapCompleteFlag == 1)
{
*iRawData = iWeightRawData;
ucWeightCapCompleteFlag = 0;
return 1;
}
return 0;
}
两点直线方程校准算法,用于校准实际数据
注意: 使用直线方程的首要条件是 重量传感器的线性度要好,可以使用标准砝码测试
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;
}
|