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); //显示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,需要再除以100OLED_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(); //先初始化底层的SPIuint8_t Osrs_T = 1; //Temperature oversampling x 1uint8_t Osrs_P = 3; //Pressure oversampling x 1uint8_t Mode = 3; //Normal modeuint8_t T_sb = 5; //Tstandby 1000msuint8_t Filter = 4; //Filter uint8_t Spi3w_en = 0; //3-wire SPI Disableuint8_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.可以通过大气压强去拓展海拔高度的计算,网上有很多公式的转换,自己选择自己所需的去换算即可。
需要整个工程代码可以在下方评论留言哦!