【模块系列】STM32BMP280

news2024/9/28 5:26:11

前言

  最进想练习下I2C的应用,手上好有BMP280也没用过,就看着机翻手册和原版手册,开始嘎嘎写库函数了。库的命名应该还1是比较规范了吧,就是手册对于最终值的计算方式很迷糊,所以现在也不能保证有可靠性啊,大家看着来用吧。

注意:该BMP280库不一定能用,仅供参考。我没有参考过别的库的数据。也不知道可不可靠。

环境

  • 开发板:STM32C6T6最小系统板

  • 案例的代码环境:Keil5+STM32CubeMX生成的HAL库,OLED(4P)+BMP280

  • 案例接线:BMP280,OLED模块VCC接3.3V。BMP280和OLED的SDA接到PB9,SCL接到PB8。BMP280模块的SDD引脚接GND,代表I2C七位地址为0x76(接GND为0x76,接VCC为0x77)。

特点

下述介绍参考数据手册

  • 支持I2C协议,3、4线SPI协议
  • 支持三种模式:睡眠,正常,强制。控制功耗
  • 气压相对精度:±0.12 hPa,气压绝对精度:±1 hPa
  • 压力测量可以选择,关闭或5种分辨率(x1,x2,x4,x8,x16)。温度测量可以选择,关闭或5种分辨率(x1,x2,x4,x8,x16)。内置IIR波器,系数范围为 0(关闭) 至 16

思路

  这里讲一下手册中,我觉得迷糊的点在哪吧。在下面的BMP280库的代码中,相信大家也能看到在数据转换函数中有大量注释,官方手册貌似写了,两个转换方法,标题分别为名为补偿函数,计算函数,可是这两个函数基本一样,参于运算的变量也一样。也就是在寄存器获取温度或气压的ADC在分别输入对应函数在转换出来后,在乘上分辨率,就可以了。

  可问题就在:1.官方举例的0.01的分辨率不存在啊,2.按照流程乘上自己设置分辨率的数值不可能对的。3. 而且在运算时好像压根没用到分辨率啊,不过这个我怀疑是不是它直接校正在修正数中了。 4. 一开始我的计算流程是:读出ADC—乘于分辨率,可是这样结果不可能对。就按手册中的流程:读出ADC—放入官方转换函数—乘于分辨率,也不对。最后在实验几次后,就按读出ADC—放入官方转换函数,读出的结果倒是能看,解释环境的情况了。

  总的来说,手册读出流程写的感觉不是很好啊。

代码

  代码方面除了CubeMX生成的工程框架外,还导入了OLED(4P),自制了MyI2C,BMP280库,假如其它项目要用到的话注意也要导入这几个库。下面仅展示BMP280库,完整工程文件会放在文章末尾的。

BMP280.H

#ifndef __BMP280__H__
#define __BMP280__H__

#define BMP280_ADDRESS				0xEC		//八位地址
#define BMP280_ADDRESS_7BIT 	0x76		//七位地址(SDO接GND为0x76,接VCC为0x77)

#define BMP280_ID 						0xD0		// 器件ID
#define BMP280_RESET 					0xE0		// 复位
#define BMP280_STATUS 				0xF3		// 状态
#define BMP280_CTRL_MEAS 			0xF4		// 控制--设置设备的数据采集选项(电源,温度,气压)
#define BMP280_CONFIG 				0xF5		// 配置--设置设备的速率、滤波器和接口选项。在正常模式下,对"配置"寄存器的写入可能会被忽略。睡眠模式下的写入不会被忽略。
#define BMP280_PRESS_MSB  		0xF7		// 气压数据--高8位
#define BMP280_PRESS_LSB 			0xF8		// 气压数据--中8位
#define BMP280_PRESS_XLSB 		0xF9		// 气压数据--低4位(8为中的高4位)
#define BMP280_TEMP_MSB 			0xFA		// 温度数据--高8位
#define BMP280_TEMP_LSB 			0xFB		// 温度数据--中8位
#define BMP280_TEMP_XLSB 			0xFC		// 温度数据--低4位(8为中的高4位)

// 以下为校准数据,两个寄存器(0X88/0X89)的值为一个16位的数据,默认连读,所以就不写两个寄存器地址了
#define BMP280_CALIBRATION_T1		0x88		// unsigned short
#define BMP280_CALIBRATION_T2		0x8A		// signed short
#define BMP280_CALIBRATION_T3		0x8C		// signed short
#define BMP280_CALIBRATION_P1		0x8E		// unsigned short
#define BMP280_CALIBRATION_P2		0x90		// signed short
#define BMP280_CALIBRATION_P3		0x92    // signed short
#define BMP280_CALIBRATION_P4		0x94    // signed short
#define BMP280_CALIBRATION_P5		0x96    // signed short
#define BMP280_CALIBRATION_P6		0x98    // signed short
#define BMP280_CALIBRATION_P7		0x9A    // signed short
#define BMP280_CALIBRATION_P8		0x9C    // signed short
#define BMP280_CALIBRATION_P9		0x9E    // signed short
#define BMP280_CALIBRATION_xx		0xA1		// 保留


typedef unsigned          		char uint8_t;
typedef unsigned short     		int uint16_t;
typedef unsigned           		int uint32_t;
typedef long signed int 			BMP280_S32_t;
typedef long unsigned int 		BMP280_U32_t;
typedef long long signed int 	BMP280_S64_t;

