#include "bsp_bmp390.h" #include "bsp_motor.h" #include "bsp_led.h" #include "bsp_key.h" #include "CONFIG.h" #include "log.h" #include "bsp_ml307r.h" #include "SLEEP.h" #include "bsp_valve.h" uint8_t flag; uint8_t keydown_flag = 0; uint8_t keydown_time = 0; uint8_t volatile fault_state = 0; // 安全阈值参数统一定义 #define SAFETY_AUTO_OPEN_THRESHOLD 3 // 自动开阀阈值(连续检测次数) #define SAFETY_MICRO_LEAK_THRESHOLD 5 // 微泄漏检测阈值(连续检测次数) #define SAFETY_MICRO_LEAK_PRESS_DIFF 15 // 微泄漏压力差阈值(Pa),对应流量约0.3L/min #define SAFETY_OVER_TEMP_THRESHOLD 65 // 超温阈值(℃) #define SAFETY_GAS_REQUEST_PRESS_DIFF 50 // 用气请求压力差阈值(Pa) typedef struct { int in_press_raw; int out_press_raw; int8_t in_temp; int8_t out_temp; int8_t atom_temp; int in_press; // 表压 单位Pa int out_press; int atom_press; // 进气端和出气端压力差值 单位Pa int in_out_press_diff; } TsValveRawData; TsValveRawData ValveRawData; TsValveRawData ValveRawData_buffer[5]; typedef struct { uint16_t over_press; uint16_t low_press; uint8_t over_temp; int over_flow_press_diff_1kpa; int over_flow_press_diff_2kpa; int over_flow_press_diff_3kpa; } TsValveInfo; TsValveInfo ValveInfo; // 安全保护状态结构体 typedef struct { // 自动开阀相关 uint8_t auto_open_count; // 自动开阀检测计数 uint8_t auto_open_flag; // 自动开阀标志 // 微泄漏相关 uint8_t micro_leak_count; // 微泄漏检测计数 uint8_t micro_leak_flag; // 微泄漏标志 // 超温相关 uint8_t over_temp_flag; // 超温标志 // 延时关阀相关 uint8_t auto_close_enabled; // 延时关阀功能是否启用 uint8_t auto_close_check_count; // 无流量检测次数计数 uint8_t auto_close_active; // 延时关阀检测是否激活 uint32_t auto_close_start_time; // 延时关阀开始时间 } TsValveSafetyStatus; // 安全状态全局变量 TsValveSafetyStatus valve_safety = {0}; extern uint8_t motor_flag; extern Shell shell; static tmosTaskID check_task_id = INVALID_TASK_ID; typedef enum { kPressIn = 0, kPressOut = 1, kPressAtom = 2, kPressMaxIndex } TePressSensorIndex; static tmosTaskID press_task_id = INVALID_TASK_ID; #define PRESS_IN_CS_HIGH() GPIOA_SetBits(GPIO_Pin_8) #define PRESS_IN_CS_LOW() GPIOA_ResetBits(GPIO_Pin_8) #define PRESS_OUT_CS_HIGH() GPIOA_SetBits(GPIO_Pin_2) #define PRESS_OUT_CS_LOW() GPIOA_ResetBits(GPIO_Pin_2) #define PRESS_ATOM_CS_HIGH() GPIOA_SetBits(GPIO_Pin_0) #define PRESS_ATOM_CS_LOW() GPIOA_ResetBits(GPIO_Pin_0) uint8_t volatile press_done_flag = 0; uint8_t SPI0_SendByte(uint8_t data); void SPI_CsStart(TePressSensorIndex index); void SPI_CsStop(TePressSensorIndex index); /* Variable to store the device address */ static uint8_t dev_in_addr; static uint8_t dev_out_addr; static uint8_t dev_atom_addr; uint8_t Bmp_ReadData(uint8_t *reg_data, uint32_t len) { while (len--) { *reg_data = SPI0_SendByte(0x00); reg_data++; } return BMP3_INTF_RET_SUCCESS; } BMP3_INTF_RET_TYPE Bmp_WriteData(const uint8_t *reg_data, uint32_t len) { uint8_t i = 0; for (i = 0; i < len; i++) { SPI0_SendByte(reg_data[i]); } return BMP3_INTF_RET_SUCCESS; } BMP3_INTF_RET_TYPE BMP390_IN_SPI_Read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr) { BMP3_INTF_RET_TYPE rslt = 0; uint8_t reg_spi[1] = {(reg_addr & 0x7F) | 0x80}; SPI_CsStart(kPressIn); // 拉低片选 Bmp_WriteData(reg_spi, 1); // 写入控制字节 rslt = Bmp_ReadData(reg_data, len); SPI_CsStop(kPressIn); return rslt; } /*! * SPI write function map to COINES platform */ BMP3_INTF_RET_TYPE BMP390_IN_SPI_Write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr) { uint8_t reg_spi[1] = {reg_addr & 0x7f}; BMP3_INTF_RET_TYPE rslt = 0; SPI_CsStart(kPressIn); Bmp_WriteData(reg_spi, 1); rslt = Bmp_WriteData(reg_data, len); SPI_CsStop(kPressIn); // printf("BMP390_OUT_SPI_Write: %d" , rslt); return rslt; } /*! * SPI read function map to COINES platform */ BMP3_INTF_RET_TYPE BMP390_OUT_SPI_Read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr) { BMP3_INTF_RET_TYPE rslt = 0; uint8_t reg_spi[1] = {(reg_addr & 0x7F) | 0x80}; SPI_CsStart(kPressOut); // 拉低片选 Bmp_WriteData(reg_spi, 1); // 写入控制字节 rslt = Bmp_ReadData(reg_data, len); SPI_CsStop(kPressOut); return rslt; } /*! * SPI write function map to COINES platform */ BMP3_INTF_RET_TYPE BMP390_OUT_SPI_Write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr) { uint8_t reg_spi[1] = {reg_addr & 0x7f}; BMP3_INTF_RET_TYPE rslt = 0; SPI_CsStart(kPressOut); Bmp_WriteData(reg_spi, 1); rslt = Bmp_WriteData(reg_data, len); SPI_CsStop(kPressOut); // printf("BMP390_OUT_SPI_Write: %d" , rslt); return rslt; } BMP3_INTF_RET_TYPE BMP390_ATOM_SPI_Read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr) { BMP3_INTF_RET_TYPE rslt = 0; uint8_t reg_spi[1] = {(reg_addr & 0x7F) | 0x80}; SPI_CsStart(kPressAtom); // 拉低片选 Bmp_WriteData(reg_spi, 1); // 写入控制字节 rslt = Bmp_ReadData(reg_data, len); SPI_CsStop(kPressAtom); return rslt; } /*! * SPI write function map to COINES platform */ BMP3_INTF_RET_TYPE BMP390_ATOM_SPI_Write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr) { uint8_t reg_spi[1] = {reg_addr & 0x7f}; BMP3_INTF_RET_TYPE rslt = 0; SPI_CsStart(kPressAtom); Bmp_WriteData(reg_spi, 1); rslt = Bmp_WriteData(reg_data, len); SPI_CsStop(kPressAtom); // printf("BMP390_OUT_SPI_Write: %d" , rslt); return rslt; } void bmp3_delay_us(uint32_t period, void *intf_ptr) { DelayUs(period); } void bmp3_check_rslt(const char api_name[], int8_t rslt) { switch (rslt) { case BMP3_OK: /* Do nothing */ break; case BMP3_E_NULL_PTR: printf("API [%s] Error [%d] : Null pointer\r\n", api_name, rslt); break; case BMP3_E_COMM_FAIL: printf("API [%s] Error [%d] : Communication failure\r\n", api_name, rslt); break; case BMP3_E_INVALID_LEN: printf("API [%s] Error [%d] : Incorrect length parameter\r\n", api_name, rslt); break; case BMP3_E_DEV_NOT_FOUND: printf("API [%s] Error [%d] : Device not found\r\n", api_name, rslt); break; case BMP3_E_CONFIGURATION_ERR: printf("API [%s] Error [%d] : Configuration Error\r\n", api_name, rslt); break; case BMP3_W_SENSOR_NOT_ENABLED: printf("API [%s] Error [%d] : Warning when Sensor not enabled\r\n", api_name, rslt); break; case BMP3_W_INVALID_FIFO_REQ_FRAME_CNT: printf("API [%s] Error [%d] : Warning when Fifo watermark level is not in limit\r\n", api_name, rslt); break; default: printf("API [%s] Error [%d] : Unknown error code\r\n", api_name, rslt); break; } } BMP3_INTF_RET_TYPE BMP390_IN_InterfaceInit(struct bmp3_dev *bmp3, uint8_t intf) { int8_t rslt = BMP3_OK; /* Bus configuration : SPI */ if (intf == BMP3_SPI_INTF) { printf("SPI Interface\n"); bmp3->read = BMP390_IN_SPI_Read; bmp3->write = BMP390_IN_SPI_Write; bmp3->intf = BMP3_SPI_INTF; printf("spi init ok\r\n"); } DelayMs(100); bmp3->delay_us = bmp3_delay_us; bmp3->intf_ptr = &dev_in_addr; return rslt; } BMP3_INTF_RET_TYPE BMP390_OUT_InterfaceInit(struct bmp3_dev *bmp3, uint8_t intf) { int8_t rslt = BMP3_OK; /* Bus configuration : SPI */ if (intf == BMP3_SPI_INTF) { printf("SPI Interface\n"); bmp3->read = BMP390_OUT_SPI_Read; bmp3->write = BMP390_OUT_SPI_Write; bmp3->intf = BMP3_SPI_INTF; printf("spi init ok\r\n"); } DelayMs(100); bmp3->delay_us = bmp3_delay_us; bmp3->intf_ptr = &dev_out_addr; return rslt; } BMP3_INTF_RET_TYPE BMP390_ATOM_InterfaceInit(struct bmp3_dev *bmp3, uint8_t intf) { int8_t rslt = BMP3_OK; /* Bus configuration : SPI */ if (intf == BMP3_SPI_INTF) { printf("SPI Interface\n"); bmp3->read = BMP390_ATOM_SPI_Read; bmp3->write = BMP390_ATOM_SPI_Write; bmp3->intf = BMP3_SPI_INTF; printf("spi init ok\r\n"); } DelayMs(100); bmp3->delay_us = bmp3_delay_us; bmp3->intf_ptr = &dev_atom_addr; return rslt; } void SPI_CsStart(TePressSensorIndex index) { switch (index) { case kPressIn: PRESS_IN_CS_LOW(); break; case kPressOut: PRESS_OUT_CS_LOW(); break; case kPressAtom: PRESS_ATOM_CS_LOW(); break; default: break; } } void SPI_CsStop(TePressSensorIndex index) { switch (index) { case kPressIn: PRESS_IN_CS_HIGH(); break; case kPressOut: PRESS_OUT_CS_HIGH(); break; case kPressAtom: PRESS_ATOM_CS_HIGH(); break; default: break; } } uint8_t SPI0_SendByte(uint8_t data) { R8_SPI0_BUFFER = data; while (!(R8_SPI0_INT_FLAG & RB_SPI_FREE)); return (R8_SPI0_BUFFER); } void PRESS_IO_SPI_Init(void) { /** * CSB1: PA3 * CSB2: PA5 * CSB3: PA0 * SCL: PA13 * SDA: PA14 * SDO: PA15 */ // SDA: MOSI // SDO: MISO GPIOA_SetBits(GPIO_Pin_2); GPIOA_ModeCfg(GPIO_Pin_2, GPIO_ModeOut_PP_5mA); GPIOA_SetBits(GPIO_Pin_8); GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeOut_PP_5mA); GPIOA_SetBits(GPIO_Pin_0); GPIOA_ModeCfg(GPIO_Pin_0, GPIO_ModeOut_PP_5mA); SPI_CsStop(kPressIn); SPI_CsStop(kPressOut); SPI_CsStop(kPressAtom); // spi初始化,模式0 GPIOA_ModeCfg(GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeOut_PP_5mA); GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_PU); SPI0_MasterDefInit(); } void PRESS_LowerIO_Init(void) { // BMP390默认供电时,其他IO都是高电平,INT引脚为低电平 // SPI GPIOA_SetBits(GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15); GPIOA_ModeCfg(GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15, GPIO_ModeIN_PU); // CSB3: PA0 GPIOA_SetBits(GPIO_Pin_2); GPIOA_ModeCfg(GPIO_Pin_2, GPIO_ModeIN_PU); // CSB2: PA5 GPIOA_SetBits(GPIO_Pin_8); GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); // CSB1: PA3 GPIOA_SetBits(GPIO_Pin_0); GPIOA_ModeCfg(GPIO_Pin_0, GPIO_ModeIN_PU); } void Lower_IO_Deinit(void) { // LED GPIOB_ResetBits(LED_VALVE_R_PIN | LED_VALVE_G_PIN); GPIOB_ModeCfg(LED_VALVE_R_PIN | LED_VALVE_G_PIN, GPIO_ModeIN_PD); GPIOA_ResetBits(LED_VBAT_PIN | LED_ALARM_PIN); GPIOA_ModeCfg(LED_VBAT_PIN | LED_ALARM_PIN, GPIO_ModeIN_PD); // KEY | RESET KEY | boot KEY GPIOB_ResetBits(KEY_BPIN); GPIOB_ModeCfg(KEY_BPIN, GPIO_ModeIN_PU); // GPIOB_ResetBits(GPIO_Pin_23 | GPIO_Pin_22); // GPIOB_ModeCfg(GPIO_Pin_23 | GPIO_Pin_22, GPIO_ModeIN_PD); // ADC GPIOA_ResetBits(GPIO_Pin_4); GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_Floating); ADC_DisablePower(); // BMP390 // INT1: PA2 | INT2: PA6 | INT3: PA12 GPIOA_ModeCfg(GPIO_Pin_6 | GPIO_Pin_9 | GPIO_Pin_3, GPIO_ModeIN_PD); // spi初始化 GPIOA_ModeCfg(GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeIN_PD); GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_PD); // 4G // 关闭3.8V供电 GPIOB_ResetBits(ENABLE_3_8_V); GPIOB_ModeCfg(ENABLE_3_8_V, GPIO_ModeIN_PD); // 将控制引脚设为下拉,减少漏电流 GPIOB_ModeCfg(ML307_PWR_PIN | ML307_RST_PIN, GPIO_ModeIN_PD); // UART引脚 GPIOB_ModeCfg(ML307_UART_TX_PIN, GPIO_ModeIN_PD); GPIOB_ModeCfg(ML307_UART_RX_PIN, GPIO_ModeIN_PU); // SIM卡检测引脚配置为下拉输入 GPIOB_ModeCfg(USIM_DECT_PIN, GPIO_ModeIN_PD); // motor // GPIOA_ResetBits(COIL_ADC); // GPIOA_ModeCfg(COIL_ADC, GPIO_ModeIN_PD); // IN1 + ; IN2 + // GPIOB_SetBits(COIL_A); // GPIOB_SetBits(COIL_B); // GPIOB_ModeCfg(COIL_A | COIL_B, GPIO_ModeIN_PD); // UART3 // GPIOB_ModeCfg(GPIO_Pin_21 | GPIO_Pin_20, GPIO_ModeIN_PD); // // 关闭UART3时钟 // sys_safe_access_enable(); // R8_SLP_CLK_OFF0 |= RB_SLP_CLK_UART3; // sys_safe_access_disable(); // // 关闭shell和日志系统 // shell.write = NULL; // 禁用shell输出 // 关闭外部低速晶振 // GPIOA_ModeCfg(GPIO_Pin_10 | GPIO_Pin_11, GPIO_ModeIN_PD); } void PRESS_LowPower(void) { Lower_IO_Deinit(); if (press_done_flag == 1) { PRESS_LowerIO_Init(); } } int8_t ret = 0; uint8_t loop = 0; struct bmp3_dev DevIn; struct bmp3_dev DevOut; struct bmp3_dev DevAtom; uint16_t settings_sel; struct bmp3_data data = {0}; struct bmp3_settings settings = {0}; struct bmp3_status status = {{0}}; // T,P int32_t T[3] = {0}; int32_t P[3] = {0}; // 定义滑动窗口函数 void slideValveRawDataBuffer(TsValveRawData *newData) { // 将数组元素左移一位 for (int i = 0; i < 4; i++) { tmos_memcpy(&ValveRawData_buffer[i], &ValveRawData_buffer[i + 1], sizeof(TsValveRawData)); } // 将新数据存入数组[4] tmos_memcpy(&ValveRawData_buffer[4], &newData[0], sizeof(TsValveRawData)); // for (int i = 0; i < 5; i++) // { // logDebug("Buffer[%d]: in_press=%d, out_press=%d, diff=%d", // i, // ValveRawData_buffer[i].in_press, // ValveRawData_buffer[i].out_press, // ValveRawData_buffer[i].in_out_press_diff); // } } __HIGH_CODE __attribute__((noinline)) uint16_t BMP390_ProcessEvent(uint8_t task_id, uint16_t events) { if (events & BMP390_IN_START) { press_done_flag = 0; PRESS_IO_SPI_Init(); settings.op_mode = BMP3_MODE_FORCED; ret = bmp3_set_op_mode(&settings, &DevIn); bmp3_check_rslt("bmp3_set_op_mode", ret); return (events ^ BMP390_IN_START); } else if (events & BMP390_OUT_START) { press_done_flag = 0; PRESS_IO_SPI_Init(); settings.op_mode = BMP3_MODE_FORCED; ret = bmp3_set_op_mode(&settings, &DevOut); bmp3_check_rslt("bmp3_set_op_mode", ret); return (events ^ BMP390_OUT_START); } else if (events & BMP390_ATOM_START) { press_done_flag = 0; PRESS_IO_SPI_Init(); settings.op_mode = BMP3_MODE_FORCED; ret = bmp3_set_op_mode(&settings, &DevAtom); bmp3_check_rslt("bmp3_set_op_mode", ret); return (events ^ BMP390_ATOM_START); } else if (events & BMP390_EVT_READ) { PRESS_IO_SPI_Init(); #if 0 PRESS_IO_SPI_Init(); // IN ret = bmp3_get_status(&status, &DevIn); bmp3_check_rslt("bmp3_get_status", ret); /* Read temperature and pressure data iteratively based on data ready interrupt */ if ((ret == BMP3_OK) && (status.intr.drdy == BMP3_ENABLE)) { /* * First parameter indicates the type of data to be read * BMP3_PRESS_TEMP : To read pressure and temperature data * BMP3_TEMP : To read only temperature data * BMP3_PRESS : To read only pressure data */ ret = bmp3_get_sensor_data(BMP3_PRESS_TEMP, &data, &DevIn); bmp3_check_rslt("bmp3_get_sensor_data", ret); /* NOTE : Read status register again to clear data ready interrupt status */ ret = bmp3_get_status(&status, &DevIn); bmp3_check_rslt("bmp3_get_status", ret); #ifdef BMP3_FLOAT_COMPENSATION printf("IN[%d] T: %.2f deg C, P: %.2f Pa\n", loop, (data.temperature), (data.pressure)); #else printf("IN[%d] T: %ld deg C, P: %lu Pa\n", loop, (long int)(int32_t)(data.temperature / 100), (long unsigned int)(uint32_t)(data.pressure / 100)); #endif } // OUT ret = bmp3_get_status(&status, &DevOut); bmp3_check_rslt("bmp3_get_status", ret); /* Read temperature and pressure data iteratively based on data ready interrupt */ if ((ret == BMP3_OK) && (status.intr.drdy == BMP3_ENABLE)) { /* * First parameter indicates the type of data to be read * BMP3_PRESS_TEMP : To read pressure and temperature data * BMP3_TEMP : To read only temperature data * BMP3_PRESS : To read only pressure data */ ret = bmp3_get_sensor_data(BMP3_PRESS_TEMP, &data, &DevOut); bmp3_check_rslt("bmp3_get_sensor_data", ret); /* NOTE : Read status register again to clear data ready interrupt status */ ret = bmp3_get_status(&status, &DevOut); bmp3_check_rslt("bmp3_get_status", ret); #ifdef BMP3_FLOAT_COMPENSATION printf("OUT[%d] T: %.2f deg C, P: %.2f Pa\n", loop, (data.temperature), (data.pressure)); #else printf("OUT[%d] T: %ld deg C, P: %lu Pa\n", loop, (long int)(int32_t)(data.temperature / 100), (long unsigned int)(uint32_t)(data.pressure / 100)); #endif loop = loop + 1; } tmos_start_task(press_task_id, WF5803_EVT_START, MS1_TO_SYSTEM_TIME(2000)); #endif if (flag == 1) { ret = bmp3_get_status(&status, &DevIn); // 配置中断引脚为锁存模式,需要读取int_status.drdy位才能清除中断状态标志 bmp3_check_rslt("bmp3_get_status", ret); if (status.intr.drdy == BMP3_ENABLE) { /* * First parameter indicates the type of data to be read * BMP3_PRESS_TEMP : To read pressure and temperature data * BMP3_TEMP : To read only temperature data * BMP3_PRESS : To read only pressure data */ ret = bmp3_get_sensor_data(BMP3_PRESS_TEMP, &data, &DevIn); bmp3_check_rslt("bmp3_get_sensor_data", ret); /* NOTE : Read status register again to clear data ready interrupt status */ ret = bmp3_get_status(&status, &DevIn); bmp3_check_rslt("bmp3_get_status", ret); // printf("IN[%d] T: %ld deg C, P: %lu Pa\r\n", loop, (long int)(int32_t)(data.temperature / 100), // (long unsigned int)(uint32_t)(data.pressure / 100)); T[0] = (int32_t)(data.temperature / 100); P[0] = (uint32_t)(data.pressure / 100); } // tmos_start_task(press_task_id, BMP390_ATOM_START, MS1_TO_SYSTEM_TIME(100)); tmos_start_task(press_task_id, BMP390_OUT_START, MS1_TO_SYSTEM_TIME(500)); // 100 // tmos_start_task(press_task_id, BMP390_IN_START, MS1_TO_SYSTEM_TIME(1000)); } else if (flag == 2) { ret = bmp3_get_status(&status, &DevOut); // 配置中断引脚为锁存模式,需要读取int_status.drdy位才能清除中断状态标志 bmp3_check_rslt("bmp3_get_status", ret); if (status.intr.drdy == BMP3_ENABLE) { /* * First parameter indicates the type of data to be read * BMP3_PRESS_TEMP : To read pressure and temperature data * BMP3_TEMP : To read only temperature data * BMP3_PRESS : To read only pressure data */ ret = bmp3_get_sensor_data(BMP3_PRESS_TEMP, &data, &DevOut); bmp3_check_rslt("bmp3_get_sensor_data", ret); /* NOTE : Read status register again to clear data ready interrupt status */ ret = bmp3_get_status(&status, &DevOut); bmp3_check_rslt("bmp3_get_status", ret); // printf("OUT[%d] T: %ld deg C, P: %lu Pa\r\n", loop, (long int)(int32_t)(data.temperature / 100), // (long unsigned int)(uint32_t)(data.pressure / 100)); T[1] = (int32_t)(data.temperature / 100); P[1] = (uint32_t)(data.pressure / 100); } tmos_start_task(press_task_id, BMP390_ATOM_START, MS1_TO_SYSTEM_TIME(500)); // 100 // tmos_start_task(press_task_id, BMP390_OUT_START, MS1_TO_SYSTEM_TIME(1000)); } else if (flag == 3) { ret = bmp3_get_status(&status, &DevAtom); // 配置中断引脚为锁存模式,需要读取int_status.drdy位才能清除中断状态标志 bmp3_check_rslt("bmp3_get_status", ret); if (status.intr.drdy == BMP3_ENABLE) { /* * First parameter indicates the type of data to be read * BMP3_PRESS_TEMP : To read pressure and temperature data * BMP3_TEMP : To read only temperature data * BMP3_PRESS : To read only pressure data */ ret = bmp3_get_sensor_data(BMP3_PRESS_TEMP, &data, &DevAtom); bmp3_check_rslt("bmp3_get_sensor_data", ret); /* NOTE : Read status register again to clear data ready interrupt status */ ret = bmp3_get_status(&status, &DevAtom); bmp3_check_rslt("bmp3_get_status", ret); // printf("ATOM[%d] T: %ld deg C, P: %lu Pa\r\n", loop, (long int)(int32_t)(data.temperature / 100), // (long unsigned int)(uint32_t)(data.pressure / 100)); T[2] = (int32_t)(data.temperature / 100); P[2] = (uint32_t)(data.pressure / 100); logDebug("**********************************"); logDebug("%d, %d, %d, %d, %d, %d \r\n", T[0], T[1], T[2], P[0], P[1], P[2]); logDebug("P1: %d,P2: %d ,^P: %d \r\n", P[0] - P[2], P[1] - P[2], P[0] - P[1]); logDebug("**********************************"); } tmos_start_task(press_task_id, BMP390_IN_START, MS1_TO_SYSTEM_TIME(500)); // 100 // tmos_start_task(press_task_id, BMP390_ATOM_START, MS1_TO_SYSTEM_TIME(1000)); } flag = 0; press_done_flag = 1; // TODO:读完三个气压传感器数据后在做计算 ValveRawData.in_press_raw = P[0]; ValveRawData.out_press_raw = P[1]; ValveRawData.atom_press = P[2]; ValveRawData.in_temp = T[0]; ValveRawData.out_temp = T[1]; ValveRawData.atom_temp = T[2]; ValveRawData.in_press = ValveRawData.in_press_raw - ValveRawData.atom_press; ValveRawData.out_press = ValveRawData.out_press_raw - ValveRawData.atom_press; ValveRawData.in_out_press_diff = ValveRawData.in_press - ValveRawData.out_press; logDebug("in_press: %d, out_press: %d, atom_press: %d\r\n", ValveRawData.in_press, ValveRawData.out_press, ValveRawData.atom_press); logDebug("in_temp: %d, out_temp: %d, atom_temp: %d\r\n", ValveRawData.in_temp, ValveRawData.out_temp, ValveRawData.atom_temp); logDebug("in_out_press_diff: %d\r\n", ValveRawData.in_out_press_diff); // 刷新ValveRawData_buffer,把之前的ValveRawData按时间顺序向右滑动 // ,最新的ValveRawData 存在数组[4] slideValveRawDataBuffer(&ValveRawData); loop = loop + 1; return (events ^ BMP390_EVT_READ); } return 0; } void VALVE_SetInfo() { ValveInfo.over_press = 6200; ValveInfo.low_press = 800; ValveInfo.over_temp = 65; ValveInfo.over_flow_press_diff_1kpa = 500; ValveInfo.over_flow_press_diff_2kpa = 500; ValveInfo.over_flow_press_diff_3kpa = 500; } void BSP_PRESS_Init(void) { PRESS_IO_SPI_Init(); // 中断引脚的配置 GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeIN_PD); GPIOA_ITModeCfg(GPIO_Pin_9, GPIO_ITMode_RiseEdge); GPIOA_ModeCfg(GPIO_Pin_3, GPIO_ModeIN_PD); GPIOA_ITModeCfg(GPIO_Pin_3, GPIO_ITMode_RiseEdge); GPIOA_ModeCfg(GPIO_Pin_6, GPIO_ModeIN_PD); GPIOA_ITModeCfg(GPIO_Pin_6, GPIO_ITMode_RiseEdge); PWR_PeriphWakeUpCfg(ENABLE, RB_GPIO_WAKE_MODE | RB_SLP_GPIO_WAKE, Long_Delay); PFIC_EnableIRQ(GPIO_A_IRQn); // IN ret = BMP390_IN_InterfaceInit(&DevIn, BMP3_SPI_INTF); bmp3_check_rslt("BMP390_OUT_InterfaceInit", ret); ret = bmp3_init(&DevIn); bmp3_check_rslt("bmp3_init", ret); settings.int_settings.drdy_en = BMP3_ENABLE; settings.int_settings.latch = BMP3_INT_PIN_LATCH; settings.int_settings.level = BMP3_INT_PIN_ACTIVE_HIGH; settings.int_settings.output_mode = BMP3_INT_PIN_PUSH_PULL; settings.press_en = BMP3_ENABLE; settings.temp_en = BMP3_ENABLE; settings.odr_filter.press_os = BMP3_OVERSAMPLING_2X; // BMP3_OVERSAMPLING_2X settings.odr_filter.temp_os = BMP3_OVERSAMPLING_2X; // BMP3_OVERSAMPLING_2X settings.odr_filter.odr = BMP3_ODR_0_39_HZ; // BMP3_ODR_1_5_HZ settings.odr_filter.iir_filter = BMP3_IIR_FILTER_COEFF_1; // BMP3_IIR_FILTER_COEFF_3 settings_sel = BMP3_SEL_PRESS_EN | BMP3_SEL_TEMP_EN | BMP3_SEL_PRESS_OS | BMP3_SEL_TEMP_OS | BMP3_SEL_ODR | BMP3_SEL_DRDY_EN | BMP3_SEL_IIR_FILTER | BMP3_SEL_OUTPUT_MODE | BMP3_SEL_LEVEL | BMP3_SEL_LATCH; ret = bmp3_set_sensor_settings(settings_sel, &settings, &DevIn); bmp3_check_rslt("bmp3_set_sensor_settings", ret); // OUT ret = BMP390_OUT_InterfaceInit(&DevOut, BMP3_SPI_INTF); bmp3_check_rslt("BMP390_OUT_InterfaceInit", ret); ret = bmp3_init(&DevOut); bmp3_check_rslt("bmp3_init", ret); settings.int_settings.drdy_en = BMP3_ENABLE; settings.int_settings.latch = BMP3_INT_PIN_LATCH; settings.int_settings.level = BMP3_INT_PIN_ACTIVE_HIGH; settings.int_settings.output_mode = BMP3_INT_PIN_PUSH_PULL; settings.press_en = BMP3_ENABLE; settings.temp_en = BMP3_ENABLE; settings.odr_filter.press_os = BMP3_OVERSAMPLING_2X; settings.odr_filter.temp_os = BMP3_OVERSAMPLING_2X; settings.odr_filter.odr = BMP3_ODR_0_39_HZ; settings.odr_filter.iir_filter = BMP3_IIR_FILTER_COEFF_1; settings_sel = BMP3_SEL_PRESS_EN | BMP3_SEL_TEMP_EN | BMP3_SEL_PRESS_OS | BMP3_SEL_TEMP_OS | BMP3_SEL_ODR | BMP3_SEL_DRDY_EN | BMP3_SEL_IIR_FILTER | BMP3_SEL_OUTPUT_MODE | BMP3_SEL_LEVEL | BMP3_SEL_LATCH; ret = bmp3_set_sensor_settings(settings_sel, &settings, &DevOut); bmp3_check_rslt("bmp3_set_sensor_settings", ret); // ATOM ret = BMP390_ATOM_InterfaceInit(&DevAtom, BMP3_SPI_INTF); bmp3_check_rslt("BMP390_ATOM_InterfaceInit", ret); ret = bmp3_init(&DevAtom); bmp3_check_rslt("bmp3_init", ret); settings.int_settings.drdy_en = BMP3_ENABLE; settings.int_settings.latch = BMP3_INT_PIN_LATCH; settings.int_settings.level = BMP3_INT_PIN_ACTIVE_HIGH; settings.int_settings.output_mode = BMP3_INT_PIN_PUSH_PULL; settings.press_en = BMP3_ENABLE; settings.temp_en = BMP3_ENABLE; settings.odr_filter.press_os = BMP3_OVERSAMPLING_2X; settings.odr_filter.temp_os = BMP3_OVERSAMPLING_2X; settings.odr_filter.odr = BMP3_ODR_0_39_HZ; settings.odr_filter.iir_filter = BMP3_IIR_FILTER_COEFF_1; settings_sel = BMP3_SEL_PRESS_EN | BMP3_SEL_TEMP_EN | BMP3_SEL_PRESS_OS | BMP3_SEL_TEMP_OS | BMP3_SEL_ODR | BMP3_SEL_DRDY_EN | BMP3_SEL_IIR_FILTER | BMP3_SEL_OUTPUT_MODE | BMP3_SEL_LEVEL | BMP3_SEL_LATCH; ret = bmp3_set_sensor_settings(settings_sel, &settings, &DevAtom); bmp3_check_rslt("bmp3_set_sensor_settings", ret); press_task_id = TMOS_ProcessEventRegister(BMP390_ProcessEvent); tmos_set_event(press_task_id, BMP390_IN_START); // tmos_set_event(press_task_id, BMP390_OUT_START); // tmos_set_event(press_task_id, BMP390_ATOM_START); VALVE_SetInfo(); } /** * @brief 判断参考值是否在测量值的误差范围内 * * @param ref_value 参考值 * @param measured_value 测量值 * @param tolerance 误差范围(正负) * * @return uint8_t 返回 1 表示在范围内,返回 0 表示不在范围内 */ uint8_t isWithinTolerance(int32_t ref_value, int32_t measured_value, uint8_t tolerance) { if ((measured_value - tolerance <= ref_value) && (ref_value <= measured_value + tolerance)) { return 1; // 在范围内 } else { return 0; // 不在范围内 } } /** * @brief 检测管道是否无流量状态 * * @return uint8_t 返回1表示无流量,返回0表示有流量 */ uint8_t isNoFlowDetected(void) { // 检测进出口压差是否在无流量阈值范围内 (0±2Pa) if (ValveRawData.in_out_press_diff >= -AUTO_CLOSE_NO_FLOW_THRESHOLD && ValveRawData.in_out_press_diff <= AUTO_CLOSE_NO_FLOW_THRESHOLD) { logDebug("No flow detected: pressure diff = %d Pa", ValveRawData.in_out_press_diff); return 1; // 无流量 } logDebug("Flow detected: pressure diff = %d Pa", ValveRawData.in_out_press_diff); return 0; // 有流量 } /** * @brief 启动延时关阀功能 */ void startAutoCloseTimer(void) { if (!valve_safety.auto_close_enabled) { valve_safety.auto_close_enabled = 1; valve_safety.auto_close_active = 1; valve_safety.auto_close_check_count = 0; valve_safety.auto_close_start_time = BSP_Get_Tick(); logDebug("Auto close timer started"); // 开始第一次检测,延时5分钟 tmos_start_task(check_task_id, AUTO_CLOSE_CHECK_EVT, MS1_TO_SYSTEM_TIME(AUTO_CLOSE_CHECK_INTERVAL_MS)); // 设置35分钟超时保护(30分钟+5分钟误差容限) tmos_start_task(check_task_id, AUTO_CLOSE_TIMEOUT_EVT, MS1_TO_SYSTEM_TIME(35 * 60 * 1000)); } } /** * @brief 停止延时关阀功能 */ void stopAutoCloseTimer(void) { if (valve_safety.auto_close_enabled) { valve_safety.auto_close_enabled = 0; valve_safety.auto_close_active = 0; valve_safety.auto_close_check_count = 0; // 停止定时器 tmos_stop_task(check_task_id, AUTO_CLOSE_CHECK_EVT); tmos_stop_task(check_task_id, AUTO_CLOSE_TIMEOUT_EVT); logDebug("Auto close timer stopped"); } } uint16_t Check_ProcessEvent(uint8_t task_id, uint16_t events) { if (events & CHECK_EVT_START) { // logDebug("fault_state = %d \r\n",fault_state); if (!fault_state) { // TODO:状态切换不对 if (gValveData.switch_status == kOpened) { // 延时关阀功能启动条件检测 // 只在未启动延时关阀时检测无流量状态,一旦启动就交给定时检测处理 if (!valve_safety.auto_close_enabled) { if (isNoFlowDetected()) { startAutoCloseTimer(); logDebug("延时关阀启动:检测到无流量状态"); } } // 超压检测 // 后端关阀,进气端压力超过阈值6200关阀 // 流量0.45时候,进气端压力超过阈值6200关阀 if (ValveRawData.in_press >= ValveInfo.over_press) { logError("******************************"); logError("超压关阀"); logDebug("in_press = %d; over_press = %d", ValveRawData.in_press, ValveInfo.over_press); VALVE_CLOSE(); fault_state = 1; // 超压关阀时停止延时关阀功能 stopAutoCloseTimer(); tmos_start_task(check_task_id, MOTOR_STOP_EVT, MS1_TO_SYSTEM_TIME(CHARGE_TIME_MS)); } // 欠压检测 // else if (ValveRawData.in_press <= ValveInfo.low_press) // { // VALVE_CLOSE(); // fault_state = 2; // // 欠压关阀时停止延时关阀功能 // stopAutoCloseTimer(); // tmos_start_task(check_task_id, MOTOR_STOP_EVT, MS1_TO_SYSTEM_TIME(CHARGE_TIME_MS)); // logError("******************************"); // logError("欠压关阀"); // } #if 1 // 1、过流自动关闭: // 进气端压力2kpa时,额定流量调到0.9 // 进气端压力升到 3kpa左右时,阀门不能关,流量不超过1.4 // 3、进气端压力 1kpa左右时,出气端阀口全开,需要关闭(过流自动关闭) // if (isWithinTolerance(1000, ValveRawData.in_press, 50) // && ValveRawData.in_out_press_diff) // { // /* code */ // } // 进气端压力2kpa时,额定流量调到1.4(切断流量)要关阀 if (ValveRawData.in_out_press_diff >= ValveInfo.over_flow_press_diff_2kpa) { if (keydown_flag > 0) { logDebug("keydown_time !%d", keydown_time); keydown_time++; if (keydown_time > 25) { keydown_time = 0; keydown_flag = 0; } } else { keydown_time = 0; VALVE_CLOSE(); logError("******************************"); fault_state = 3; tmos_start_task(check_task_id, MOTOR_STOP_EVT, MS1_TO_SYSTEM_TIME(CHARGE_TIME_MS)); logDebug("Over current status !"); } } #endif } else if (gValveData.switch_status == kClosed) { // 阀门关闭时停止延时关阀功能 if (valve_safety.auto_close_enabled) { stopAutoCloseTimer(); } // 点火开阀 // 监测ValveRawData_buffer,当前最新的压差值大于上一秒的压差 if (isWithinTolerance(ValveRawData_buffer[2].in_press, ValveRawData_buffer[4].in_press, 50) && ValveRawData_buffer[4].in_out_press_diff >= 900) { logError("******************************"); logError("点火开阀"); for (int i = 2; i < 5; i++) { logDebug("[%d]: in_press = %d; out_press = %d; in_out_press_diff = %d", i, ValveRawData_buffer[i].in_press, ValveRawData_buffer[i].out_press, ValveRawData_buffer[i].in_out_press_diff); } VALVE_OPEN(); tmos_start_task(check_task_id, MOTOR_STOP_EVT, MS1_TO_SYSTEM_TIME(CHARGE_TIME_MS)); } // else // { // logDebug("点火开阀失败"); // for (int i = 2; i < 5; i++) // { // logDebug("[%d]: in_press = %d; out_press = %d; in_out_press_diff = %d", i // , ValveRawData_buffer[i].in_press, ValveRawData_buffer[i].out_press, ValveRawData_buffer[i].in_out_press_diff); // } // } } // 超温关阀功能:检测至少两个传感器的温度超过阈值 if (!valve_safety.over_temp_flag && gValveData.switch_status == kOpened) { // 计算超过阈值的传感器数量 uint8_t over_temp_count = 0; // 检查三个传感器的温度是否超过阈值 if (T[0] > SAFETY_OVER_TEMP_THRESHOLD) over_temp_count++; if (T[1] > SAFETY_OVER_TEMP_THRESHOLD) over_temp_count++; if (T[2] > SAFETY_OVER_TEMP_THRESHOLD) over_temp_count++; // 如果至少有两个传感器超过阈值,触发关阀 if (over_temp_count >= 2) { logDebug("Over temperature detected! T1=%d, T2=%d, T3=%d", T[0], T[1], T[2]); valve_safety.over_temp_flag = 1; motor_flag = 2; // 触发关阀 } } } // logDebug("motor_flag_end = %d",motor_flag); // 手动关阀 if (motor_flag == 1) { motor_flag = 0; LED_VALVE_OPEN; VALVE_OPEN(); keydown_flag = 1; IotFlag_t.Valve_Open_flag = 1; fault_state = 0; logDebug("motor/LED open!!!"); tmos_start_task(check_task_id, MOTOR_STOP_EVT, MS1_TO_SYSTEM_TIME(CHARGE_TIME_MS)); } else if (motor_flag == 2) { motor_flag = 0; LED_VALVE_CLOSE; VALVE_CLOSE(); // fault_state = 4; // 微泄漏关阀后重置标志 if (valve_safety.micro_leak_flag) { valve_safety.micro_leak_flag = 0; logDebug("Micro leak protection activated"); } // 超温关阀后重置标志 if (valve_safety.over_temp_flag) { valve_safety.over_temp_flag = 0; logDebug("Over temperature protection activated"); } logDebug("motor/LED close!!!"); tmos_start_task(check_task_id, MOTOR_STOP_EVT, MS1_TO_SYSTEM_TIME(CHARGE_TIME_MS)); } else if (motor_flag == 3) { motor_flag = 0; if (gValveData.switch_status == kOpened) { LED_VALVE_OPEN; } else { LED_VALVE_CLOSE; } // DelayMs(500); } tmos_start_task(check_task_id, CHECK_EVT_START, MS1_TO_SYSTEM_TIME(200)); // 100 return (events ^ CHECK_EVT_START); } if (events & MOTOR_STOP_EVT) { VALVE_STOP(); logDebug("motor STOP"); // DelayMs(1500); // if(fault_state == 4) // { // IotFlag_t.Valve_Close_flag = 1; // Iot_Send_Data(); // } return (events ^ MOTOR_STOP_EVT); } // 延时关阀检测事件处理 if (events & AUTO_CLOSE_CHECK_EVT) { if (valve_safety.auto_close_enabled && valve_safety.auto_close_active) { valve_safety.auto_close_check_count++; logDebug("延时关阀第%d次检测 (共需6次)", valve_safety.auto_close_check_count); // 检测当前是否仍为无流量状态 if (isNoFlowDetected()) { logDebug("第%d次检测确认无流量 (in_out_press_diff=%d Pa)", valve_safety.auto_close_check_count, ValveRawData.in_out_press_diff); // 如果已经检测了6次(30分钟),执行关阀 if (valve_safety.auto_close_check_count >= AUTO_CLOSE_CHECK_COUNT) { logError("******************************"); logError("延时关阀:30分钟无流量,自动关闭阀门"); logError("6次检测均确认无流量,总耗时: %d ms", BSP_Get_Tick() - valve_safety.auto_close_start_time); // 执行关阀动作 motor_flag = 2; // 触发关阀 // 停止延时关阀功能 stopAutoCloseTimer(); } else { // 继续下一次检测,再等5分钟 logDebug("第%d次检测完成,5分钟后进行第%d次检测", valve_safety.auto_close_check_count, valve_safety.auto_close_check_count + 1); tmos_start_task(check_task_id, AUTO_CLOSE_CHECK_EVT, MS1_TO_SYSTEM_TIME(AUTO_CLOSE_CHECK_INTERVAL_MS)); } } else { // 检测到有流量,停止延时关阀 logDebug("第%d次检测发现有流量 (in_out_press_diff=%d Pa),停止延时关阀", valve_safety.auto_close_check_count, ValveRawData.in_out_press_diff); stopAutoCloseTimer(); } } return (events ^ AUTO_CLOSE_CHECK_EVT); } // 延时关阀超时事件处理(备用安全机制) if (events & AUTO_CLOSE_TIMEOUT_EVT) { if (valve_safety.auto_close_enabled) { logError("******************************"); logError("延时关阀:超时保护,强制关闭阀门"); // 强制执行关阀动作 motor_flag = 2; // 触发关阀 // 停止延时关阀功能 stopAutoCloseTimer(); } return (events ^ AUTO_CLOSE_TIMEOUT_EVT); } return 0; } void Function_Check(void) { check_task_id = TMOS_ProcessEventRegister(Check_ProcessEvent); tmos_set_event(check_task_id, CHECK_EVT_START); } __INTERRUPT __HIGH_CODE void GPIOA_IRQHandler(void) { if (R16_PA_INT_IF & GPIO_Pin_9) { R16_PA_INT_IF = GPIO_Pin_9; flag = 1; tmos_set_event(press_task_id, BMP390_EVT_READ); } else if (R16_PA_INT_IF & GPIO_Pin_3) { R16_PA_INT_IF = GPIO_Pin_3; flag = 2; tmos_set_event(press_task_id, BMP390_EVT_READ); } else if (R16_PA_INT_IF & GPIO_Pin_6) { R16_PA_INT_IF = GPIO_Pin_6; flag = 3; tmos_set_event(press_task_id, BMP390_EVT_READ); } }