diff --git a/Core/Inc/stm32f4xx_it.h b/Core/Inc/stm32f4xx_it.h index cf2001d..107969d 100644 --- a/Core/Inc/stm32f4xx_it.h +++ b/Core/Inc/stm32f4xx_it.h @@ -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); diff --git a/Core/Src/main.c b/Core/Src/main.c index 13caef5..d013b86 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -35,6 +35,7 @@ #include "correction.h" #include "data_storage.h" #include "system_monitor.h" +#include "config_manager.h" #include #include /* 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 - // 发送校正后的数据包到串口 - RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t)); -#endif + // 发送校正后的数据包到串口(运行时配置) + if (Config_IsUartOutputEnabled()) { + RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t)); + } } else { // 4b. 校正失败或未启用,使用原始数据 PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2]); -#if DATA_OUTPUT_MODE_UART - // 发送原始数据包到串口 - RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t)); -#endif + // 发送原始数据包到串口(运行时配置) + if (Config_IsUartOutputEnabled()) { + RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t)); + } } - // 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,10 +515,19 @@ 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) { - // 开始数据记录 - StartRecording(); + // 开始数据记录(如果存储功能已启用) + if (Config_IsStorageEnabled()) { + StartRecording(); + } } } } else { diff --git a/Core/Src/stm32f4xx_it.c b/Core/Src/stm32f4xx_it.c index 51eddad..8b9d8bd 100644 --- a/Core/Src/stm32f4xx_it.c +++ b/Core/Src/stm32f4xx_it.c @@ -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. */ diff --git a/Core/Src/usart.c b/Core/Src/usart.c index 1cd8aa9..e10acf0 100644 --- a/Core/Src/usart.c +++ b/Core/Src/usart.c @@ -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 */ diff --git a/STM_ATEM_F405.ioc b/STM_ATEM_F405.ioc index 461ad24..3007b64 100644 --- a/STM_ATEM_F405.ioc +++ b/STM_ATEM_F405.ioc @@ -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 diff --git a/User/Config_Manager_Guide.md b/User/Config_Manager_Guide.md new file mode 100644 index 0000000..ae329ca --- /dev/null +++ b/User/Config_Manager_Guide.md @@ -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` diff --git a/User/UART_Monitoring_Feature.md b/User/UART_Monitoring_Feature.md new file mode 100644 index 0000000..aa2730a --- /dev/null +++ b/User/UART_Monitoring_Feature.md @@ -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` 返回次数) +- 按时间段的发送速率统计 diff --git a/User/config_manager.c b/User/config_manager.c new file mode 100644 index 0000000..b6fac44 --- /dev/null +++ b/User/config_manager.c @@ -0,0 +1,234 @@ +#include "config_manager.h" +#include "fatfs.h" +#include "ff.h" +#include +#include + +// 全局配置变量 +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; +} diff --git a/User/config_manager.h b/User/config_manager.h new file mode 100644 index 0000000..23232bc --- /dev/null +++ b/User/config_manager.h @@ -0,0 +1,42 @@ +#ifndef CONFIG_MANAGER_H +#define CONFIG_MANAGER_H + +#include "main.h" +#include + +// 配置文件路径 +#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 diff --git a/User/data_storage.c b/User/data_storage.c index 68e445d..a9bbdf7 100644 --- a/User/data_storage.c +++ b/User/data_storage.c @@ -1,5 +1,6 @@ #include "data_storage.h" #include "system_monitor.h" +#include "config_manager.h" #include #include #include @@ -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) { // 即使保存失败,也继续使用该文件夹 // 这不是致命错误 } diff --git a/User/rs485_driver.c b/User/rs485_driver.c index 10ca307..1418c80 100644 --- a/User/rs485_driver.c +++ b/User/rs485_driver.c @@ -1,4 +1,5 @@ #include "rs485_driver.h" +#include "system_monitor.h" #include 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; diff --git a/User/system_monitor.c b/User/system_monitor.c index c441603..02eb8ac 100644 --- a/User/system_monitor.c +++ b/User/system_monitor.c @@ -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 ); // 写入监控数据 diff --git a/User/system_monitor.h b/User/system_monitor.h index d267681..701599d 100644 --- a/User/system_monitor.h +++ b/User/system_monitor.h @@ -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);