/************************	建议搭配表(官方手册写的) ********************************

过采样设置					压力过采样									典型压力分辨率		建议的温度过采样		
压力测量跳过				跳过(输出设置为0x80000)			---							根据需要
超低功							x1												16 位/2.62 Pa		x1
低功率							×2												17 位/1.31 帕		×1
标准分辨率					×4												18 位/0.66 Pa		x1
高分辨率						×8												19 位/0.33 Pa		×1
超高分辨率					×16												20 位/0.16 帕		×2

********************************************************************************/

/*	电源模式配置
睡眠模式:不进行测量。
正常模式:在测量期和非活动待机期之间的自动永久循环。
强制模式:只进行一次测量。测量结束后,传感器返回休眠模式。
*/
typedef enum
{
	BMP280_Power_Sleep		= 0x00,				// 睡眠模式
	BMP280_Power_Coerce		= 0x01,				// 强制模式
	BMP280_Power_Normal		= 0x03,				// 正常模式
}
BMP280_PowerConfig;

// 气压采样配置
typedef enum
{
	BMP280_Press_No		= 0x00,				// 跳过气压测量
	BMP280_Press_X1		= 0x04,				// 分辨率 X1 	(16位/2.26Pa)
	BMP280_Press_X2		= 0x08,				// 分辨率 X2 	(17位/1.31Pa)
	BMP280_Press_X4		= 0x0C,				// 分辨率 X4 	(18位/0.66Pa)
	BMP280_Press_X8		= 0x10,				// 分辨率 X8 	(19位/0.33Pa)
	BMP280_Press_X16	= 0x1C,				// 分辨率 X16	(20位/0.16Pa)
}
BMP280_PressConfig;

// 温度采样配置
typedef enum
{
	BMP280_Temp_No		= 0x00,				// 跳过温度测量
	BMP280_Temp_X1		= 0x20,				// 分辨率 X1 	(16位/0.0050度)
	BMP280_Temp_X2		= 0x40,				// 分辨率 X2 	(17位/0.0025度)
	BMP280_Temp_X4		= 0x60,				// 分辨率 X4 	(18位/0.0012度)
	BMP280_Temp_X8		= 0x80,				// 分辨率 X8 	(19位/0.0006度)
	BMP280_Temp_X16		= 0xE0,				// 分辨率 X16	(20位/0.0003度)
}
BMP280_TempConfig;

/*************************	正常模式下的典型输出数据速率(ODR) [赫兹](官方手册写的) ***************************

过采样设置		待机[毫秒]
						0.5				62.5		125			250			500			1000		2000		4000
超低功耗			166.67		14.71		7.66		3.91		1.98		0.99		0.50		0.25
低功率				125.00		14.29		7.55		3.88		1.97		0.99		0.50		0.25
标准分辨率		83.33			13.51		7.33		3.82		1.96		0.99		0.50		0.25
高分辨率			50.00			12.20		6.92		3.71		1.92		0.98		0.50		0.25
超高分辨率		26.32			10.00		6.15		3.48		1.86		0.96		0.49		0.25

**********************************************************************************************************/
/************************************************	噪声表(官方手册写的) **************************************

****压力噪声ODR(Hz)****
典型压力均方根噪声 [Pa]
过采样设置				IIR滤波器系数
								关闭		2			4			8			16
超低功耗					3.3		1.9		1.2		0.9		0.4
低功率						2.6		1.5		1.0		0.6		0.4
标准分辨率				2.1		1.2		0.8		0.5		0.3
高分辨率					1.6		1.0		0.6		0.4		0.2
超高分辨率				1.3		0.8		0.5		0.4		0.2

****温度噪声BW(Hz)****
温度[℃]下的典型有效值噪声
温度过采样			关闭IIR过滤器
过采样 ×1			0.005
过采样 ×2			0.004
过采样 ×4			0.003
过采样 ×8			0.003
过采样 ×16			0.002

***********************************************************************************************************/

/****************************	使用场景与参数配置(官方手册写的) ************************************************
用例							模式				过采样设置		气压采样		温度采样		IIR滤波器		待机时间		ODR(Hz)		BW(Hz)
手持设备低功耗		正常				超高分辨			×16				×2				4						62.5ms		10.0			0.92
动态手持设备			正常				标准分辨			×4				×1				16					0.5ms			83.3			1.75
天气监测					强迫				超低功耗			×1				×1				关闭					1/min			1/60			全部			(最低功耗)
电梯/楼层				正常				标准分辨			×4				x1				4						125ms			7.3				0.67
跌落检测					正常				低功率				×2				×1				关闭					0.5ms			125				全部
室内导航					正常				超高分辨			×16				×2				16					0.5ms			26.3			0.55

**********************************************************************************************************/

// 正常模式下待机时间
typedef enum
{
	BMP280_Time_0MS5			= 0x00,				// 0.5 	Ms
	BMP280_Time_62MS5			= 0x20,				// 62.5	Ms
	BMP280_Time_125MS			= 0x40,				// 125	Ms
	BMP280_Time_250MS			= 0x60,				// 250	Ms
	BMP280_Time_500MS			= 0x80,				// 500	Ms
	BMP280_Time_1000MS		= 0xA0,				// 1000	Ms
	BMP280_Time_2000MS		= 0xC0,				// 2000	Ms
	BMP280_Time_4000MS		= 0xE0,				// 4000	Ms
}
BMP280_NormalMode_WaitTimeConfig;

