STM32软件SPI驱动BMP280(OLED显示)

STM32软件SPI驱动BMP280 OLED显示

  • BMP280简介
  • 寄存器简要说明
  • SPI通讯
  • 代码逻辑
  • 代码展示
  • 现象
  • 总结
  • BMP280简介

    数字接口类型:IIC(从模式3.4MHz)或SPI(3线或4线制从模式10MHz)
    气压测量范围:300~1100hPa(百帕斯卡)
    气压测量误差:±1hPa 分辨率:0.16Pa
    温度测量范围:0℃~65℃
    温度测量误差:±0.5℃(25℃下) ±1℃(0-65℃情况下)以内 分辨率:0.01℃
    工作电压:3.3V
    带M3固定螺丝孔,方便安装及固定。

    寄存器简要说明

    0xFA-0xFC:温度寄存器原始值
    0xF7-0xF9:压力寄存器原始值
    0xF4-0xF5:参数配置,待机时间(t_sb),滤波参数(fliter),3线SPI使能(spi3w_en),过采样(osrs_t,osrs_P),模式(mode)
    0xE0:默认写入0xB6,使用完整的上电复位过程复位设备
    0xF3:状态寄存器

    0xD0:ID寄存器,只读,值为0x58

    SPI通讯

    SPI模式可选择0或者3,这里使用的是模式0进行编写代码。
    SPI写:把对应寄存器的最高位位7去掉,写成固定的0即可形成SPI的写指令,这里使用的是将原有的寄存器地址和0x7F进行与操作。同时注意这里的写不是自动递增的,需要写完一个字节后再次发送写指令写下一个寄存器。

    SPI读:跟写指令一样是把位7去掉,写成固定的1形成SPI的读指令,这里使用的是原有的寄存器地址和0x80进行或操作来实现。读指令是自动递增的,读取一个指令后可以直接交换数据后读取下一寄存器的数据。

    模块还支持3线的SPI和IIC通讯,IIC通讯就是普通的IIC通讯协议,发送对应的从机地址和指令进行读写操作,从机地址由SDO引脚控制,这个模块默认拉低位为0x76,拉高则为0x77。
    3线SPI的通讯协议和4线SPI的相同,不过是通讯线只有一条为SDI,半双工通讯。

    代码逻辑

    代码展示

    这里使用的是四线SPI进行通讯,单片机使用的是STM32F103C8T6。
    main.c :

    /**
    接线(模拟SPI-4线)
    BMP280-----STM32F103C8T6
    SCL----SCK----PA5
    SDA----MOSI---PA7
    CSB----SS-----PA4
    SDO----MISO---PA6
    OLED----STM32F103C8T6
    SCL-------PB8
    SDA-------PB9
    VCC-------3V3
    GND-------GND
    **/
    int32_t	BMP_Temperature;
    uint32_t BMP_Pressure;
    int32_t BMP_Altitude;
    uint8_t ID;							//定义用于存放ID号的变量
    uint8_t ArrayRead[4];               //定义要读取数据的测试数组
    int main(void)
    {
    	/*模块初始化*/
    	OLED_Init();						//OLED初始化
    	BMP280_Init();						//BMP280初始化
        Serial_Init();                      //串口初始化
    	/*显示静态字符串*/
    	OLED_ShowString(1, 6, "BMP280");
    	OLED_ShowString(2, 1, "ID:");
    	/*显示ID号*/
    	BMP280_ReadID(&ID);			//获取BMP280的ID号
    	OLED_ShowHexNum(2, 4, ID, 2);		//显示ID
    	while (1)
    	{
            //Temperature
            //OLED显示
            BMP_Temperature = BMP280_GetTemp();
            OLED_ShowString(3, 1, "T:");
            OLED_ShowNum(3, 3, BMP_Temperature / 100.0, 2);
            OLED_ShowString(3, 5, ".");
            OLED_ShowNum(3, 6, BMP_Temperature, 2); 
            OLED_ShowString(3, 9, "C");
            //Pressure
            //OLED显示
    		BMP_Pressure =  BMP280_GetPress();
    		OLED_ShowString(4, 1, "P:"); 
            OLED_ShowNum(4, 3, BMP_Pressure / 256 / 100, 4);  //单位为hPa,需要再除以100
            OLED_ShowString(4, 7, ".");
            OLED_ShowNum(4, 8, BMP_Pressure / 25.6, 3);  
            OLED_ShowString(4, 12, "hPa");
    	}
    }
    
    

    BMP280.c

    #define BMP280_RESET_VALUE					0xB6		//复位寄存器写入值
    #define BMP280_S32_t long signed int
    #define BMP280_U32_t long unsigned int
    #define BMP280_S64_t long long signed int
    BMP280_S32_t t_fine;
    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等待忙
      * 参    数:无
      * 返 回 值:无
      */
    void BMP280_WaitBusy(void)
    {
    	uint32_t Timeout, state;
    	MySPI_Start();								//SPI起始
    	MySPI_SwapByte(BMP280_STATUS_REG | 0x80);	//交换发送读状态寄存器1的指令
        Timeout = 100000;							//给定超时计数时间
        state = MySPI_SwapByte(BMP280_DUMMY_BYTE) >> 3;
    	while ((state & 0x01) == 0x01)	//循环等待忙标志位
    	{
            Timeout --;
    		if (Timeout == 0)						//自减到0后,等待超时
    		{
                Serial_Printf("Timeout");
    			/*超时的错误处理代码,可以添加到此处*/
    			break;								//跳出等待,不等了
    		}
    	}
    	MySPI_Stop();								//SPI终止
    }
    
    /**
      * 函    数:BMP280写寄存器
      * 参    数:Address  编程的起始地址
      * 参    数:Byte 写入一个字节数据
      * 返 回 值:无
      */
    void BMP280_WriteData(uint8_t Address, uint8_t Byte)
    {
    	MySPI_Start();								//SPI起始
        MySPI_SwapByte(Address & 0x7F);             //交换发送写寄存器的指令
        MySPI_SwapByte(Byte);
    	MySPI_Stop();								//SPI终止
    	BMP280_WaitBusy();							//等待忙
    }
    /**
      * 函    数:BMP280读寄存器
      * 参    数:Address 读取数据的起始地址
      * 参    数:DataArray 用于接收读取数据的数组,通过输出参数返回
      * 参    数:Count 要读取数据的数量
      * 返 回 值:无
      */
    void BMP280_ReadData(uint8_t Address, uint8_t *DataArray, uint8_t Count)
    {
    	uint32_t i;
    	MySPI_Start();								//SPI起始
    	MySPI_SwapByte(Address | 0x80);			    //交换发送读寄存器的指令
    	for (i = 0; i < Count; i ++)				//循环Count次
    	{
    		DataArray[i] = MySPI_SwapByte(BMP280_DUMMY_BYTE);	//依次在起始地址后读取数据
    	}
    	MySPI_Stop();								//SPI终止
    }
    /**
      * 函    数:BMP280读ID
      * 参    数:*ID 用于接收读取的数据,通过输出参数返回
      * 返 回 值:无
      */
    void BMP280_ReadID(uint8_t *ID)
    {
    	MySPI_Start();								//SPI起始
    	MySPI_SwapByte(BMP280_CHIPID_REG | 0x80);	//交换发送读取ID的指令
    	*ID = MySPI_SwapByte(BMP280_DUMMY_BYTE);	//交换接收ID,通过输出参数返回
    	MySPI_Stop();								//SPI终止
    }
    /**
      * 函    数:读取转换3个连续寄存器
      * 参    数:首个读取的寄存器
      * 返 回 值:合并后的总值
      */
    long BMP280_RegReadThree(unsigned char addr)
    {
        unsigned char ArrayReadThree[3];               //定义要读取数据的测试数组
        long temp = 0;
        BMP280_ReadData(addr, ArrayReadThree, 3);
    
        temp = (long)(((unsigned long)ArrayReadThree[0] << 12)|((unsigned long)ArrayReadThree[1] << 4)|((unsigned long)ArrayReadThree[2] >> 4));
    
        return temp;
    }
    /**
      * 函    数:读取转换2个连续寄存器
      * 参    数:首个读取的寄存器
      * 返 回 值:合并后的总值
      */
    short BMP280_RegReadTwo(unsigned char addr)
    {
        unsigned char ArrayReadTwo[2];               //定义要读取数据的测试数组
        short temp = 0;
        BMP280_ReadData(addr, ArrayReadTwo, 2);   //ArrayRead[0]:LSB ArrayRead[1]:MSB 
    
        temp = (short)ArrayReadTwo[1] << 8;
        temp |= (short)ArrayReadTwo[0];
    
        return temp;
    }
    /**
      * 函    数:BMP280初始化
      * 参    数:无
      * 返 回 值:无
      */
    void BMP280_Init(void)
    {
    	MySPI_Init();					//先初始化底层的SPI
    
        uint8_t Osrs_T = 1;             //Temperature oversampling x 1
        uint8_t Osrs_P = 3;             //Pressure oversampling x 1
        uint8_t Mode = 3;               //Normal mode
        uint8_t T_sb = 5;               //Tstandby 1000ms
        uint8_t Filter = 4;             //Filter  
        uint8_t Spi3w_en = 0;           //3-wire SPI Disable
        
        uint8_t Ctrl_meas_reg = (Osrs_T << 5) | (Osrs_P << 2) | Mode;
        uint8_t Config_reg    = (T_sb << 5) | (Filter << 2) | Spi3w_en;
        
        //状态全部清零
        BMP280_WriteData(BMP280_RESET_REG, BMP280_RESET_VALUE);
        BMP280_WriteData(BMP280_CTRLMEAS_REG, Ctrl_meas_reg);
        BMP280_WriteData(BMP280_CONFIG_REG, Config_reg);
        Delay_ms(20);
        
        Dig_T1 = BMP280_RegReadTwo(BMP280_DIG_T1_LSB_REG);
        Dig_T2 = BMP280_RegReadTwo(BMP280_DIG_T2_LSB_REG);
        Dig_T3 = BMP280_RegReadTwo(BMP280_DIG_T3_LSB_REG);
        Dig_P1 = BMP280_RegReadTwo(BMP280_DIG_P1_LSB_REG);
        Dig_P2 = BMP280_RegReadTwo(BMP280_DIG_P2_LSB_REG);
        Dig_P3 = BMP280_RegReadTwo(BMP280_DIG_P3_LSB_REG);
        Dig_P4 = BMP280_RegReadTwo(BMP280_DIG_P4_LSB_REG);
        Dig_P5 = BMP280_RegReadTwo(BMP280_DIG_P5_LSB_REG);
        Dig_P6 = BMP280_RegReadTwo(BMP280_DIG_P6_LSB_REG);
        Dig_P7 = BMP280_RegReadTwo(BMP280_DIG_P7_LSB_REG);
        Dig_P8 = BMP280_RegReadTwo(BMP280_DIG_P8_LSB_REG);
        Dig_P9 = BMP280_RegReadTwo(BMP280_DIG_P9_LSB_REG);
        
    }
    
    /**
      * 函    数:BMP280获取温度值
      * 参    数:无
      * 返 回 值:温度值
      */
    int32_t BMP280_GetTemp(void)
    {
        BMP280_S32_t var1, var2, T;
        BMP280_S32_t adc_T;
        adc_T = BMP280_RegReadThree(BMP280_TEMPERATURE_MSB_REG);
        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获取压力值
      * 参    数:无
      * 返 回 值:压力值
      */
    uint32_t BMP280_GetPress(void)
    {
        BMP280_S64_t var1, var2, p;
        BMP280_S32_t adc_P;
        adc_P = BMP280_RegReadThree(BMP280_PRESSURE_MSB_REG);
        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; // avoid exception caused by division by zero
        }
        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;
    
    }
    
    

    现象

    总结

    1.复位寄存器不管写入什么值读出来都是0x00,这个寄存器可写不可读。
    2.可以通过大气压强去拓展海拔高度的计算,网上有很多公式的转换,自己选择自己所需的去换算即可。
    需要整个工程代码可以在下方评论留言哦!

    作者:优信电子

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32软件SPI驱动BMP280(OLED显示)

    发表回复