MLX90621驱动编写2
- 该传感器的讲解第一部分链接为MLX90621驱动编写1
- 该器件的温度计算总体分为2部分,Part1为器件本身的温度,用于在计算物体温度时的补偿;Part2为计算测量物体的温度。器件本身温度计算公式以及所需要的寄存器如图1所示:
图1 Ta的计算公式及所需要的寄存器
计算Ta的代码如下:
/**
**Description : 计算芯片的温度
:Ta=(-KT1_F+pow((KT1_F*KT1_F-4*KT2_F*(VTH_F-PTAT_data)),0.5))/(2*KT2_F)+25
**Param : None
**Return Code : None
**/
void Calculation_Ta(void)
{
u8 KT1_Scale=0;
u8 KT2_Scale=0;
int32_t KT1_V=0;
int32_t KT2_V=0;
int32_t VTH_V=0;
double KT1_F=0;
double KT2_F=0;
double VTH_F=0;
double tempd=0.0f;
double diff=0;
int16_t PTAT_Data=0;
/*************从EEPROM读取数据结束****************/
PTAT_Data=Frame_Data[64];
/*************从EEPROM读取数据开始****************/
KT1_Scale=(EEProm_Data[0XD2]&0XF0)>>4; //KT1_Scale
KT2_Scale=(EEProm_Data[0XD2]&0X0F);
/*************计算VTH***************/
VTH_V=256*EEProm_Data[0XDB]+EEProm_Data[0XDA];
if(VTH_V>32767)
{
VTH_V=VTH_V-65536;
}
VTH_F=(double)VTH_V/(double)(pow((double)2,(double)Reso));
/*************计算KT1***************/
KT1_V=256*EEProm_Data[0XDD]+EEProm_Data[0XDC];
if(KT1_V>32767)
{
KT1_V=KT1_V-65536;
}
KT1_F=(double)KT1_V/(double)(pow((double)2,(double)(Reso+KT1_Scale)));
/*************计算KT2***************/
KT2_V=256*EEProm_Data[0XDF]+EEProm_Data[0XDE];
if(KT2_V>32767)
{
KT2_V=KT2_V-65536;
}
KT2_F=(double)KT2_V/(double)(pow((double)2,(double)(Reso+KT2_Scale+10)));
/*************计算TA***********/
diff=VTH_F-(double)PTAT_Data; //求差
tempd=KT1_F*KT1_F-4*KT2_F*diff;//计算
tempd=pow(tempd,0.5); //开方
Ta=(tempd-KT1_F)/(2*KT2_F)+25.0f;//得到Ta
#if TEST_EN
printf("VTH_F:%f\r\n",VTH_F);
printf("KT1_F:%f\r\n",KT1_F);
printf("KT2_F:%f\r\n",KT2_F);
printf("TA:%f\r\n",Ta);
#endif
}
第二部分则是计算测量的物体的温度,该部分用到的补偿比较多,需要注意的是变量数据类型的定义,不要在程序计算的过程中溢出。该部门计算的公式如图2所示:
图2 计算物体的温度公式
敲公式太麻烦了,直接上代码吧
/**
**Description : 计算VIR(i,j)_OffsetCompensated
:VIR_Offset(i,j)=VIR(I,J)-(A(i,j)+B(i,j)*(Ta-TA0))
:A(i,j)=A_common+A_I(i,j)
**Param : None
**Return Code : None
**/
void Calculation_VIR_Offset(void)
{
u8 i=0;
u8 j=0;
u32 temp2=0;
u32 temp3=0;
int32_t sum=0;
int32_t VIR_i_j=0; //不同的i,j对应不同的Framedata数据,存储形式为补码形式
int32_t A_Common=0; //该值是EEPROM中的0XD0和0XD1组成D1为高位,D0为低8位
int16_t A_i_j_EE=0; //不同的i,j对应不同的EEPROM数据 地址为0X00-0X3F (0-63)
int16_t B_i_j_EE=0; //不同的i,j对应不同的EEPROM数据,地址为0X40-0X7F(64-127)
double A_I_J[64]={0.0f};
double B_I_J[64]={0.0F};
u8 A_i_Scale=0; //地址为0XD9的高4位
u8 B_i_Scale=0; //地址为0XD9的低4为
A_i_Scale=(EEProm_Data[0XD9]&0XF0)>>4;
B_i_Scale=EEProm_Data[0XD9]&0X0F;
/************对A_Common进行合成*****/
A_Common=256*EEProm_Data[0XD1]+EEProm_Data[0XD0];
if(A_Common>32767)
{
A_Common=A_Common-65536;
}
temp2=pow((double)2,(double)A_i_Scale); //为了防止溢出用32类型
temp3=pow((double)2,(double)B_i_Scale); //为了防止溢出用32类型
for(i=0;i<4;i++)
{
for(j=0;j<16;j++)
{
/********读取VIR[64]中的每个数据*******/
VIR_i_j=Frame_Data[i+4*j]; //取出当前像素测量的数据
if(VIR_i_j>32767)
{
VIR_i_j=VIR_i_j-65536;
}
/******计算A_I_J[64]数组中的每一个成员********/
A_i_j_EE=EEProm_Data[i+4*j];
sum=A_Common+A_i_j_EE*temp2;
A_I_J[i+4*j]=(double)(sum)/(double)temp1; //求出Ai(i,j),
/******计算B_I_J[64]数组中的每一个成员********/
B_i_j_EE=EEProm_Data[64+i+4*j]; //从EEPROM中读出
if(B_i_j_EE>127)
{
B_i_j_EE=B_i_j_EE-256;
}
B_I_J[i+4*j]=(double)B_i_j_EE/(double)(temp1*temp3);
VIR_Offset[i+4*j]=(double)VIR_i_j-(double)(A_I_J[i+4*j]+B_I_J[i+4*j]*(Ta-TA0));
#if TEST_EN
printf("当前为第:%d",i+4*j);
printf(" ");
printf("V_IR_I_J:%d",VIR_i_j);
printf(" ");
printf("A_I_J:%1.2f",A_I_J[i+4*j]);
printf(" ");
printf("B_I_J:%1.2f",B_I_J[i+4*j]);
printf(" ");
printf("VIR_Offset:%1.2f\r\n",VIR_Offset[i+4*j]);
#endif
}
}
}
/**
**Description : 计算VIR(i,j)_COMPENSATED,每个VIR补偿减去TGC和VIRCP_COMPENSATED乘积
: 首先计算VIRCP_COMPENSATED
:然后可以得到VIR(i,j)_COMPENSATED的数据
**Param : None
**Return Code : None
**/
double VIR_COMPEN[64]={0.0f}; //存储最终补偿值
double VIR_TCG_OFF[64]={0.0f}; //存放EGC补偿后的数据
void Calculation_VIR_COMPENSATED(void)
{
u8 i=0;
u8 j=0;
u32 temp3=0;
u8 B_i_Scale=0; //地址为0XD9的低4位
int32_t ACP_V=0; //ACP整数
int16_t BCP_EE=0; //BCP整数
double ACP_F=0.0f; //ACP小数
double BCP_F=0.0f; //BCP小数
double VIR_CP_OFF=0.0f; //存放CP补偿后的数据
double EMM_F=0.0f;
BCP_EE=EEProm_Data[0XD5]; //存放在EEPROM[0XD5]中
B_i_Scale=EEProm_Data[0XD9]&0X0F; //去除BiScale
ACP_V=256*EEProm_Data[0XD4]+EEProm_Data[0XD3]; //计算ACP_V
temp3=pow((double)2,(double)B_i_Scale); //为了防止溢出用32类型
/**********计算ACP***************/
if(ACP_V>32767)
{
ACP_V=ACP_V-65536;
}
ACP_F=(double)(ACP_V)/(double)temp1;
/*********计算BCP***************/
if(BCP_EE>127)
{
BCP_EE=BCP_EE-256;
}
BCP_F=(double)BCP_EE/(double)(temp1*temp3);
/***********读取VCP************/
VCP=Frame_Data[65]; //该值从Framdata[65]中读取
if(VCP>32767)
{
VCP=VCP-65536;
}
/*******计算CP补偿后的VIR**********/
VIR_CP_OFF=VCP-(ACP_F+BCP_F*(Ta-TA0));
/*******计算发射率*****************/
EMM_F=(double)(256*EEProm_Data[0XE5]+EEProm_Data[0XE4])/32768.0f;
#if TEST_EN
printf(" ");
printf("ACP_F:%1.2f",ACP_F);
printf(" ");
printf("BCP_F:%1.2f",BCP_F);
printf(" ");
printf("VCP:%d",VCP);
printf(" ");
printf("VIR_CP_OFF:%1.2f",VIR_CP_OFF);
printf(" ");
printf("EMM_F:%1.2f",EMM_F);
printf(" ");
#endif
for(i=0;i<4;i++)
{
for(j=0;j<16;j++)
{
VIR_TCG_OFF[i+4*j]=VIR_Offset[i+4*j]-TCG_F*VIR_CP_OFF;//
VIR_COMPEN[i+4*j]=VIR_TCG_OFF[i+4*j]/EMM_F; //计算得到VIR_COMPEN,一共是64个
#if TEST_EN
printf("当前为第:%d",i+4*j);
printf(" ");
printf("VIR_TCG_OFF:%1.2f",VIR_TCG_OFF[i+4*j]);
printf(" ");
printf("VIR_COMPEN:%1.2f\r\n",VIR_COMPEN[i+4*j]);
#endif
}
}
}
double a_comp[64]={0.0f};
/**
**Description : 计算a_comp(i,j)
**Param : None
**Return Code : None
**/
void Calculation_a_comp(void)
{
u8 i=0;
u8 j=0;
int32_t KSTA=0;
double a_cp=0.0f;
double KSTA_F=0;
double a_i_j_1=0.0f;
double a_i_j_2[64]={0.0f};
uint64_t a_scale1=0;
uint64_t a_scale2=0;
/****************计算KSTA********************/
KSTA=256*EEProm_Data[0XE7]+EEProm_Data[0XE6];
if(KSTA>32767)
{
KSTA=KSTA-65536;
}
KSTA_F=(double)KSTA/(double)(pow(2.0f,20.0f));
/**************计算a_comp(i,j)****************/
a_scale1=pow(2.0f,(double)EEProm_Data[0XE2]);
a_scale2=pow(2.0f,(double)EEProm_Data[0XE3]);
a_i_j_1=(double)(256*EEProm_Data[0XE1]+EEProm_Data[0XE0])/(double)a_scale1; //计算(256*a0H+a0L)/pow(2,a_scale1)
a_cp=(double)(256*EEProm_Data[0XD7]+EEProm_Data[0XD6])/(double)(a_scale1*temp1);
#if TEST_EN
printf("a_cp:%1.16f",a_cp);
#endif
for(i=0;i<4;i++)
{
for(j=0;j<16;j++)
{
a_i_j_2[i+4*j]=(double)(EEProm_Data[128+i+4*j])/(double)a_scale2; //a(i,j)的a(i,j)/a_scale2
a_i_j_2[i+4*j]=a_i_j_2[i+4*j]+a_i_j_1 ; //a(i,j)的分子部分
a_i_j_2[i+4*j]=a_i_j_2[i+4*j]/temp1; //和分母相除
a_comp[i+4*j]=(1+KSTA_F*(Ta-TA0))*(a_i_j_2[i+4*j]-TCG_F*a_cp); //最后得到a(i,j)
#if TEST_EN
printf("当前为第:%d",i+4*j);
printf(" ");
printf("a_i_j_2[i+4*j]:%1.16f",a_i_j_2[i+4*j]);
printf(" ");
printf("a_comp[i+4*j]:%1.16f",a_comp[i+4*j]);
#endif
}
}
}
uint64_t Tak4=0;
double KS4_F=0.0f;
double S_X_i_j[64]={0.0f};
/**
**Description : 计算TAK4
**Param : None
**Return Code : None
**/
void Calculation_TAK4(void)
{
Tak4=ceil(pow((double)(Ta+273.15),4.0f));//ceil函数向上取整
#if TEST_EN
printf("Tak4:%lld\r\n",Tak4);
#endif
}
/**
**Description : 计算S_X_i_j(i,j)
**Param : None
**Return Code : None
**/
void Calculation_S_X_i_j(void)
{
u8 i=0;
u8 j=0;
int16_t KS4_V=0;
Calculation_TAK4();
/*****************计算KS4_F**********/
KS4_V=EEProm_Data[0XC4];
if(KS4_V>127)
{
KS4_V=KS4_V-256;
}
KS4_F=(double)(KS4_V)/(double)(pow(2.0f,(double)(8+EEProm_Data[0XC0])));
#if TEST_EN
printf("KS4_F:%1.16f",KS4_F);
printf(" ");
#endif
for(i=0;i<4;i++)
{
for(j=0;j<16;j++)
{
S_X_i_j[i+4*j]=pow(a_comp[i+4*j],3.0f)*VIR_COMPEN[i+4*j]+pow(a_comp[i+4*j],4.0f)*Tak4;//先计算
S_X_i_j[i+4*j]=pow(S_X_i_j[i+4*j],0.25); //开四次方
S_X_i_j[i+4*j]=KS4_F*S_X_i_j[i+4*j]; //和KS4_F相乘即可
}
#if TEST_EN
printf("当前为第:%d",i+4*j);
printf(" ");
printf("S_X_i_j[i+4*j]:%1.16f\r\n",S_X_i_j[i+4*j]);
#endif
}
}
double TO_i_j[64]={0.0f};
/**
**Description : 计算物体的温度
**Param : None
**Return Code : None
**/
void Calculation_TO_i_j(void)
{
u8 i,j;
Common(); //读取一些基本数据
Calculation_Ta(); //计算TA
Calculation_VIR_Offset(); //计算VIR补偿
Calculation_VIR_COMPENSATED(); //计算完整的VIR补偿
Calculation_a_comp(); //计算a_comp(i,j)
#if MLX_BAB
Calculation_TAK4(); //计算TAK4
#else
Calculation_S_X_i_j(); //计算SX(I,J)
#endif
for(i=0;i<4;i++)
{
for(j=0;j<16;j++)
{
#if MLX_BAB
TO_i_j[i+4*j]=VIR_COMPEN[i+4*j]/(a_comp[i+4*j])+Tak4;
#else
TO_i_j[i+4*j]=VIR_COMPEN[i+4*j]/(a_comp[i+4*j]*(1-KS4_F*273.15)+S_X_i_j[i+4*j])+Tak4;//如果是BAB则KS4_F为0
#endif
TO_i_j[i+4*j]=pow(TO_i_j[i+4*j],0.25f)-273.15f; //计算得到TO(I,J)
}
}
}
通过以上步骤,即可完成对MLX90621的使用。其他的传感器也一样,有的传感器不常用,可能网上没有直接能用的驱动,这时候就需要我们按照器件手册,根据芯片手册中的时序图来进行传感器软件驱动的编写。总体经验是:先写最底层的通信协议程序,然后利用协议写传感器的读写数据函数,最后利用读写函数编写传感器的配置函数等操作函数。在编写的过程中要注意变量的数据类型,注意时序图中时序的控制等小问题。