// IIR过滤器的滤波器系数(手册中没给出具体取值,只能参考同位置寄存器取值)
typedef enum
{
	BMP280_IIRfilter_Close	= 0x00,				// 关闭滤波器
	BMP280_IIRfilter_X2			= 0x08,				// 系数2
	BMP280_IIRfilter_X4			= 0x0C,				// 系数4
	BMP280_IIRfilter_X8			= 0x10,				// 系数8
	BMP280_IIRfilter_X16		= 0x1C,				// 系数16
}
BMP280_IIRfilterConfig;

// 是否启用三线SPI接口
typedef enum
{
	BMP280_3SPIModeClose	= 0x00,				// 关闭三线SPI
	BMP280_3SPIModeOpen		= 0x01,				// 开启三线SPI
}
BMP280_3SPIMode;


// 初始化结构配置
typedef struct
{
	BMP280_TempConfig TempConfig;
	BMP280_PressConfig PressConfig;
	BMP280_PowerConfig PowerConfig;
	BMP280_3SPIMode SPIModeConfig;
	BMP280_IIRfilterConfig IIRfilterConfig;
	BMP280_NormalMode_WaitTimeConfig WaitTimeConfig;
}
BMP280_InitConfig;


/*****	底层函数	 *****/
void BMP280_DelayMs(uint16_t num);			// 毫秒级延时
uint8_t BMP280_ReadReg(uint8_t reg);		// 基于BMP280 读寄存器 ID-地址-数据
void BMP280_WriteReg(uint8_t reg,uint8_t data);			// 基于BMP280 写寄存器 ID-地址-数据
uint16_t BMP280_ReadReg_u16_2Btye(uint8_t reg);			// 基于BMP280 读寄存器 ID-地址-无符号16位_2个数据
signed short BMP280_ReadReg_s16_2Btye(uint8_t reg);	// 基于BMP280 读寄存器 ID-地址-有符号16位_2个数据

/***** 初始化函数	 *****/
void BMP280_Init(BMP280_InitConfig *init);		// 初始化BMP280
void BMP280_InitDefault(BMP280_InitConfig *init);		// 填入初始化BMP280结构缺省值

/*****	私有函数	 *****/
void _BMP280_DataCorrection(void);	// (私有)数据修正参数读取
BMP280_S32_t _BMP280_OfficialTempCorrection(BMP280_S32_t adc_T);		// (私有)官方温度的数据转换
BMP280_S32_t _BMP280_OfficialPressCorrection(BMP280_S32_t adc_P);		// (私有)官方气压的数据转换
void _BMP280_ConvertWait(BMP280_NormalMode_WaitTimeConfig config);	// (私有)转换延时

/*****	功能函数	 *****/
uint8_t BMP280_getID(void);	// 获取器件ID
void BMP280_Reset(void);			// 复位BMP280
BMP280_S32_t BMP280_getTemp(BMP280_InitConfig *init);				// 获取温度数据
BMP280_S32_t BMP280_getPress(BMP280_InitConfig *init);				// 获取气压数据
void BMP280_setTempConfig(BMP280_TempConfig config);			// 单独设置温度配置
void BMP280_setPressConfig(BMP280_PressConfig config);		// 单独设置气压配置
void BMP280_setPowerConfig(BMP280_PowerConfig config);		// 单独设置电源模式
void BMP280_set3SPIModeConfig(BMP280_3SPIMode config);		// 单独设置是否开启3线SPI模式
void BMP280_setIIRfilterConfig(BMP280_IIRfilterConfig config);		// 单独设置IIR滤波器系数
void BMP280_setWaitTimeConfig(BMP280_NormalMode_WaitTimeConfig config);	// 单独设置正常模式下待机时间
void BMP280_setTempPressPowerConfig(BMP280_TempConfig config1,BMP280_PressConfig config2,BMP280_PowerConfig config3);		// 同时设置温度配置,气压配置,电源模式
void BMP280_setWaitIIRfilterSPIConfig(BMP280_NormalMode_WaitTimeConfig config1,BMP280_IIRfilterConfig config2,BMP280_3SPIMode config3);		//	同时设置正常模式下待机时间,IIR滤波器系数,是否开启3线SPI模式

#endif

BMP280.C

#include "BMP280.h"
#include "MyI2C.h"

// 数据校正参数变量--使用频繁故改为全局变量
unsigned short dig_T1;
signed short	dig_T2,dig_T3;
unsigned short dig_P1;
signed short	dig_P2,dig_P3,dig_P4,dig_P5,dig_P6,dig_P7,dig_P8,dig_P9;
BMP280_S32_t t_fine;
	
	
/**
 * @描述:基于BMP280 写寄存器 ID-地址-数据
 */
void BMP280_WriteReg(uint8_t reg,uint8_t data)
{
	MyI2C_Start();					
	MyI2C_SendByte(BMP280_ADDRESS);			
  MyI2C_ReceiveAck();	
	MyI2C_SendByte(reg);		
  MyI2C_ReceiveAck();			
	MyI2C_SendByte(data);
	MyI2C_ReceiveAck();
  MyI2C_Stop();						
}

/**
 * @描述:基于BMP280 读寄存器 ID-地址-数据
 */
