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

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.可以通过大气压强去拓展海拔高度的计算,网上有很多公式的转换,自己选择自己所需的去换算即可。
需要整个工程代码可以在下方评论留言哦!

评论 68
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值