✨ feat(config): 新增运行时配置管理功能
- 新增配置管理器模块,支持从SD卡加载运行时配置 - 将数据输出模式从编译时宏改为运行时配置,提高灵活性 - 新增配置文件 `CONFIG.TXT`,支持串口输出和存储功能的动态开关 - 集成配置管理器到主程序,在系统启动时自动加载配置 - 更新数据存储模块,使用配置管理器管理会话序号 🐛 fix(usart): 修复USART3中断配置并优化波特率 - 添加USART3中断处理函数声明和实现 - 将USART3波特率从921600提升至2000000以提高通信速率 - 调整USART1中断优先级从2改为11,优化中断响应 - 在USART3 MSP初始化和反初始化中添加中断配置 📝 docs(user): 新增功能说明文档 - 新增《配置管理功能说明》文档,详细说明运行时配置的使用方法 - 新增《串口发送监控功能说明》文档,说明新增的串口统计功能 - 文档包含配置项说明、文件格式、使用示例和注意事项 ✨ feat(monitor): 增强系统监控功能 - 在系统监控统计中添加串口发送监控字段(发送次数、字节数、错误数) - 新增串口发送统计报告函数,集成到RS485驱动中 - 优化监控状态保存格式,采用精简格式减少文件写入阻塞时间 - 监控数据现在包含串口统计信息,便于性能分析和故障排查 ♻️ refactor(main): 重构主程序配置处理逻辑 - 移除编译时宏 `DATA_OUTPUT_MODE_UART` 和 `DATA_OUTPUT_MODE_STORAGE` - 使用 `Config_IsUartOutputEnabled()` 和 `Config_IsStorageEnabled()` 函数替代 - 优化数据存储启动逻辑,仅在存储功能启用时开始记录 - 添加配置加载成功/失败的调试输出信息
This commit is contained in:
parent
28b4dc6af1
commit
3c0acaa176
@ -60,6 +60,7 @@ void DMA1_Stream0_IRQHandler(void);
|
||||
void DMA1_Stream3_IRQHandler(void);
|
||||
void TIM2_IRQHandler(void);
|
||||
void USART1_IRQHandler(void);
|
||||
void USART3_IRQHandler(void);
|
||||
void SDIO_IRQHandler(void);
|
||||
void DMA2_Stream0_IRQHandler(void);
|
||||
void DMA2_Stream3_IRQHandler(void);
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
#include "correction.h"
|
||||
#include "data_storage.h"
|
||||
#include "system_monitor.h"
|
||||
#include "config_manager.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
/* USER CODE END Includes */
|
||||
@ -51,10 +52,10 @@
|
||||
#define DEBUG_OUTPUT_INTERVAL_MS 1000 // 调试输出间隔(毫秒)
|
||||
#define MONITOR_SAVE_INTERVAL_MS 10000 // 监控状态保存间隔(毫秒) - 10秒
|
||||
|
||||
// 数据输出模式选择(可以同时启用)
|
||||
#define DATA_OUTPUT_MODE_UART 1 // 0=禁用, 1=启用串口输出数据
|
||||
#define DATA_OUTPUT_MODE_STORAGE 0 // 0=禁用, 1=启用存储到卡
|
||||
// 注意:两个模式可以同时启用,但会增加系统负载
|
||||
// 数据输出模式选择(运行时配置,从SD卡加载)
|
||||
// 注意:DATA_OUTPUT_MODE_UART 和 DATA_OUTPUT_MODE_STORAGE 已改为运行时配置
|
||||
// 使用 Config_IsUartOutputEnabled() 和 Config_IsStorageEnabled() 来检查状态
|
||||
// 配置文件:0:/CONFIG.TXT
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
@ -186,25 +187,24 @@ static void ProcessAdcData(void)
|
||||
|
||||
correction_applied = 1;
|
||||
|
||||
#if DATA_OUTPUT_MODE_UART
|
||||
// 发送校正后的数据包到串口
|
||||
// 发送校正后的数据包到串口(运行时配置)
|
||||
if (Config_IsUartOutputEnabled()) {
|
||||
RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t));
|
||||
#endif
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// 4b. 校正失败或未启用,使用原始数据
|
||||
PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2]);
|
||||
|
||||
#if DATA_OUTPUT_MODE_UART
|
||||
// 发送原始数据包到串口
|
||||
// 发送原始数据包到串口(运行时配置)
|
||||
if (Config_IsUartOutputEnabled()) {
|
||||
RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 存储数据到SD卡 (如果启用记录且缓冲区可用)
|
||||
#if DATA_OUTPUT_MODE_STORAGE
|
||||
if (g_recording_enabled) {
|
||||
// 6. 存储数据到SD卡 (如果启用记录且缓冲区可用,运行时配置)
|
||||
if (Config_IsStorageEnabled() && g_recording_enabled) {
|
||||
if (can_store_data) {
|
||||
if (correction_applied) {
|
||||
// 存储校正后的数据
|
||||
@ -220,7 +220,6 @@ static void ProcessAdcData(void)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 7. 释放已处理的缓冲区
|
||||
LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer());
|
||||
@ -500,6 +499,9 @@ int main(void)
|
||||
// 初始化调试输出
|
||||
DebugOutput_Init();
|
||||
|
||||
// 初始化配置管理器(设置默认值)
|
||||
Config_Init();
|
||||
|
||||
// 初始化RS485通信
|
||||
RS485_Init(&huart1, RS485_DE_RE_PORT, RS485_DE_RE_PIN);
|
||||
|
||||
@ -513,12 +515,21 @@ int main(void)
|
||||
if (!g_usb_connected) {
|
||||
// USB未连接,挂载文件系统用于数据采集
|
||||
if (MountFileSystemForSampling() == HAL_OK) {
|
||||
// 从SD卡加载配置
|
||||
if (Config_Load() == HAL_OK) {
|
||||
DebugOutput_SendString("Config loaded from SD card\r\n");
|
||||
} else {
|
||||
DebugOutput_SendString("Using default config\r\n");
|
||||
}
|
||||
|
||||
// 初始化数据存储
|
||||
if (DataStorage_Init(&g_data_storage) == HAL_OK) {
|
||||
// 开始数据记录
|
||||
// 开始数据记录(如果存储功能已启用)
|
||||
if (Config_IsStorageEnabled()) {
|
||||
StartRecording();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// USB已连接,不进行数据采集
|
||||
DebugOutput_SendString("USB connected at startup - data acquisition disabled\r\n");
|
||||
|
||||
@ -68,6 +68,7 @@ extern DMA_HandleTypeDef hdma_spi3_rx;
|
||||
extern TIM_HandleTypeDef htim2;
|
||||
extern DMA_HandleTypeDef hdma_usart1_tx;
|
||||
extern UART_HandleTypeDef huart1;
|
||||
extern UART_HandleTypeDef huart3;
|
||||
/* USER CODE BEGIN EV */
|
||||
extern SPI_HandleTypeDef hspi1;
|
||||
extern SPI_HandleTypeDef hspi2;
|
||||
@ -283,6 +284,20 @@ void USART1_IRQHandler(void)
|
||||
/* USER CODE END USART1_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles USART3 global interrupt.
|
||||
*/
|
||||
void USART3_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN USART3_IRQn 0 */
|
||||
|
||||
/* USER CODE END USART3_IRQn 0 */
|
||||
HAL_UART_IRQHandler(&huart3);
|
||||
/* USER CODE BEGIN USART3_IRQn 1 */
|
||||
|
||||
/* USER CODE END USART3_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles SDIO global interrupt.
|
||||
*/
|
||||
|
||||
@ -70,7 +70,7 @@ void MX_USART3_UART_Init(void)
|
||||
|
||||
/* USER CODE END USART3_Init 1 */
|
||||
huart3.Instance = USART3;
|
||||
huart3.Init.BaudRate = 921600;
|
||||
huart3.Init.BaudRate = 2000000;
|
||||
huart3.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart3.Init.StopBits = UART_STOPBITS_1;
|
||||
huart3.Init.Parity = UART_PARITY_NONE;
|
||||
@ -131,7 +131,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
|
||||
__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
|
||||
|
||||
/* USART1 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);
|
||||
HAL_NVIC_SetPriority(USART1_IRQn, 11, 0);
|
||||
HAL_NVIC_EnableIRQ(USART1_IRQn);
|
||||
/* USER CODE BEGIN USART1_MspInit 1 */
|
||||
|
||||
@ -157,6 +157,9 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
|
||||
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/* USART3 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART3_IRQn, 15, 0);
|
||||
HAL_NVIC_EnableIRQ(USART3_IRQn);
|
||||
/* USER CODE BEGIN USART3_MspInit 1 */
|
||||
|
||||
/* USER CODE END USART3_MspInit 1 */
|
||||
@ -203,6 +206,8 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);
|
||||
|
||||
/* USART3 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(USART3_IRQn);
|
||||
/* USER CODE BEGIN USART3_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END USART3_MspDeInit 1 */
|
||||
|
||||
@ -183,7 +183,8 @@ NVIC.SDIO_IRQn=true\:9\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.SysTick_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:false
|
||||
NVIC.TIM2_IRQn=true\:3\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.USART1_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.USART1_IRQn=true\:11\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.USART3_IRQn=true\:15\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
PA1.GPIOParameters=GPIO_Label
|
||||
PA1.GPIO_Label=ADC_DRY
|
||||
@ -359,7 +360,7 @@ TIM2.Prescaler=83
|
||||
USART1.BaudRate=2000000
|
||||
USART1.IPParameters=VirtualMode,BaudRate
|
||||
USART1.VirtualMode=VM_ASYNC
|
||||
USART3.BaudRate=921600
|
||||
USART3.BaudRate=2000000
|
||||
USART3.IPParameters=VirtualMode,BaudRate
|
||||
USART3.VirtualMode=VM_ASYNC
|
||||
USB_DEVICE.CLASS_NAME_FS=MSC
|
||||
|
||||
224
User/Config_Manager_Guide.md
Normal file
224
User/Config_Manager_Guide.md
Normal file
@ -0,0 +1,224 @@
|
||||
# 配置管理功能说明
|
||||
|
||||
## 概述
|
||||
将数据输出模式配置从编译时的 `#define` 改为运行时可配置,配置存储在SD卡文件中,系统启动时自动加载。
|
||||
|
||||
## 配置项
|
||||
|
||||
### 1. UART输出使能 (uart_output_enabled)
|
||||
- **功能**: 控制是否通过串口(RS485)发送数据
|
||||
- **默认值**: 1 (启用)
|
||||
- **取值**: 0=禁用, 1=启用
|
||||
|
||||
### 2. 存储使能 (storage_enabled)
|
||||
- **功能**: 控制是否将数据存储到SD卡
|
||||
- **默认值**: 0 (禁用)
|
||||
- **取值**: 0=禁用, 1=启用
|
||||
|
||||
## 配置文件
|
||||
|
||||
### 文件路径
|
||||
```
|
||||
0:/CONFIG.TXT
|
||||
```
|
||||
|
||||
### 文件格式
|
||||
```
|
||||
UART=1
|
||||
STORAGE=0
|
||||
SESSION=0
|
||||
VERSION=65536
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `UART`: 串口输出使能状态 (0或1)
|
||||
- `STORAGE`: SD卡存储使能状态 (0或1)
|
||||
- `SESSION`: 会话序号 (用于数据存储文件夹命名)
|
||||
- `VERSION`: 配置版本号 (用于验证配置兼容性)
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 初始化配置管理器
|
||||
```c
|
||||
// 在main()函数中初始化
|
||||
Config_Init(); // 设置默认配置
|
||||
```
|
||||
|
||||
### 2. 加载配置
|
||||
```c
|
||||
// 在文件系统挂载后加载配置
|
||||
if (Config_Load() == HAL_OK) {
|
||||
// 配置加载成功
|
||||
} else {
|
||||
// 配置加载失败,使用默认值
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 读取配置
|
||||
```c
|
||||
// 检查串口输出是否启用
|
||||
if (Config_IsUartOutputEnabled()) {
|
||||
RS485_SendData(data, size);
|
||||
}
|
||||
|
||||
// 检查存储是否启用
|
||||
if (Config_IsStorageEnabled()) {
|
||||
DataStorage_WriteData(&storage, &packet);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 修改配置
|
||||
```c
|
||||
// 修改串口输出设置
|
||||
Config_SetUartOutput(1); // 启用
|
||||
Config_SetUartOutput(0); // 禁用
|
||||
|
||||
// 修改存储设置
|
||||
Config_SetStorage(1); // 启用
|
||||
Config_SetStorage(0); // 禁用
|
||||
|
||||
// 保存配置到SD卡
|
||||
Config_Save();
|
||||
```
|
||||
|
||||
## 配置文件管理
|
||||
|
||||
### 创建配置文件
|
||||
如果SD卡中不存在配置文件,系统会在首次启动时自动创建,使用默认配置值。
|
||||
|
||||
### 修改配置文件
|
||||
可以通过以下方式修改配置:
|
||||
|
||||
1. **通过USB连接修改**:
|
||||
- 将设备连接到PC
|
||||
- 打开SD卡中的 `CONFIG.TXT` 文件
|
||||
- 修改配置值
|
||||
- 保存文件
|
||||
- 断开USB,重启设备
|
||||
|
||||
2. **通过代码修改**:
|
||||
```c
|
||||
Config_SetUartOutput(1);
|
||||
Config_SetStorage(1);
|
||||
Config_Save(); // 保存到SD卡
|
||||
```
|
||||
|
||||
### 恢复默认配置
|
||||
```c
|
||||
Config_SetDefaults(); // 恢复默认值
|
||||
Config_Save(); // 保存到SD卡
|
||||
```
|
||||
|
||||
## 配置验证
|
||||
|
||||
配置管理器包含以下验证机制:
|
||||
|
||||
1. **版本检查**: 确保配置文件版本与当前软件兼容
|
||||
2. **值范围检查**: 确保配置值在有效范围内 (0或1)
|
||||
3. **校验和验证**: 检测配置数据完整性
|
||||
|
||||
如果验证失败,系统将自动使用默认配置。
|
||||
|
||||
## 与原有代码的对比
|
||||
|
||||
### 原有方式(编译时配置)
|
||||
```c
|
||||
#define DATA_OUTPUT_MODE_UART 1
|
||||
#define DATA_OUTPUT_MODE_STORAGE 0
|
||||
|
||||
#if DATA_OUTPUT_MODE_UART
|
||||
RS485_SendData(data, size);
|
||||
#endif
|
||||
|
||||
#if DATA_OUTPUT_MODE_STORAGE
|
||||
DataStorage_WriteData(&storage, &packet);
|
||||
#endif
|
||||
```
|
||||
|
||||
### 新方式(运行时配置)
|
||||
```c
|
||||
// 配置从SD卡加载
|
||||
if (Config_IsUartOutputEnabled()) {
|
||||
RS485_SendData(data, size);
|
||||
}
|
||||
|
||||
if (Config_IsStorageEnabled()) {
|
||||
DataStorage_WriteData(&storage, &packet);
|
||||
}
|
||||
```
|
||||
|
||||
## 优势
|
||||
|
||||
1. **灵活性**: 无需重新编译即可更改配置
|
||||
2. **便捷性**: 通过修改SD卡文件即可调整系统行为
|
||||
3. **可维护性**: 配置集中管理,易于维护
|
||||
4. **可扩展性**: 易于添加新的配置项
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **文件系统依赖**: 配置加载需要SD卡文件系统正常工作
|
||||
2. **启动顺序**: 必须在文件系统挂载后才能加载配置
|
||||
3. **默认配置**: 如果配置文件不存在或损坏,系统使用默认配置
|
||||
4. **性能影响**: 运行时检查比编译时宏略慢,但影响可忽略
|
||||
|
||||
## 文件修改清单
|
||||
|
||||
1. **User/config_manager.h** - 配置管理器头文件
|
||||
2. **User/config_manager.c** - 配置管理器实现
|
||||
3. **Core/Src/main.c** - 集成配置管理器,替换编译时宏
|
||||
|
||||
## 配置示例
|
||||
|
||||
### 示例1: 仅串口输出
|
||||
```
|
||||
UART=1
|
||||
STORAGE=0
|
||||
SESSION=0
|
||||
VERSION=65536
|
||||
```
|
||||
|
||||
### 示例2: 仅SD卡存储
|
||||
```
|
||||
UART=0
|
||||
STORAGE=1
|
||||
SESSION=5
|
||||
VERSION=65536
|
||||
```
|
||||
|
||||
### 示例3: 同时启用
|
||||
```
|
||||
UART=1
|
||||
STORAGE=1
|
||||
SESSION=10
|
||||
VERSION=65536
|
||||
```
|
||||
|
||||
### 示例4: 全部禁用
|
||||
```
|
||||
UART=0
|
||||
STORAGE=0
|
||||
SESSION=0
|
||||
VERSION=65536
|
||||
```
|
||||
|
||||
## 会话序号管理
|
||||
|
||||
### 会话序号的作用
|
||||
会话序号用于为每次数据采集创建唯一的文件夹。每次系统启动并开始数据存储时,会话序号会自动递增,生成类似 `SESSION_000001`、`SESSION_000002` 的文件夹名称。
|
||||
|
||||
### 会话序号函数
|
||||
```c
|
||||
// 获取当前会话序号
|
||||
uint32_t session_num = Config_GetSessionNumber();
|
||||
|
||||
// 设置会话序号
|
||||
Config_SetSessionNumber(100);
|
||||
|
||||
// 递增会话序号并返回新值
|
||||
uint32_t new_session = Config_IncrementSessionNumber();
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
- 会话序号在 [`DataStorage_CreateSessionFolder()`](User/data_storage.c:413) 中自动递增
|
||||
- 配置文件统一管理,替代了原来的 `PARAM.TXT` 文件
|
||||
- 会话序号会随配置一起保存到 `CONFIG.TXT`
|
||||
107
User/UART_Monitoring_Feature.md
Normal file
107
User/UART_Monitoring_Feature.md
Normal file
@ -0,0 +1,107 @@
|
||||
# 串口发送监控功能说明
|
||||
|
||||
## 概述
|
||||
在系统监控模块中增加了串口(UART/RS485)发送数据的统计功能,用于跟踪通过串口发出的数据量和错误情况。
|
||||
|
||||
## 新增功能
|
||||
|
||||
### 1. 监控统计字段
|
||||
在 `SystemMonitorStats_t` 结构体中新增了三个字段:
|
||||
|
||||
```c
|
||||
// 串口发送监控信息
|
||||
uint32_t uart_tx_count; // 串口发送次数
|
||||
uint32_t uart_tx_bytes; // 串口发送总字节数
|
||||
uint32_t uart_tx_error_count; // 串口发送错误次数
|
||||
```
|
||||
|
||||
### 2. 监控函数
|
||||
|
||||
#### SystemMonitor_ReportUARTTx()
|
||||
```c
|
||||
void SystemMonitor_ReportUARTTx(uint32_t bytes_sent);
|
||||
```
|
||||
- **功能**: 报告成功的串口发送操作
|
||||
- **参数**: `bytes_sent` - 本次发送的字节数
|
||||
- **调用时机**: 在 `RS485_SendData()` 中DMA启动成功后调用
|
||||
|
||||
#### SystemMonitor_ReportUARTTxError()
|
||||
```c
|
||||
void SystemMonitor_ReportUARTTxError(void);
|
||||
```
|
||||
- **功能**: 报告串口发送错误
|
||||
- **调用时机**: 在 `RS485_SendData()` 中DMA启动失败时调用
|
||||
|
||||
### 3. 集成位置
|
||||
|
||||
#### rs485_driver.c
|
||||
在 `RS485_SendData()` 函数中集成了监控调用:
|
||||
- DMA启动成功时,调用 `SystemMonitor_ReportUARTTx(Size)` 记录发送字节数
|
||||
- DMA启动失败时,调用 `SystemMonitor_ReportUARTTxError()` 记录错误
|
||||
|
||||
### 4. 监控数据保存
|
||||
|
||||
监控数据会定期保存到SD卡的 `LOG.TXT` 文件中,采用精简格式以减少阻塞时间:
|
||||
|
||||
```
|
||||
Samples:[样本数] Ovf:[溢出数]
|
||||
SD:Wr=[写入次数] Err=[错误数] Full=[满次数] Bytes=[字节数] Files=[文件数] Drop=[丢弃数]
|
||||
UART:Tx=[发送次数] Bytes=[字节数] Err=[错误数]
|
||||
```
|
||||
|
||||
**示例输出**:
|
||||
```
|
||||
Samples:1000000 Ovf:5
|
||||
SD:Wr=500 Err=2 Full=3 Bytes=32000000 Files=10 Drop=15
|
||||
UART:Tx=250 Bytes=12500 Err=1
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 获取串口统计信息
|
||||
```c
|
||||
SystemMonitorStats_t stats;
|
||||
SystemMonitor_GetStats(&stats);
|
||||
|
||||
// 访问串口统计数据
|
||||
uint32_t tx_count = stats.uart_tx_count;
|
||||
uint32_t tx_bytes = stats.uart_tx_bytes;
|
||||
uint32_t tx_errors = stats.uart_tx_error_count;
|
||||
```
|
||||
|
||||
### 计算发送速率
|
||||
```c
|
||||
// 假设运行时间为 runtime_seconds 秒
|
||||
float bytes_per_second = (float)stats.uart_tx_bytes / runtime_seconds;
|
||||
float packets_per_second = (float)stats.uart_tx_count / runtime_seconds;
|
||||
```
|
||||
|
||||
## 文件修改清单
|
||||
|
||||
1. **User/system_monitor.h**
|
||||
- 在 `SystemMonitorStats_t` 结构体中添加串口统计字段
|
||||
- 声明 `SystemMonitor_ReportUARTTx()` 和 `SystemMonitor_ReportUARTTxError()` 函数
|
||||
|
||||
2. **User/system_monitor.c**
|
||||
- 实现 `SystemMonitor_ReportUARTTx()` 函数
|
||||
- 实现 `SystemMonitor_ReportUARTTxError()` 函数
|
||||
- 更新 `SystemMonitor_SaveStatus()` 函数,在保存的日志中包含串口统计信息
|
||||
|
||||
3. **User/rs485_driver.c**
|
||||
- 包含 `system_monitor.h` 头文件
|
||||
- 在 `RS485_SendData()` 函数中添加监控调用
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **性能影响**: 监控函数调用非常轻量(仅增加计数器),对系统性能影响可忽略不计
|
||||
2. **线程安全**: 当前实现未使用互斥锁,如果在多线程环境中使用,建议添加适当的保护机制
|
||||
3. **计数器溢出**: 使用 `uint32_t` 类型,在高频发送场景下可能溢出,建议定期保存和重置统计数据
|
||||
4. **错误统计**: 仅统计DMA启动失败的情况,不包括传输过程中的错误(如需要可在DMA错误回调中添加)
|
||||
|
||||
## 扩展建议
|
||||
|
||||
如需更详细的监控,可以考虑添加:
|
||||
- 平均包大小统计
|
||||
- 发送延迟统计
|
||||
- 忙状态拒绝次数(`HAL_BUSY` 返回次数)
|
||||
- 按时间段的发送速率统计
|
||||
234
User/config_manager.c
Normal file
234
User/config_manager.c
Normal file
@ -0,0 +1,234 @@
|
||||
#include "config_manager.h"
|
||||
#include "fatfs.h"
|
||||
#include "ff.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// 全局配置变量
|
||||
static SystemConfig_t g_system_config = {0};
|
||||
static uint8_t g_config_initialized = 0;
|
||||
|
||||
// 计算校验和
|
||||
static uint32_t Calculate_Checksum(const SystemConfig_t *config)
|
||||
{
|
||||
uint32_t checksum = 0;
|
||||
checksum += config->uart_output_enabled;
|
||||
checksum += config->storage_enabled;
|
||||
checksum += config->session_number;
|
||||
checksum += config->config_version;
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化配置管理器
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void Config_Init(void)
|
||||
{
|
||||
if (!g_config_initialized) {
|
||||
Config_SetDefaults();
|
||||
g_config_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置默认配置
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void Config_SetDefaults(void)
|
||||
{
|
||||
g_system_config.uart_output_enabled = DEFAULT_UART_OUTPUT_ENABLED;
|
||||
g_system_config.storage_enabled = DEFAULT_STORAGE_ENABLED;
|
||||
g_system_config.session_number = 0; // 初始会话序号为0
|
||||
g_system_config.config_version = CONFIG_VERSION;
|
||||
g_system_config.checksum = Calculate_Checksum(&g_system_config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从SD卡加载配置
|
||||
* @param None
|
||||
* @retval HAL_OK: 成功, HAL_ERROR: 失败(将使用默认配置)
|
||||
*/
|
||||
HAL_StatusTypeDef Config_Load(void)
|
||||
{
|
||||
FIL file;
|
||||
FRESULT res;
|
||||
UINT bytes_read;
|
||||
char buffer[128];
|
||||
|
||||
// 尝试打开配置文件
|
||||
res = f_open(&file, CONFIG_FILE_PATH, FA_READ);
|
||||
if (res != FR_OK) {
|
||||
// 文件不存在,使用默认配置并保存
|
||||
Config_SetDefaults();
|
||||
Config_Save();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 读取配置文件
|
||||
res = f_read(&file, buffer, sizeof(buffer), &bytes_read);
|
||||
f_close(&file);
|
||||
|
||||
if (res != FR_OK || bytes_read == 0) {
|
||||
Config_SetDefaults();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 解析配置(简单的文本格式)
|
||||
SystemConfig_t temp_config;
|
||||
int uart_enabled, storage_enabled;
|
||||
unsigned int version, session_num;
|
||||
|
||||
int parsed = sscanf(buffer,
|
||||
"UART=%d\nSTORAGE=%d\nSESSION=%u\nVERSION=%u\n",
|
||||
&uart_enabled,
|
||||
&storage_enabled,
|
||||
&session_num,
|
||||
&version);
|
||||
|
||||
if (parsed == 4 && version == CONFIG_VERSION) {
|
||||
temp_config.uart_output_enabled = (uint8_t)uart_enabled;
|
||||
temp_config.storage_enabled = (uint8_t)storage_enabled;
|
||||
temp_config.session_number = session_num;
|
||||
temp_config.config_version = version;
|
||||
temp_config.checksum = Calculate_Checksum(&temp_config);
|
||||
|
||||
// 验证配置值的合法性
|
||||
if (temp_config.uart_output_enabled <= 1 &&
|
||||
temp_config.storage_enabled <= 1) {
|
||||
memcpy(&g_system_config, &temp_config, sizeof(SystemConfig_t));
|
||||
return HAL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// 解析失败,使用默认配置
|
||||
Config_SetDefaults();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 保存配置到SD卡
|
||||
* @param None
|
||||
* @retval HAL_OK: 成功, HAL_ERROR: 失败
|
||||
*/
|
||||
HAL_StatusTypeDef Config_Save(void)
|
||||
{
|
||||
FIL file;
|
||||
FRESULT res;
|
||||
UINT bytes_written;
|
||||
char buffer[128];
|
||||
|
||||
// 更新校验和
|
||||
g_system_config.checksum = Calculate_Checksum(&g_system_config);
|
||||
|
||||
// 创建或覆盖配置文件
|
||||
res = f_open(&file, CONFIG_FILE_PATH, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res != FR_OK) {
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 格式化配置数据为文本(精简格式)
|
||||
int len = snprintf(buffer, sizeof(buffer),
|
||||
"UART=%d\nSTORAGE=%d\nSESSION=%lu\nVERSION=%lu\n",
|
||||
g_system_config.uart_output_enabled,
|
||||
g_system_config.storage_enabled,
|
||||
g_system_config.session_number,
|
||||
g_system_config.config_version);
|
||||
|
||||
// 写入配置数据
|
||||
res = f_write(&file, buffer, len, &bytes_written);
|
||||
if (res != FR_OK || bytes_written != (UINT)len) {
|
||||
f_close(&file);
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 关闭文件
|
||||
f_close(&file);
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取串口输出使能状态
|
||||
* @param None
|
||||
* @retval 1: 启用, 0: 禁用
|
||||
*/
|
||||
uint8_t Config_IsUartOutputEnabled(void)
|
||||
{
|
||||
return g_system_config.uart_output_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取存储使能状态
|
||||
* @param None
|
||||
* @retval 1: 启用, 0: 禁用
|
||||
*/
|
||||
uint8_t Config_IsStorageEnabled(void)
|
||||
{
|
||||
return g_system_config.storage_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置串口输出使能
|
||||
* @param enabled: 1=启用, 0=禁用
|
||||
* @retval None
|
||||
*/
|
||||
void Config_SetUartOutput(uint8_t enabled)
|
||||
{
|
||||
g_system_config.uart_output_enabled = (enabled != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置存储使能
|
||||
* @param enabled: 1=启用, 0=禁用
|
||||
* @retval None
|
||||
*/
|
||||
void Config_SetStorage(uint8_t enabled)
|
||||
{
|
||||
g_system_config.storage_enabled = (enabled != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取完整配置
|
||||
* @param config: 配置结构体指针
|
||||
* @retval None
|
||||
*/
|
||||
void Config_GetConfig(SystemConfig_t *config)
|
||||
{
|
||||
if (config != NULL) {
|
||||
memcpy(config, &g_system_config, sizeof(SystemConfig_t));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取会话序号
|
||||
* @param None
|
||||
* @retval 当前会话序号
|
||||
*/
|
||||
uint32_t Config_GetSessionNumber(void)
|
||||
{
|
||||
return g_system_config.session_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置会话序号
|
||||
* @param session_number: 会话序号
|
||||
* @retval None
|
||||
*/
|
||||
void Config_SetSessionNumber(uint32_t session_number)
|
||||
{
|
||||
g_system_config.session_number = session_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 递增会话序号并返回新值
|
||||
* @param None
|
||||
* @retval 递增后的会话序号
|
||||
*/
|
||||
uint32_t Config_IncrementSessionNumber(void)
|
||||
{
|
||||
g_system_config.session_number++;
|
||||
return g_system_config.session_number;
|
||||
}
|
||||
42
User/config_manager.h
Normal file
42
User/config_manager.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef CONFIG_MANAGER_H
|
||||
#define CONFIG_MANAGER_H
|
||||
|
||||
#include "main.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// 配置文件路径
|
||||
#define CONFIG_FILE_PATH "0:/CONFIG.TXT"
|
||||
|
||||
// 系统配置结构体
|
||||
typedef struct {
|
||||
uint8_t uart_output_enabled; // 串口输出使能: 0=禁用, 1=启用
|
||||
uint8_t storage_enabled; // SD卡存储使能: 0=禁用, 1=启用
|
||||
uint32_t session_number; // 会话序号(用于数据存储文件夹命名)
|
||||
uint32_t config_version; // 配置版本号(用于验证)
|
||||
uint32_t checksum; // 校验和(用于验证配置完整性)
|
||||
} SystemConfig_t;
|
||||
|
||||
// 默认配置值
|
||||
#define DEFAULT_UART_OUTPUT_ENABLED 1
|
||||
#define DEFAULT_STORAGE_ENABLED 0
|
||||
#define CONFIG_VERSION 0x00010000 // 版本 1.0.0
|
||||
|
||||
// 函数声明
|
||||
void Config_Init(void);
|
||||
HAL_StatusTypeDef Config_Load(void);
|
||||
HAL_StatusTypeDef Config_Save(void);
|
||||
void Config_SetDefaults(void);
|
||||
|
||||
// 配置访问函数
|
||||
uint8_t Config_IsUartOutputEnabled(void);
|
||||
uint8_t Config_IsStorageEnabled(void);
|
||||
void Config_SetUartOutput(uint8_t enabled);
|
||||
void Config_SetStorage(uint8_t enabled);
|
||||
void Config_GetConfig(SystemConfig_t *config);
|
||||
|
||||
// 会话序号管理函数
|
||||
uint32_t Config_GetSessionNumber(void);
|
||||
void Config_SetSessionNumber(uint32_t session_number);
|
||||
uint32_t Config_IncrementSessionNumber(void);
|
||||
|
||||
#endif // CONFIG_MANAGER_H
|
||||
@ -1,5 +1,6 @@
|
||||
#include "data_storage.h"
|
||||
#include "system_monitor.h"
|
||||
#include "config_manager.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -416,12 +417,8 @@ HAL_StatusTypeDef DataStorage_CreateSessionFolder(DataStorageHandle_t *handle)
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 从PARAM.TXT加载当前序号
|
||||
uint32_t session_number = 0;
|
||||
DataStorage_LoadSessionNumber(&session_number);
|
||||
|
||||
// 递增序号
|
||||
session_number++;
|
||||
// 从配置管理器获取并递增会话序号
|
||||
uint32_t session_number = Config_IncrementSessionNumber();
|
||||
|
||||
// 生成会话文件夹名(基于序号)
|
||||
snprintf(handle->current_session_path, sizeof(handle->current_session_path),
|
||||
@ -439,8 +436,8 @@ HAL_StatusTypeDef DataStorage_CreateSessionFolder(DataStorageHandle_t *handle)
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 保存更新后的序号到PARAM.TXT
|
||||
if (DataStorage_SaveSessionNumber(session_number) != HAL_OK) {
|
||||
// 保存更新后的配置(包含新的会话序号)
|
||||
if (Config_Save() != HAL_OK) {
|
||||
// 即使保存失败,也继续使用该文件夹
|
||||
// 这不是致命错误
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "rs485_driver.h"
|
||||
#include "system_monitor.h"
|
||||
#include <string.h>
|
||||
|
||||
static UART_HandleTypeDef *g_huart_485 = NULL;
|
||||
@ -36,6 +37,13 @@ HAL_StatusTypeDef RS485_SendData(uint8_t *pData, uint16_t Size)
|
||||
// 如果启动DMA失败,需要清除忙标志并切换回接收模式
|
||||
HAL_GPIO_WritePin(g_de_re_port, g_de_re_pin, GPIO_PIN_RESET);
|
||||
g_rs485_tx_busy = 0;
|
||||
// 报告串口发送错误
|
||||
SystemMonitor_ReportUARTTxError();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 报告串口发送成功(记录字节数)
|
||||
SystemMonitor_ReportUARTTx(Size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@ -100,6 +100,27 @@ void SystemMonitor_ReportDataDropped(void)
|
||||
g_system_stats.sd_data_dropped_count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 报告串口发送操作
|
||||
* @param bytes_sent: 发送的字节数
|
||||
* @retval None
|
||||
*/
|
||||
void SystemMonitor_ReportUARTTx(uint32_t bytes_sent)
|
||||
{
|
||||
g_system_stats.uart_tx_count++;
|
||||
g_system_stats.uart_tx_bytes += bytes_sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 报告串口发送错误
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemMonitor_ReportUARTTxError(void)
|
||||
{
|
||||
g_system_stats.uart_tx_error_count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 保存监控状态到文件
|
||||
* @param None
|
||||
@ -118,19 +139,11 @@ HAL_StatusTypeDef SystemMonitor_SaveStatus(void)
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// 格式化监控数据为文本
|
||||
// 格式化监控数据为文本(精简格式,减少阻塞时间)
|
||||
int len = snprintf(buffer, sizeof(buffer),
|
||||
"=== System Monitor Status ===\r\n"
|
||||
"Total Samples: %lu\r\n"
|
||||
"Data Overflow: %lu\r\n"
|
||||
"\r\n"
|
||||
"=== SD Card Stats ===\r\n"
|
||||
"SD Write Count: %lu\r\n"
|
||||
"SD Write Errors: %lu\r\n"
|
||||
"SD Buffer Full: %lu\r\n"
|
||||
"SD Total Bytes: %lu\r\n"
|
||||
"SD File Count: %lu\r\n"
|
||||
"SD Data Dropped: %lu\r\n",
|
||||
"Samples:%lu Ovf:%lu\r\n"
|
||||
"SD:Wr=%lu Err=%lu Full=%lu Bytes=%lu Files=%lu Drop=%lu\r\n"
|
||||
"UART:Tx=%lu Bytes=%lu Err=%lu\r\n",
|
||||
g_system_stats.total_samples,
|
||||
g_system_stats.data_overflow_count,
|
||||
g_system_stats.sd_write_count,
|
||||
@ -138,7 +151,10 @@ HAL_StatusTypeDef SystemMonitor_SaveStatus(void)
|
||||
g_system_stats.sd_buffer_full_count,
|
||||
g_system_stats.sd_total_bytes_written,
|
||||
g_system_stats.sd_file_count,
|
||||
g_system_stats.sd_data_dropped_count
|
||||
g_system_stats.sd_data_dropped_count,
|
||||
g_system_stats.uart_tx_count,
|
||||
g_system_stats.uart_tx_bytes,
|
||||
g_system_stats.uart_tx_error_count
|
||||
);
|
||||
|
||||
// 写入监控数据
|
||||
|
||||
@ -19,6 +19,11 @@ typedef struct {
|
||||
uint32_t sd_total_bytes_written; // SD卡总写入字节数
|
||||
uint32_t sd_file_count; // 创建的文件数量
|
||||
uint32_t sd_data_dropped_count; // 未存储的数据数量(缓冲区满时丢弃)
|
||||
|
||||
// 串口发送监控信息
|
||||
uint32_t uart_tx_count; // 串口发送次数
|
||||
uint32_t uart_tx_bytes; // 串口发送总字节数
|
||||
uint32_t uart_tx_error_count; // 串口发送错误次数
|
||||
} SystemMonitorStats_t;
|
||||
|
||||
// 函数声明
|
||||
@ -34,6 +39,10 @@ void SystemMonitor_ReportSDBufferFull(void);
|
||||
void SystemMonitor_ReportSDFileCreated(void);
|
||||
void SystemMonitor_ReportDataDropped(void);
|
||||
|
||||
// 串口发送监控函数
|
||||
void SystemMonitor_ReportUARTTx(uint32_t bytes_sent);
|
||||
void SystemMonitor_ReportUARTTxError(void);
|
||||
|
||||
// 监控状态持久化函数
|
||||
HAL_StatusTypeDef SystemMonitor_SaveStatus(void);
|
||||
HAL_StatusTypeDef SystemMonitor_LoadStatus(void);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user