This commit is contained in:
2026-02-24 09:58:06 +08:00
parent fb4e311fbe
commit 9d69b29eed
161 changed files with 20379 additions and 7340 deletions
+159
View File
@@ -0,0 +1,159 @@
#include "app.h"
#include "app_timer.h"
#include "app_leakage.h"
#include "stdio.h"
#include "string.h"
#include "bsp_Uart.h"
#include "bsp_Wdg.h"
#include "bsp_Led.h"
#include "bsp_Flash.h"
#include "bsp_W5500.h"
#include "bsp_w25q.h"
#include "bsp_DS1302.h"
#include "bsp_relay.h"
#include "bsp_buzzer.h"
#include "proto_modbus_master_leakage.h"
#include "proto_modbus_slave_ex.h"
#include "gui_tjc_hmi.h"
const char *HwVersion = "V1.0";
char SwVersion[24] = "V0.001.0";
void task_idle(void);
void task_10ms(void);
void task_50ms(void);
void task_100ms(void);
void task_200ms(void);
void task_500ms(void);
void task_1s(void);
void task_2s(void);
#define APP_TIMER_TASK_NUM (sizeof(app_timer_task) / sizeof(app_timer_class_t))
/*定义任务*/
app_timer_class_t app_timer_task[] =
{
{0, 1, 1, task_idle }, /*空闲任务一直执行*/
{0, 3, 10, task_10ms },
{0, 7, 50, task_50ms },
{0, 11, 100, task_100ms },
{0, 13, 200, task_200ms },
{0, 17, 500, task_500ms },
{0, 19, 1000, task_1s },
{0, 23, 2000, task_2s },
};
/******************************************
* 函数: AppInit
* 功能: 初始化
* 参数: 无
* 返回: 无
* 描述: 无
******************************************/
void app_init(void)
{
/*flash*/
Usr_Flash.Init();
/*串口初始化*/
com_uart1.init(&com_uart1);
com_uart2.init(&com_uart2);
com_uart3.init(&com_uart3);
com_uart4.init(&com_uart4);
com_uart6.init(&com_uart6);
/*网口*/
W5500.Init();
/*屏幕通讯*/
tjc_hmi.init();
/*modbus协议*/
modbus_slave_ex.init();
/*子系统*/
modbus_leakage[APP_COM1].init(&modbus_leakage[APP_COM1]);
modbus_leakage[APP_COM2].init(&modbus_leakage[APP_COM2]);
modbus_leakage[APP_COM3].init(&modbus_leakage[APP_COM3]);
modbus_leakage[APP_COM4].init(&modbus_leakage[APP_COM4]);
/*外设通讯*/
DS1302.Init();
relay.init();
buzzer.init();
led.init();
/*分时复用,时间片轮询*/
app_timer.init(APP_TIMER_TASK_NUM,app_timer_task);
//Wdg.Init();
}
/******************************************
* 函数: App_task
* 功能: 分时复用
* 参数: 无
* 返回: 无
* 描述: 主循环中调用
******************************************/
void app_task(void)
{
app_timer.task();
task_idle();
W5500.Task();
}
/*空闲执行的函数*/
void task_idle(void)
{
com_uart1.rx_task(&com_uart1);
com_uart2.rx_task(&com_uart2);
com_uart3.rx_task(&com_uart3);
com_uart4.rx_task(&com_uart4);
com_uart6.rx_task(&com_uart6);
}
void task_10ms(void)
{
}
void task_50ms(void)
{
}
void task_100ms(void)
{
}
void task_200ms(void)
{
}
void task_500ms(void)
{
led.task();
//tdlas.tx_task();
}
void task_1s(void)
{
leakage.task();
DS1302.Task();
buzzer.task();
relay.task();
}
void task_2s(void)
{
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef _APP_H_
#define _APP_H_
extern const char *HwVersion;
extern char SwVersion[24];
void app_init(void);
void app_task(void);
#endif
+355
View File
@@ -0,0 +1,355 @@
#include "app_alarm.h"
#include <string.h>
#include "bsp_w25q.h"
static void history_clear_all(void);
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record);
static void history_init(void);
static void history_save_metadata(void);
app_leakage_t leakage =
{
.region_num = 0,
.sub_device_num = 0,
.init = NULL,
.task = app_leakage_task
};
app_leakage_t *p_leakage = &leakage;
app_hitory_t history =
{
.read_history = history_read_record,
.clean_history = history_clear_all,
.init_history = history_init
};
/*区域分类,将同一区域名的设备划分到一起*/
void app_leakage_region_classify(void)
{
u16 i,j;
u8 add_region_flag;
/*数量及相关数据清零*/
p_leakage->region_num = 0;
p_leakage->sub_device_num = 0;
memset(p_leakage->region_data,0,sizeof(p_leakage->region_data));
/*遍历子系统*/
for(i=0;i<APP_LEAKAGE_SUB_DEVICE_NUM;i++)
{
add_region_flag = 1; /*添加新区域*/
/*设备使能*/
if(ENABLE == p_leakage->sub_device_data[i].flash_data.state)
{
p_leakage->sub_device_num++;/*子系统总数量++*/
/*遍历区域*/
for(j=0;j<APP_LEAKAGE_SUB_DEVICE_NUM;j++)
{
if(0 == memcmp(p_leakage->region_data[j].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN))/*名称相同*/
{
/*添加子设备*/
p_leakage->region_data[j].sub_device_index[p_leakage->region_data[j].leakage_num] = i;/*绑定子设备索引*/
p_leakage->region_data[j].sub_device_num++; /*区域中子系统数据++*/
add_region_flag = 0;/*不添加新区域*/
break;
}
}
/*没有找到相同名称*/
if(add_region_flag)/*添加新区域*/
{
/*复制名称*/
memcpy(p_leakage->region_data[p_leakage->region_num].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN);
p_leakage->region_data[p_leakage->region_num].sub_device_index[p_leakage->region_data[p_leakage->region_num].leakage_num] = i;/*绑定子设备索引*/
p_leakage->region_data[p_leakage->region_num].sub_device_num++; /*区域中子系统数据++*/
p_leakage->region_num++; /*区域数量++*/
}
}
}
}
/*异常状态设备数量统计*/
void app_leakage_task(void)
{
static u16 prev_ch_state[APP_LEAKAGE_SUB_DEVICE_NUM][APP_LEAKAGE_SUB_DEVICE_CH_NUM] = {0};
u16 i, j, k, sub_device_index;
static u8 initialized = 0;
/* 初始化历史模块 */
if(!initialized)
{
history.init_history();
initialized = 1;
}
/* 初始化区域异常统计 */
for(i = 0; i < p_leakage->region_num; i++)
{
p_leakage->region_data[i].leakage_num = 0;
p_leakage->region_data[i].open_num = 0;
p_leakage->region_data[i].time_out_num = 0;
}
/* 检测状态变化并统计异常数量 */
for(i = 0; i < p_leakage->region_num; i++)
{
for(j = 0; j < p_leakage->region_data[i].sub_device_num; j++)
{
sub_device_index = p_leakage->region_data[i].sub_device_index[j];
/* 检查设备是否启用 */
if(p_leakage->sub_device_data[sub_device_index].flash_data.state != ENABLE)
{
continue;
}
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
{
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
u16 prev_state = prev_ch_state[sub_device_index][k];
u16 leak_distance = p_leakage->sub_device_data[sub_device_index].ch_data[k].distance;
/* 检测状态变化并记录历史报警 */
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE))
{
/* 漏液报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE, leak_distance);
}
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN))
{
/* 断带报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_OPEN, 0);
}
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT))
{
/* 通讯超时报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT, 0);
}
/* 更新历史状态 */
prev_ch_state[sub_device_index][k] = current_state;
}
/* 统计区域异常设备数量 - 按设备统计 */
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
{
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT)
{
p_leakage->region_data[i].time_out_num++;
continue; /* 通讯超时,设备已离线,不再检查其他异常 */
}
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN)
{
p_leakage->region_data[i].open_num++;
}
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE)
{
p_leakage->region_data[i].leakage_num++;
}
}
}
}
}
/* 获取当前时间 */
static void get_current_time(u8 *time_buffer)
{
// RTC_TimeTypeDef sTime;
// RTC_DateTypeDef sDate;
//
// /* 获取RTC时间 */
// HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
// HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
//
// /* 年: 2字节 (例如: 2024 -> 0x07 0xE8) */
// uint16_t year = 2000 + sDate.Year; /* RTC年份通常从2000开始 */
// time_buffer[0] = (year >> 8) & 0xFF; /* 高字节 */
// time_buffer[1] = year & 0xFF; /* 低字节 */
// time_buffer[2] = sDate.Month; /* 月 */
// time_buffer[3] = sDate.Date; /* 日 */
// time_buffer[4] = sTime.Hours; /* 时 */
// time_buffer[5] = sTime.Minutes; /* 分 */
}
/* 从Flash读取历史报警元数据 */
static void history_read_metadata(void)
{
app_leakage_history_metadata_t temp_metadata;
w25q32.read(W25Q32_HISTORY_ALARM_METADATA_ADDR,
(uint8_t*)&temp_metadata,
sizeof(app_leakage_history_metadata_t));
if(temp_metadata.total_records <= temp_metadata.max_records &&
temp_metadata.write_index < temp_metadata.max_records)
{
/* 数据有效,复制到全局变量 */
memcpy(&leakage.history_metadata, &temp_metadata, sizeof(app_leakage_history_metadata_t));
}
else
{
/* 数据无效,初始化 */
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
/* 保存到Flash */
history_save_metadata();
}
}
/* 保存历史报警元数据到Flash */
static void history_save_metadata(void)
{
/* 擦除元数据扇区 */
w25q32_sector_erase(W25Q32_HISTORY_ALARM_METADATA_ADDR);
/* 写入元数据 */
w25q32.write(W25Q32_HISTORY_ALARM_METADATA_ADDR,
(uint8_t*)&leakage.history_metadata,
sizeof(app_leakage_history_metadata_t));
}
/* 计算记录在Flash中的地址 */
static uint32_t history_calc_record_addr(u32 record_index)
{
return W25Q32_HISTORY_ALARM_DATA_ADDR +
(record_index * HISTORY_ALARM_RECORD_SIZE);
}
/* 获取记录所在的扇区地址 */
static uint32_t history_calc_sector_addr(u32 record_index)
{
uint32_t record_addr = history_calc_record_addr(record_index);
return record_addr & ~(W25Q32_SECTOR_SIZE - 1); /* 4K对齐 */
}
/* 添加历史报警记录 */
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance)
{
app_leakage_history_alarm_t new_alarm;
uint32_t write_addr;
/* 填充报警记录 */
memset(&new_alarm, 0, sizeof(app_leakage_history_alarm_t));
/* 区域名 */
if(region_idx < leakage.region_num)
{
memcpy(new_alarm.region_name, leakage.region_data[region_idx].name,
APP_LEAKAGE_STRING_NANE_LEN);
}
/* 设备ID和名称 */
if(device_idx < APP_LEAKAGE_SUB_DEVICE_NUM)
{
new_alarm.device_id = leakage.sub_device_data[device_idx].flash_data.modbus_id;
memcpy(new_alarm.device_name, leakage.sub_device_data[device_idx].flash_data.device_name,
APP_LEAKAGE_STRING_NANE_LEN);
}
/* 报警类型、通道和漏液距离 */
new_alarm.alarm_type = alarm_type;
new_alarm.channel = channel;
new_alarm.leak_distance = leak_distance;
/* 开始时间 */
get_current_time(new_alarm.start_time);
/* 计算写入地址 */
write_addr = history_calc_record_addr(leakage.history_metadata.write_index);
/* 检查是否需要擦除新扇区 */
uint32_t current_sector = history_calc_sector_addr(leakage.history_metadata.write_index);
uint32_t prev_sector = history_calc_sector_addr(
(leakage.history_metadata.write_index == 0) ?
leakage.history_metadata.max_records - 1 :
leakage.history_metadata.write_index - 1);
/* 如果切换到新扇区,需要擦除 */
if(current_sector != prev_sector)
{
w25q32_sector_erase(current_sector);
}
/* 写入记录 */
w25q32.write(write_addr, (uint8_t*)&new_alarm, HISTORY_ALARM_RECORD_SIZE);
/* 更新元数据 */
leakage.history_metadata.write_index++;
if(leakage.history_metadata.write_index >= leakage.history_metadata.max_records)
{
leakage.history_metadata.write_index = 0;
}
if(leakage.history_metadata.total_records < leakage.history_metadata.max_records)
{
leakage.history_metadata.total_records++;
}
/* 保存元数据 */
history_save_metadata();
}
/* 读取历史报警记录 */
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record)
{
if(record_index >= leakage.history_metadata.total_records)
{
return 0; /* 记录索引无效 */
}
/* 计算实际存储索引(考虑循环队列) */
uint32_t actual_index;
if(leakage.history_metadata.total_records == leakage.history_metadata.max_records)
{
/* 缓冲区已满,计算相对索引 */
actual_index = (leakage.history_metadata.write_index + record_index) %
leakage.history_metadata.max_records;
}
else
{
/* 缓冲区未满,直接读取 */
actual_index = record_index;
}
uint32_t read_addr = history_calc_record_addr(actual_index);
w25q32.read(read_addr, (uint8_t*)record, HISTORY_ALARM_RECORD_SIZE);
return 1;
}
/* 清空所有历史报警记录 */
static void history_clear_all(void)
{
/* 重置元数据 */
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
/* 保存元数据 */
history_save_metadata();
/* 擦除所有数据扇区(可选) */
for(uint32_t i = 0; i < HISTORY_ALARM_SECTORS_NEEDED; i++)
{
uint32_t sector_addr = W25Q32_HISTORY_ALARM_DATA_ADDR + i * W25Q32_SECTOR_SIZE;
w25q32_sector_erase(sector_addr);
}
}
/* 初始化历史报警模块 */
static void history_init(void)
{
/* 读取元数据 */
history_read_metadata();
}
+99
View File
@@ -0,0 +1,99 @@
#ifndef _APP_ALARM_H_
#define _APP_ALARM_H_
#include "main.h"
#define ENABLE (1)
#define DISABLE (0)
#define APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE (0x0001) /*漏液状态*/
#define APP_LEAKAGE_SUB_DEVICE_STATE_OPEN (0x0002) /*断带状态*/
#define APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT (0xf000) /*通讯超时*/
#define APP_LEAKAGE_STRING_NANE_LEN (10)
#define APP_LEAKAGE_SUB_DEVICE_NUM (32)
#define APP_LEAKAGE_SUB_DEVICE_CH_NUM (4)
void app_leakage_task(void);
void app_leakage_region_classify(void);
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance);
/*子设备存储的参数*/
typedef struct
{
u8 state; /*状态 使能 非使能*/
u8 com_port; /*端口*/
u8 modbus_id; /*modbus id*/
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /*设备名*/
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名*/
}app_leakage_sub_device_flash_data_t;
/*子设备信息*/
typedef struct
{
app_leakage_sub_device_flash_data_t flash_data; /*flash存储数据*/
struct
{
u16 state; /*状态*/
u16 distance; /*漏液距离*/
}ch_data[APP_LEAKAGE_SUB_DEVICE_CH_NUM]; /*通道数据*/
u8 heartbeat; /*心跳包,0-59循环*/
u8 test_mode; /*测试模式,0=正常,1-4=测试对应通道*/
}app_leakage_sub_device_class_t;
/*区域信息*/
typedef struct
{
u8 leakage_num; /*漏液数量*/
u8 open_num; /*断带数量*/
u8 time_out_num; /*通讯超时数量*/
u8 sub_device_num; /*设备总数量*/
u8 name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名称*/
u8 sub_device_index[APP_LEAKAGE_SUB_DEVICE_NUM]; /*设备的索引*/
}app_leakage_region_data_class_t;
/* 历史报警记录结构 */
typedef struct
{
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 区域名 */
u8 device_id; /* 设备ID */
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 设备名称 */
u16 alarm_type; /* 报警类型 */
u8 start_time[6]; /* 开始时间: 年(2字节)月日时分 */
u16 leak_distance; /* 漏液距离 (0表示非漏液报警) */
u8 channel; /* 通道号 (0-3) */
} app_leakage_history_alarm_t;
/* 历史报警管理结构 */
typedef struct
{
u32 total_records; /* 总记录数 */
u32 write_index; /* 写指针 */
u32 read_index; /* 读指针 */
u32 max_records; /* 最大记录数 */
} app_leakage_history_metadata_t;
typedef struct
{
u8 region_num;
u8 sub_device_num;
app_leakage_region_data_class_t region_data[APP_LEAKAGE_SUB_DEVICE_NUM];
app_leakage_sub_device_class_t sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM];
app_leakage_history_metadata_t history_metadata;
void (*init)(void); /*初始化*/
void (*task)(void); /*执行任务*/
}app_leakage_t;
typedef struct
{
u8 (*read_history)(u32, app_leakage_history_alarm_t *);
void (*clean_history)(void);
void (*init_history)(void);
}app_hitory_t;
extern app_hitory_t history;
#endif
+77
View File
@@ -0,0 +1,77 @@
#include "app_com.h"
#include "app_leakage.h"
#include "proto_modbus_master_leakage.h"
/*com口对应的串口*/
bsp_uart_t *com_to_uart[APP_COM_NUM] =
{
&com_uart4,
&com_uart2,
&com_uart3,
&com_uart1,
};
static void app_com_uart_baud_rate_set(app_com_class_t * p_com,u16 baud_rate);
static void app_com_class_update(void );
static void app_com_init(app_com_class_t * p_com);
app_com_t app_com=
{
};
static void app_com_init(app_com_class_t * p_com)
{
if(p_com == &app_com.com[APP_COM1])
p_com->com_uart = com_to_uart[APP_COM1];
else if(p_com == &app_com.com[APP_COM2])
p_com->com_uart = com_to_uart[APP_COM2];
else if(p_com == &app_com.com[APP_COM3])
p_com->com_uart = com_to_uart[APP_COM3];
else if(p_com == &app_com.com[APP_COM4])
p_com->com_uart = com_to_uart[APP_COM4];
}
/*串口配置*/
static void app_com_uart_baud_rate_set(app_com_class_t * p_com,u16 baud_rate)
{
p_com->com_uart->set.baud_rate(p_com->com_uart,baud_rate);
}
/*将同一com口的设备进行划分*/
static void app_com_class_update(void )
{
u16 i,j;
u8 com_index,id;
/********************************************总数清零******************************************************/
for(i=0;i<APP_COM_NUM;i++)
{
modbus_leakage[i].sensor_num = 0;
}
/*遍历子系统*/
for(i=0;i<APP_LEAKAGE_SUB_DEVICE_NUM;i++)
{
/*设备使能*/
if(ENABLE == leakage.sub_device_data[i].flash_data.state)
{
/********************************************COM口划分******************************************************/
com_index = leakage.sub_device_data[i].flash_data.com;
id = leakage.sub_device_data[i].flash_data.modbus_id;
/*绑定modbus id*/
modbus_leakage[com_index].sensor[modbus_leakage[com_index].sensor_num].comm.id = id;
/*绑定子设备索引索引*/
modbus_leakage[com_index].sensor[modbus_leakage[com_index].sensor_num].comm.leakage_data_index = i;
/*comm口设备总数++*/
modbus_leakage[com_index].sensor_num++;
}
}
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef _APP_COM_H_
#define _APP_COM_H_
#include "main.h"
#include "app_leakage.h"
#include "bsp_uart.h"
#define APP_COM_NUM (4)
#define APP_COM1 (0)
#define APP_COM2 (1)
#define APP_COM3 (2)
#define APP_COM4 (3)
typedef struct
{
u8 baudrate; /*波特率*/
}app_com_flash_data_t;
typedef struct app_com_class_t app_com_class_t;
struct app_com_class_t
{
app_com_flash_data_t flash_data; /*flash数据*/
bsp_uart_t *com_uart; /*绑定的实际物理串口*/
struct
{
void (*baud_rate)(app_com_class_t *,u16); /*设置波特率*/
}set;
void (*init)(app_com_class_t *); /*初始化*/
};
typedef struct
{
app_com_class_t com[APP_COM_NUM];
void (*class_update)(void ); /*com区域分类*/
}app_com_t;
extern app_com_t app_com;
extern bsp_uart_t *com_to_uart[APP_COM_NUM];
#endif
+359
View File
@@ -0,0 +1,359 @@
#include "app_leakage.h"
#include <string.h>
#include "bsp_w25q.h"
static void history_clear_all(void);
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record);
static void history_init(void);
static void history_save_metadata(void);
app_leakage_t leakage =
{
.region_num = 0,
.sub_device_num = 0,
.init = NULL,
.task = app_leakage_task
};
app_leakage_t *p_leakage = &leakage;
app_hitory_t history =
{
.read_history = history_read_record,
.clean_history = history_clear_all,
.init_history = history_init
};
/*区域分类,将同一区域名的设备划分到一起*/
void app_leakage_region_classify(void)
{
u16 i,j;
u8 add_region_flag;
/*数量及相关数据清零*/
p_leakage->region_num = 0;
p_leakage->sub_device_num = 0;
memset(p_leakage->region_data,0,sizeof(p_leakage->region_data));
/*遍历子系统*/
for(i=0;i<APP_LEAKAGE_SUB_DEVICE_NUM;i++)
{
add_region_flag = 1; /*添加新区域*/
/*设备使能*/
if(ENABLE == p_leakage->sub_device_data[i].flash_data.state)
{
p_leakage->sub_device_num++;/*子系统总数量++*/
/********************************************区域划分******************************************************/
/*遍历区域*/
for(j=0;j<APP_LEAKAGE_SUB_DEVICE_NUM;j++)
{
if(0 == memcmp(p_leakage->region_data[j].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN))/*名称相同*/
{
/*添加子设备*/
p_leakage->region_data[j].sub_device_index[p_leakage->region_data[j].leakage_num] = i;/*绑定子设备索引*/
p_leakage->region_data[j].sub_device_num++; /*区域中子系统数据++*/
add_region_flag = 0;/*不添加新区域*/
break;
}
}
/*没有找到相同名称*/
if(add_region_flag)/*添加新区域*/
{
/*复制名称*/
memcpy(p_leakage->region_data[p_leakage->region_num].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN);
p_leakage->region_data[p_leakage->region_num].sub_device_index[p_leakage->region_data[p_leakage->region_num].leakage_num] = i;/*绑定子设备索引*/
p_leakage->region_data[p_leakage->region_num].sub_device_num++; /*区域中子系统数据++*/
p_leakage->region_num++; /*区域数量++*/
}
}
}
}
/*异常状态设备数量统计*/
void app_leakage_task(void)
{
static u16 prev_ch_state[APP_LEAKAGE_SUB_DEVICE_NUM][APP_LEAKAGE_SUB_DEVICE_CH_NUM] = {0};
u16 i, j, k, sub_device_index;
static u8 initialized = 0;
/* 初始化历史模块 */
if(!initialized)
{
history.init_history();
initialized = 1;
}
/* 初始化区域异常统计 */
for(i = 0; i < p_leakage->region_num; i++)
{
p_leakage->region_data[i].leakage_num = 0;
p_leakage->region_data[i].open_num = 0;
p_leakage->region_data[i].time_out_num = 0;
}
/* 检测状态变化并统计异常数量 */
for(i = 0; i < p_leakage->region_num; i++)
{
for(j = 0; j < p_leakage->region_data[i].sub_device_num; j++)
{
sub_device_index = p_leakage->region_data[i].sub_device_index[j];
/* 检查设备是否启用 */
if(p_leakage->sub_device_data[sub_device_index].flash_data.state != ENABLE)
{
continue;
}
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
{
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
u16 prev_state = prev_ch_state[sub_device_index][k];
u16 leak_distance = p_leakage->sub_device_data[sub_device_index].ch_data[k].distance;
/* 检测状态变化并记录历史报警 */
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE))
{
/* 漏液报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE, leak_distance);
}
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN))
{
/* 断带报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_OPEN, 0);
}
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT))
{
/* 通讯超时报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT, 0);
}
/* 更新历史状态 */
prev_ch_state[sub_device_index][k] = current_state;
}
/* 统计区域异常设备数量 - 按设备统计 */
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
{
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT)
{
p_leakage->region_data[i].time_out_num++;
continue; /* 通讯超时,设备已离线,不再检查其他异常 */
}
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN)
{
p_leakage->region_data[i].open_num++;
}
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE)
{
p_leakage->region_data[i].leakage_num++;
}
}
}
}
}
/* 获取当前时间 */
static void get_current_time(u8 *time_buffer)
{
// RTC_TimeTypeDef sTime;
// RTC_DateTypeDef sDate;
//
// /* 获取RTC时间 */
// HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
// HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
//
// /* 年: 2字节 (例如: 2024 -> 0x07 0xE8) */
// uint16_t year = 2000 + sDate.Year; /* RTC年份通常从2000开始 */
// time_buffer[0] = (year >> 8) & 0xFF; /* 高字节 */
// time_buffer[1] = year & 0xFF; /* 低字节 */
// time_buffer[2] = sDate.Month; /* 月 */
// time_buffer[3] = sDate.Date; /* 日 */
// time_buffer[4] = sTime.Hours; /* 时 */
// time_buffer[5] = sTime.Minutes; /* 分 */
}
/* 从Flash读取历史报警元数据 */
static void history_read_metadata(void)
{
app_leakage_history_metadata_t temp_metadata;
w25q32.read(W25Q32_HISTORY_ALARM_METADATA_ADDR,
(uint8_t*)&temp_metadata,
sizeof(app_leakage_history_metadata_t));
if(temp_metadata.total_records <= temp_metadata.max_records &&
temp_metadata.write_index < temp_metadata.max_records)
{
/* 数据有效,复制到全局变量 */
memcpy(&leakage.history_metadata, &temp_metadata, sizeof(app_leakage_history_metadata_t));
}
else
{
/* 数据无效,初始化 */
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
/* 保存到Flash */
history_save_metadata();
}
}
/* 保存历史报警元数据到Flash */
static void history_save_metadata(void)
{
/* 擦除元数据扇区 */
w25q32_sector_erase(W25Q32_HISTORY_ALARM_METADATA_ADDR);
/* 写入元数据 */
w25q32.write(W25Q32_HISTORY_ALARM_METADATA_ADDR,
(uint8_t*)&leakage.history_metadata,
sizeof(app_leakage_history_metadata_t));
}
/* 计算记录在Flash中的地址 */
static uint32_t history_calc_record_addr(u32 record_index)
{
return W25Q32_HISTORY_ALARM_DATA_ADDR +
(record_index * HISTORY_ALARM_RECORD_SIZE);
}
/* 获取记录所在的扇区地址 */
static uint32_t history_calc_sector_addr(u32 record_index)
{
uint32_t record_addr = history_calc_record_addr(record_index);
return record_addr & ~(W25Q32_SECTOR_SIZE - 1); /* 4K对齐 */
}
/* 添加历史报警记录 */
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance)
{
app_leakage_history_alarm_t new_alarm;
uint32_t write_addr;
/* 填充报警记录 */
memset(&new_alarm, 0, sizeof(app_leakage_history_alarm_t));
/* 区域名 */
if(region_idx < leakage.region_num)
{
memcpy(new_alarm.region_name, leakage.region_data[region_idx].name,
APP_LEAKAGE_STRING_NANE_LEN);
}
/* 设备ID和名称 */
if(device_idx < APP_LEAKAGE_SUB_DEVICE_NUM)
{
new_alarm.device_id = leakage.sub_device_data[device_idx].flash_data.modbus_id;
memcpy(new_alarm.device_name, leakage.sub_device_data[device_idx].flash_data.device_name,
APP_LEAKAGE_STRING_NANE_LEN);
}
/* 报警类型、通道和漏液距离 */
new_alarm.alarm_type = alarm_type;
new_alarm.channel = channel;
new_alarm.leak_distance = leak_distance;
/* 开始时间 */
get_current_time(new_alarm.start_time);
/* 计算写入地址 */
write_addr = history_calc_record_addr(leakage.history_metadata.write_index);
/* 检查是否需要擦除新扇区 */
uint32_t current_sector = history_calc_sector_addr(leakage.history_metadata.write_index);
uint32_t prev_sector = history_calc_sector_addr(
(leakage.history_metadata.write_index == 0) ?
leakage.history_metadata.max_records - 1 :
leakage.history_metadata.write_index - 1);
/* 如果切换到新扇区,需要擦除 */
if(current_sector != prev_sector)
{
w25q32_sector_erase(current_sector);
}
/* 写入记录 */
w25q32.write(write_addr, (uint8_t*)&new_alarm, HISTORY_ALARM_RECORD_SIZE);
/* 更新元数据 */
leakage.history_metadata.write_index++;
if(leakage.history_metadata.write_index >= leakage.history_metadata.max_records)
{
leakage.history_metadata.write_index = 0;
}
if(leakage.history_metadata.total_records < leakage.history_metadata.max_records)
{
leakage.history_metadata.total_records++;
}
/* 保存元数据 */
history_save_metadata();
}
/* 读取历史报警记录 */
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record)
{
if(record_index >= leakage.history_metadata.total_records)
{
return 0; /* 记录索引无效 */
}
/* 计算实际存储索引(考虑循环队列) */
uint32_t actual_index;
if(leakage.history_metadata.total_records == leakage.history_metadata.max_records)
{
/* 缓冲区已满,计算相对索引 */
actual_index = (leakage.history_metadata.write_index + record_index) %
leakage.history_metadata.max_records;
}
else
{
/* 缓冲区未满,直接读取 */
actual_index = record_index;
}
uint32_t read_addr = history_calc_record_addr(actual_index);
w25q32.read(read_addr, (uint8_t*)record, HISTORY_ALARM_RECORD_SIZE);
return 1;
}
/* 清空所有历史报警记录 */
static void history_clear_all(void)
{
/* 重置元数据 */
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
/* 保存元数据 */
history_save_metadata();
/* 擦除所有数据扇区(可选) */
for(uint32_t i = 0; i < HISTORY_ALARM_SECTORS_NEEDED; i++)
{
uint32_t sector_addr = W25Q32_HISTORY_ALARM_DATA_ADDR + i * W25Q32_SECTOR_SIZE;
w25q32_sector_erase(sector_addr);
}
}
/* 初始化历史报警模块 */
static void history_init(void)
{
/* 读取元数据 */
history_read_metadata();
}
+100
View File
@@ -0,0 +1,100 @@
#ifndef _APP_LEAKAGE_H_
#define _APP_LEAKAGE_H_
#include "main.h"
#define ENABLE (1)
#define DISABLE (0)
#define APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE (0x0001) /*漏液状态*/
#define APP_LEAKAGE_SUB_DEVICE_STATE_OPEN (0x0002) /*断带状态*/
#define APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT (0xf000) /*通讯超时*/
#define APP_LEAKAGE_STRING_NANE_LEN (10)
#define APP_LEAKAGE_SUB_DEVICE_NUM (32)
#define APP_LEAKAGE_SUB_DEVICE_CH_NUM (4)
void app_leakage_task(void);
void app_leakage_region_classify(void);
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance);
/*子设备存储的参数*/
typedef struct
{
u8 state; /*状态 使能 非使能*/
u8 com; /*端口*/
u8 modbus_id; /*modbus id*/
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /*设备名*/
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名*/
}app_leakage_sub_device_flash_data_t;
/*子设备信息*/
typedef struct
{
app_leakage_sub_device_flash_data_t flash_data; /*flash存储数据*/
struct
{
u16 state; /*状态*/
u16 distance; /*漏液距离*/
}ch_data[APP_LEAKAGE_SUB_DEVICE_CH_NUM]; /*通道数据*/
u8 heartbeat; /*心跳包,0-59循环*/
u8 test_mode; /*测试模式,0=正常,1-4=测试对应通道*/
}app_leakage_sub_device_class_t;
/*区域信息*/
typedef struct
{
u8 leakage_num; /*漏液数量*/
u8 open_num; /*断带数量*/
u8 time_out_num; /*通讯超时数量*/
u8 sub_device_num; /*设备总数量*/
u8 name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名称*/
u8 sub_device_index[APP_LEAKAGE_SUB_DEVICE_NUM]; /*设备的索引*/
}app_leakage_region_data_class_t;
/* 历史报警记录结构 */
typedef struct
{
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 区域名 */
u8 device_id; /* 设备ID */
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 设备名称 */
u16 alarm_type; /* 报警类型 */
u8 start_time[6]; /* 开始时间: 年(2字节)月日时分 */
u16 leak_distance; /* 漏液距离 (0表示非漏液报警) */
u8 channel; /* 通道号 (0-3) */
} app_leakage_history_alarm_t;
/* 历史报警管理结构 */
typedef struct
{
u32 total_records; /* 总记录数 */
u32 write_index; /* 写指针 */
u32 read_index; /* 读指针 */
u32 max_records; /* 最大记录数 */
} app_leakage_history_metadata_t;
typedef struct
{
u8 region_num;
u8 sub_device_num;
app_leakage_region_data_class_t region_data[APP_LEAKAGE_SUB_DEVICE_NUM];
app_leakage_sub_device_class_t sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM];
app_leakage_history_metadata_t history_metadata;
void (*init)(void); /*初始化*/
void (*task)(void); /*执行任务*/
}app_leakage_t;
typedef struct
{
u8 (*read_history)(u32, app_leakage_history_alarm_t *);
void (*clean_history)(void);
void (*init_history)(void);
}app_hitory_t;
extern app_leakage_t leakage;
extern app_hitory_t history;
#endif
+195
View File
@@ -0,0 +1,195 @@
#include "app_timer.h"
#include "app.h"
/* 函数声明 */
static void app_timer_task(void);
static void app_timer_init(u8 task_num, app_timer_class_t *p_timer_class);
static void app_timer_task_increment_int(u16 ms_tick);
/******************************************
* 结构体: app_timer
* 功能: 应用定时器实例
* 描述: 定时器控制结构体的具体实例
*******************************************/
app_timer_t app_timer =
{
.p_timer_class = NULL,
.init = app_timer_init,
.task = app_timer_task,
.increment_int = app_timer_task_increment_int,
};
/* 全局指针,指向定时器结构体 */
app_timer_t *p_app_timer = &app_timer;
/******************************************
* 函数: app_timer_init
* 功能: 定时器初始化
* 参数: task_num - 任务数量
* p_timer_class - 任务时间片数组指针
* 返回: 无
* 描述: 初始化定时器,设置任务数量和任务数组
*******************************************/
static void app_timer_init(u8 task_num, app_timer_class_t *p_timer_class)
{
p_app_timer->task_num = task_num;
p_app_timer->p_timer_class = p_timer_class;
}
/******************************************
* 函数: app_timer_task
* 功能: 定时器任务调度
* 参数: 无
* 返回: 无
* 描述: 执行所有已到时间的任务
*******************************************/
static void app_timer_task(void)
{
u16 i;
/* 检查任务数组是否有效 */
if(NULL == p_app_timer->p_timer_class)
{
return;
}
/* 遍历所有任务 */
for (i = 0; i < p_app_timer->task_num; i++)
{
/* 检查任务是否需要执行 */
if (p_app_timer->p_timer_class[i].run_flag)
{
p_app_timer->p_timer_class[i].run_flag = 0; /* 清除执行标志 */
/* 检查任务函数是否有效 */
if (p_app_timer->p_timer_class[i].task == NULL)
{
continue;
}
/* 执行任务函数 */
p_app_timer->p_timer_class[i].task();
}
}
}
/******************************************
* 函数: app_timer_task_increment_int
* 功能: 中断递增函数
* 参数: ms_tick - 毫秒增量
* 返回: 无
* 描述: 在中断中调用,更新定时器计数器和检查任务时间片
*******************************************/
static void app_timer_task_increment_int(u16 ms_tick)
{
u16 i;
/* 更新毫秒级计数器 */
p_app_timer->ms_tick++;
/* 更新秒级计数器 */
if(p_app_timer->ms_tick >= 1000)
{
p_app_timer->s_tick++;
}
/* 检查任务数组是否有效 */
if(NULL == p_app_timer->p_timer_class)
{
return;
}
/* 更新所有任务的时间片计数器 */
for (i = 0; i < p_app_timer->task_num; i++)
{
/* 检查任务计数器是否有效 */
if (p_app_timer->p_timer_class[i].timer_count)
{
p_app_timer->p_timer_class[i].timer_count--;
/* 检查是否到达任务执行时间 */
if (p_app_timer->p_timer_class[i].timer_count == 0)
{
p_app_timer->p_timer_class[i].run_flag = 1;
p_app_timer->p_timer_class[i].timer_count = p_app_timer->p_timer_class[i].timer_reload;
}
}
}
}
/******************************************
* 函数: app_timer_check_time_out
* 功能: 检查超时
* 参数: time_start - 计时开始时间
* time_now - 当前时间
* time_out - 超时时间
* 返回: TIME_TRUE - 已超时,TIME_FALSE - 未超时
* 描述: 检查从time_start开始经过time_out时间后是否超时,
* 考虑了计数器溢出的情况
*******************************************/
u8 app_timer_check_time_out(u16 time_start, u16 time_now, u16 time_out)
{
u16 timer_activate_val;
/* 计算触发时间 */
timer_activate_val = time_out + time_start;
/* 考虑计数器溢出情况 */
if (timer_activate_val > time_start)
{
/* 未发生溢出 */
if ((time_now >= timer_activate_val) || (time_now < time_start))
{
return TIME_TRUE;
}
}
else if ((time_now >= timer_activate_val) && (time_now < time_start))
{
/* 发生溢出且当前时间在溢出后 */
return TIME_TRUE;
}
return TIME_FALSE;
}
/******************************************
* 函数: app_timer_check_run_time
* 功能: 计算剩余运行时间
* 参数: time_start - 计时开始时间
* time_now - 当前时间
* time_out - 超时时间
* 返回: 剩余时间(毫秒)
* 描述: 配合app_timer_check_time_out函数使用,
* 计算距离超时还有多少时间,考虑了计数器溢出
*******************************************/
u16 app_timer_check_run_time(u16 time_start, u16 time_now, u16 time_out)
{
u16 timer_activate_val;
/* 计算触发时间 */
timer_activate_val = time_out + time_start;
/* 考虑计数器溢出情况 */
if (timer_activate_val > time_start)
{
/* 未发生溢出,直接计算剩余时间 */
return (timer_activate_val - time_now);
}
else
{
/* 发生溢出,计算溢出后的剩余时间 */
return (65535U - time_now + timer_activate_val);
}
}
/******************************************
* 函数: delay_ms
* 功能: 阻塞式延时
* 参数: delay - 延时时间(毫秒)
* 返回: 无
* 描述: 使用HAL库提供的延时函数实现阻塞式延时
*******************************************/
void delay_ms(u16 delay)
{
HAL_Delay(delay);
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef _APP_TIMER_H_
#define _APP_TIMER_H_
#include "main.h"
/* 时间相关宏定义 */
#define TIME_TRUE 1U /* 时间已到 */
#define TIME_FALSE 0U /* 时间未到 */
/******************************************
* 结构体: app_timer_class_t
* 功能: 任务时间片结构体
* 描述: 定义单个任务的时间片调度参数
*******************************************/
typedef struct
{
u8 run_flag; /* 调度标志,1:调度,0:挂起 */
u16 timer_count; /* 时间片计数值 */
u16 timer_reload; /* 时间片重载值 */
void (*task)(void); /* 任务函数指针 */
} app_timer_class_t;
/******************************************
* 结构体: app_timer_t
* 功能: 应用定时器结构体
* 描述: 管理所有任务的定时调度
*******************************************/
typedef struct
{
u16 ms_tick; /* 滴答毫秒级计数器 */
u16 s_tick; /* 滴答秒级计数器 */
u16 task_num; /* 任务数量 */
app_timer_class_t *p_timer_class; /* 任务时间片数组指针 */
void (*init)(u8, app_timer_class_t *); /* 初始化函数指针 */
void (*task)(void); /* 定时器任务函数指针 */
void (*increment_int)(u16); /* 中断递增函数指针 */
} app_timer_t;
/* 函数声明 */
u8 app_timer_check_time_out(u16 time_start, u16 time_now, u16 time_out);
u16 app_timer_check_run_time(u16 time_start, u16 time_now, u16 time_out);
void delay_ms(u16 delay);
/* 声明外部变量 */
extern app_timer_t app_timer;
#endif
+4
View File
@@ -0,0 +1,4 @@
#include "gas_data.h"
gas_data_t gas_data[SENSOR_NUM];
+38
View File
@@ -0,0 +1,38 @@
#ifndef _GAS_DATA_H__
#define _GAS_DATA_H__
#include "main.h"
#define SENSOR_NUM 16
typedef struct
{
u8 ver[20]; /*软件版本号*/
u8 sn[20]; /*SN号*/
u16 range; /*量程*/
s16 value; /*浓度*/
u16 pp_ad; /*峰峰值*/
u16 r_pp_ad; /*原始峰峰值*/
u16 pp_pix; /*峰峰值坐标*/
u16 light_ad; /*光功率*/
u16 tec_set_value; /*tec设定值*/
u16 tec_temp; /*tec温度*/
s16 temp; /*环境温度*/
u16 light_ad_max; /*波形最大值*/
u16 light_ad_min; /*波形最小值*/
u16 state_code; /*状态码*/
u16 dc_offset; /*直流偏置*/
//u16 ad_befor_multiple; /*AD前放大倍数*/
u16 demod_multiple; /*锁相放大倍数*/
//u16 mode; /*模式状态*/
s16 calib_temp; /*标定时的温度*/
u16 calib_press; /*标定时的压力*/
u16 calib_humidity; /*标定时的湿度*/
u16 fac_calib_code_h;
u16 fac_calib_code_l; /*厂家标定时的状态码*/
u16 reserve[1]; /*预留*/
}gas_data_t;
extern gas_data_t gas_data[SENSOR_NUM];
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef _USR_CONFIG_H_
#define _USR_CONFIG_H_
#define USR_TRUE (1U)
#define USR_FALSE (0U)
#define USR_ENABLE (1U)
#define USR_DISABLE (0U)
#define USR_ON (1U)
#define USR_OFF (0U)
#endif