的使用(BP神经网络气压数据滤波))
目录一、介绍1、IIC接口2、BME280传感器引脚3、相关寄存器说明4、数据处理过程5、测量流程二、cubeMX配置1、选择IIC2、选择引脚三、代码1 BMP280初始化代码1.1 校准数据读取参数 BMP280_ReadCalibData()1.2 配置 BMP280 传感器的工作模式和过采样精度1.3 配置滤波2 读取原始数据2.1 读取规则2.1.1 处理 data[0] (MSB)((uint32_t)data[0]) 12 解释2.1.2 处理 data[1] (LSB)((uint32_t)data[1]) 4 解释2.1.3 处理 data[2] (XLSB)((uint32_t)data[2]) 4 解释2.1.4 按位或 | 合并2.1.5 读取数据代码3 温度补偿和压力补偿4 压力转海拔5 对外接口2.4.1 解释void BMP280GetData(float *pressure, float *temperature, float *asl)一 介绍代码地址该模块的核心是博世Bosch– BME280生产的下一代数字温度湿度和压力传感器。它是BMP180BMP085或BMP183等传感器的后继产品。1 IIC接口该模块具有一个简单的两线式I2C接口可以轻松地与您选择的任何微控制器接口。BMP280模块的默认I2C地址为0x76 HEX。2 BME280传感器引脚BME280模块只有4个与外界连接的引脚。连接如下VIN是模块的电源可以在3.3V至5V之间的任何范围内。GND接地。SCL是I2C接口的串行时钟引脚。SDA是I2C接口的串行数据引脚。3 相关寄存器说明测量控制寄存器ctrl_meas0xF4Bit7~Bit5osrs_t[2:0] 控制温度采样模式主要是采样数据的位数位数越大精度越高。Bit4~Bit2osrs_p[2:0] 控制大气压强采样模式主要是采样数据的位数位数越大精度越高。Bit1~Bit0mode[1:0] 传感器工作模式控制00为Sleep Mode01/10为Forced Mode11为 Normal Mode。配置寄存器config0xF5身份编号寄存器id0xD0寄存器内固定值为0x58读取0xD0数据的时候传感器返回0x58代表身份辨认完毕。复位寄存器reset0xE0写入0xB6时所有寄存器除身份编号寄存器数据全部清零。4 数据处理过程该传感器是使用测量值和校准值初始化 中获得通过公式计算得出的相关公式在datasheet中已经贴出了还给了样本数据公式挺复杂的建议先把公式抄到程序中然后用样本数据传进去测试一遍结果对不对保证公式没抄错。数据处理中有个坑请注意就是读取补偿值数据的时候下图的数据存储 位是LSB/MSB即数据是反过来存储的低位字节在前高位字节在后所以处理数据的时候要注意。压力和温度计算公式写的公式代码long bmp280_GetValue(void) { long adc_T; long adc_P; long var1, var2, t_fine, T, p; adc_T bmp280_MultipleReadThree(BMP280_TEMP_ADDR); adc_P bmp280_MultipleReadThree(BMP280_PRESS_ADDR); if(adc_P 0) { return 0; } //Temperature var1 (((double)adc_T)/16384.0-((double)dig_T1)/1024.0)*((double)dig_T2); var2 ((((double)adc_T)/131072.0-((double)dig_T1)/8192.0)*(((double)adc_T) /131072.0-((double)dig_T1)/8192.0))*((double)dig_T3); t_fine (unsigned long)(var1var2); T (var1var2)/5120.0; //Pressure var1 ((double)t_fine/2.0)-64000.0; var2 var1*var1*((double)dig_P6)/32768.0; var2 var2 var1*((double)dig_P5)*2.0; var2 (var2/4.0)(((double)dig_P4)*65536.0); var1 (((double)dig_P3)*var1*var1/524288.0((double)dig_P2)*var1)/524288.0; var1 (1.0var1/32768.0)*((double)dig_P1); p 1048576.0-(double)adc_P; p (p-(var2/4096.0))*6250.0/var1; var1 ((double)dig_P9)*p*p/2147483648.0; var2 p*((double)dig_P8)/32768.0; p p(var1var2((double)dig_P7))/16.0; return p; }5 测量流程1初始化包括I2C初始化和传感器通信用串口初始化和上位机通信用查看数据传感器初始化。数据全部清零写数据0xB6到地址0xE0读芯片ID读地址0xD0设置测量控制寄存器写数据0xFF到地址0xF4测量数据位20BitNormal Mode设置配置寄存器写数据0x00到地址0xF5测量间隔时间0.5ms读取补偿值数据I2C循环读取传感器参数代入公式计算获得结果并且将结果通过串口输出到上位机。二 cubeMX配置1 选择IIC2 选择引脚三 代码1 BMP280初始化代码先初始化BMP280即读取芯片 ID 寄存器的值固定为 0x58。uint8_t BMP280_Init(void) { uint8_t id; /* 读 ID */ BMP280_Read(BMP280_CHIPID_REG, id, 1); /*BMP280_CHIPID_REG 芯片ID*/ if (id ! 0x58) return 0; // BMP280 ID 固定为 0x58 /* 读校准参数 */ BMP280_ReadCalibData(); /* 设置采样 正常模式 */ uint8_t ctrl (BMP280_OVERSAMP_16X 5) | (BMP280_OVERSAMP_8X 2) | BMP280_NORMAL_MODE; BMP280_Write(BMP280_CTRLMEAS_REG, ctrl); /* 配置滤波 (IIR16, standby0.5ms) */ uint8_t cfg (0x04 2); BMP280_Write(BMP280_CONFIG_REG, cfg); return id; }1.1 校准数据读取参数 BMP280_ReadCalibData()作用是读取并解析芯片出厂时烧录在内部的校准参数Calibration Data。BMP280 传感器在出厂时由于制造工艺的微小偏差每个芯片的测量特性都会略有不同。为了消除这些误差博世Bosch在芯片的 ROM 中写入了 11 个校准参数1个温度相关10个气压相关。在读取真实的温度和气压值之前必须先读取这些校准参数并在后续的数据处理中使用它们进行数学补偿计算。从0x88这里开始顺序读 24 字节BMP280 通过 I2C 传输数据时采用的是小端模式即低字节LSB在前高字节MSB在后。以dig_T1为例buf[0]是低 8 位buf[1]是高 8 位。buf[1] 8将高 8 位左移 8 位放到 16 位整数的高半部分。| buf[0]使用按位或OR操作将低 8 位填充到低半部分。这样还原了芯片内部的 16 位数据。static void BMP280_ReadCalibData(void) { uint8_t buf[24]; BMP280_Read(BMP280_DIG_T1_LSB_REG, buf, 24); bmp280Cal.dig_T1 (uint16_t)(buf[1] 8 | buf[0]); bmp280Cal.dig_T2 (int16_t)(buf[3] 8 | buf[2]); bmp280Cal.dig_T3 (int16_t)(buf[5] 8 | buf[4]); bmp280Cal.dig_P1 (uint16_t)(buf[7] 8 | buf[6]); bmp280Cal.dig_P2 (int16_t)(buf[9] 8 | buf[8]); bmp280Cal.dig_P3 (int16_t)(buf[11] 8 | buf[10]); bmp280Cal.dig_P4 (int16_t)(buf[13] 8 | buf[12]); bmp280Cal.dig_P5 (int16_t)(buf[15] 8 | buf[14]); bmp280Cal.dig_P6 (int16_t)(buf[17] 8 | buf[16]); bmp280Cal.dig_P7 (int16_t)(buf[19] 8 | buf[18]); bmp280Cal.dig_P8 (int16_t)(buf[21] 8 | buf[20]); bmp280Cal.dig_P9 (int16_t)(buf[23] 8 | buf[22]); }1.2配置 BMP280 传感器的工作模式和过采样精度向 BMP280 的ctrl_meas寄存器地址0xF4写入一个控制字节ctrl同时设置了以下三个核心参数温度过采样率(Temperature Oversampling)气压过采样率(Pressure Oversampling)传感器电源/工作模式(Power Mode)压力过采样温度过采样电源配置寄存器/* 设置采样 正常模式 */ uint8_t ctrl (BMP280_OVERSAMP_16X 5) | (BMP280_OVERSAMP_8X 2) | BMP280_NORMAL_MODE; BMP280_Write(BMP280_CTRLMEAS_REG, ctrl);/* 控制与配置寄存器 */ #define BMP280_CTRLMEAS_REG 0xF4 #define BMP280_CONFIG_REG 0xF5 /* 电源模式 */ #define BMP280_SLEEP_MODE (0x00) #define BMP280_FORCED_MODE (0x01) #define BMP280_NORMAL_MODE (0x03) /* 过采样设置 */ #define BMP280_OVERSAMP_1X (0x01) #define BMP280_OVERSAMP_2X (0x02) #define BMP280_OVERSAMP_4X (0x03) #define BMP280_OVERSAMP_8X (0x04) #define BMP280_OVERSAMP_16X (0x05)温度过采样配置 (Bit 7~5)BMP280_OVERSAMP_16X 5 解释含义将温度测量的过采样倍数设置为 16倍 (16X)。 5因为温度过采样占据寄存器的 Bit 7、6、5即从第 5 位开始的 3 个比特。将配置值16X 对应的宏定义值通常为101二进制即十进制的 5左移 5 位使其对齐到这三个高位上。作用16 倍过采样可以大幅降低温度读取时的噪声提高测量精度但会稍微增加转换时间和功耗。气压过采样配置 (Bit 4~2)BMP280_OVERSAMP_8X 2 解释含义将气压测量的过采样倍数设置为8倍 (8X)。 2因为气压过采样占据寄存器的 Bit 4、3、2即从第 2 位开始的 3 个比特。将配置值8X 对应的宏定义值通常为100二进制即十进制的 4左移 2 位使其对齐到这三个中间位上。作用气压信号通常比温度信号包含更多高频噪声设置 8 倍过采样能在精度和响应速度之间取得良好的平衡。工作模式配置 (Bit 1~0)BMP280_NORMAL_MODE 解释含义将传感器设置为正常模式 (Normal Mode)。位操作正常模式占据 Bit 1 和 Bit 0。该宏定义的值通常为11二进制即十进制的3。因为它正好在最低两位所以不需要左移。作用在正常模式下传感器会在测量和待机Standby状态之间循环自动运行按照设定的周期自动更新温度和气压数据非常适合需要持续监测的应用。数据合并与写入|(按位或操作)将上述三部分配置好的比特位通过“按位或”组合成一个完整的 8 位字节。BMP280_Write()将最终组合好的控制字节 ctrl写入到 BMP280 的CTRL_MEAS寄存器中。1.3 配置滤波配置 BMP280 的滤波器和待机时间。向 BMP280 的config寄存器地址0xF5写入一个配置字节cfg同时设置了以下两个核心参数IIR 滤波器系数 (IIR Filter Coefficient)待机时间 (Standby Time)/* 配置滤波 (IIR16, standby0.5ms) */ uint8_t cfg (0x04 2); BMP280_Write(BMP280_CONFIG_REG, cfg);IIR 滤波器配置 (Bit 4~2)uint8_t cfg (0x04 2) 解释含义将 IIR 滤波器的系数设置为16。作用IIR 滤波器可以有效滤除气压数据中的高频噪声如门窗开关、风吹引起的瞬间气压波动。系数 16 是较高的滤波级别能输出非常平滑的气压数据但响应速度会变慢。2 读取原始数据2.1 读取规则BMP280 的数据寄存器是连续排列的。从BMP280_PRESSURE_MSB_REG0xF7开始连续读 6 个字节刚好能把气压和温度的数据一次性全读出来参考手册。BMP280 内部 ADC 转换出的气压和温度数据不是完整的 3 字节24位而是 20 位的有效数据。data[0](MSB)包含了 20 位数据中最高的 8 位Bit 19~12。data[1](LSB)包含了 20 位数据中中间的 8 位Bit 11~4。data[2](XLSB)包含了 20 位数据中最低的 4 位Bit 3~0并且这 4 位数据存放在这个字节的高 4 位上低 4 位是无效的用x表示。2.1.1 处理data[0](MSB)((uint32_t)data[0]) 12 解释为什么要转(uint32_t)因为data[0]是 8 位的uint8_t。如果直接左移 12 位数据会溢出丢失转成 32 位后就有足够的空间来移位了。 12把0xAB向左移动 12 位让它占据 20 位数据的最高 8 位Bit 19~12。结果0x000AB0002.1.2 处理data[1](LSB)((uint32_t)data[1]) 4 解释 4把0xCD向左移动 4 位让它占据 20 位数据的中间 8 位Bit 11~4。结果0x00000CD02.1.3 处理data[2](XLSB)((uint32_t)data[2]) 4 解释注意这里是右移因为data[2]里的有效数据0xE在高 4 位我们需要把它向右推 4 位移到最低的 4 位Bit 3~0上。结果0x0000000E0xE0 4 0x0E2.1.4 按位或|合并把上面三部分用|按位或拼在一起0x000ABCDE (最终的 20 位气压原始值)。在按位或操作完成后结果是一个 32 位的无符号整数。但 BMP280 官方的补偿算法Compensation formula中要求传入的原始 ADC 值必须是带符号的 32 位整数int32_t。所以在最后赋值时强制转换成了int32_t以确保后续调用补偿函数时数据类型匹配避免计算错误。数组索引寄存器地址内容含义data[0]0xF7press_msb气压最高有效位data[1]0xF8press_lsb气压次有效位data[2]0xF9press_xlsb气压扩展位data[3]0xFAtemp_msb温度最高有效位data[4]0xFBtemp_lsb温度次有效位data[5]0xFCtemp_xlsb温度扩展位2.1.5 读取数据代码/* 静态变量 */ static int32_t bmp280RawPressure 0; static int32_t bmp280RawTemperature 0; static BMP280_Calib_TypeDef bmp280Cal; /* 数据寄存器 */ #define BMP280_PRESSURE_MSB_REG 0xF7 // 连续读 6 字节: P(3) T(3) /* 读取原始数据 */ static void BMP280_ReadRaw(void) { uint8_t data[6]; BMP280_Read(BMP280_PRESSURE_MSB_REG, data, 6); bmp280RawPressure (int32_t)((((uint32_t)data[0]) 12) | (((uint32_t)data[1]) 4) | ((uint32_t)data[2] 4)); bmp280RawTemperature (int32_t)((((uint32_t)data[3]) 12) | (((uint32_t)data[4]) 4) | ((uint32_t)data[5] 4)); }3 温度补偿和压力补偿传感器读出的原始 ADC 值并不是真实的温度它受到芯片制造偏差的影响。BMP280 在出厂时会在内部的 PROM 存储器中写入一组校准参数dig_T1,dig_T2,dig_T3dig_P1等。补偿算法就是用这些出厂校准参数对原始 ADC 值进行数学修正计算绝对精准的物理值。以下补偿算法完全照搬 BMP280 官方数据手册提供的标准算法这些公式是博世原厂通过极其复杂的物理标定得出的定点数算法代码中大量的和移位操作本质上是为了在没有浮点运算器FPU的低端单片机如 STM32F103、8051上用整数乘除和移位来代替浮点数乘除从而极大地提高计算速度。调用顺序是强制的必须先调用温度补偿再调用气压补偿正确做法每次读取数据后先执行BMP280_CompensateT()再执行BMP280_CompensateP()。因为气压函数内部使用了温度函数算出来的t_fine变量。单位换算温度如果返回值是2543需要自己在应用层除以 100.0得到25.43 ℃。气压如果返回值是101325单位直接就是Pa。如果想换算成百帕hPa或毫巴mbar除以 100.0 即可1013.25 hPa。如果想换算成标准大气压atm除以 101325.0。/* 校准数据读取 */ static void BMP280_ReadCalibData(void) { uint8_t buf[24]; BMP280_Read(BMP280_DIG_T1_LSB_REG, buf, 24); bmp280Cal.dig_T1 (uint16_t)(buf[1] 8 | buf[0]); bmp280Cal.dig_T2 (int16_t)(buf[3] 8 | buf[2]); bmp280Cal.dig_T3 (int16_t)(buf[5] 8 | buf[4]); bmp280Cal.dig_P1 (uint16_t)(buf[7] 8 | buf[6]); bmp280Cal.dig_P2 (int16_t)(buf[9] 8 | buf[8]); bmp280Cal.dig_P3 (int16_t)(buf[11] 8 | buf[10]); bmp280Cal.dig_P4 (int16_t)(buf[13] 8 | buf[12]); bmp280Cal.dig_P5 (int16_t)(buf[15] 8 | buf[14]); bmp280Cal.dig_P6 (int16_t)(buf[17] 8 | buf[16]); bmp280Cal.dig_P7 (int16_t)(buf[19] 8 | buf[18]); bmp280Cal.dig_P8 (int16_t)(buf[21] 8 | buf[20]); bmp280Cal.dig_P9 (int16_t)(buf[23] 8 | buf[22]); } static BMP280_Calib_TypeDef bmp280Cal; /* 温度补偿 */ static int32_t BMP280_CompensateT(int32_t adc_T) { int32_t var1, var2, T; var1 ((((adc_T 3) - ((int32_t)bmp280Cal.dig_T1 1))) * ((int32_t)bmp280Cal.dig_T2)) 11; var2 (((((adc_T 4) - ((int32_t)bmp280Cal.dig_T1)) * ((adc_T 4) - ((int32_t)bmp280Cal.dig_T1))) 12) * ((int32_t)bmp280Cal.dig_T3)) 14; bmp280Cal.t_fine var1 var2; T (bmp280Cal.t_fine * 5 128) 8; return T; // ℃*100 } /* 压力补偿 */ static uint32_t BMP280_CompensateP(int32_t 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; // Pa }4 压力转海拔这段代码是 BMP280 应用中最常用的“附加功能”利用气压值来推算当前的海拔高度。使用的是国际民航组织ICAO标准大气模型ISA中的气压-高度公式Barometric Formula/* 压力转海拔 */ static float BMP280_PressureToAltitude(float pressure) { return 44330.0f * (1.0f - powf(pressure / 101325.0f, 0.1903f)); }5 对外接口这段代码是 BMP280 驱动程序的“总出口”是用户最终调用的 API 接口。它将前面所有的底层操作读取、补偿、转换封装成一个简单易用的函数。2.4.1 解释void BMP280GetData(float *pressure, float *temperature, float *asl)void函数没有返回值通过指针返回数据。三个指针参数这是 C 语言中典型的“多值返回”技巧。float *pressure指向气压结果的指针。float *temperature指向温度结果的指针。float *asl指向海拔高度结果的指针Above Sea Level。/* 对外接口 */ void BMP280GetData(float *pressure, float *temperature, float *asl) { BMP280_ReadRaw(); *temperature BMP280_CompensateT(bmp280RawTemperature) / 100.0f; *pressure BMP280_CompensateP(bmp280RawPressure) / 256000.0f; // kPa *asl BMP280_PressureToAltitude(*pressure * 1000.0f); }四 BP神经网络气压数据滤波完整工作流1 数据采集1.1 采集方案从BMP280和MS561采集数据用于训练。