uint8_t BMP280_ReadReg(uint8_t reg)
{
	uint8_t reData = 0;
	MyI2C_Start();					
	MyI2C_SendByte(BMP280_ADDRESS);		
	MyI2C_ReceiveAck();	
	MyI2C_SendByte(reg);			
  MyI2C_ReceiveAck();
	
	MyI2C_Start();	
	MyI2C_SendByte(BMP280_ADDRESS | 0x01);		
	MyI2C_ReceiveAck();	
	reData = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	
	MyI2C_Stop();		
  return reData;
}

/**
 * @描述:基于BMP280 读寄存器 ID-地址-无符号16位_2个数据
 */
uint16_t BMP280_ReadReg_u16_2Btye(uint8_t reg)
{
	uint16_t reData = 0;
	MyI2C_Start();					
	MyI2C_SendByte(BMP280_ADDRESS);		
	MyI2C_ReceiveAck();	
	MyI2C_SendByte(reg);			
  MyI2C_ReceiveAck();
	
	MyI2C_Start();	
	MyI2C_SendByte(BMP280_ADDRESS | 0x01);		
	MyI2C_ReceiveAck();	
	reData = MyI2C_ReceiveByte();
	MyI2C_SendAck(0);
	reData |= (MyI2C_ReceiveByte() << 8);
	MyI2C_SendAck(1);
	
	MyI2C_Stop();		
  return reData;
}

/**
 * @描述:基于BMP280 读寄存器 ID-地址-有符号16位_2个数据
 */
signed short BMP280_ReadReg_s16_2Btye(uint8_t reg)
{
	signed short reData = 0;
	MyI2C_Start();					
	MyI2C_SendByte(BMP280_ADDRESS);		
	MyI2C_ReceiveAck();	
	MyI2C_SendByte(reg);			
  MyI2C_ReceiveAck();
	
	MyI2C_Start();	
	MyI2C_SendByte(BMP280_ADDRESS | 0x01);		
	MyI2C_ReceiveAck();	
	reData = MyI2C_ReceiveByte();
	reData <<= 8;
	MyI2C_SendAck(0);
	reData |= MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	
	MyI2C_Stop();		
  return reData;
}


/**
* @描述:毫秒级延时
* @参数:num:延时多少毫秒
*/
void BMP280_DelayMs(uint16_t ms)
{
	for(uint16_t i = 0;ms > i;i++)
	{
		MyI2C_DelayUs(1000);
	}
}


/**
* @描述:获取器件ID
* @返回:id为0x58
*/
uint8_t BMP280_getID(void)
{
	return BMP280_ReadReg(BMP280_ID);
}

/**
* @描述:获取器件状态
* @返回:每当转换运行时自动设置为'1',当结果被传输到数据寄存器时自动设置为'0'。
*/
uint8_t BMP280_getStatus(void)
{
	// 第4位是转换完成与否的状态(第1位也有个状态位,看介绍好像是
	// 什么影子寄存器的复制?不清楚所以就不返回)
	return BMP280_ReadReg(BMP280_STATUS) >> 3;
}

/**
* @描述:复位BMP280
*/
void BMP280_Reset(void)
{
	BMP280_WriteReg(0xE0,0xB0);
}

/**
* @描述:(私有)转换延时
*/
void _BMP280_ConvertWait(BMP280_NormalMode_WaitTimeConfig config)
{
	switch(config)
	{
		case BMP280_Time_0MS5:
			BMP280_DelayMs(1);
		break;
		case BMP280_Time_62MS5:
			BMP280_DelayMs(64);
		break;
		case BMP280_Time_125MS:
			BMP280_DelayMs(130);
		break;
		case BMP280_Time_250MS:
			BMP280_DelayMs(260);
		break;
		case BMP280_Time_500MS:
			BMP280_DelayMs(510);
		break;
		case BMP280_Time_1000MS:
			BMP280_DelayMs(1010);
		break;
		case BMP280_Time_2000MS:
			BMP280_DelayMs(2020);
		break;
		case BMP280_Time_4000MS:
			BMP280_DelayMs(4010);
		break;
	}
}

/**
* @描述:(私有)数据修正参数读取
*/
void _BMP280_DataCorrection(void)
{
	dig_T1 = BMP280_ReadReg_u16_2Btye(BMP280_CALIBRATION_T1);
	dig_T2 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_T2);
	dig_T3 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_T3);
	
	dig_P1 = BMP280_ReadReg_u16_2Btye(BMP280_CALIBRATION_P1);
	dig_P2 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_P2);
	dig_P3 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_P3);
	dig_P4 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_P4);
	dig_P5 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_P5);
	dig_P6 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_P6);
	dig_P7 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_P7);
	dig_P8 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_P8);
	dig_P9 = BMP280_ReadReg_s16_2Btye(BMP280_CALIBRATION_P9);
}

/**
* @描述:(私有)官方温度的数据转换
*/
BMP280_S32_t _BMP280_OfficialTempCorrection(BMP280_S32_t adc_T)
{
	BMP280_S32_t var1,var2,T;
	var1 = ((((adc_T>>3) - ((BMP280_S32_t) dig_T1<<1))) * ((BMP280_S32_t) dig_T2)) >> 11;
	var2 = (((((adc_T>>4) - ((BMP280_S32_t) dig_T1)) * ((adc_T>>4) - ((BMP280_S32_t) dig_T1)))>>12)*((BMP280_S32_t) dig_T3))>> 14;
	t_fine = var1 + var2;
	T = (t_fine * 5 + 128) >> 8;
  return T;
}

