基于STM32的大气压传感器驱动,代码开源!!!

文章目录

    • 概要
    • 整体架构流程
    • 技术名词解释
    • 技术细节
    • 小结

开发环境

MCU STM32F103C8T6
传感器 BMP280
软件 keil MDK
标准库

一、概要

        BMP280是一款专为移动应用设计的绝对气压传感器。传感器模块封装在一个非常紧凑的8引脚金属盖LGA封装中,占地面积仅为2.0×2.5 mm2,封装高度为0.95 mm。它的小尺寸和2.7µA@1Hz的低功耗允许在手机、GPS模块或手表等电池驱动设备中实现。

基于STM32的大气压传感器驱动,代码开源!!!_第1张图片

 1.1 参数信息

根据数据手册,获取到我们需要的基本参数如下:

Pressure range(压力范围) 300-1100Pa
Package 8-pin LGA metal-lid

Relative accuracy (相对精度)

(950 … 1050hPa @25°C)

±0.12 hPa, equiv. to ±1 m

Absolute accuracy(绝对精度)

(950 ...1050 hPa, 0 ...+40 °C)

typ. ±1 hPa
Digital interfaces(接口) I²C (up to 3.4 MHz) 
SPI (3 and 4 wire, up to 10 MHz)
Temperature range (温度范围) -40 … +85 °C

1.2 硬件接口

        我们在上面已经得知,该传感器接口有IIC和SPI,那么,选择其中一种即可,而本文选择的IIC。 现在需要根据芯片手册目录,找到对应的文章内容。

基于STM32的大气压传感器驱动,代码开源!!!_第2张图片 

二、软件

2.1 内存映射与寄存器描述

        与设备的所有通信都是通过从寄存器中读取和写入寄存器来执行的。

        寄存器的宽度为8位。有几个寄存器是保留的;它们不应该被写入,并且在读取它们时不保证特定的值。

基于STM32的大气压传感器驱动,代码开源!!!_第3张图片

 1.Register 0xD0 “id”

        “id”寄存器包含芯片标识号chip_id[7:0],它是0x58。一旦设备完成通电重置,就可以读取此数字。

2.Register 0xE0 “reset” 

        “重置”寄存器包含软重置字reset[7:0]。如果值0xB6被写入寄存器,则使用完整的通电重置程序重置设备。写入0xB6以外的其他值没有任何效果。读出的值总是0x00。

3. Register 0xF3 “status” 

“状态”寄存器包含两位,表示设备的状态。

这里只给出三个描述,其他的请参考手册阅读。程序全部定义成宏

#define BMP280_CHIPID_REG                    0xD0  /*Chip ID Register */
#define BMP280_RESET_REG                     0xE0  /*Softreset Register */
#define BMP280_STATUS_REG                    0xF3  /*Status Register */
#define BMP280_CTRLMEAS_REG                  0xF4  /*Ctrl Measure Register */
#define BMP280_CONFIG_REG                    0xF5  /*Configuration Register */
#define BMP280_PRESSURE_MSB_REG              0xF7  /*Pressure MSB Register */
#define BMP280_PRESSURE_LSB_REG              0xF8  /*Pressure LSB Register */
#define BMP280_PRESSURE_XLSB_REG             0xF9  /*Pressure XLSB Register */
#define BMP280_TEMPERATURE_MSB_REG           0xFA  /*Temperature MSB Reg */
#define BMP280_TEMPERATURE_LSB_REG           0xFB  /*Temperature LSB Reg */
#define BMP280_TEMPERATURE_XLSB_REG          0xFC  /*Temperature XLSB Reg */

2.2 IIC地址

        手册说明:The 7-bit device address is 111011x. The 6 MSB bits are fixed. The last bit is changeable by SDO value and can be changed during operation. Connecting SDO to GND results in slave address 1110110 (0x76); connection it to VDDIO results in slave address 1110111 (0x77), which is the same as BMP180’s I²C address. The SDO pin cannot be left floating; if left floating, the I²C address will be undefined.

提示:大概意思就是说,地址7位,6位为固定,最后一位可以通过SDO修改。SDO连接GND,IIC从机地址为0x76,连接到VDD,从机地址为0x77。

2.3 IIC写数据

直接看数据

基于STM32的大气压传感器驱动,代码开源!!!_第4张图片

 上图表示IIC多字节写入,整理步骤如下:

  1. STM32发送开始信号(Start)
  2. 接着发送从机地址,这里为0x67,需要根据自己的硬件判断
  3. 从机会发送一个应答引号,(ACK)
  4. 主机收到应答信号后才能继续发送数据
  5. 可以看到,数据位组合方式为:一个寄存器地址+应答+一个寄存器数据+应答
  6. 最后发送停止信号

注意:从机地址一般带有读写位,这里的从机地址就不能只是发送0x76 

这样,整个写数据通信发送完成。

2.4 IIC读数据

读数据与写数据类似:

基于STM32的大气压传感器驱动,代码开源!!!_第5张图片

读数据步骤:

  1. STM32发送开始信号
  2. 发送从机地址
  3. 从机回应一个ACK
  4. 接收发送寄存器地址
  5. 返回一个应答
  6. 主机又会发送开始信号和从机地址
  7. 返回一个应答ACK
  8. 接着就是寄存器数据 
  9. 最后返回非应答信号
  10. 停止信号

多字节多数据就完成了。

2.5 数据补偿

        BMP280输出由ADC输出值组成。然而,每个传感元件的行为不同,并且必须使用一组校准参数来计算实际压力和温度。第3.11.3章中的推荐计算使用不动点算法。在高级语言中,如Matlab 或LabVIEW, 定点代码可能得不到很好的支持。在这种情况下,可以使用附录8.1中的浮点代码作为替代。对于8位微控制器,可变大小可能受到限制。在这种情况下,附录8.2中给出了精度降低的简化32位整数代码

