IoT_SCV_CH584M/bsp/src/bsp_bmp390.c

1238 lines
42 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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