/**
* @描述:(私有)官方气压的数据转换
*/
BMP280_S32_t _BMP280_OfficialPressCorrection(BMP280_S32_t adc_P)
{
	// 参考网友的
//    BMP280_S64_t  var1, var2,P;
//    var1 = (((BMP280_S64_t )t_fine)>>1) - (BMP280_S64_t )64000;
//    var2 = (((var1>>2) * (var1>>2)) >> 11) * ((BMP280_S64_t )dig_P6);
//    var2 = var2 + ((var1*((BMP280_S64_t )dig_P5))<<1);
//    var2 = (var2>>2)+(((BMP280_S64_t )dig_P4)<<16);
//    var1 = (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((BMP280_S64_t )dig_P2) * var1)>>1))>>18;
//    var1 = ((((32768+var1))*((BMP280_S64_t )dig_P1))>>15);
//    if (var1 == 0)
//    {
//        return 0;
//    }    
//    P = (((BMP280_S64_t )(((BMP280_S64_t )1048576)-adc_P)-(var2>>12)))*3125;
//    if(P<0x80000000)
//    {
//       P = (P << 1) / ((BMP280_U32_t ) var1);   
//    }
//    else
//    {
//        P = (P / (BMP280_U32_t )var1) * 2;    
//    }
//    var1 = (((BMP280_S32_t )dig_P9) * ((BMP280_S32_t )(((P>>3) * (P>>3))>>13)))>>12;
//    var2 = (((BMP280_S32_t )(P>>2)) * ((BMP280_S32_t )dig_P8))>>13;
//    P = (BMP280_U32_t )((BMP280_S32_t )P + ((var1 + var2 + dig_P7) >> 4));
//    return P;

	// 官方文档的V1.1
	// 官方说Q24.8 格式(24 个整数位和 8 个小数位)的无符号 32 位整数返回压力(单位 Pa)。
	// "24674867 "的输出值代表 24674867/256 = 96386.2  Pa = 963.862 hPa BMP280_U32_t
	BMP280_S64_t var1,var2, p;
	var1 = ((BMP280_S64_t)t_fine) - 128000;var2 = var1 * var1 * (BMP280_S64_t) dig_P6;
	var2 = var2 + ((var1*(BMP280_S64_t) dig_P5)<<17);
	var2 = var2 + (((BMP280_S64_t)dig_P4)<<35);
	var1 = ((var1 * var1 * (BMP280_S64_t) dig_P3)>>8)+ ((var1 * (BMP280_S64_t) dig_P2) <<12); 
	var1 = (((((BMP280_S64_t) 1) <<47) +var1)) * ((BMP280_S64_t) dig_P1) >>33;
	if(var1 == 0)return 0; // 避免因除数为零而产生异常
	p= 1048576 - adc_P;
	p = (((p<<31)-var2) *3125) / var1;
	var1 = (((BMP280_S64_t)dig_P9) * (p>>13) * (p>>13)) >> 25;
	var2 = (((BMP280_S64_t)dig_P8) * p)>> 19;
	p= ((p + var1 + var2) >> 8) + (((BMP280_S64_t) dig_P7)<<4);
	
	return ((BMP280_U32_t)p)/256;
}


/**
* @描述:获取温度数据
* @返回:返回值除于100才是温度数据,
*       假如返回2488,那么温度为24.88
*/
BMP280_S32_t BMP280_getTemp(BMP280_InitConfig *init)
{
	BMP280_S32_t data = 0;	// 温度ADC
	BMP280_S32_t var1 = 0;
	BMP280_S32_t var2 = 0;
	
	float redata;
	
	MyI2C_Start();					
	MyI2C_SendByte(BMP280_ADDRESS);		
	MyI2C_ReceiveAck();	
	MyI2C_SendByte(BMP280_TEMP_MSB);			
  MyI2C_ReceiveAck();
	
	MyI2C_Start();	
	MyI2C_SendByte(BMP280_ADDRESS | 0x01);		
	MyI2C_ReceiveAck();	
	data = MyI2C_ReceiveByte();
	MyI2C_SendAck(0);
	data <<= 8;
	data |= MyI2C_ReceiveByte();
	MyI2C_SendAck(0);
	data <<= 4;
	data |= (MyI2C_ReceiveByte() >> 4);
	MyI2C_SendAck(1);
	
	MyI2C_Stop();

	// 数据处理
	_BMP280_DataCorrection();
	// 计算处理
	// var1 = ((((data>>3) - ((BMP280_S32_t) dig_T1<<1))) * ((BMP280_S32_t) dig_T2)) >> 11;
	// var2 = (((((data>>4) - ((BMP280_S32_t) dig_T1)) * ((data>>4) - ((BMP280_S32_t) dig_T1)))>>12)*((BMP280_S32_t) dig_T3))>> 14;
	// t_fine = var1 + var2;
	
	//个人认为这应该是补偿运算
	// var1 = (((double)dig_T1)/16384.0 - ((double)dig_T1)/1024.0)*((double)dig_T2);
	// var2 = ((((double)data)/131072.0 - ((double)dig_T1)/8192.0)*(((double)data)/131072.0-((double)dig_T1)/8192.0))*((double)dig_T3);
	// t_fine = (BMP280_S32_t)(var1 + var2);
	
	// data = t_fine;
	// data = _BMP280_OfficialCorrection(data);
	
	// 大概率有用的一个
	redata = data;
	// 原始数据乘于分辨率(还有根据配置丢弃部分位数)
	/*
	switch(init->TempConfig)
	{
		case BMP280_Temp_No:
			redata = 0;
		break;
		case BMP280_Temp_X1:
			// 保留16位
			//data &= 0x0000FFFF; 
			redata = data * 0.005;
		break;
		case BMP280_Temp_X2:
			// 保留17位
			// data &= 0x0001FFFF; 
			redata = data * 0.0025;
		break;
		case BMP280_Temp_X4:
			// 保留18位
			//data &= 0x0003FFFF; 
			redata = data * 0.0012;
		break;
		case BMP280_Temp_X8:
			// 保留19位
			//data &= 0x0007FFFF; 
			redata = data * 0.0006;
		break;
		case BMP280_Temp_X16:
			// 保留20位
			//data &= 0x000FFFFF; 
			redata = data * 0.0003;
		break;
		default:
			redata = 0;
		break;
	}
	*/
	// 下一个转换延时
	_BMP280_ConvertWait(init->WaitTimeConfig);
	// return redata;
	return _BMP280_OfficialTempCorrection(redata);
}

