BMP280气压传感器模块详解

⭐模块介绍

        BMP280 是一款高精度、低功耗的数字气压传感器,由博世(Bosch)公司生产,广泛应用于各种气象站、无人机、智能家居、移动设备等领域。它不仅可以测量气压,还能通过测量气压的变化来计算出高度,非常适合用于需要高度测量的应用。

主要特点:

  1. 高精度:BMP280 具有非常高的精度,压力分辨率可达 0.18 Pa,能够实现 1.5 米的高度分辨率,适合用于精确测量高度的应用场景。

  2. 低功耗:该传感器的功耗非常低,适合用于需要长时间运行的低功耗设备,比如电池供电的移动设备。

  3. 宽量程:BMP280 的气压测量范围为 300 hPa 到 1100 hPa,能够覆盖从海平面到约 9000 米的高度。

  4. 高稳定性:传感器的温度补偿功能使其在温度变化较大的环境中仍能保持高精度和高稳定性。

  5. 接口灵活:支持 I2C 和 SPI 两种通信接口,方便与各种主控芯片(如 STM32、Arduino、ESP8266 等)连接使用。

应用场景:

  • 气象监测:用于测量大气压力、预测天气变化。
  • 高度测量:用于无人机、登山导航、飞行器等的高度测量。
  • 智能家居:应用于空调控制、通风系统优化等。
  • 室内导航:结合其他传感器,可用于室内定位,提供更加精准的位置服务。
  • 使用方法:

    BMP280 的使用较为简单,只需要通过 I2C 或 SPI 接口与微控制器(如 Arduino、STM32 等)相连,并通过相应的库或驱动程序进行初始化和数据读取即可。在大多数情况下,厂商都会提供开源的库,方便用户快速上手。

    电气特性:

  • 工作电压:1.71V ~ 3.6V
  • 工作温度:-40℃ ~ +85℃
  • 功耗:正常模式下约 3.6µA,睡眠模式下约 0.1µA
  • 相关资源:

  • 数据手册:详细的 BMP280 数据手册中包括了所有的电气特性、寄存器设置以及具体的应用设计建议。
  • 示例代码:可以在网上找到大量针对不同微控制器的 BMP280 示例代码,便于快速开发。
  • BMP280 以其高精度、低功耗和易于使用的特点成为了广泛应用的气压传感器选择。如果你需要进行气压或高度测量,BMP280 无疑是一个不错的选择。

    ⭐实物图

    ⭐模块代码

    #include "bmp280.h"
    
    
    //初始化IIC
    void BMP_IIC_Init(void)
    {					     
    	GPIO_InitTypeDef GPIO_InitStructure;
    	//RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟 
    	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );	
    	   
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP ;                            //推挽输出
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
     
    	IIC_SCL=1;
    	IIC_SDA=1;
    
    }
    //产生IIC起始信号
    void BMP_IIC_Start(void)
    {
    	SDA_OUT();                                                                 //sda线输出
    	IIC_SDA=1;	  	  
    	IIC_SCL=1;
    	delay_us(4);
     	IIC_SDA=0;                                                                 //START:when CLK is high,DATA change form high to low 
    	delay_us(4);
    	IIC_SCL=0;                                                                 //钳住I2C总线,准备发送或接收数据 
    }	  
    //产生IIC停止信号
    void BMP_IIC_Stop(void)
    {
    	SDA_OUT();                                                                 //sda线输出
    	IIC_SCL=0;
    	IIC_SDA=0;                                                                 //STOP:when CLK is high DATA change form low to high
     	delay_us(4);
    	IIC_SCL=1; 
    	IIC_SDA=1;                                                                 //发送I2C总线结束信号
    	delay_us(4);							   	
    }
    //等待应答信号到来
    //返回值:1,接收应答失败
    //        0,接收应答成功
    u8 BMP_IIC_Wait_Ack(void)
    {
    	u8 ucErrTime=0;
    	SDA_IN();                                                                  //SDA设置为输入  
    	IIC_SDA=1;delay_us(1);	   
    	IIC_SCL=1;delay_us(1);	 
    	while(READ_SDA)
    	{
    		ucErrTime++;
    		if(ucErrTime>250)
    		{
    			BMP_IIC_Stop();
    			return 1;
    		}
    	}
    	IIC_SCL=0;                                                                 //时钟输出0 	   
    	return 0;  
    } 
    //产生ACK应答
    void BMP_IIC_Ack(void)
    {
    	IIC_SCL=0;
    	SDA_OUT();
    	IIC_SDA=0;
    	delay_us(2);
    	IIC_SCL=1;
    	delay_us(2);
    	IIC_SCL=0;
    }
    //不产生ACK应答		    
    void BMP_IIC_NAck(void)
    {
    	IIC_SCL=0;
    	SDA_OUT();
    	IIC_SDA=1;
    	delay_us(2);
    	IIC_SCL=1;
    	delay_us(2);
    	IIC_SCL=0;
    }					 				     
    //IIC发送一个字节
    //返回从机有无应答
    //1,有应答
    //0,无应答			  
    void BMP_IIC_Send_Byte(u8 txd)
    {                        
        u8 t;   
    	SDA_OUT(); 	    
        IIC_SCL=0;                                                                 //拉低时钟开始数据传输
        for(t=0;t<8;t++)
        {              
            IIC_SDA=(txd&0x80)>>7;
            txd<<=1; 	  
    		delay_us(2);                                                           //对TEA5767这三个延时都是必须的
    		IIC_SCL=1;
    		delay_us(2); 
    		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;
    	SDA_IN();                                                                  //SDA设置为输入
        for(i=0;i<8;i++ )
    	{
            IIC_SCL=0; 
            delay_us(2);
    		IIC_SCL=1;
            receive<<=1;
            if(READ_SDA)receive++;   
    		delay_us(1); 
        }					 
        if (!ack)
            BMP_IIC_NAck();                                                            //发送nACK
        else
            BMP_IIC_Ack();                                                             //发送ACK   
        return receive;
    }
    
    //从指定地址读出一个数据
    //ReadAddr:开始读数的地址  
    //返回值  :读到的数据
    u8 BMP_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 BMP_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 BMP_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 BMP_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( );	
    }
    
    
    
    /*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*/);
    
    bool BMP280_Init(void)
    {	
        if (isInit)
            return true;
    
    	BMP_IIC_Init();		                                                           /*初始化I2C*/
        delay_ms(20);
    	
    	bmp280ID=BMP_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;
    
        /* 读取校准数据 */
        BMP_iicDevRead(BMP280_ADDR,BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG,24,(u8 *)&bmp280Cal);	
    	BMP_iicDevWriteByte(BMP280_ADDR,BMP280_CTRL_MEAS_REG,BMP280_MODE);
    	BMP_iicDevWriteByte(BMP280_ADDR,BMP280_CONFIG_REG,5<<2);		               /*配置IIR滤波*/
    	
    //	printf("BMP280 Calibrate Registor Are: \r\n");
    //	for(i=0;i<24;i++)
    //		printf("Registor %2d: 0x%X\n",i,p[i]);
    	
        isInit=true;
        return true;
    }
    
    static void bmp280GetPressure(void)
    {
        u8 data[BMP280_DATA_FRAME_SIZE];
    
        // read data from sensor
        BMP_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;
    }
    
    // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
    // Output value of "24674867" represents 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;
        }
    }
    
    

    ⭐获取更多资料

    我用夸克网盘分享了「1 BMP280.zip」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
    链接:https://pan.quark.cn/s/993320cdcce1
    提取码:LQTZ

    作者:鑫瑞科技~~~

    物联沃分享整理
    物联沃-IOTWORD物联网 » BMP280气压传感器模块详解

    发表回复