前篇介绍了寄存器的配置,本篇继续介绍代码的实现,如果有对寄存器不明白的地方可以去看前篇文章https://blog.csdn.net/bunanananaa/article/details/145188798
由于本文主要是记录BMP280传感器的使用,所以对IIC通信就不再赘述.上篇文章讲了BMP280的测量流程为:1.上电检查ID 2.读取补偿寄存器的值 3.复位并配置寄存器 4.检测配置是否成功 5.获取数值 6.数据补偿计算,所以我们先对BMP280初始化,也就是完成前四步.
IIC读取函数
/*****************************************************************************
* 功 能:在从机中读取一个字节数据
* 参 数:I2C_Addr 从机地址
reg 读取目标寄存器
*buf 用于保存数据的地址
* 返回值:0成功;1失败
* 备 注:无
*****************************************************************************/
uint8_t IIC_ReadByteFromSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t *buf);
/*****************************************************************************
* 功 能:在从机中连续读取多个字节数据
* 参 数:I2C_Addr 从机地址
reg 读取目标寄存器
*buf 用于保存数据的地址
* 返回值:0成功;1失败
* 备 注:无
*****************************************************************************/
uint8_t IIC_ReadMultByteFromSlave(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data);
/*****************************************************************************
* 功 能:向从机写入一个字节数据
* 参 数:I2C_Addr 从机地址
reg 读取目标寄存器
buf 写入的数据
* 返回值:0成功;1失败
* 备 注:无
*****************************************************************************/
uint8_t IIC_WriteByteToSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t buf);
这四个函数是我内部已经封装好的读写函数以防后面函数中出现不明白,具体的参数和返回值可以看注释部分标注的很详细.
下面来介绍BMP280初始化这部分代码
寄存器宏定义:
首先是将BMP280的寄存器全部进行宏定义,有利于后面在看代码时能够快速的知道某一步操作的寄存器是干嘛的
//芯片地址
#define bmp280_address 0xEC
//配置寄存器地址
#define bmp280_id 0xD0
#define bmp280_reset 0xE0
#define bmp280_status 0xF3
#define bmp280_ctrl_meas 0xF4
#define bmp280_config 0xF5
//数据寄存器地址
#define bmp280_press_msb 0xF7
#define bmp280_press_lsb 0xF8
#define bmp280_press_xsb 0xF9
#define bmp280_temp_msb 0xFA
#define bmp280_temp_lsb 0xFB
#define bmp280_temp_xsb 0xFC
//校准数据寄存器地址
#define bmp280_dig_t1_lsb 0x88
#define bmp280_dig_t1_msb 0x89
#define bmp280_dig_t2_lsb 0x8A
#define bmp280_dig_t2_msb 0x8B
#define bmp280_dig_t3_lsb 0x8C
#define bmp280_dig_t3_msb 0x8D
#define bmp280_dig_p1_lsb 0x8E
#define bmp280_dig_p1_msb 0x8F
#define bmp280_dig_p2_lsb 0x90
#define bmp280_dig_p2_msb 0x91
#define bmp280_dig_p3_lsb 0x92
#define bmp280_dig_p3_msb 0x93
#define bmp280_dig_p4_lsb 0x94
#define bmp280_dig_p4_msb 0x95
#define bmp280_dig_p5_lsb 0x96
#define bmp280_dig_p5_msb 0x97
#define bmp280_dig_p6_lsb 0x98
#define bmp280_dig_p6_msb 0x99
#define bmp280_dig_p7_lsb 0x9A
#define bmp280_dig_p7_msb 0x9B
#define bmp280_dig_p8_lsb 0x9C
#define bmp280_dig_p8_msb 0x9D
#define bmp280_dig_p9_lsb 0x9E
#define bmp280_dig_p9_msb 0x9F
BMP280初始化:
1.ID读取函数
/*****************************************************************************
* 函 数:uint8_t BMP280_check_id(void)
* 功 能:检测id是否正确
* 参 数:无
* 返回值:0正确; 1失败并打印
* 备 注:无
*****************************************************************************/
uint8_t BMP280_check_id(void)
{
uint8_t buf;
IIC_ReadByteFromSlave(bmp280_address,bmp280_id,&buf);//IIC在从机中读取一个字节
if(buf==0x58)//从机的ID是固定的,检查读出的数据是否匹配
{
return 0;
}
else
{
printf("BMP280 no connected...\r\n");
return 1;
}
}
2.获取校准值
首先定义一个结构体来保存我们获取到的校准值(注意结构体内的数据类型),获取结构体之后通过函数将读取到的数值保存到结构体内,代码如下.
//定义一个结构体来保存校准寄存器内的数据,注意t1与p1是无符号16位,其他是有符号16位!!
typedef struct
{
uint16_t dig_t1;
int16_t dig_t2;
int16_t dig_t3;
uint16_t dig_p1;
int16_t dig_p2;
int16_t dig_p3;
int16_t dig_p4;
int16_t dig_p5;
int16_t dig_p6;
int16_t dig_p7;
int16_t dig_p8;
int16_t dig_p9;
} bmp280_Calib;
bmp280_Calib bmp280_cal;//创建结构体
/*****************************************************************************
* 函 数:void BMP280_get_Cal_value(void)
* 功 能:获取校准值
* 参 数:无
* 返回值:无
* 备 注:无
*****************************************************************************/
void BMP280_get_Cal_value(void)
{
uint8_t buf[24];
IIC_ReadMultByteFromSlave(bmp280_address,bmp280_dig_t1_lsb,24,buf);//IIC读取连续字节的数据
bmp280_cal.dig_t1=(buf[1]<<8)+buf[0];//将buf中的值传入给结构体,注意MSB在前,LSB在后.
bmp280_cal.dig_t2=(buf[3]<<8)+buf[2];
bmp280_cal.dig_t3=(buf[5]<<8)+buf[4];
bmp280_cal.dig_p1=(buf[7]<<8)+buf[6];
bmp280_cal.dig_p2=(buf[9]<<8)+buf[8];
bmp280_cal.dig_p3=(buf[11]<<8)+buf[10];
bmp280_cal.dig_p4=(buf[13]<<8)+buf[12];
bmp280_cal.dig_p5=(buf[15]<<8)+buf[14];
bmp280_cal.dig_p6=(buf[17]<<8)+buf[16];
bmp280_cal.dig_p7=(buf[19]<<8)+buf[18];
bmp280_cal.dig_p8=(buf[21]<<8)+buf[20];
bmp280_cal.dig_p9=(buf[23]<<8)+buf[22];
}
3.复位函数
向复位寄存器写入固定的0xb6来复位
/*****************************************************************************
* 函 数:uint8_t BMP280_reset(void)
* 功 能:BMP280复位
* 参 数:无
* 返回值:0复位成功; 1复位失败打印
* 备 注:无
*****************************************************************************/
uint8_t BMP280_reset(void)
{
if(IIC_WriteByteToSlave(bmp280_address,bmp280_reset,0XB6)==0)
{
return 0;
}
else
{
printf("BMP280RESET FAIL....\r\n");
return 1;
}
}
4.配置寄存器
在配置完寄存器后读取我们所配置的寄存器,查看是否配置成功.
/*****************************************************************************
* 函 数:void BMP280_config(void)
* 功 能:配置BMP280并检测配置是否正确
* 参 数:无
* 返回值:无
* 备 注:在函数内对芯片进行配置如下
* 电源模式:正常模式
* 温度传感器配置:17bit/0.0025℃
* 压力传感器配置:20bit/0.16pa
* 待机时长配置:0.5ms
* 滤波器配置:16
* SPI是否启用:否(对spi3w_en[0]写0)
*****************************************************************************/
void BMP280_config(void)
{
uint8_t buff_1=0;
uint8_t buff_2=0;
IIC_WriteByteToSlave(bmp280_address,bmp280_ctrl_meas,0x57);
IIC_WriteByteToSlave(bmp280_address,bmp280_config,0x10);
IIC_ReadByteFromSlave(bmp280_address,bmp280_ctrl_meas,&buff_1);
IIC_ReadByteFromSlave(bmp280_address,bmp280_config,&buff_2);
if((buff_1==0x57)&&(buff_2==0x10))
{
printf("BMP280CONFIG SUCCESS");
}
else
{
printf("BMP280CONFIG FAIL....");
}
}
5.BMP280初始化函数
若初始化失败会提示在哪一步失败并且退出函数不再执行后面的函数,如果初始化成功则会通过串口打印"BMP280CONFIG SUCCESS"字样.
/*****************************************************************************
* 函 数:void BMP280_Init(void)
* 功 能:BMP280初始化
* 参 数:无
* 返回值:无
* 备 注:无
*****************************************************************************/
void BMP280_Init(void)
{
if(BMP280_check_id()!=0)//检查ID是否正确,若不正确直接退出不继续进行.
{
return;
}
BMP280_get_Cal_value();//获取校准值
if(BMP280_reset()!=0)//BMP280复位
{
return;
}
BMP280_config();//对BMP280寄存器进行配置
}
下面来介绍数据计算函数,根据官方提供的函数作为参考实现对温度,压力值的计算.
1.获取芯片内部ADC的值
/*****************************************************************************
* 函 数:void BMP280_get_data(void)
* 功 能:获取芯片内部传感器ADC的值
* 参 数:无
* 返回值:无
* 备 注:都为原始数据不能直接使用
*****************************************************************************/
int32_t bmp280_press_data,bmp280_temp_data,t_fine;//用于保存芯片内读取到的ADC的值
void BMP280_get_data(void)
{
uint8_t buf[6];
IIC_ReadMultByteFromSlave(bmp280_address,bmp280_press_msb,6,buf);
bmp280_press_data=(int32_t)(((buf[0])<<12)|((buf[1])<<4)|((buf[2])>>4));
bmp280_temp_data=(int32_t)(((buf[3])<<12)|((buf[4])<<4)|((buf[5])>>4));
}
2.温度补偿计算
/*****************************************************************************
* 函 数:int32_t BMP280_compensate_T(int32_t adc_T)
* 功 能:通过补偿计算出温度的值
* 参 数:芯片内部温度传感器的ADC值
* 返回值:温度值*100 (将返回值/100就得到当前温度)
* 备 注:无
*****************************************************************************/
int32_t BMP280_compensate_T(int32_t adc_T)
{
int32_t var1,var2,T;
var1=((((adc_T>>3)-((int32_t)bmp280_cal.dig_t1<<1)))*((int32_t)bmp280_cal.dig_t2))>>11;
var2=(((((adc_T>>4)-((int32_t)bmp280_cal.dig_t1))*((adc_T>>4)-((int32_t)bmp280_cal.dig_t1)))>>12)*((int32_t)bmp280_cal.dig_t3))>>14;
t_fine=var1+var2;
T=(t_fine*5+128)>>8;
return T;
}
3.大气压补偿计算
/*****************************************************************************
* 函 数:uint32_t BMP280_compensate_P(int32_t adc_P)
* 功 能:通过补偿计算出大气压的值
* 参 数:芯片内部压力传感器的ADC值
* 返回值:大气压值 单位为Pa
* 备 注:无
*****************************************************************************/
uint32_t BMP280_compensate_P(int32_t adc_P)
{
int64_t var1,var2,p;
var1=((int64_t)t_fine)-128000;
var2=var1*var1*(int64_t)bmp280_cal.dig_p6;
var2=var2+((var1*(int64_t)bmp280_cal.dig_p5)<<17);
var2=var2+(((int64_t)bmp280_cal.dig_p4)<<35);
var1=((var1*var1*(int64_t)bmp280_cal.dig_p3)>>8)+((var1*(int64_t)bmp280_cal.dig_p2)<<12);
var1=(((((int64_t)1)<<47)+var1))*((int64_t)bmp280_cal.dig_p1)>>33;
if (var1==0)
{
return 0;
}
p=1048576-adc_P;
p=(((p<<31)-var2)*3125)/var1;
var1=(((int64_t)bmp280_cal.dig_p9)*(p>>13)*(p>>13))>>25;
var2=(((int64_t)bmp280_cal.dig_p8)*p)>>19;
p=((p+var1+var2)>>8)+(((int64_t)bmp280_cal.dig_p7)<<4);
return(uint32_t)p/256;
}
最后在主函数内将芯片读取的ADC值传入给这两个补偿函数的参数就可以计算出温度和大气压的值了.
最后附上我这边测得的数据图,还是比较准确的.