/**
* @描述:获取气压数据
* @返回:返回值除于100才是气压数据,
*       假如返回123456,那么气压为1234.56
*/
BMP280_S32_t BMP280_getPress(BMP280_InitConfig *init)
{
	BMP280_S32_t data = 0;
	float redata;
	
	MyI2C_Start();					
	MyI2C_SendByte(BMP280_ADDRESS);		
	MyI2C_ReceiveAck();	
	MyI2C_SendByte(BMP280_PRESS_MSB);			
  MyI2C_ReceiveAck();
	
	MyI2C_Start();	
	MyI2C_SendByte(BMP280_ADDRESS | 0x01);		
	MyI2C_ReceiveAck();	
	data = MyI2C_ReceiveByte();
	MyI2C_SendAck(0);
	data <<= 8;
	data |= MyI2C_ReceiveByte();
	MyI2C_SendAck(0);
	data <<= 4;
	data |= (MyI2C_ReceiveByte() >> 4);
	MyI2C_SendAck(1);
	
	MyI2C_Stop();
	
	// 数据处理
	_BMP280_DataCorrection();
	redata = data;
	// 原始数据乘于分辨率
	/*
	switch(init->PressConfig)
	{
		case BMP280_Press_No:
			redata = 0;
		break;
		case BMP280_Press_X1:
			// 保留16位
			data &= 0x0000FFFF; 
			redata = data * 2.26;
		break;
		case BMP280_Press_X2:
			// 保留17位
			data &= 0x0001FFFF;
			redata = data * 1.31;
		break;
		case BMP280_Press_X4:
			// 保留18位
			data &= 0x0003FFFF; 
			redata = data * 0.66;
		break;
		case BMP280_Press_X8:
			// 保留19位
			data &= 0x0007FFFF; 
			redata = data * 0.33;
		break;
		case BMP280_Press_X16:
			// 保留20位
			data &= 0x000FFFFF; 
			redata = data * 0.16;
		break;
		default:
			redata = 0;
		break;
	}
	*/
	// 下一个转换延时
	_BMP280_ConvertWait(init->WaitTimeConfig);
	
	return _BMP280_OfficialPressCorrection(redata);
}

/**
* @描述:单独设置温度配置
*/
void BMP280_setTempConfig(BMP280_TempConfig config)
{
	uint8_t data;
	data = BMP280_ReadReg(BMP280_CTRL_MEAS);
	data &= 0x1F;
	data |= config;
	BMP280_WriteReg(BMP280_CTRL_MEAS,data);
}

/**
* @描述:单独设置气压配置
*/
void BMP280_setPressConfig(BMP280_PressConfig config)
{
	uint8_t data;
	data = BMP280_ReadReg(BMP280_CTRL_MEAS);
	data &= 0xE3;
	data |= config;
	BMP280_WriteReg(BMP280_CTRL_MEAS,data);
}

/**
* @描述:单独设置电源模式
*/
void BMP280_setPowerConfig(BMP280_PowerConfig config)
{
	uint8_t data;
	data = BMP280_ReadReg(BMP280_CTRL_MEAS);
	data &= 0xFC;
	data |= config;
	BMP280_WriteReg(BMP280_CTRL_MEAS,data);
}

/**
* @描述:同时设置温度配置,气压配置,电源模式
*/
void BMP280_setTempPressPowerConfig(BMP280_TempConfig config1,BMP280_PressConfig config2,BMP280_PowerConfig config3)
{
	uint8_t data;
	data = 0x00 | config1 | config2 | config3;
	BMP280_WriteReg(BMP280_CTRL_MEAS,data);
}

/**
* @描述:单独设置正常模式下待机时间
*/
void BMP280_setWaitTimeConfig(BMP280_NormalMode_WaitTimeConfig config)
{
	uint8_t data;
	data = BMP280_ReadReg(BMP280_CONFIG);
	data &= 0x1F;
	data |= config;
	BMP280_WriteReg(BMP280_CONFIG,data);
}

/**
* @描述:单独设置IIR滤波器系数
*/
void BMP280_setIIRfilterConfig(BMP280_IIRfilterConfig config)
{
	uint8_t data;
	data = BMP280_ReadReg(BMP280_CONFIG);
	data &= 0xE3;
	data |= config;
	BMP280_WriteReg(BMP280_CONFIG,data);
}

/**
* @描述:单独设置是否开启3线SPI模式
*/
void BMP280_set3SPIModeConfig(BMP280_3SPIMode config)
{
	uint8_t data;
	data = BMP280_ReadReg(BMP280_CONFIG);
	data &= 0xFE;
	data |= config;
	BMP280_WriteReg(BMP280_CONFIG,data);
}

/**
* @描述:同时设置正常模式下待机时间,IIR滤波器系数,是否开启3线SPI模式
*/
void BMP280_setWaitIIRfilterSPIConfig(BMP280_NormalMode_WaitTimeConfig config1,BMP280_IIRfilterConfig config2,BMP280_3SPIMode config3)
{
	uint8_t data;
	data = 0x00 | config1 | config2 | config3;
	BMP280_WriteReg(BMP280_CONFIG,data);
}

/**
* @描述:初始化BMP280
* @参数:init:BMP280初始化的结构体
*/
void BMP280_Init(BMP280_InitConfig *init)
{
	// 按照手持设备低功耗案例配置
	// BMP280_setTempPressPowerConfig(BMP280_Temp_X2,BMP280_Press_X16,BMP280_Power_Normal);
	// BMP280_setWaitIIRfilterSPIConfig(BMP280_Time_62MS5,BMP280_IIRfilter_X4,BMP280_3SPIModeClose);
	BMP280_setTempPressPowerConfig(init->TempConfig,init->PressConfig,init->PowerConfig);
	BMP280_setWaitIIRfilterSPIConfig(init->WaitTimeConfig,init->IIRfilterConfig,init->SPIModeConfig);
}

/**
* @描述:填入初始化BMP280结构缺省值
* @参数:init:BMP280初始化的结构体
*/
void BMP280_InitDefault(BMP280_InitConfig *init)
{
	// 按照手持设备低功耗案例配置
	init->TempConfig = BMP280_Temp_X2;
	init->PressConfig = BMP280_Press_X16;
	init->PowerConfig = BMP280_Power_Normal;
	init->WaitTimeConfig = BMP280_Time_62MS5;
	init->IIRfilterConfig = BMP280_IIRfilter_X4;
	init->SPIModeConfig   = BMP280_3SPIModeClose;
}

现象

  转换完后得到的整数,按照手册函数中的分辨率要求,除100后,得到的数值应该基本符合环境数了。

在这里插入图片描述

在这里插入图片描述

工程

链接包含资料:Keil5工程代码*1,BMP280资料手册(英文)*1,BMP280资料手册(机翻中文)*1

链接:https://pan.baidu.com/s/10XcvWtbkSfZHFbgQUA_e8A  提取码:k21q

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1379599.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSM框架整合:掌握Spring+Spring MVC+MyBatis的完美结合!

SSM整合 1.1 流程分析1.2 整合配置步骤1&#xff1a;创建Maven的web项目步骤2:添加依赖步骤3:创建项目包结构步骤4:创建SpringConfig配置类步骤5:创建JdbcConfig配置类步骤6:创建MybatisConfig配置类步骤7:创建jdbc.properties步骤8:创建SpringMVC配置类步骤9:创建Web项目入口配…

力扣日记1.13-【二叉树篇】669. 修剪二叉搜索树

力扣日记&#xff1a;【二叉树篇】669. 修剪二叉搜索树 日期&#xff1a;2023.1.13 参考&#xff1a;代码随想录、力扣 669. 修剪二叉搜索树 题目描述 难度&#xff1a;中等 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树…

1992年-2020年ESA_CCI土地覆盖数据介绍、下载与数据分享

数据介绍 ESA CCI Land Cover是欧洲空间局&#xff08;European Space Agency&#xff0c;ESA&#xff09;的一个项目&#xff0c;其目标是生成全球土地覆盖的高质量、一致性和长期的时间序列数据&#xff0c;分辨率大约为300米。 该项目是ESA气候变化计划&#xff08;Climate…

Linux中安装字体

问题说明 wps 安装后打开文件部分字体出现乱码&#xff0c;原因主要是linux中缺少windows中的相关字体&#xff0c;只要从windows电脑中的字体拷贝到linux系统中并安装就能解决问题 对ubuntu 和manjora有效。 安装字体 字体下载地址可参考附录 在 Linux 中&#xff0c;一次…

强化学习应用(五):基于Q-learning的无人机物流路径规划研究(提供Python代码)

一、Q-learning简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于马尔可夫决策过程&#xff08;MDP&#xff09;的问题。它通过学习一个价值函数来指导智能体在环境中做出决策&#xff0c;以最大化累积奖励。 Q-learning算法的核心思想是通过不断更新一个称为Q值的…

机器人模仿学习之动作分块ACT算法的代码剖析、部署训练

前言 本文最早是属于《斯坦福Mobile ALOHA背后的关键技术&#xff1a;动作分块ACT算法的原理解析》的第二、第三部分&#xff0c;涉及到动作分块ACT的代码剖析与部署训练 但因为想把ACT的代码逐行剖析的更细致些&#xff0c;加之为避免上一篇文章太过于长&#xff0c;故把动作…

使用Nginx作为反向代理服务器在Linux中的最佳实践

在Linux环境下&#xff0c;Nginx因其高效性能、稳定性以及丰富的功能集而广泛用于作为反向代理服务器。以下是在Linux中使用Nginx作为反向代理服务器的最佳实践&#xff1a; 1. 安装与配置 首先&#xff0c;确保你的Linux发行版已经安装了Nginx。大多数Linux发行版都提供了Ng…

【上分日记】第369场周赛(分类讨论 + 数学 + 前缀和)

文章目录 前言正文1.3000. 对角线最长的矩形的面积2.3001. 捕获黑皇后需要的最少移动次数3.3002. 移除后集合的最多元素数3.3003. 执行操作后的最大分割数量 总结尾序 前言 终于考完试了&#xff0c;考了四天&#xff0c;也耽搁了四天&#xff0c;这就赶紧来补这场周赛的题了&a…

java求链表中倒数第k个结点

下面我用两种方法求解&#xff1a; 第一种方法&#xff1a;通常我们做这种题就是求出链表的长度length&#xff0c;然后呢length-k的值就是我们要从链表头部走几步就可以了&#xff0c;代码解释&#xff1a; public class Solution {public class ListNode {int val;ListNode…

Star 8K+,使用.NET开发的开源NoSQL数据库

LiteDB 是一个轻量级、快速、易用的 .NET NoSQL 嵌入式数据库&#xff0c;完全用 C# 托管代码开发&#xff0c;并且是免费和开源的。它非常适合在移动应用&#xff08;Xamarin iOS/Android&#xff09;和小型的桌面/Web 应用中使用。 主要特点 简单易用的 API&#xff0c;类似…

信号量机制

1965年&#xff0c;由荷兰学者迪科斯彻Dijkstra提出&#xff08;P、V分别代表荷兰语的Proberen &#xff08;test&#xff09;和Verhogen &#xff08;increment&#xff09;&#xff09;、是一种卓有成效的进程同步机制。 信号量-软件解决方案&#xff1a; 保证两个或多个代码…

Javascript jQuery简介

✨前言✨ 1.如果代码对您有帮助 欢迎点赞&#x1f44d;收藏⭐哟 后面如有问题可以私信评论哟&#x1f5d2;️ 2.博主后面将持续更新哟&#x1f618;&#x1f389;本章目录&#x1f389; &#x1f95d;一.jQuery简介&#x1f965;二.JQeury常用API&#x1f347;1.jQeury选择…

c JPEG编码,此程序没有处现MCU中亮度分量的排序

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/videodev2.h> //v4l2 头文件 #include <strin…

UE5蓝图-脚部IK

引擎版本&#xff1a;UE5.2 脚部IK做不做的区别&#xff1a; 图1是没有做脚步IK&#xff0c;我们的角色一部分的脚像是浮在半空中&#xff0c;图2是做了脚步IK&#xff0c;我们的角色就是一部分在地上&#xff0c;一部分在物体上。从上面的两个图可以看出&#xff0c;制作脚步…

Leetcode 剑指 Offer II 061. 查找和最小的 K 对数字

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定两个以升序排列的整数数组 nums1 和 nums2 , 以及一个整数 k…

[oeasy]python0004_游乐场_和python一起玩耍_python解释器_数学运算

和python玩耍 &#x1f94a; Python 回忆 上次 了解shell环境中的命令 命令作用whoami显示当前用户名pwd显示当前文件夹ls列出当前文件夹下的内容python3仿佛进入大于号黑洞 这python3 怎么玩啊&#xff01;&#x1f620; 说好的python教程呢&#xff1f;&#x1f914; 运…

2023一带一路暨金砖国家技能发展与技术创新大赛“网络安全”赛项省选拔赛样题卷②

2023金砖国家职业技能竞赛"网络安全" 赛项省赛选拔赛样题 2023金砖国家职业技能竞赛 省赛选拔赛样题第一阶段&#xff1a;职业素养与理论技能项目1. 职业素养项目1. 职业素养项目2. 网络安全项目3. 安全运营 第二阶段&#xff1a;安全运营项目1. 操作系统安全配置与加…

哈希表的实现(1)----除留余数法实现

一&#xff0c;哈希表的介绍 哈希表是一种通过哈希思想实现的一种数据结构。哈希表这种数据结构的特点便是可以通过一个值快速的定位这个值所在的位置实现插入&#xff0c;删除&#xff0c;查找。在这篇博客里面&#xff0c;我们便来实现一个通过除留余数法实现的一个哈希表。 …

tl431几种不常见的接法

tl431可调电源电路图分析 精密电压基准IC TL431是我们常见的精密电压基准IC &#xff0c;应用非常广泛。其输出压连续可调达36V&#xff0c;工作电流范围宽达0.1--100mA&#xff0c;动态电阻典型值为0.22欧&#xff0c;输出杂波低。图1是利用它作电压基准和驱动外加场效应管K7…

泛微OA-Ecology8表单中填充用友U8数据

文章目录 1、需求及效果1.1 需求1.2 效果 2、思路及实现步骤2.1 思路2.2 实现步骤 3.结语 1、需求及效果 1.1 需求 在OA中填写表单中时候&#xff0c;比如物料号还需要从U8中查找后才能填写&#xff0c;非常的麻烦。想要在填写表单的时候可以搜索&#xff0c;并且带出其他的关…