基于STM32H7R3的遠程隧道氣壓監(jiān)測終端
前言
在當今的交通網(wǎng)絡中,隧道扮演著舉足輕重的角色,無論是公路、鐵路還是地鐵,隧道都極大地縮短了行程,提高了通行效率。然而,你是否知道,隧道內(nèi)的氣壓變化其實暗藏玄機,與我們的出行安全緊密相連。
當隧道內(nèi)外氣壓失衡時,可能會引發(fā)一系列問題。比如,氣壓差過大可能導致車輛耳鳴、頭暈,影響駕駛員的注意力和反應能力,給行車安全帶來隱患;對于隧道結(jié)構本身而言,長期異常的氣壓波動還可能加速墻壁、襯砌的老化與損壞。此外,在一些特殊情況下,如火災、爆炸事故發(fā)生時,氣壓的急劇變化更是關乎人員能否安全疏散。
為了精準掌控隧道內(nèi)的氣壓狀況,基于 STM32H7R3 的遠程隧道氣壓監(jiān)測終端應運而生。這款監(jiān)測終端如同一位忠誠的 “氣壓衛(wèi)士”,時刻堅守崗位,為隧道安全保駕護航。
硬件設計框圖
整個設計以正點原子的開發(fā)板作為原型設計模板,主控為STM32H7R3,配合BMP388 氣壓傳感器檢測隧道內(nèi)部的氣壓、六軸傳感器8658A完成隧道形變監(jiān)測,完成主要的隧道安全情況的檢測。
主控STM32H7R3是 STM32H7 系列中的高性價比子系列,內(nèi)置高性能 Cortex-M7 內(nèi)核,主頻高達 600MHz,這就好比給終端配備了一臺超強動力的引擎,使其擁有閃電般的運算速度,能夠快速處理各類復雜的數(shù)據(jù)。
與傳統(tǒng)芯片相比,STM32H7R3 在數(shù)據(jù)處理能力上有著質(zhì)的飛躍。以常見的 STM32F103 系列為例,其主頻大多在 72MHz 左右,而 STM32H7R3 的 600MHz 主頻意味著它每秒能夠執(zhí)行的指令數(shù)遠超前者,在處理大量氣壓數(shù)據(jù)時更加得心應手,幾乎不會出現(xiàn)卡頓現(xiàn)象,確保了監(jiān)測的實時性。
不僅如此,STM32H7R3 還具備強大的存儲能力。它集成了大容量的內(nèi)部 SRAM 存儲器,同時擁有高速的外部存儲接口,無論是運行程序所需的空間,還是存儲采集到的氣壓數(shù)據(jù),都能輕松應對。這就好比給你一個超大的倉庫,你可以隨心所欲地存放各種物品,不用擔心空間不足。在面對隧道氣壓監(jiān)測這種需要長時間、不間斷采集和存儲數(shù)據(jù)的任務時,強大的存儲能力尤為重要,它能夠記錄下氣壓的每一個細微變化,為后續(xù)的分析提供充足的數(shù)據(jù)支持。
在這款基于 STM32H7R3 的監(jiān)測終端中,選用的是高精度、高穩(wěn)定性的氣壓傳感器。它具備諸多優(yōu)勢,例如其精度可達 ±0.01hPa,相較于普通精度為 ±0.1hPa 的傳感器,能夠捕捉到更為細微的氣壓波動,就如同用高倍顯微鏡去觀察物體,不放過任何一個細節(jié)。而且,它的穩(wěn)定性極佳,在長時間、復雜的隧道環(huán)境下,依然能夠穩(wěn)定輸出準確的數(shù)據(jù),不會因為溫度、濕度的變化或者輕微的震動而出現(xiàn)較大偏差。這得益于其先進的溫度補償算法,能夠自動抵消環(huán)境溫度對氣壓測量的影響,確保數(shù)據(jù)的可靠性。
為了讓氣壓傳感器始終保持最佳狀態(tài),定期的校準與維護必不可少。一般來說,每隔一段時間(如一個月),就需要使用標準氣壓源對傳感器進行校準,檢查其測量值與標準值之間的偏差,若偏差超出允許范圍,則通過特定的校準程序?qū)鞲衅鬟M行調(diào)整。同時,還要注意傳感器的防護,避免灰塵、水汽等雜質(zhì)進入傳感器內(nèi)部影響其性能,
軟件處理流程
在軟件處理流程長,我們采取了分時處理的方式,隔一段時間采集氣壓以及姿態(tài)數(shù)據(jù),并對數(shù)據(jù)進行粗略的處理,保證數(shù)據(jù)的穩(wěn)定性。
整體的處理流程如上圖所示,按照順序完成氣壓、姿態(tài)傳感器的處理,以及報警狀態(tài)的上送
實物測試
整體的硬件連接如圖,外接BMP388傳感器模塊,配合開發(fā)板上的姿態(tài)傳感器一起作為此次的終端傳感器。
整體的數(shù)據(jù)顯示如上圖。
在測試過程中的數(shù)據(jù)調(diào)試波形測試。
代碼展示
`
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)
{
/* 切換匿名數(shù)據(jù)上報開關 */
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)
{
/* 上報匿名狀態(tài)幀 */
qmi8658_send_data(accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);/* 發(fā)送加速度+陀螺儀原始數(shù)據(jù) */
usart1_report_imu((int)(euler_angle[1] * 100), (int)(euler_angle[0] * 100), (int)(euler_angle[2] * 100), 0, 0, 0); /* Pitch和Roll角位置調(diào)換 */
}
}
LED0_TOGGLE();
delay_ms(200);
}
}
`
整體的主函數(shù)如上圖,后期我將把所有的源碼通過附件上傳
`/**
@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);
}
//產(chǎn)生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總線,準備發(fā)送或接收數(shù)據(jù)
BMP388_IIC_Delay(1);
}
//產(chǎn)生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 ;//發(fā)送I2C總線結(jié)束信號
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;
}
//產(chǎn)生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;
}
//不產(chǎn)生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發(fā)送一個字節(jié)
//返回從機有無應答
//1,有應答
//0,無應答
void BMP388_IIC_Send_Byte(unsigned char txd)
{
unsigned char t;
BMP388_SDA_OUT();
BMP388_IIC_SCL_L;//拉低時鐘開始數(shù)據(jù)傳輸
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個字節(jié),ack=1時,發(fā)送ACK,ack=0,發(fā)送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();//發(fā)送nACK
else
BMP388_IIC_Ack(); //發(fā)送ACK
return receive;
}
//--以上是驅(qū)動代碼,需要做更改---
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);//發(fā)送器件地址+寫命令
if(BMP388_IIC_Wait_Ack())//等待應答
{
BMP388_IIC_Stop();
return ;
}
BMP388_IIC_Send_Byte(RegAddr);//寫寄存器地址
BMP388_IIC_Wait_Ack();//等待應答
BMP388_IIC_Send_Byte(value);//發(fā)送數(shù)據(jù)
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 的驅(qū)動代碼圖
產(chǎn)品的意義
以某山區(qū)高速公路隧道為例,在安裝監(jiān)測終端之前,隧道管理部門主要依靠人工巡檢來監(jiān)測氣壓變化,不僅耗費大量人力物力,而且監(jiān)測頻率低、時效性差。一旦遇到惡劣天氣或者突發(fā)事故,很難及時掌握隧道內(nèi)氣壓的異常波動,給應急處置帶來極大困難。
安裝了遠程隧道氣壓監(jiān)測終端后,情況得到了顯著改善。在一次暴雨引發(fā)的山體滑坡事故中,隧道一端入口附近堆積了大量土石,導致氣流受阻,隧道內(nèi)氣壓急劇變化。監(jiān)測終端憑借其高精度的氣壓傳感器,迅速捕捉到了這一異常,在短短幾分鐘內(nèi)就通過 4G 網(wǎng)絡將氣壓數(shù)據(jù)和警報信息發(fā)送至監(jiān)控中心。監(jiān)控中心工作人員根據(jù)實時數(shù)據(jù),第一時間采取了交通管制措施,引導車輛有序疏散,避免了因氣壓問題導致駕駛員身體不適以及可能發(fā)生的車輛碰撞事故,同時也為后續(xù)的搶險救援工作提供了有力的數(shù)據(jù)支持,保障了人員的生命財產(chǎn)安全。
又如,某城市地鐵隧道在日常運營中,由于列車頻繁進出站,隧道內(nèi)氣流復雜,氣壓波動頻繁。以往由于缺乏精準的氣壓監(jiān)測手段,隧道襯砌的微小損壞難以被及時發(fā)現(xiàn),日積月累,對隧道結(jié)構安全構成潛在威脅。引入該監(jiān)測終端后,通過長時間、連續(xù)的數(shù)據(jù)采集與分析,運營方能夠清晰地掌握氣壓變化規(guī)律,提前發(fā)現(xiàn)因氣壓異常引發(fā)的襯砌結(jié)構應力變化,及時安排維護檢修,有效延長了隧道的使用壽命,降低了運營風險。
通過這些實際案例可以看出,基于 STM32H7R3 的遠程隧道氣壓監(jiān)測終端就如同隧道的 “安全衛(wèi)士”,無論是應對突發(fā)災害還是保障日常運營,它都能以精準的數(shù)據(jù)、高效的傳輸和穩(wěn)定的性能,全方位提升隧道的安全性與可靠性,讓我們的出行更加安心。
附件:
*附件:STM32H7R3-BMP388.rar
發(fā)表于 01-04 11:18
評論