基于STM32H7R3的远程隧道气压监测终端
前言
在当今的交通网络中,隧道扮演着举足轻重的角色,无论是公路、铁路还是地铁,隧道都极大地缩短了行程,提高了通行效率。然而,你是否知道,隧道内的气压变化其实暗藏玄机,与我们的出行安全紧密相连。
当隧道内外气压失衡时,可能会引发一系列问题。比如,气压差过大可能导致车辆耳鸣、头晕,影响驾驶员的注意力和反应能力,给行车安全带来隐患;对于隧道结构本身而言,长期异常的气压波动还可能加速墙壁、衬砌的老化与损坏。此外,在一些特殊情况下,如火灾、爆炸事故发生时,气压的急剧变化更是关乎人员能否安全疏散。
为了精准掌控隧道内的气压状况,基于 STM32H7R3 的远程隧道气压监测终端应运而生。这款监测终端如同一位忠诚的 “气压卫士”,时刻坚守岗位,为隧道安全保驾护航。
硬件设计框图
整个设计以正点原子的开发板作为原型设计模板,主控为STM32H7R3,配合BMP388 气压传感器检测隧道内部的气压、六轴传感器8658A完成隧道形变监测,完成主要的隧道安全情况的检测。
主控STM32H7R3是 STM32H7 系列中的高性价比子系列,内置高性能 Cortex-M7 内核,主频高达 600MHz,这就好比给终端配备了一台超强动力的引擎,使其拥有闪电般的运算速度,能够快速处理各类复杂的数据。
与传统芯片相比,STM32H7R3 在数据处理能力上有着质的飞跃。以常见的 STM32F103 系列为例,其主频大多在 72MHz 左右,而 STM32H7R3 的 600MHz 主频意味着它每秒能够执行的指令数远超前者,在处理大量气压数据时更加得心应手,几乎不会出现卡顿现象,确保了监测的实时性。
不仅如此,STM32H7R3 还具备强大的存储能力。它集成了大容量的内部 SRAM 存储器,同时拥有高速的外部存储接口,无论是运行程序所需的空间,还是存储采集到的气压数据,都能轻松应对。这就好比给你一个超大的仓库,你可以随心所欲地存放各种物品,不用担心空间不足。在面对隧道气压监测这种需要长时间、不间断采集和存储数据的任务时,强大的存储能力尤为重要,它能够记录下气压的每一个细微变化,为后续的分析提供充足的数据支持。
在这款基于 STM32H7R3 的监测终端中,选用的是高精度、高稳定性的气压传感器。它具备诸多优势,例如其精度可达 ±0.01hPa,相较于普通精度为 ±0.1hPa 的传感器,能够捕捉到更为细微的气压波动,就如同用高倍显微镜去观察物体,不放过任何一个细节。而且,它的稳定性极佳,在长时间、复杂的隧道环境下,依然能够稳定输出准确的数据,不会因为温度、湿度的变化或者轻微的震动而出现较大偏差。这得益于其先进的温度补偿算法,能够自动抵消环境温度对气压测量的影响,确保数据的可靠性。
为了让气压传感器始终保持最佳状态,定期的校准与维护必不可少。一般来说,每隔一段时间(如一个月),就需要使用标准气压源对传感器进行校准,检查其测量值与标准值之间的偏差,若偏差超出允许范围,则通过特定的校准程序对传感器进行调整。同时,还要注意传感器的防护,避免灰尘、水汽等杂质进入传感器内部影响其性能,
软件处理流程
在软件处理流程长,我们采取了分时处理的方式,隔一段时间采集气压以及姿态数据,并对数据进行粗略的处理,保证数据的稳定性。
整体的处理流程如上图所示,按照顺序完成气压、姿态传感器的处理,以及报警状态的上送
实物测试
整体的硬件连接如图,外接BMP388传感器模块,配合开发板上的姿态传感器一起作为此次的终端传感器。
整体的数据显示如上图。
在测试过程中的数据调试波形测试。
代码展示
`
int main(void)
{
uint8_t t = 0;
uint8_t key;
uint8_t report = 0;
float temperature;
float gyro[3];
float accel[3];
float euler_angle[3] = {0, 0, 0};
sys_mpu_config(); /* 配置MPU */
sys_cache_enable();/* 使能Cache */
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(300, 6, 2); /* 配置时钟,600MHz */
delay_init(600);/* 初始化延时 */
usart_init(500000);/* 初始化串口 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
pressSensorInit(&enPressureType);
hyperram_init();/* 初始化HyperRAM */
lcd_init(); /* 初始化LCD */
lcd_show_string(30, 50, 200, 16, 16, \"STM32\", RED);
lcd_show_string(30, 70, 200, 16, 16, \"QMI8658A TEST\", RED);
lcd_show_string(30, 90, 200, 16, 16, \"ATOM@ALIENTEK\", RED);
lcd_show_string(30, 110, 200, 16, 16, \"KEY0:UPLOAD ON/OFF\", RED);
while (qmi8658_init() != 0)/* 初始化QMI8658A */
{
lcd_show_string(30, 130, 200, 16, 16, \"QMI8658A Error!\", RED);
delay_ms(500);
lcd_show_string(30, 130, 200, 16, 16, \"Please Check!\", RED);
delay_ms(500);
LED0_TOGGLE();
}
lcd_show_string(30, 130, 200, 16, 16, \"QMI8658A Ready!\", RED);
lcd_show_string(30, 150, 200, 16, 16, \"UPLOAD OFF\", BLUE);
lcd_show_string(30, 170, 200, 16, 16, \"Temp : . C\", BLUE);
lcd_show_string(30, 190, 200, 16, 16, \"Pitch: . C\", BLUE);
lcd_show_string(30, 210, 200, 16, 16, \"Roll : . C\", BLUE);
lcd_show_string(30, 230, 200, 16, 16, \"Yaw: . C\", BLUE);
lcd_show_string(30, 260, 200, 16, 16, \"BMP388 TEST\", RED);
lcd_show_string(30, 280, 200, 16, 16, \"Press:Pa \", BLUE);
lcd_show_string(30, 300, 200, 16, 16, \"Alti :cm \", BLUE);
while (1)
{
qmi8658_read_xyz(accel, gyro);
pressSensorDataGet(&s32TemperatureVal, &s32PressureVal, &s32AltitudeVal);
key = key_scan(0);
if (key == KEY0_PRES)
{
/* 切换匿名数据上报开关 */
report = !report;
if (report == 0)
{
lcd_show_string(30, 150, 200, 16, 16, \"UPLOAD OFF\", BLUE);
}
else
{
lcd_show_string(30, 150, 200, 16, 16, \"UPLOAD ON \", BLUE);
}
}
/* 获取并显示温度 */
show_data(30, 170, qmi8658_get_temperature());
/* 获取并显示欧拉角 */
if (g_imu_init)
{
imu_get_eulerian_angles(accel, gyro, euler_angle, IMU_DELTA_T);
show_data(30, 190, euler_angle[0]);
show_data(30, 210, euler_angle[1]);
show_data(30, 230, euler_angle[2]);
lcd_show_num(80, 280,s32PressureVal ,9,16, BLUE);
lcd_show_num(80, 300, s32AltitudeVal,9,16, BLUE );
if (report != 0)
{
/* 上报匿名状态帧 */
qmi8658_send_data(accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);/* 发送加速度+陀螺仪原始数据 */
usart1_report_imu((int)(euler_angle[1] * 100), (int)(euler_angle[0] * 100), (int)(euler_angle[2] * 100), 0, 0, 0); /* Pitch和Roll角位置调换 */
}
}
LED0_TOGGLE();
delay_ms(200);
}
}
`
整体的主函数如上图,后期我将把所有的源码通过附件上传
`/**
@file BMP388.cpp
@authorWaveshare Team
@version V1.0
@date Dec-2018
@BriefT
@attention
THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
TIME. AS A RESULT, WAVESHARE SHALL NOT BE HELD LIABLE FOR ANY
DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
© COPYRIGHT 2018 Waveshare
*/
#include \"DRV_BMP388.h\"
////初始化IIC
void BMP388_IIC_Init(void)
{
////-----------
//LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
//LL_GPIO_SetPinMode(BMP388_SDA_Port,BMP388_SDA_Pin |BMP388_SCL_Pin,LL_GPIO_MODE_OUTPUT);
//LL_GPIO_SetPinOutputType(GPIOB,BMP388_SDA_Pin |BMP388_SCL_Pin,LL_GPIO_OUTPUT_PUSHPULL);//推挽输出
//LL_GPIO_SetPinSpeed(GPIOB,BMP388_SDA_Pin |BMP388_SCL_Pin,LL_GPIO_SPEED_FREQ_VERY_HIGH);//IO口速度
//LL_GPIO_SetPinPull(GPIOB,BMP388_SDA_Pin |BMP388_SCL_Pin,LL_GPIO_PULL_UP);
////--PB10,PB11 输出高--
////--PB10:SCLPB11:SDA
//LL_GPIO_SetOutputPin(BMP388_SDA_Port,BMP388_SDA_Pin);
//LL_GPIO_SetOutputPin(BMP388_SCL_Port,BMP388_SCL_Pin);
////--地址脚--
// LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
//LL_GPIO_SetPinMode(GPIOB,LL_GPIO_PIN_12,LL_GPIO_MODE_OUTPUT);
//LL_GPIO_SetPinOutputType(GPIOB,LL_GPIO_PIN_12,LL_GPIO_OUTPUT_PUSHPULL);//推挽输出
//LL_GPIO_SetPinSpeed(GPIOB,LL_GPIO_PIN_12,LL_GPIO_SPEED_FREQ_VERY_HIGH);//IO口速度
//LL_GPIO_SetPinPull(GPIOB,LL_GPIO_PIN_12,LL_GPIO_PULL_UP);
// //--地址引脚,设置地址为0x76--
//LL_GPIO_ResetOutputPin(GPIOB,LL_GPIO_PIN_12);
GPIO_InitTypeDef gpio_init_struct = {0};
__HAL_RCC_GPIOE_CLK_ENABLE();
/* 配置LED0控制引脚 */
gpio_init_struct.Pin = BMP388_SDA_Pin;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(BMP388_SDA_Port, &gpio_init_struct);
/* 配置LED0控制引脚 */
gpio_init_struct.Pin = BMP388_SCL_Pin;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(BMP388_SCL_Port, &gpio_init_struct);
}
//--设置SDA为输出方向
void BMP388_SDA_OUT(void)
{
GPIO_InitTypeDef gpio_init_struct = {0};
gpio_init_struct.Pin = BMP388_SDA_Pin;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(BMP388_SDA_Port, &gpio_init_struct);
BMP388_IIC_Delay(1);
}
//--设置SDA为输入方向
void BMP388_SDA_IN(void)
{
GPIO_InitTypeDef gpio_init_struct = {0};
gpio_init_struct.Pin = BMP388_SDA_Pin;
gpio_init_struct.Mode = GPIO_MODE_INPUT;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(BMP388_SDA_Port, &gpio_init_struct);
BMP388_IIC_Delay(1);
}
//产生IIC起始信号
void BMP388_IIC_Start(void)
{
BMP388_SDA_OUT();//sda线输出
BMP388_IIC_SDA_H ;
BMP388_IIC_SCL_H;
BMP388_IIC_Delay(1);
BMP388_IIC_SDA_L;//START:when CLK is high,DATA change form high to low
BMP388_IIC_Delay(1);
BMP388_IIC_SCL_L;//钳住I2C总线,准备发送或接收数据
BMP388_IIC_Delay(1);
}
//产生IIC停止信号
void BMP388_IIC_Stop(void)
{
BMP388_SDA_OUT();//sda线输出
BMP388_IIC_SCL_L;
BMP388_IIC_SDA_L;//STOP:when CLK is high DATA change form low to high
BMP388_IIC_Delay(1);
BMP388_IIC_SCL_H;
BMP388_IIC_Delay(1);
BMP388_IIC_SDA_H ;//发送I2C总线结束信号
BMP388_IIC_Delay(1);
}
//等待应答信号到来
//返回值:1,接收应答失败
//0,接收应答成功
unsigned char BMP388_IIC_Wait_Ack(void)
{
unsigned char ucErrTime=0;
BMP388_SDA_IN();//SDA设置为输入
BMP388_IIC_SDA_H ;BMP388_IIC_Delay(1);
BMP388_IIC_SCL_H;BMP388_IIC_Delay(1);
while(BMP388_READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
BMP388_IIC_Stop();
return 1;
}
}
BMP388_IIC_SCL_L;//时钟输出0
return 0;
}
//产生ACK应答
void BMP388_IIC_Ack(void)
{
BMP388_IIC_SCL_L;
BMP388_SDA_OUT();
BMP388_IIC_SDA_L;
BMP388_IIC_Delay(1);
BMP388_IIC_SCL_H;
BMP388_IIC_Delay(1);
BMP388_IIC_SCL_L;
}
//不产生ACK应答
void BMP388_IIC_NAck(void)
{
BMP388_IIC_SCL_L;
BMP388_SDA_OUT();
BMP388_IIC_SDA_H ;
BMP388_IIC_Delay(1);
BMP388_IIC_SCL_H;
BMP388_IIC_Delay(1);
BMP388_IIC_SCL_L;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void BMP388_IIC_Send_Byte(unsigned char txd)
{
unsigned char t;
BMP388_SDA_OUT();
BMP388_IIC_SCL_L;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
//--BMP388_IIC_SDA=(txd&0x80)>>7;
if(((txd&0x80)>>7)==0x01)
BMP388_IIC_SDA_H;
else
BMP388_IIC_SDA_L;
txd<<=1;
BMP388_IIC_SCL_H;
BMP388_IIC_Delay(1);
BMP388_IIC_SCL_L;
BMP388_IIC_Delay(1);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
unsigned char BMP388_IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
BMP388_SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
BMP388_IIC_SCL_L;
BMP388_IIC_Delay(1);
BMP388_IIC_SCL_H;
receive<<=1;
if(BMP388_READ_SDA)
receive++;
BMP388_IIC_Delay(1);
}
if (!ack)
BMP388_IIC_NAck();//发送nACK
else
BMP388_IIC_Ack(); //发送ACK
return receive;
}
//--以上是驱动代码,需要做更改---
static BMP388_ST_AVG gsstBMP388AvgFilter[3];
static BMP388_ST_CALI gsstCali;
static unsigned char bmp388Check(void);
static uint8_t bmp388Init(void);
static void bmp388DataGet(int32_t* ps32Temp, int32_t* ps32Press, int32_t*ps32Alti);
static void bmp388GetCalibrationData(void);
static int64_t bmp388CompensateTemp(uint32_t u32RegData);
static int64_t bmp388CompensatePress(uint32_t u32RegData);
static void bmp388CalAvgValue(uint8_t *pu8Index, int32_t *ps32AvgBuffer, int32_t s32InVal, int32_t *ps32OutVal);
uint8_t I2C_ReadOneByte(uint8_t DevAddr, uint8_t RegAddr)
{
uint8_t u8Ret;
BMP388_IIC_Start();
BMP388_IIC_Send_Byte(DevAddr|0);//--写地址--
BMP388_IIC_Wait_Ack();
BMP388_IIC_Send_Byte(RegAddr);
BMP388_IIC_Wait_Ack();
BMP388_IIC_Start();
BMP388_IIC_Send_Byte(DevAddr|1);//--写地址--
BMP388_IIC_Wait_Ack();
u8Ret=BMP388_IIC_Read_Byte(0);
return u8Ret;
}
void I2C_WriteOneByte(uint8_t DevAddr, uint8_t RegAddr, uint8_t value)
{
BMP388_IIC_Start();
BMP388_IIC_Send_Byte(DevAddr|0);//发送器件地址+写命令
if(BMP388_IIC_Wait_Ack())//等待应答
{
BMP388_IIC_Stop();
return ;
}
BMP388_IIC_Send_Byte(RegAddr);//写寄存器地址
BMP388_IIC_Wait_Ack();//等待应答
BMP388_IIC_Send_Byte(value);//发送数据
if(BMP388_IIC_Wait_Ack())//等待ACK
{
BMP388_IIC_Stop();
return ;
}
BMP388_IIC_Stop();
return;
}
/******************************************************************************
pressure sensor module*
******************************************************************************/
void BMP388_IIC_Delay(uint32_t u32Count)
{
volatile uint32_t i;
while(u32Count --)
for(i = 0;i < 420;i ++);
}
void pressSensorInit(PRESS_EN_SENSOR_TYPY *penPressSensorTyep)
{
unsigned charbRet = false;
// -- i2cInit();修改
BMP388_IIC_Init();
bRet = bmp388Check();
if( true == bRet)
{
*penPressSensorTyep = PRESS_EN_SENSOR_TYPY_BMP388;
bmp388Init();
}
else
{
*penPressSensorTyep = PRESS_EN_SENSOR_TYPY_MAX;
}
}
void pressSensorDataGet(int32_t* ps32Temp, int32_t* ps32Press, int32_tps32Alti)
{
bmp388DataGet( ps32Temp, ps32Press, ps32Alti);
return;
}
/*****************************************************************************
BMP388 sensor device *
******************************************************************************/
static unsigned charbmp388Check(void)
{
unsigned charbRet = false;
if(BMP388_REG_VAL_WIA == I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_WIA))
{
bRet = true;
}
return bRet;
}
static uint8_t bmp388Init(void)
{
uint8_t u8RegData;
uint8_t u8Ret;
//reset
u8RegData = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_STATUS);
if( u8RegData & BMP388_REG_VAL_CMD_RDY )
{
I2C_WriteOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_CMD, BMP388_REG_VAL_SOFT_RESET);
BMP388_IIC_Delay(5);
u8RegData = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_ERR);
if( u8RegData & BMP388_REG_VAL_CMD_ERR)
{
u8Ret =0;
return u8Ret;
}
}
//calibration data read
bmp388GetCalibrationData();
//seting
I2C_WriteOneByte( I2C_ADD_BMP388, BMP388_REG_ADD_PWR_CTRL,
BMP388_REG_VAL_PRESS_EN | BMP388_REG_VAL_TEMP_EN | BMP388_REG_VAL_NORMAL_MODE);
return 0;
}
static void bmp388DataGet(int32_t* ps32Temp, int32_t* ps32Press, int32_t*ps32Alti)
{
uint32_t u32TempRegData, u32PressRegData;
uint8_t u8Xlsb, u8Lsb, u8Msb;
int32_t s32Pressure0 = 101325;// Mean Sea Level Pressure = 1013.25 hPA (1hPa = 100Pa = 1mbar)
int32_t s32Temp, s32Press, s32Alti;
u8Xlsb= I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_TEMP_XLSB);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_TEMP_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_TEMP_MSB);
u32TempRegData = u8Msb;
u32TempRegData <<= 8;
u32TempRegData |= u8Lsb;
u32TempRegData <<= 8;
u32TempRegData |= u8Xlsb;
u8Xlsb= I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_PRESS_XLSB);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_PRESS_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_PRESS_MSB);
u32PressRegData = u8Msb;
u32PressRegData <<= 8;
u32PressRegData |= u8Lsb;
u32PressRegData <<= 8;
u32PressRegData |= u8Xlsb;
s32Temp= bmp388CompensateTemp(u32TempRegData);
s32Press = bmp388CompensatePress(u32PressRegData);
s32Alti= 4433000 * (1 - pow((float)((float)((float)(s32Press)/100.0f) / (float)s32Pressure0), 0.1903));
bmp388CalAvgValue( &(gsstBMP388AvgFilter[0].u8Index), gsstBMP388AvgFilter[0].s32AvgBuffer, s32Temp,ps32Temp );
bmp388CalAvgValue( &(gsstBMP388AvgFilter[1].u8Index), gsstBMP388AvgFilter[1].s32AvgBuffer, s32Press, ps32Press);
bmp388CalAvgValue( &(gsstBMP388AvgFilter[2].u8Index), gsstBMP388AvgFilter[2].s32AvgBuffer, s32Alti,ps32Alti );
return;
}
static void bmp388GetCalibrationData(void)
{
uint8_t u8Lsb, u8Msb;
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T1_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T1_MSB);
gsstCali.T1 = u8Msb;
gsstCali.T1 <<= 8;
gsstCali.T1 |= u8Lsb;
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T2_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T2_MSB);
gsstCali.T2 = u8Msb;
gsstCali.T2 <<= 8;
gsstCali.T2 |= u8Lsb;
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T3);
gsstCali.T3 = (int8_t)(u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P1_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P1_MSB);
gsstCali.P1 = (int16_t)(u8Msb << 8 | u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P2_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P2_MSB);
gsstCali.P2 = (int16_t)(u8Msb << 8 | u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P3);
gsstCali.P3 = (int8_t)(u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P4);
gsstCali.P4 = (int8_t)(u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P5_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P5_MSB);
gsstCali.P5 = (u8Msb << 8 | u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P6_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P6_MSB);
gsstCali.P6 = (u8Msb << 8 | u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P7);
gsstCali.P7 = (int8_t)(u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P8);
gsstCali.P8 = (int8_t)(u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P9_LSB);
u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P9_MSB);
gsstCali.P9 = (int16_t)(u8Msb << 8 | u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P10);
gsstCali.P10 = (int8_t)(u8Lsb);
u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P11);
gsstCali.P11 = (int8_t)(u8Lsb);
return;
}
static int64_t bmp388CompensateTemp(uint32_t u32RegData)
{
uint64_t partial_data1;
uint64_t partial_data2;
uint64_t partial_data3;
int64_t partial_data4;
int64_t partial_data5;
int64_t partial_data6;
int64_t comp_temp;
partial_data1 = (uint64_t)(u32RegData - (256 * (uint64_t)(gsstCali.T1)));
partial_data2 = (uint64_t)(gsstCali.T2 * partial_data1);
partial_data3 = (uint64_t)(partial_data1 * partial_data1);
partial_data4 = (int64_t)(((int64_t)partial_data3) * ((int64_t)gsstCali.T3));
partial_data5 = ((int64_t)(((int64_t)partial_data2) * 262144) + (int64_t)partial_data4);
partial_data6 = (int64_t)(((int64_t)partial_data5) / 4294967296);
/* Store t_lin in dev. structure for pressure calculation */
gsstCali.T_fine = partial_data6;
comp_temp = (int64_t)((partial_data6 * 25)/ 16384);
return comp_temp;
}
static int64_t bmp388CompensatePress(uint32_t u32RegData)
{
int64_t partial_data1;
int64_t partial_data2;
int64_t partial_data3;
int64_t partial_data4;
int64_t partial_data5;
int64_t partial_data6;
int64_t offset;
int64_t sensitivity;
uint64_t comp_press;
partial_data1 = gsstCali.T_fine * gsstCali.T_fine;
partial_data2 = partial_data1 / 64;
partial_data3 = (partial_data2 * gsstCali.T_fine) / 256;
partial_data4 = (gsstCali.P8 * partial_data3) / 32;
partial_data5 = (gsstCali.P7 * partial_data1) * 16;
partial_data6 = (gsstCali.P6 * gsstCali.T_fine) * 4194304;
offset = (int64_t)((int64_t)(gsstCali.P5) * (int64_t)140737488355328) +
partial_data4 + partial_data5 + partial_data6;
partial_data2 = (((int64_t)gsstCali.P4) * partial_data3) / 32;
partial_data4 = (gsstCali.P3 * partial_data1) * 4;
partial_data5 = ((int64_t)(gsstCali.P2) - 16384) * ((int64_t)gsstCali.T_fine) * 2097152;
sensitivity = (((int64_t)(gsstCali.P1) - 16384) * (int64_t)70368744177664) +
partial_data2 + partial_data4 + partial_data5;
partial_data1 = (sensitivity / 16777216) * u32RegData;
partial_data2 = (int64_t)(gsstCali.P10) * (int64_t)(gsstCali.T_fine);
partial_data3 = partial_data2 + (65536 * (int64_t)(gsstCali.P9));
partial_data4 = (partial_data3 * u32RegData) / 8192;
partial_data5 = (partial_data4 * u32RegData) / 512;
partial_data6 = (int64_t)((uint64_t)u32RegData * (uint64_t)u32RegData);
partial_data2 = ((int64_t)(gsstCali.P11) * (int64_t)(partial_data6)) / 65536;
partial_data3 = (partial_data2 * u32RegData) / 128;
partial_data4 = (offset / 4) + partial_data1 + partial_data5 + partial_data3;
comp_press = (((uint64_t)partial_data4 * 25) / (uint64_t)1099511627776);
return comp_press;
}
static void bmp388CalAvgValue(uint8_t *pu8Index, int32_t *ps32AvgBuffer, int32_t s32InVal, int32_t *ps32OutVal)
{
uint8_t i;
*(ps32AvgBuffer + ((*pu8Index) ++)) = s32InVal;
*pu8Index &= 0x07;
*ps32OutVal = 0;
for(i = 0; i < 8; i ++)
{
*ps32OutVal += *(ps32AvgBuffer + i);
}
*ps32OutVal >>= 3;
return;
}
`
BMP388 的驱动代码图
产品的意义
以某山区高速公路隧道为例,在安装监测终端之前,隧道管理部门主要依靠人工巡检来监测气压变化,不仅耗费大量人力物力,而且监测频率低、时效性差。一旦遇到恶劣天气或者突发事故,很难及时掌握隧道内气压的异常波动,给应急处置带来极大困难。
安装了远程隧道气压监测终端后,情况得到了显著改善。在一次暴雨引发的山体滑坡事故中,隧道一端入口附近堆积了大量土石,导致气流受阻,隧道内气压急剧变化。监测终端凭借其高精度的气压传感器,迅速捕捉到了这一异常,在短短几分钟内就通过 4G 网络将气压数据和警报信息发送至监控中心。监控中心工作人员根据实时数据,第一时间采取了交通管制措施,引导车辆有序疏散,避免了因气压问题导致驾驶员身体不适以及可能发生的车辆碰撞事故,同时也为后续的抢险救援工作提供了有力的数据支持,保障了人员的生命财产安全。
又如,某城市地铁隧道在日常运营中,由于列车频繁进出站,隧道内气流复杂,气压波动频繁。以往由于缺乏精准的气压监测手段,隧道衬砌的微小损坏难以被及时发现,日积月累,对隧道结构安全构成潜在威胁。引入该监测终端后,通过长时间、连续的数据采集与分析,运营方能够清晰地掌握气压变化规律,提前发现因气压异常引发的衬砌结构应力变化,及时安排维护检修,有效延长了隧道的使用寿命,降低了运营风险。
通过这些实际案例可以看出,基于 STM32H7R3 的远程隧道气压监测终端就如同隧道的 “安全卫士”,无论是应对突发灾害还是保障日常运营,它都能以精准的数据、高效的传输和稳定的性能,全方位提升隧道的安全性与可靠性,让我们的出行更加安心。
附件:
*附件:STM32H7R3-BMP388.rar
发表于 01-04 11:18
评论