2.5.1 计算要求

        下表显示了在GCC优化级别为O2的32位Cortex-M3微控制器上进行补偿计算所需的时钟周期数。此控制器不包含浮点单元,因此模拟所有浮点计算。浮点仅推荐用于存在FPU的PC应用程序。

基于STM32的大气压传感器驱动,代码开源!!!_第6张图片

2.5.2 微调参数

微调参数在生产过程中编程到设备的非易失性存储器(NVM)中,客户不能更改。每个补偿字是存储在2的补码中的16位有符号或无符号整数值。由于存储器被组织成8位字,所以必须始终组合两个字才能表示补偿字。8位寄存器被命名为calib00…calib25,并存储在存储器地址0x88…0xA1。

对应的补偿字对于温度补偿相关值被命名为dig_T#,而对于压力补偿相关值则被命名为dig_P#。

 我们也将所有数据定义成宏

#define BMP280_DIG_T1_LSB_REG                0x88
#define BMP280_DIG_T1_MSB_REG                0x89
#define BMP280_DIG_T2_LSB_REG                0x8A
#define BMP280_DIG_T2_MSB_REG                0x8B
#define BMP280_DIG_T3_LSB_REG                0x8C
#define BMP280_DIG_T3_MSB_REG                0x8D
#define BMP280_DIG_P1_LSB_REG                0x8E
#define BMP280_DIG_P1_MSB_REG                0x8F
#define BMP280_DIG_P2_LSB_REG                0x90
#define BMP280_DIG_P2_MSB_REG                0x91
#define BMP280_DIG_P3_LSB_REG                0x92
#define BMP280_DIG_P3_MSB_REG                0x93
#define BMP280_DIG_P4_LSB_REG                0x94
#define BMP280_DIG_P4_MSB_REG                0x95
#define BMP280_DIG_P5_LSB_REG                0x96
#define BMP280_DIG_P5_MSB_REG                0x97
#define BMP280_DIG_P6_LSB_REG                0x98
#define BMP280_DIG_P6_MSB_REG                0x99
#define BMP280_DIG_P7_LSB_REG                0x9A
#define BMP280_DIG_P7_MSB_REG                0x9B
#define BMP280_DIG_P8_LSB_REG                0x9C
#define BMP280_DIG_P8_MSB_REG                0x9D
#define BMP280_DIG_P9_LSB_REG                0x9E
#define BMP280_DIG_P9_MSB_REG                0x9F

 2.5.3 补偿公式

        手册强烈建议使用Bosch Sensortec提供的API进行读数和补偿。如果不需要这样做,也提供了其他补偿公式:

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;
}

下图显示了压力和温度测量的详细算法。

基于STM32的大气压传感器驱动,代码开源!!!_第7张图片

三、程序实现

关于IIC协议这里不再叙述,就正常的通信,主要讲述传感器部分

3.1 传感器初始化

uint8_t BMP280_Init(void)
{
    uint8_t bmp280_id;
    uint8_t tmp[10];

    Sensors_I2C_ReadRegister(BMP280_SLAVE_ADDRESS, BMP280_CHIPID_REG, 1, &bmp280_id);

    /* 读取校准数据 */
    Sensors_I2C_ReadRegister(BMP280_SLAVE_ADDRESS, BMP280_DIG_T1_LSB_REG,24,(u8 *)&bmp280Cal);

    tmp[0] = BMP280_MODE;
    Sensors_I2C_WriteRegister(BMP280_SLAVE_ADDRESS, BMP280_CTRLMEAS_REG, 1, tmp);

    tmp[0] = (5<<2);
    Sensors_I2C_WriteRegister(BMP280_SLAVE_ADDRESS, BMP280_CONFIG_REG, 1, tmp);	

    return bmp280_id;
}
  1.  初始化获取ID
  2. 读取校准数据
  3. 写温度,大气压或采样,设置电源模式,寄存器是0xF4
  4. 寄存器设置设备的速率、过滤器和接口选项

 手册对寄存器中有详细的描述,具体什么意思可以参考用户手册

3.2 获取数据 

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;/*单位度*/

	*asl = BMP280PressureToAltitude(pressure);	/*转换成海拔*/
}

static void BMP280GetPressure(void)
{
    u8 data[BMP280_DATA_FRAME_SIZE];

    // read data from sensor
    Sensors_I2C_ReadRegister(BMP280_SLAVE_ADDRESS, BMP280_PRESSURE_MSB_REG, BMP280_DATA_FRAME_SIZE, (u8 *)&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));
}

         获取数据的简单来说就是IIC通信,手册中提到寄存器0xF7-0xF9为大气压, 0xFA…0xFC为温度。通过读取寄存器的只可以获取原始温度,大气压。

大气压寄存器如下:

基于STM32的大气压传感器驱动,代码开源!!!_第8张图片

         大概就是一共20位的数据,分为MSB,LSB,XLSB,XLSB就取决于精度了。获取数据后可以做一些滤波处理,比如均值滤波等,例如:

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;
	}
}

         经过一些滤波后的数据,看起来比较稳定。另外也可以将温度输出出来,也可以将大气压转换成海拔等。这里就不讲述了,大致一样的操作。

小结

        大气压传感器的通信是比较简单的,就是基于IIC,但是主要的还是传感器的校准以及补偿算法等。并且传感器的手册是英文的,对英语不是特别感冒的朋友(说的就是我),可能费劲。需要花费更多的时间去理解。本文就是简单的驱动,如果有错误的地方,及时提出更正。

你可能感兴趣的:(传感器驱动,stm32,嵌入式硬件,单片机)