> 技术文档 > STM32软件SPI驱动BMP280(OLED显示)_stm32 bmp280

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


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-----STM32F103C8T6SCL----SCK----PA5SDA----MOSI---PA7CSB----SS-----PA4SDO----MISO---PA6OLED----STM32F103C8T6SCL-------PB8SDA-------PB9VCC-------3V3GND-------GND**/int32_tBMP_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);//显示IDwhile (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_VALUE0xB6//复位寄存器写入值#define BMP280_S32_t long signed int#define BMP280_U32_t long unsigned int#define BMP280_S64_t long long signed intBMP280_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.可以通过大气压强去拓展海拔高度的计算,网上有很多公式的转换,自己选择自己所需的去换算即可。
需要整个工程代码可以在下方评论留言哦!