STM_ATEM/Core/Src/main.c
zhoujie fee2e96eaa feat(system): 优化系统性能并简化监控模块
- 新增VSCode编辑器配置,启用保存时自动格式化
- 新增DMA2_Stream5和USART1中断处理函数,优化SPI传输性能
- 移除TIM1相关配置和性能监控模块,简化系统架构
- 优化GPIO配置,将ADC_SYNC和PA8引脚合并配置
- 简化系统监控模块,仅保留采样计数和数据溢出统计
- 优化SPI配置,使用16位数据宽度并提高DMA优先级
- 提高USART波特率(USART1:2Mbps, USART3:921600bps)
- 优化LTC2508驱动,增加初始化状态检查和缓冲区大小
- 修正数据存储模块,使用校正数据包而非校正结果结构体
- 优化RS485驱动,使用中断传输并添加传输完成回调
- 更新IOC配置文件,移除TIM1并调整中断优先级配置
- 新增系统监控简化说明文档,详细记录架构变更
2026-02-06 22:45:25 +08:00

706 lines
19 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.

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "fatfs.h"
#include "sdio.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ltc2508_driver.h"
#include "rs485_driver.h"
#include "data_packet.h"
#include "correction.h"
#include "data_storage.h"
#include "system_monitor.h"
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
// 串口输出控制开关
#define ENABLE_UART_DEBUG_OUTPUT 1
#define DEBUG_OUTPUT_INTERVAL_MS 1000 // 调试输出间隔(毫秒)
// 监控功能宏开关
#define ENABLE_SYSTEM_MONITOR 1 // 系统监控开关
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
// 外部SPI句柄声明
extern SPI_HandleTypeDef hspi1;
extern SPI_HandleTypeDef hspi2;
extern SPI_HandleTypeDef hspi3;
extern TIM_HandleTypeDef htim2;
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart3;
// 校正参数
CorrectionParams_t g_correction_params;
// 数据包
DataPacket_t g_data_packet;
CorrectedDataPacket_t g_corrected_packet;
// 数据存储句柄
DataStorageHandle_t g_data_storage;
// 系统状态
static uint8_t g_recording_enabled = 0;
// USB连接状态管理
static uint8_t g_usb_connected = 0;
static uint8_t g_fatfs_mounted_for_sampling = 0;
static uint32_t g_last_usb_check = 0;
// 性能监控和调试输出
static uint32_t g_last_debug_output = 0;
static uint8_t g_debug_output_enabled = ENABLE_UART_DEBUG_OUTPUT;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
static void StartRecording(void);
static void StopRecording(void);
static void ProcessAdcData(void);
// USB连接状态管理函数
static uint8_t CheckUSBConnectionStatus(void);
static void HandleUSBConnectionChange(void);
static HAL_StatusTypeDef MountFileSystemForSampling(void);
static void UnmountFileSystemForSampling(void);
static void DebugOutput_Init(void);
static void DebugOutput_SendString(const char* str);
static void DebugOutput_PrintSystemStats(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/**
* @brief 开始数据记录
* @retval None
*/
static void StartRecording(void)
{
if (!g_recording_enabled) {
if (DataStorage_StartRecording(&g_data_storage) == HAL_OK) {
g_recording_enabled = 1;
}
}
}
/**
* @brief 停止数据记录
* @retval None
*/
static void StopRecording(void)
{
if (g_recording_enabled) {
g_recording_enabled = 0;
DataStorage_StopRecording(&g_data_storage);
}
}
/**
* @brief 处理ADC数据
* @retval None
*/
static void ProcessAdcData(void)
{
// 检查ADC数据是否准备就绪
LTC2508_BufferTypeDef *ready_buffer = NULL;
if (LTC2508_GetReadyBuffer(&ready_buffer) == LTC2508_OK && ready_buffer != NULL)
{
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_IncrementSampleCount();
#endif
// 1. 从双缓冲区获取数据并合并 (高位16位在前)
int32_t raw_adc[NUM_LTC2508];
for (uint8_t i = 0; i < NUM_LTC2508; i++) {
raw_adc[i] = (int32_t)(((uint32_t)ready_buffer->data[i][0] << 16) | ready_buffer->data[i][1]);
}
// 3. 应用校正算法
CorrectionResult_t correction_result;
uint8_t correction_applied = 0;
if (g_correction_params.params_valid &&
Apply_Correction(raw_adc[0], raw_adc[1], raw_adc[2],
&correction_result, &g_correction_params) == HAL_OK) {
// 4a. 打包校正后的数据
PackCorrectedData(&g_corrected_packet,
correction_result.corrected_x,
correction_result.corrected_y,
correction_result.corrected_z);
correction_applied = 1;
// 发送校正后的数据包
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]);
// 发送原始数据包
RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t));
}
// 6. 存储数据到SD卡 (如果启用记录)
if (g_recording_enabled) {
if (correction_applied) {
// 存储校正后的数据
DataStorage_WriteCorrectedData(&g_data_storage, &g_corrected_packet);
} else {
// 存储原始数据
DataStorage_WriteData(&g_data_storage, &g_data_packet);
}
}
// 7. 释放已处理的缓冲区
LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer());
} else {
// 数据来不及处理
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportDataOverflow();
#endif
}
}
/**
* @brief 初始化调试输出
* @retval None
*/
static void DebugOutput_Init(void)
{
// USART3已在MX_USART3_UART_Init()中初始化
if (g_debug_output_enabled) {
DebugOutput_SendString("\r\n=== System Debug Output Initialized ===\r\n");
}
}
/**
* @brief 通过USART3发送字符串
* @param str: 要发送的字符串
* @retval None
*/
static void DebugOutput_SendString(const char* str)
{
if (!g_debug_output_enabled || str == NULL) {
return;
}
HAL_UART_Transmit(&huart3, (uint8_t*)str, strlen(str), 100);
}
/**
* @brief 输出系统监控统计信息
* @retval None
*/
static void DebugOutput_PrintSystemStats(void)
{
#if ENABLE_SYSTEM_MONITOR
if (!g_debug_output_enabled) {
return;
}
char buffer[128];
SystemMonitorStats_t sys_stats;
SystemMonitor_GetStats(&sys_stats);
snprintf(buffer, sizeof(buffer),
"\r\n=== System Stats ===\r\n"
"Total Samples: %lu\r\n"
"Data Overflow: %lu\r\n",
sys_stats.total_samples,
sys_stats.data_overflow_count);
DebugOutput_SendString(buffer);
#endif
}
/**
* @brief 检查USB连接状态
* @retval 1: USB已连接, 0: USB未连接
*/
static uint8_t CheckUSBConnectionStatus(void)
{
// 通过检查USB设备状态来判断是否连接到PC
extern USBD_HandleTypeDef hUsbDeviceFS;
// 检查USB设备是否已配置枚举完成
if (hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED) {
return 1; // USB已连接并配置
}
return 0; // USB未连接或未配置
}
/**
* @brief 处理USB连接状态变化
* @retval None
*/
static void HandleUSBConnectionChange(void)
{
uint8_t current_usb_status = CheckUSBConnectionStatus();
if (current_usb_status != g_usb_connected) {
g_usb_connected = current_usb_status;
if (g_usb_connected) {
// USB连接停止数据采集卸载文件系统用于USB存储
DebugOutput_SendString("USB Connected: Stopping data acquisition\r\n");
// 停止数据记录
StopRecording();
// 卸载用于采样的文件系统
UnmountFileSystemForSampling();
} else {
// USB断开重新挂载文件系统开始数据采集
DebugOutput_SendString("USB Disconnected: Starting data acquisition\r\n");
// 挂载文件系统用于数据采集
if (MountFileSystemForSampling() == HAL_OK) {
// 重新初始化数据存储
if (DataStorage_Init(&g_data_storage) == HAL_OK) {
StartRecording();
}
}
}
}
}
/**
* @brief 为数据采集挂载文件系统
* @retval HAL_OK: 成功, HAL_ERROR: 失败
*/
static HAL_StatusTypeDef MountFileSystemForSampling(void)
{
extern FATFS SDFatFS;
extern char SDPath[4];
extern SD_HandleTypeDef hsd;
if (g_fatfs_mounted_for_sampling) {
return HAL_OK; // 已经挂载
}
// 初始化SD卡
if (HAL_SD_Init(&hsd) != HAL_OK) {
DebugOutput_SendString("SD card init failed\r\n");
return HAL_ERROR;
}
// FRESULT format_result = f_mkfs(SDPath, FM_FAT32, 0, NULL, 0);
// 尝试挂载文件系统
FRESULT mount_result = f_mount(&SDFatFS, SDPath, 1);
if (mount_result != FR_OK) {
if (mount_result == FR_NO_FILESYSTEM)
{
DebugOutput_SendString("No filesystem found, formatting...\r\n");
// 格式化为FAT32
FRESULT format_result = f_mkfs(SDPath, FM_FAT32, 0, NULL, 0);
if (format_result == FR_OK) {
DebugOutput_SendString("Format successful, remounting...\r\n");
mount_result = f_mount(&SDFatFS, SDPath, 1);
if (mount_result != FR_OK) {
DebugOutput_SendString("Remount after format failed\r\n");
return HAL_ERROR;
}
} else {
DebugOutput_SendString("Format failed\r\n");
return HAL_ERROR;
}
} else {
DebugOutput_SendString("Mount failed with other error\r\n");
return HAL_ERROR;
}
}
g_fatfs_mounted_for_sampling = 1;
DebugOutput_SendString("Filesystem mounted for sampling\r\n");
return HAL_OK;
}
/**
* @brief 卸载用于数据采集的文件系统
* @retval None
*/
static void UnmountFileSystemForSampling(void)
{
extern FATFS SDFatFS;
extern char SDPath[4];
if (!g_fatfs_mounted_for_sampling) {
return; // 已经卸载
}
// 卸载文件系统
f_mount(NULL, SDPath, 0);
g_fatfs_mounted_for_sampling = 0;
DebugOutput_SendString("Filesystem unmounted for USB mode\r\n");
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
HAL_Delay(200);
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_SDIO_SD_Init();
MX_SPI1_Init();
MX_SPI2_Init();
MX_SPI3_Init();
MX_USART1_UART_Init();
MX_FATFS_Init();
MX_USB_DEVICE_Init();
MX_USART3_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
// SD_NAND_Init_And_Mount();
// SD_Test_Write();
// SD_Test_Read();
// 初始化系统监控
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_Init();
#endif
// 初始化调试输出
DebugOutput_Init();
// 初始化RS485通信
RS485_Init(&huart1, RS485_DE_RE_PORT, RS485_DE_RE_PIN);
// 初始化校正参数
Init_CorrectionParams(&g_correction_params);
Load_CorrectionParams_FromFlash(&g_correction_params);
// 检查初始USB连接状态并相应初始化
HAL_Delay(2000);
g_usb_connected = CheckUSBConnectionStatus();
if (!g_usb_connected) {
// USB未连接挂载文件系统用于数据采集
if (MountFileSystemForSampling() == HAL_OK) {
// 初始化数据存储
if (DataStorage_Init(&g_data_storage) == HAL_OK) {
// 开始数据记录
StartRecording();
}
}
} else {
// USB已连接不进行数据采集
DebugOutput_SendString("USB connected at startup - data acquisition disabled\r\n");
while(1)
{
;
}
}
// 启动TIM2定时器用于1ms周期的ADC数据处理
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) {
Error_Handler();
}
// 初始化LTC2508驱动
if (LTC2508_Init(&hspi1, &hspi2, &hspi3) != LTC2508_OK) {
Error_Handler();
}
// 触发信号引脚初始化
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 定期任务
uint32_t current_tick = HAL_GetTick();
// USB连接状态检测 (每500ms检测一次)
if (current_tick - g_last_usb_check >= 500) {
HandleUSBConnectionChange();
g_last_usb_check = current_tick;
}
// 处理数据存储后台任务 (轮询方式)
if (g_recording_enabled) {
DataStorage_ProcessBackgroundTasks(&g_data_storage);
}
// 定期输出调试信息 (每1秒输出一次)
if (g_debug_output_enabled && (current_tick - g_last_debug_output >= DEBUG_OUTPUT_INTERVAL_MS)) {
DebugOutput_PrintSystemStats();
g_last_debug_output = current_tick;
}
// ADC采样由PA1外部中断触发不在主循环中触发
// 可以在这里添加其他低优先级任务
}
// 停止数据记录
StopRecording();
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/**
* @brief 外部中断回调函数 - ADC数据就绪信号
* @param GPIO_Pin: 触发中断的GPIO引脚
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
static uint32_t cnt = 0;
if(LTC2508_IsInited() == 0) return;
cnt ++;
// if(cnt % 5 == 0)
{
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
if (GPIO_Pin == ADC_DRY_Pin) {
// ADC数据就绪触发DMA读取
LTC2508_TriggerDmaRead();
}
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
}
}
/**
* @brief SPI DMA传输完成回调函数
* @param hspi: SPI句柄指针
* @retval None
*/
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
// 调用LTC2508驱动的DMA完成回调
LTC2508_DmaComplete_Callback(hspi);
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
// 调用LTC2508驱动的DMA完成回调
LTC2508_DmaComplete_Callback(hspi);
}
/**
* @brief SPI错误回调函数
* @param hspi: SPI句柄指针
* @retval None
*/
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
// 调用LTC2508驱动的错误回调
LTC2508_ErrorCallback(hspi);
}
/**
* @brief TIM2回调函数 - 1ms定时器中断处理ADC数据
* @param htim: TIM句柄指针
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) {
// ADC是4KHz采样率定时器是1KHz需要在每次1ms中断中处理多个ADC数据
// 循环处理所有可用的ADC数据直到没有新数据为止
uint8_t processed_count = 0;
const uint8_t max_process_per_interrupt = 8; // 限制每次中断最多处理的数据量,避免中断时间过长
while (processed_count < max_process_per_interrupt) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
ProcessAdcData();
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
processed_count++;
}
}
}
/**
* @brief UART传输完成回调函数
* @param huart: UART句柄指针
* @retval None
*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart1) {
// RS485传输完成回调
RS485_TxCpltCallback(huart);
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
// 停止所有DMA传输
HAL_SPI_DMAStop(&hspi1);
HAL_SPI_DMAStop(&hspi2);
HAL_SPI_DMAStop(&hspi3);
// 停止数据记录
g_recording_enabled = 0;
DataStorage_StopRecording(&g_data_storage);
// 禁用中断并进入无限循环
__disable_irq();
while (1)
{
// 可以在这里添加LED指示或其他错误指示
HAL_Delay(500);
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */