一、环境安装
请看 https://www.iceasy.com/review/1900025119838572545
二、BMP280介绍



三、硬件连接
FTHR-G0001开发板 ----------> BMP280模块
GND ----------> GND
VCC ----------> VCC
PA0 ----------> SCL
PA1 ----------> SDA
四、代码
BMP280.c
/* Files include */
#include <stdio.h>
#include "platform.h"
#include "i2c_gpio.h"
#include "delay.h"
#include <math.h>
#include "stdbool.h"
//#include "u8g2.h"
/* Private typedef ****************************************************************************************************/
/* Private define *****************************************************************************************************/
/* Private macro ******************************************************************************************************/
#define BMP280_IIC_SCL(x) GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)(x))
#define BMP280_IIC_SDA(x) GPIO_WriteBit(GPIOA, GPIO_Pin_1, (BitAction)(x))
#define BMP280_READ_SDA() GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)
//注意:
//模块5V供电
//SD0接地,模块使用IIC通信
/*bmp280 气压和温度过采样 工作模式*/
#define BMP280_PRESSURE_OSR (BMP280_OVERSAMP_8X)
#define BMP280_TEMPERATURE_OSR (BMP280_OVERSAMP_16X)
#define BMP280_MODE (BMP280_PRESSURE_OSR<<2|BMP280_TEMPERATURE_OSR<<5|BMP280_NORMAL_MODE)
typedef struct
{
u16 dig_T1; /* calibration T1 data */
s16 dig_T2; /* calibration T2 data */
s16 dig_T3; /* calibration T3 data */
u16 dig_P1; /* calibration P1 data */
s16 dig_P2; /* calibration P2 data */
s16 dig_P3; /* calibration P3 data */
s16 dig_P4; /* calibration P4 data */
s16 dig_P5; /* calibration P5 data */
s16 dig_P6; /* calibration P6 data */
s16 dig_P7; /* calibration P7 data */
s16 dig_P8; /* calibration P8 data */
s16 dig_P9; /* calibration P9 data */
s32 t_fine; /* calibration t_fine data */
} bmp280Calib;
bmp280Calib bmp280Cal;
static u8 bmp280ID = 0;
static bool isInit = false;
static s32 bmp280RawPressure = 0;
static s32 bmp280RawTemperature = 0;
static void bmp280GetPressure( void );
static void presssureFilter( float* in, float* out );
static float bmp280PressureToAltitude( float* pressure/*, float* groundPressure, float* groundTemp*/ );
/* Private variables **************************************************************************************************/
/* Private functions **************************************************************************************************/
/***********************************************************************************************************************
* @brief
* @note none
* @param none
* @retval none
*********************************************************************************************************************/
void i2c_init( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
BMP280_IIC_SCL( 1 );
BMP280_IIC_SDA( 1 );
}
//产生IIC起始信号
void BMP_IIC_Start( void )
{
BMP280_IIC_SDA( 1 );
BMP280_IIC_SCL( 1 );
Delay_us( 4 );
BMP280_IIC_SDA( 0 ); //START:when CLK is high,DATA change form high to low
Delay_us( 4 );
BMP280_IIC_SCL( 0 ); //钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void BMP_IIC_Stop( void )
{
BMP280_IIC_SCL( 0 );
BMP280_IIC_SDA( 0 ); //STOP:when CLK is high DATA change form low to high
Delay_us( 4 );
BMP280_IIC_SCL( 1 );
BMP280_IIC_SDA( 1 ); //发送I2C总线结束信号
Delay_us( 4 );
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 BMP_IIC_Wait_Ack( void )
{
u8 ucErrTime = 0;
BMP280_IIC_SDA( 1 );
Delay_us( 1 );
BMP280_IIC_SCL( 1 );
Delay_us( 1 );
while( BMP280_READ_SDA() )
{
ucErrTime++;
if( ucErrTime > 250 )
{
BMP_IIC_Stop();
return 1;
}
}
BMP280_IIC_SCL( 0 ); //时钟输出0
return 0;
}
//产生ACK应答
void BMP_IIC_Ack( void )
{
BMP280_IIC_SCL( 0 );
BMP280_IIC_SDA( 0 );
Delay_us( 2 );
BMP280_IIC_SCL( 1 );
Delay_us( 2 );
BMP280_IIC_SCL( 0 );
}
//不产生ACK应答
void BMP_IIC_NAck( void )
{
BMP280_IIC_SCL( 0 );
BMP280_IIC_SDA( 1 );
Delay_us( 2 );
BMP280_IIC_SCL( 1 );
Delay_us( 2 );
BMP280_IIC_SCL( 0 );
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void BMP_IIC_Send_Byte( u8 txd )
{
u8 t;
BMP280_IIC_SCL( 0 ); //拉低时钟开始数据传输
for( t = 0; t < 8; t++ )
{
if ( txd & 0x80 )
BMP280_IIC_SDA( 1 );
else
BMP280_IIC_SDA( 0 );
txd <<= 1;
Delay_us( 2 ); //对TEA5767这三个延时都是必须的
BMP280_IIC_SCL( 1 );
Delay_us( 2 );
BMP280_IIC_SCL( 0 );
Delay_us( 2 );
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 BMP_IIC_Read_Byte( unsigned char ack )
{
unsigned char i, receive = 0;
BMP280_IIC_SDA( 1 );
BMP280_IIC_SCL( 0 );
for( i = 0; i < 8; i++ )
{
BMP280_IIC_SCL( 1 );
Delay_us( 2 );
receive <<= 1;
if( BMP280_READ_SDA() )receive++;
Delay_us( 2 );
BMP280_IIC_SCL( 0 );
}
if ( !ack )
BMP_IIC_NAck(); //发送nACK
else
BMP_IIC_Ack(); //发送ACK
return receive;
}
//从指定地址读出一个数据
//ReadAddr:开始读数的地址
//返回值 :读到的数据
u8 iicDevReadByte( u8 devaddr, u8 addr )
{
u8 temp = 0;
BMP_IIC_Start();
BMP_IIC_Send_Byte( devaddr ); //发送器件写命令
BMP_IIC_Wait_Ack();
BMP_IIC_Send_Byte( addr ); //发送低地址
BMP_IIC_Wait_Ack();
BMP_IIC_Start();
BMP_IIC_Send_Byte( devaddr | 1 ); //发送器件读命令
BMP_IIC_Wait_Ack();
temp = BMP_IIC_Read_Byte( 0 );
BMP_IIC_Stop(); //产生一个停止条件
return temp;
}
//连续读多个字节
//addr:起始地址
//rbuf:读数据缓存
//len:数据长度
void iicDevRead( u8 devaddr, u8 addr, u8 len, u8* rbuf )
{
int i = 0;
BMP_IIC_Start();
BMP_IIC_Send_Byte( devaddr );
BMP_IIC_Wait_Ack();
BMP_IIC_Send_Byte( addr ); //地址自增
BMP_IIC_Wait_Ack();
BMP_IIC_Start();
BMP_IIC_Send_Byte( devaddr | 1 );
BMP_IIC_Wait_Ack();
for( i = 0; i < len; i++ )
{
if( i == len - 1 )
{
rbuf[i] = BMP_IIC_Read_Byte( 0 ); //最后一个字节不应答
}
else
rbuf[i] = BMP_IIC_Read_Byte( 1 );
}
BMP_IIC_Stop( );
}
//从指定地址写入一个数据
//WriteAddr :写入数据的目的地址
//DataToWrite:要写入的数据
void iicDevWriteByte( u8 devaddr, u8 addr, u8 data )
{
BMP_IIC_Start();
BMP_IIC_Send_Byte( devaddr ); //发送器件写命令
BMP_IIC_Wait_Ack();
BMP_IIC_Send_Byte( addr ); //发送低地址
BMP_IIC_Wait_Ack();
BMP_IIC_Send_Byte( data ); //发送字节
BMP_IIC_Wait_Ack();
BMP_IIC_Stop(); //产生一个停止条件
}
//连续写多个字节
//addr:起始地址
//wbuf:写数据缓存
//len:数据的长度
void iicDevWrite( u8 devaddr, u8 addr, u8 len, u8* wbuf )
{
int i = 0;
BMP_IIC_Start();
BMP_IIC_Send_Byte( devaddr );
BMP_IIC_Wait_Ack();
BMP_IIC_Send_Byte( addr ); //地址自增
BMP_IIC_Wait_Ack();
for( i = 0; i < len; i++ )
{
BMP_IIC_Send_Byte( wbuf[i] );
BMP_IIC_Wait_Ack();
}
BMP_IIC_Stop( );
}
bool BMP280Init( void )
{
i2c_init(); /*初始化I2C*/
Delay_ms( 20 );
bmp280ID = iicDevReadByte( BMP280_ADDR, BMP280_CHIP_ID ); /* 读取bmp280 ID*/
if( bmp280ID == BMP280_DEFAULT_CHIP_ID )
printf( "BMP280 ID IS: 0x%X\n", bmp280ID );
else
return false;
/* 读取校准数据 */
iicDevRead( BMP280_ADDR, BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG, 24, ( u8* )&bmp280Cal );
iicDevWriteByte( BMP280_ADDR, BMP280_CTRL_MEAS_REG, BMP280_MODE );
iicDevWriteByte( BMP280_ADDR, BMP280_CONFIG_REG, 5 << 2 ); /*配置IIR滤波*/
isInit = true;
return true;
}
static void bmp280GetPressure( void )
{
u8 data[BMP280_DATA_FRAME_SIZE];
// read data from sensor
iicDevRead( BMP280_ADDR, BMP280_PRESSURE_MSB_REG, BMP280_DATA_FRAME_SIZE, data );
bmp280RawPressure = ( s32 )( ( ( ( uint32_t )( data[0] ) ) << 12 ) | ( ( ( uint32_t )( data[1] ) ) << 4 ) | ( ( uint32_t )data[2] >> 4 ) );
bmp280RawTemperature = ( s32 )( ( ( ( uint32_t )( data[3] ) ) << 12 ) | ( ( ( uint32_t )( data[4] ) ) << 4 ) | ( ( uint32_t )data[5] >> 4 ) );
}
// Returns temperature in DegC, resolution is 0.01 DegC. Output value of "5123" equals 51.23 DegC
// t_fine carries fine temperature as global value
static s32 bmp280CompensateT( s32 adcT )
{
s32 var1, var2, T;
var1 = ( ( ( ( adcT >> 3 ) - ( ( s32 )bmp280Cal.dig_T1 << 1 ) ) ) * ( ( s32 )bmp280Cal.dig_T2 ) ) >> 11;
var2 = ( ( ( ( ( adcT >> 4 ) - ( ( s32 )bmp280Cal.dig_T1 ) ) * ( ( adcT >> 4 ) - ( ( s32 )bmp280Cal.dig_T1 ) ) ) >> 12 ) * ( ( s32 )bmp280Cal.dig_T3 ) ) >> 14;
bmp280Cal.t_fine = var1 + var2;
T = ( bmp280Cal.t_fine * 5 + 128 ) >> 8;
return T;
}
// 以 Q24.8 格式(24 个整数位和 8 个小数位)将压力以 Pa 为单位返回为无符号 32 位整数。
// “24674867”的输出值表示 24674867/256 = 96386.2 Pa = 963.862 hPa
static uint32_t bmp280CompensateP( s32 adcP )
{
int64_t var1, var2, p;
var1 = ( ( int64_t )bmp280Cal.t_fine ) - 128000;
var2 = var1 * var1 * ( int64_t )bmp280Cal.dig_P6;
var2 = var2 + ( ( var1 * ( int64_t )bmp280Cal.dig_P5 ) << 17 );
var2 = var2 + ( ( ( int64_t )bmp280Cal.dig_P4 ) << 35 );
var1 = ( ( var1 * var1 * ( int64_t )bmp280Cal.dig_P3 ) >> 8 ) + ( ( var1 * ( int64_t )bmp280Cal.dig_P2 ) << 12 );
var1 = ( ( ( ( ( int64_t )1 ) << 47 ) + var1 ) ) * ( ( int64_t )bmp280Cal.dig_P1 ) >> 33;
if ( var1 == 0 )
return 0;
p = 1048576 - adcP;
p = ( ( ( p << 31 ) - var2 ) * 3125 ) / var1;
var1 = ( ( ( int64_t )bmp280Cal.dig_P9 ) * ( p >> 13 ) * ( p >> 13 ) ) >> 25;
var2 = ( ( ( int64_t )bmp280Cal.dig_P8 ) * p ) >> 19;
p = ( ( p + var1 + var2 ) >> 8 ) + ( ( ( int64_t )bmp280Cal.dig_P7 ) << 4 );
return( uint32_t )p;
}
#define FILTER_NUM 5
#define FILTER_A 0.1f
/*限幅平均滤波法*/
static void presssureFilter( float* in, float* out )
{
static u8 i = 0;
static float filter_buf[FILTER_NUM] = {0.0};
double filter_sum = 0.0;
u8 cnt = 0;
float deta;
if( filter_buf[i] == 0.0f )
{
filter_buf[i] = *in;
*out = *in;
if( ++i >= FILTER_NUM )
i = 0;
}
else
{
if( i )
deta = *in - filter_buf[i - 1];
else
deta = *in - filter_buf[FILTER_NUM - 1];
if( fabs( deta ) < FILTER_A )
{
filter_buf[i] = *in;
if( ++i >= FILTER_NUM )
i = 0;
}
for( cnt = 0; cnt < FILTER_NUM; cnt++ )
{
filter_sum += filter_buf[cnt];
}
*out = filter_sum / FILTER_NUM;
}
}
void BMP280GetData( float* pressure, float* temperature, float* asl )
{
static float t;
static float p;
bmp280GetPressure();
t = bmp280CompensateT( bmp280RawTemperature ) / 100.0;
p = bmp280CompensateP( bmp280RawPressure ) / 25600.0;
presssureFilter( &p, pressure );
*temperature = ( float )t; /*单位度*/
*pressure = ( float )p ; /*单位hPa*/
*asl = bmp280PressureToAltitude( pressure ); /*转换成海拔*/
}
#define CONST_PF 0.1902630958 //(1/5.25588f) Pressure factor
#define FIX_TEMP 25 // Fixed Temperature. ASL is a function of pressure and temperature, but as the temperature changes so much (blow a little towards the flie and watch it drop 5 degrees) it corrupts the ASL estimates.
// TLDR: Adjusting for temp changes does more harm than good.
/*
* Converts pressure to altitude above sea level (ASL) in meters
*/
static float bmp280PressureToAltitude( float* pressure/*, float* groundPressure, float* groundTemp*/ )
{
if ( *pressure > 0 )
{
return( ( pow( ( 1015.7f / *pressure ), CONST_PF ) - 1.0f ) * ( FIX_TEMP + 273.15f ) ) / 0.0065f;
}
else
{
return 0;
}
}
/********************************************** (C) Copyright MindMotion **********************************************/BMP280.h
/* Define to prevent recursive inclusion */
#ifndef _I2C_GPIO_H_
#define _I2C_GPIO_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Files include */
#include "hal_conf.h"
#define BMP280_ADDR (0xEC)
#define BMP280_DEFAULT_CHIP_ID (0x58)
#define BMP280_CHIP_ID (0xD0) /* Chip ID Register */
#define BMP280_RST_REG (0xE0) /* Softreset Register */
#define BMP280_STAT_REG (0xF3) /* Status Register */
#define BMP280_CTRL_MEAS_REG (0xF4) /* Ctrl Measure Register */
#define BMP280_CONFIG_REG (0xF5) /* Configuration Register */
#define BMP280_PRESSURE_MSB_REG (0xF7) /* Pressure MSB Register */
#define BMP280_PRESSURE_LSB_REG (0xF8) /* Pressure LSB Register */
#define BMP280_PRESSURE_XLSB_REG (0xF9) /* Pressure XLSB Register */
#define BMP280_TEMPERATURE_MSB_REG (0xFA) /* Temperature MSB Reg */
#define BMP280_TEMPERATURE_LSB_REG (0xFB) /* Temperature LSB Reg */
#define BMP280_TEMPERATURE_XLSB_REG (0xFC) /* Temperature XLSB Reg */
#define BMP280_SLEEP_MODE (0x00)
#define BMP280_FORCED_MODE (0x01)
#define BMP280_NORMAL_MODE (0x03)
#define BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG (0x88)
#define BMP280_PRESSURE_TEMPERATURE_CALIB_DATA_LENGTH (24)
#define BMP280_DATA_FRAME_SIZE (6)
#define BMP280_OVERSAMP_SKIPPED (0x00)
#define BMP280_OVERSAMP_1X (0x01)
#define BMP280_OVERSAMP_2X (0x02)
#define BMP280_OVERSAMP_4X (0x03)
#define BMP280_OVERSAMP_8X (0x04)
#define BMP280_OVERSAMP_16X (0x05)
void i2c_init(void);
bool BMP280Init(void);
void BMP280GetData(float* pressure, float* temperature, float* asl);
#ifdef __cplusplus
}
#endif
#endif /* _I2C_MASTER_SIMULATEWITHGPIO_H_ */
/********************************************** (C) Copyright MindMotion **********************************************/
