diff --git a/Core/Src/main.c b/Core/Src/main.c index 064be6f..44d8fce 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -32,6 +32,9 @@ #include "ltc2508_driver.h" #include "rs485_driver.h" #include "data_packet.h" +#include "correction.h" +#include "data_storage.h" +#include "system_monitor.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -52,8 +55,15 @@ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ -//CorrectionParams_t g_correction_params; +// 校正参数 +CorrectionParams_t g_correction_params; +// 数据包 DataPacket_t g_data_packet; +// 数据存储句柄 +DataStorageHandle_t g_data_storage; +// 系统状态 +static uint32_t g_last_monitor_update = 0; +static uint8_t g_recording_enabled = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ @@ -107,14 +117,34 @@ int main(void) MX_USB_DEVICE_Init(); MX_USART3_UART_Init(); /* USER CODE BEGIN 2 */ - LTC2508_Init(&hspi1, &hspi2, &hspi3); + // 初始化系统监控 + SystemMonitor_Init(); + SystemMonitor_SetState(SYSTEM_STATE_INIT); + + // 初始化LTC2508驱动 + if (LTC2508_Init(&hspi1, &hspi2, &hspi3) != LTC2508_OK) { + SystemMonitor_ReportError(SYSTEM_ERROR_ADC); + Error_Handler(); + } + + // 初始化RS485通信 RS485_Init(&huart1, RS485_DE_RE_PORT, RS485_DE_RE_PIN); -// Init_CorrectionParams(&g_correction_params); - -// HAL_HRTIM_SimplePWMStart(&hhrtim1, HRTIM_TIMERINDEX_TIMER_A, HRTIM_OUTPUT_TA1); - - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); + + // 初始化校正参数 + Init_CorrectionParams(&g_correction_params); + Load_CorrectionParams_FromFlash(&g_correction_params); + + // 初始化数据存储 + if (DataStorage_Init(&g_data_storage) != HAL_OK) { + SystemMonitor_ReportError(SYSTEM_ERROR_STORAGE); + } + + // 系统初始化完成 + SystemMonitor_SetState(SYSTEM_STATE_IDLE); + + // 触发信号引脚初始化 + 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 */ @@ -124,38 +154,64 @@ int main(void) /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ + // 系统监控更新 (每100ms更新一次) + uint32_t current_tick = HAL_GetTick(); + if (current_tick - g_last_monitor_update >= 100) { + SystemMonitor_Update(); + g_last_monitor_update = current_tick; + } + + // 检查ADC数据是否准备就绪 if (g_adc_data_ready_flag) { - g_adc_data_ready_flag = 0; // �����־ + g_adc_data_ready_flag = 0; // 清除标志 + SystemMonitor_SetState(SYSTEM_STATE_SAMPLING); - // 1. �ϲ����� (�����16λ��ǰ) + // 1. 合并数据 (高位16位在前) int32_t raw_adc[NUM_LTC2508]; raw_adc[0] = (int32_t)(((uint32_t)g_adc_data[0][0] << 16) | g_adc_data[0][1]); raw_adc[1] = (int32_t)(((uint32_t)g_adc_data[1][0] << 16) | g_adc_data[1][1]); raw_adc[2] = (int32_t)(((uint32_t)g_adc_data[2][0] << 16) | g_adc_data[2][1]); -#if 0 - // 2. У�� - float corrected_x, corrected_y, corrected_z; - Apply_Correction(raw_adc[0], raw_adc[1], raw_adc[2], - &corrected_x, &corrected_y, &corrected_z, - &g_correction_params); + // 2. 验证数据有效性 + for (uint8_t i = 0; i < NUM_LTC2508; i++) { + if (LTC2508_ValidateData(i) != LTC2508_OK) { + SystemMonitor_ReportError(SYSTEM_ERROR_ADC); + continue; // 跳过无效数据 + } + } - // 3. ��У����� float תΪ int32_t (������Ҫ��������) - int32_t final_adc1 = (int32_t)(corrected_x); - int32_t final_adc2 = (int32_t)(corrected_y); - int32_t final_adc3 = (int32_t)(corrected_z); + // 3. 应用校正算法 + CorrectionResult_t correction_result; + if (Apply_Correction(raw_adc[0], raw_adc[1], raw_adc[2], + &correction_result, &g_correction_params) == HAL_OK) { + + // 4. 打包校正后的数据 + PackData(&g_data_packet, (int32_t)correction_result.corrected_x, + (int32_t)correction_result.corrected_y, + (int32_t)correction_result.corrected_z); + } else { + // 校正失败,使用原始数据 + PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2]); + } - // 4. ��� - PackData(&g_data_packet, (uint32_t)final_adc1, (uint32_t)final_adc2, (uint32_t)final_adc3); -#endif + // 5. 发送数据包 + if (RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t)) != HAL_OK) { + SystemMonitor_ReportError(SYSTEM_ERROR_COMMUNICATION); + } - // 4. ��� - PackData(&g_data_packet, raw_adc[0] , raw_adc[1] , raw_adc[2]); - - // 5. ���� - RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t)); + // 6. 存储数据到SD卡 (如果启用记录) + if (g_recording_enabled) { + SystemMonitor_SetState(SYSTEM_STATE_RECORDING); + if (DataStorage_WriteData(&g_data_storage, &g_data_packet) != HAL_OK) { + SystemMonitor_ReportError(SYSTEM_ERROR_STORAGE); + } + } + + SystemMonitor_SetState(SYSTEM_STATE_IDLE); } + + // ADC采样由PA1外部中断触发,不在主循环中触发 } /* USER CODE END 3 */ } diff --git a/USB_DEVICE/App/usbd_storage_if.c b/USB_DEVICE/App/usbd_storage_if.c index 394943f..cdfa36b 100644 --- a/USB_DEVICE/App/usbd_storage_if.c +++ b/USB_DEVICE/App/usbd_storage_if.c @@ -22,7 +22,8 @@ #include "usbd_storage_if.h" /* USER CODE BEGIN INCLUDE */ - +#include "fatfs.h" +#include "ff.h" /* USER CODE END INCLUDE */ /* Private typedef -----------------------------------------------------------*/ @@ -31,7 +32,11 @@ /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ +extern SD_HandleTypeDef hsd; +extern FATFS SDFatFS; +extern char SDPath[4]; +static uint8_t sd_initialized = 0; /* USER CODE END PV */ /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY @@ -177,8 +182,19 @@ USBD_StorageTypeDef USBD_Storage_Interface_fops_FS = int8_t STORAGE_Init_FS(uint8_t lun) { /* USER CODE BEGIN 2 */ - UNUSED(lun); - + UNUSED(lun); + + // 初始化SD卡 + if (HAL_SD_Init(&hsd) != HAL_OK) { + return (USBD_FAIL); + } + + // 挂载文件系统 + if (f_mount(&SDFatFS, SDPath, 1) != FR_OK) { + return (USBD_FAIL); + } + + sd_initialized = 1; return (USBD_OK); /* USER CODE END 2 */ } @@ -194,9 +210,20 @@ int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_ { /* USER CODE BEGIN 3 */ UNUSED(lun); - - *block_num = STORAGE_BLK_NBR; - *block_size = STORAGE_BLK_SIZ; + + if (!sd_initialized) { + return (USBD_FAIL); + } + + HAL_SD_CardInfoTypeDef cardinfo; + if (HAL_SD_GetCardInfo(&hsd, &cardinfo) == HAL_OK) { + *block_num = cardinfo.LogBlockNbr; + *block_size = cardinfo.LogBlockSize; + } else { + *block_num = STORAGE_BLK_NBR; + *block_size = STORAGE_BLK_SIZ; + } + return (USBD_OK); /* USER CODE END 3 */ } @@ -210,8 +237,17 @@ int8_t STORAGE_IsReady_FS(uint8_t lun) { /* USER CODE BEGIN 4 */ UNUSED(lun); - - return (USBD_OK); + + if (!sd_initialized) { + return (USBD_FAIL); + } + + HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(&hsd); + if (state == HAL_SD_CARD_TRANSFER) { + return (USBD_OK); + } + + return (USBD_FAIL); /* USER CODE END 4 */ } @@ -241,10 +277,15 @@ int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t bl { /* USER CODE BEGIN 6 */ UNUSED(lun); - UNUSED(buf); - UNUSED(blk_addr); - UNUSED(blk_len); - + + if (!sd_initialized || buf == NULL) { + return (USBD_FAIL); + } + + if (HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, HAL_MAX_DELAY) != HAL_OK) { + return (USBD_FAIL); + } + return (USBD_OK); /* USER CODE END 6 */ } @@ -261,10 +302,15 @@ int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t b { /* USER CODE BEGIN 7 */ UNUSED(lun); - UNUSED(buf); - UNUSED(blk_addr); - UNUSED(blk_len); - + + if (!sd_initialized || buf == NULL) { + return (USBD_FAIL); + } + + if (HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, HAL_MAX_DELAY) != HAL_OK) { + return (USBD_FAIL); + } + return (USBD_OK); /* USER CODE END 7 */ } diff --git a/User/correction.c b/User/correction.c index ce34a59..21581ca 100644 --- a/User/correction.c +++ b/User/correction.c @@ -1,102 +1,157 @@ #include "correction.h" -//#include "fmac.h" -//#include "cordic.h" +#include +#include "stddef.h" -// 外部的 FMAC 和 CORDIC 句柄 -//extern FMAC_HandleTypeDef hfmac; -//extern CORDIC_HandleTypeDef hcordic; +static float input_vector[3]; +static float output_vector[3]; /** - * @brief 初始化校正参数(示例) + * @brief 初始化校正参数为默认值 * @param params: 参数结构体指针 * @retval None */ void Init_CorrectionParams(CorrectionParams_t *params) { - // --- 请在这里填充你从校准中得到的实际参数 --- - // 偏移 + if (params == NULL) return; + + // 初始化偏移为0 params->offset_x = 0.0f; params->offset_y = 0.0f; params->offset_z = 0.0f; - - // 灵敏度/非正交矩阵 (这里假设为单位矩阵) - params->scale_xx = 1.0f; params->scale_xy = 0.0f; params->scale_xz = 0.0f; - params->scale_yx = 0.0f; params->scale_yy = 1.0f; params->scale_yz = 0.0f; - params->scale_zx = 0.0f; params->scale_zy = 0.0f; params->scale_zz = 1.0f; + + // 初始化为单位矩阵 + memset(params->correction_matrix, 0, sizeof(params->correction_matrix)); + params->correction_matrix[0] = 1.0f; // [0,0] + params->correction_matrix[4] = 1.0f; // [1,1] + params->correction_matrix[8] = 1.0f; // [2,2] + + #if USE_ARM_DSP + // 初始化ARM DSP矩阵实例 (3x3矩阵) + arm_mat_init_f32(¶ms->matrix_inst, 3, 3, params->correction_matrix); + #endif + + params->params_valid = 1; } /** - * @brief 应用三分量校正 - * @param raw_x, raw_y, raw_z: 原始 ADC 数据 - * @param corrected_x, corrected_y, corrected_z: 校正后数据的指针 - * @param params: 校正参数 + * @brief 设置校正矩阵 + * @param params: 参数结构体指针 + * @param matrix: 3x3校正矩阵(行优先存储) * @retval None */ -void Apply_Correction(int32_t raw_x, int32_t raw_y, int32_t raw_z, - float *corrected_x, float *corrected_y, float *corrected_z, - CorrectionParams_t *params) +void Set_CorrectionMatrix(CorrectionParams_t *params, const float *matrix) { - // 1. 将原始数据转换为浮点数 - float x_f = (float)raw_x; - float y_f = (float)raw_y; - float z_f = (float)raw_z; - float temp_x, temp_y, temp_z; - - // 2. 灵敏度/非正交校正 (矩阵乘法) - // temp_X = Sxx*x_f + Sxy*y_f + Sxz*z_f - // temp_Y = Syx*x_f + Syy*y_f + Syz*z_f - // temp_Z = Szx*x_f + Szy*y_f + Szz*z_f - // 使用 FMAC 加速 (Q1.15 格式) - // FMAC 通常处理定点数,我们需要将 float 转为 Q1.15 - // 或者,如果 FMAC 配置支持浮点,可以直接用浮点 - // 这里先用纯 C 实现,并标记出 FMAC 可用的地方 - - temp_x = params->scale_xx * x_f + params->scale_xy * y_f + params->scale_xz * z_f; - temp_y = params->scale_yx * x_f + params->scale_yy * y_f + params->scale_yz * z_f; - temp_z = params->scale_zx * x_f + params->scale_zy * y_f + params->scale_zz * z_f; - - // 3. 偏移校正 - *corrected_x = temp_x - params->offset_x; - *corrected_y = temp_y - params->offset_y; - *corrected_z = temp_z - params->offset_z; - - // --- 使用 FMAC 的示例 (需要配置 FMAC 和数据格式转换) --- - /* - // 假设输入 x_f, y_f, z_f 和系数 params->scale_** 已转换为 Q1.15 - int16_t input_vector[3] = { (int16_t)(x_f * 32768.0f), (int16_t)(y_f * 32768.0f), (int16_t)(z_f * 32768.0f) }; - int16_t coeffs_x[3] = { (int16_t)(params->scale_xx * 32768.0f), (int16_t)(params->scale_xy * 32768.0f), (int16_t)(params->scale_xz * 32768.0f) }; - int16_t coeffs_y[3] = { (int16_t)(params->scale_yx * 32768.0f), (int16_t)(params->scale_yy * 32768.0f), (int16_t)(params->scale_yz * 32768.0f) }; - int16_t coeffs_z[3] = { (int16_t)(params->scale_zx * 32768.0f), (int16_t)(params->scale_zy * 32768.0f), (int16_t)(params->scale_zz * 32768.0f) }; - int16_t result_vector[3]; - - // 计算 X - FMAC_FilterConfig(&hfmac, coeffs_x, 3, input_vector, result_vector, ...); // 配置 FIR - HAL_FMAC_FilterStart(&hfmac, ...); - while(HAL_FMAC_PollForTransfer(&hfmac, 10) != HAL_OK); - temp_x = (float)result_vector[0] / 32768.0f; // 转换回 float (近似) - - // 计算 Y - FMAC_FilterConfig(&hfmac, coeffs_y, 3, input_vector, result_vector, ...); - HAL_FMAC_FilterStart(&hfmac, ...); - while(HAL_FMAC_PollForTransfer(&hfmac, 10) != HAL_OK); - temp_y = (float)result_vector[0] / 32768.0f; - - // 计算 Z - FMAC_FilterConfig(&hfmac, coeffs_z, 3, input_vector, result_vector, ...); - HAL_FMAC_FilterStart(&hfmac, ...); - while(HAL_FMAC_PollForTransfer(&hfmac, 10) != HAL_OK); - temp_z = (float)result_vector[0] / 32768.0f; - - *corrected_x = temp_x - params->offset_x; - *corrected_y = temp_y - params->offset_y; - *corrected_z = temp_z - params->offset_z; - */ - - // --- 使用 CORDIC 的示例 (例如,计算校正后向量的模和角度) --- - /* - // 伪代码 - CORDIC_Config(&hcordic, ...); // 配置为计算模和相位 - HAL_CORDIC_Calculate(&hcordic, input_coords, output_coords, ...); - // 等待 CORDIC 完成 - */ + if (params == NULL || matrix == NULL) return; + + memcpy(params->correction_matrix, matrix, sizeof(params->correction_matrix)); + + #if USE_ARM_DSP + // 重新初始化ARM DSP矩阵实例 + arm_mat_init_f32(¶ms->matrix_inst, 3, 3, params->correction_matrix); + #endif } + +/** + * @brief 设置校正偏移 + * @param params: 参数结构体指针 + * @param offset_x, offset_y, offset_z: 偏移值 + * @retval None + */ +void Set_CorrectionOffsets(CorrectionParams_t *params, float offset_x, float offset_y, float offset_z) +{ + if (params == NULL) return; + + params->offset_x = offset_x; + params->offset_y = offset_y; + params->offset_z = offset_z; +} + +/** + * @brief 应用三分量校正 - 使用ARM DSP库优化 + * @param raw_x, raw_y, raw_z: 原始 ADC 数据 + * @param result: 校正结果结构体指针 + * @param params: 校正参数 + * @retval HAL_StatusTypeDef + */ +HAL_StatusTypeDef Apply_Correction(int32_t raw_x, int32_t raw_y, int32_t raw_z, + CorrectionResult_t *result, + const CorrectionParams_t *params) +{ + if (result == NULL || params == NULL || !params->params_valid) { + return HAL_ERROR; + } + + // 1. 将原始数据转换为浮点数并归一化 + input_vector[0] = (float)raw_x; + input_vector[1] = (float)raw_y; + input_vector[2] = (float)raw_z; + + #if USE_ARM_DSP + // 2. 使用ARM DSP库进行矩阵乘法运算 + arm_matrix_instance_f32 input_mat, output_mat; + arm_mat_init_f32(&input_mat, 3, 1, input_vector); + arm_mat_init_f32(&output_mat, 3, 1, output_vector); + + arm_status status = arm_mat_mult_f32(¶ms->matrix_inst, &input_mat, &output_mat); + if (status != ARM_MATH_SUCCESS) { + return HAL_ERROR; + } + + // 3. 应用偏移校正 + result->corrected_x = output_vector[0] - params->offset_x; + result->corrected_y = output_vector[1] - params->offset_y; + result->corrected_z = output_vector[2] - params->offset_z; + + #else + // 传统矩阵乘法实现(当ARM DSP库不可用时) + const float *matrix = params->correction_matrix; + + output_vector[0] = matrix[0] * input_vector[0] + matrix[1] * input_vector[1] + matrix[2] * input_vector[2]; + output_vector[1] = matrix[3] * input_vector[0] + matrix[4] * input_vector[1] + matrix[5] * input_vector[2]; + output_vector[2] = matrix[6] * input_vector[0] + matrix[7] * input_vector[1] + matrix[8] * input_vector[2]; + + // 应用偏移校正 + result->corrected_x = output_vector[0] - params->offset_x; + result->corrected_y = output_vector[1] - params->offset_y; + result->corrected_z = output_vector[2] - params->offset_z; + #endif + + // 4. 设置时间戳和状态 + result->timestamp = HAL_GetTick(); + result->correction_applied = 1; + + return HAL_OK; +} + +/** + * @brief 从Flash加载校正参数 + * @param params: 参数结构体指针 + * @retval None + */ +void Load_CorrectionParams_FromFlash(CorrectionParams_t *params) +{ + if (params == NULL) return; + + // TODO: 实现从Flash读取校正参数 + // 这里可以使用STM32的内部Flash或外部Flash存储 + // 暂时使用默认参数 + Init_CorrectionParams(params); +} + +/** + * @brief 保存校正参数到Flash + * @param params: 参数结构体指针 + * @retval HAL_StatusTypeDef + */ +HAL_StatusTypeDef Save_CorrectionParams_ToFlash(const CorrectionParams_t *params) +{ + if (params == NULL || !params->params_valid) { + return HAL_ERROR; + } + + // TODO: 实现保存校正参数到Flash + // 这里可以使用STM32的内部Flash或外部Flash存储 + + return HAL_OK; +} + diff --git a/User/correction.h b/User/correction.h index 4dc8673..7e143dd 100644 --- a/User/correction.h +++ b/User/correction.h @@ -1,20 +1,51 @@ #ifndef CORRECTION_H #define CORRECTION_H -#include "main.h" // For CORDIC and FMAC handles +#include "main.h" #include -// 假设的校正参数结构体,你需要填充实际参数 +// 使用ARM DSP库进行矩阵运算 +#ifdef ARM_MATH_CM4 +#include "arm_math.h" +#define USE_ARM_DSP 1 +#else +#define USE_ARM_DSP 0 +#endif + +// 校正参数结构体 typedef struct { + // 偏移参数 float offset_x, offset_y, offset_z; - float scale_xx, scale_xy, scale_xz; - float scale_yx, scale_yy, scale_yz; - float scale_zx, scale_zy, scale_zz; + + // 3x3校正矩阵 (行优先存储) + float correction_matrix[9]; + + // ARM DSP矩阵实例 + #if USE_ARM_DSP + arm_matrix_instance_f32 matrix_inst; + #endif + + // 校正参数有效标志 + uint8_t params_valid; } CorrectionParams_t; -void Init_CorrectionParams(CorrectionParams_t *params); // 初始化参数 -void Apply_Correction(int32_t raw_x, int32_t raw_y, int32_t raw_z, - float *corrected_x, float *corrected_y, float *corrected_z, - CorrectionParams_t *params); +// 校正结果结构体 +typedef struct { + float corrected_x; + float corrected_y; + float corrected_z; + uint32_t timestamp; + uint8_t correction_applied; +} CorrectionResult_t; + +// 函数声明 +void Init_CorrectionParams(CorrectionParams_t *params); +void Set_CorrectionMatrix(CorrectionParams_t *params, const float *matrix); +void Set_CorrectionOffsets(CorrectionParams_t *params, float offset_x, float offset_y, float offset_z); +HAL_StatusTypeDef Apply_Correction(int32_t raw_x, int32_t raw_y, int32_t raw_z, + CorrectionResult_t *result, + const CorrectionParams_t *params); +void Load_CorrectionParams_FromFlash(CorrectionParams_t *params); +HAL_StatusTypeDef Save_CorrectionParams_ToFlash(const CorrectionParams_t *params); #endif // CORRECTION_H \ No newline at end of file diff --git a/User/data_packet.c b/User/data_packet.c index fdb79c7..0970258 100644 --- a/User/data_packet.c +++ b/User/data_packet.c @@ -1,7 +1,9 @@ #include "data_packet.h" +#include "stddef.h" +#include "stm32f4xx_hal.h" -// CRC16-MODBUS -uint16_t Calculate_CRC16(uint8_t *data, uint16_t len) { +// CRC16-MODBUS算法实现 +uint16_t Calculate_CRC16(const uint8_t *data, uint16_t len) { uint16_t crc = 0xFFFF; for (uint16_t i = 0; i < len; i++) { crc ^= data[i]; @@ -18,21 +20,86 @@ uint16_t Calculate_CRC16(uint8_t *data, uint16_t len) { void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3) { - // packet->start_byte = PACKET_START_BYTE; // Incorrect assignment - uint32_t start = PACKET_START_BYTE; - packet->start_byte[0] = (start >> 24) & 0xFF; // A5 - packet->start_byte[1] = (start >> 16) & 0xFF; // A5 - packet->start_byte[2] = (start >> 8) & 0xFF; // 5A - packet->start_byte[3] = (start) & 0xFF; // 5A + if (packet == NULL) return; - // MCU 原生字节序 (小端) + // 设置包头 + packet->start_byte = PACKET_START_BYTE; + + // 设置时间戳 + packet->timestamp = HAL_GetTick(); + + // 设置ADC数据 packet->adc_data1 = adc1; packet->adc_data2 = adc2; packet->adc_data3 = adc3; - // 计算校验和 (只计算 ADC 数据部分) - // uint16_t checksum = Calculate_CRC16((uint8_t*)&packet->adc_data1, sizeof(uint32_t) * 3); - // packet->checksum = checksum; // 校验和也用小端 + // 计算校验和 (不包括校验和字段本身和包尾) + uint16_t checksum = Calculate_CRC16((uint8_t*)packet, + sizeof(DataPacket_t) - sizeof(packet->checksum) - sizeof(packet->end_byte)); + packet->checksum = checksum; -// packet->end_byte = PACKET_END_BYTE; + // 设置包尾 + packet->end_byte = PACKET_END_BYTE; +} + +uint8_t ValidatePacket(const DataPacket_t *packet) +{ + if (packet == NULL) return 0; + + // 检查包头 + if (packet->start_byte != PACKET_START_BYTE) return 0; + + // 检查包尾 + if (packet->end_byte != PACKET_END_BYTE) return 0; + + // 验证校验和 + uint16_t calculated_crc = Calculate_CRC16((uint8_t*)packet, + sizeof(DataPacket_t) - sizeof(packet->checksum) - sizeof(packet->end_byte)); + + if (calculated_crc != packet->checksum) return 0; + + return 1; // 验证通过 +} + +uint8_t ValidateCorrectedPacket(const CorrectedDataPacket_t *packet) +{ + if (packet == NULL) return 0; + + // 检查包头 + if (packet->start_byte != PACKET_START_BYTE) return 0; + + // 检查包尾 + if (packet->end_byte != PACKET_END_BYTE) return 0; + + // 验证校验和 + uint16_t calculated_crc = Calculate_CRC16((uint8_t*)packet, + sizeof(CorrectedDataPacket_t) - sizeof(packet->checksum) - sizeof(packet->end_byte)); + + if (calculated_crc != packet->checksum) return 0; + + return 1; // 验证通过 +} + +void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z) +{ + if (packet == NULL) return; + + // 设置包头 + packet->start_byte = PACKET_START_BYTE; + + // 设置时间戳 + packet->timestamp = HAL_GetTick(); + + // 设置校正后数据 + packet->corrected_x = x; + packet->corrected_y = y; + packet->corrected_z = z; + + // 计算校验和 + uint16_t checksum = Calculate_CRC16((uint8_t*)packet, + sizeof(CorrectedDataPacket_t) - sizeof(packet->checksum) - sizeof(packet->end_byte)); + packet->checksum = checksum; + + // 设置包尾 + packet->end_byte = PACKET_END_BYTE; } diff --git a/User/data_packet.h b/User/data_packet.h index b2aa246..106c3e9 100644 --- a/User/data_packet.h +++ b/User/data_packet.h @@ -4,19 +4,35 @@ #include #define PACKET_START_BYTE 0xFFFFFFFF -#define PACKET_END_BYTE 0x55 +#define PACKET_END_BYTE 0x0000 -// 数据包结构 +// 数据包结构 - 启用校验和和包尾 typedef struct __attribute__((packed)) { - uint8_t start_byte[4]; // 包头 - int32_t adc_data1; // ADC1 数据 (高位在前) - int32_t adc_data2; // ADC2 数据 (高位在前) - int32_t adc_data3; // ADC3 数据 (高位在前) - // uint16_t checksum; // 校验和 (例如 CRC16, 高位在前) - // uint8_t end_byte; // 包尾 + uint32_t start_byte; // 包头 (4字节) + uint32_t timestamp; // 时间戳 (4字节) + int32_t adc_data1; // ADC1 数据 (4字节) + int32_t adc_data2; // ADC2 数据 (4字节) + int32_t adc_data3; // ADC3 数据 (4字节) + uint16_t checksum; // CRC16校验和 (2字节) + uint16_t end_byte; // 包尾 (2字节) } DataPacket_t; -uint16_t Calculate_CRC16(uint8_t *data, uint16_t len); +// 校正后数据包结构 +typedef struct __attribute__((packed)) { + uint32_t start_byte; // 包头 + uint32_t timestamp; // 时间戳 + float corrected_x; // 校正后X轴数据 + float corrected_y; // 校正后Y轴数据 + float corrected_z; // 校正后Z轴数据 + uint16_t checksum; // CRC16校验和 + uint16_t end_byte; // 包尾 +} CorrectedDataPacket_t; + +// 函数声明 +uint16_t Calculate_CRC16(const uint8_t *data, uint16_t len); void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3); +void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z); +uint8_t ValidatePacket(const DataPacket_t *packet); +uint8_t ValidateCorrectedPacket(const CorrectedDataPacket_t *packet); #endif // DATA_PACKET_H diff --git a/User/data_storage.c b/User/data_storage.c new file mode 100644 index 0000000..b09174c --- /dev/null +++ b/User/data_storage.c @@ -0,0 +1,195 @@ +#include "data_storage.h" +#include +#include + +/** + * @brief 初始化数据存储模块 + * @param handle: 数据存储句柄指针 + * @retval HAL_StatusTypeDef + */ +HAL_StatusTypeDef DataStorage_Init(DataStorageHandle_t *handle) +{ + if (handle == NULL) { + return HAL_ERROR; + } + + // 初始化句柄 + memset(handle, 0, sizeof(DataStorageHandle_t)); + + // 创建数据存储目录 + FRESULT res = f_mkdir(DATA_STORAGE_PATH); + if (res != FR_OK && res != FR_EXIST) { + return HAL_ERROR; + } + + handle->stats.state = DATA_STORAGE_IDLE; + handle->initialized = 1; + + return HAL_OK; +} + +/** + * @brief 停止数据记录 + * @param handle: 数据存储句柄指针 + * @retval HAL_StatusTypeDef + */ +HAL_StatusTypeDef DataStorage_StopRecording(DataStorageHandle_t *handle) +{ + if (handle == NULL || !handle->initialized) { + return HAL_ERROR; + } + + if (handle->stats.state != DATA_STORAGE_RECORDING) { + return HAL_OK; // 没有在记录中 + } + + // 刷新缓冲区 + DataStorage_Flush(handle); + + // 关闭文件 + f_close(&handle->file); + + handle->stats.state = DATA_STORAGE_IDLE; + + return HAL_OK; +} + +/** + * @brief 写入数据包到存储 + * @param handle: 数据存储句柄指针 + * @param packet: 数据包指针 + * @retval HAL_StatusTypeDef + */ +HAL_StatusTypeDef DataStorage_WriteData(DataStorageHandle_t *handle, const DataPacket_t *packet) +{ + if (handle == NULL || packet == NULL || !handle->initialized) { + return HAL_ERROR; + } + + if (handle->stats.state != DATA_STORAGE_RECORDING) { + return HAL_ERROR; + } + + // 检查缓冲区空间 + if (handle->buffer_index + sizeof(DataPacket_t) > DATA_STORAGE_BUFFER_SIZE) { + // 刷新缓冲区 + if (DataStorage_Flush(handle) != HAL_OK) { + handle->stats.error_count++; + return HAL_ERROR; + } + } + + // 复制数据到缓冲区 + memcpy(&handle->buffer[handle->buffer_index], packet, sizeof(DataPacket_t)); + handle->buffer_index += sizeof(DataPacket_t); + handle->stats.total_samples++; + + return HAL_OK; +} + +/** + * @brief 刷新缓冲区到文件 + * @param handle: 数据存储句柄指针 + * @retval HAL_StatusTypeDef + */ +HAL_StatusTypeDef DataStorage_Flush(DataStorageHandle_t *handle) +{ + if (handle == NULL || !handle->initialized || handle->buffer_index == 0) { + return HAL_OK; + } + + UINT bytes_written; + FRESULT res = f_write(&handle->file, handle->buffer, handle->buffer_index, &bytes_written); + + if (res != FR_OK || bytes_written != handle->buffer_index) { + handle->stats.error_count++; + return HAL_ERROR; + } + + // 同步到存储设备 + f_sync(&handle->file); + + handle->stats.current_file_size += bytes_written; + handle->buffer_index = 0; + + // 检查文件大小是否超过限制 + if (handle->stats.current_file_size >= DATA_STORAGE_FILE_MAX_SIZE) { + f_close(&handle->file); + DataStorage_CreateNewFile(handle); + } + + return HAL_OK; +} + +/** + * @brief 创建新的数据文件 + * @param handle: 数据存储句柄指针 + * @retval HAL_StatusTypeDef + */ +HAL_StatusTypeDef DataStorage_CreateNewFile(DataStorageHandle_t *handle) +{ + if (handle == NULL || !handle->initialized) { + return HAL_ERROR; + } + + // 生成文件名 (基于时间戳) + uint32_t timestamp = HAL_GetTick(); + snprintf(handle->stats.current_filename, sizeof(handle->stats.current_filename), + "%s%s%08lX.dat", DATA_STORAGE_PATH, DATA_STORAGE_FILE_PREFIX, timestamp); + + // 创建并打开文件 + FRESULT res = f_open(&handle->file, handle->stats.current_filename, + FA_CREATE_ALWAYS | FA_WRITE); + + if (res != FR_OK) { + handle->stats.error_count++; + return HAL_ERROR; + } + + handle->stats.file_count++; + handle->stats.current_file_size = 0; + + return HAL_OK; +} + +/** + * @brief 获取数据存储统计信息 + * @param handle: 数据存储句柄指针 + * @param stats: 统计信息结构体指针 + * @retval None + */ +void DataStorage_GetStats(DataStorageHandle_t *handle, DataStorageStats_t *stats) +{ + if (handle == NULL || stats == NULL || !handle->initialized) { + return; + } + + memcpy(stats, &handle->stats, sizeof(DataStorageStats_t)); +} + +/** + * @brief 开始数据记录 + * @param handle: 数据存储句柄指针 + * @retval HAL_StatusTypeDef + */ +HAL_StatusTypeDef DataStorage_StartRecording(DataStorageHandle_t *handle) +{ + if (handle == NULL || !handle->initialized) { + return HAL_ERROR; + } + + if (handle->stats.state == DATA_STORAGE_RECORDING) { + return HAL_OK; // 已经在记录中 + } + + // 创建新文件 + if (DataStorage_CreateNewFile(handle) != HAL_OK) { + handle->stats.state = DATA_STORAGE_ERROR; + return HAL_ERROR; + } + + handle->stats.state = DATA_STORAGE_RECORDING; + handle->buffer_index = 0; + + return HAL_OK; +} \ No newline at end of file diff --git a/User/data_storage.h b/User/data_storage.h new file mode 100644 index 0000000..7bb0213 --- /dev/null +++ b/User/data_storage.h @@ -0,0 +1,54 @@ +#ifndef DATA_STORAGE_H +#define DATA_STORAGE_H + +#include "main.h" +#include "fatfs.h" +#include "ff.h" +#include "data_packet.h" +#include "correction.h" +#include + +// 数据存储配置 +#define DATA_STORAGE_BUFFER_SIZE 1024 // 缓冲区大小(字节) +#define DATA_STORAGE_FILE_MAX_SIZE (10*1024*1024) // 单个文件最大10MB +#define DATA_STORAGE_PATH "0:/DATA/" // 数据存储路径 +#define DATA_STORAGE_FILE_PREFIX "ADC_DATA_" // 文件名前缀 + +// 数据存储状态 +typedef enum { + DATA_STORAGE_IDLE = 0, + DATA_STORAGE_RECORDING, + DATA_STORAGE_ERROR, + DATA_STORAGE_FULL +} DataStorageState_t; + +// 数据存储统计信息 +typedef struct { + uint32_t total_samples; + uint32_t current_file_size; + uint32_t file_count; + uint32_t error_count; + DataStorageState_t state; + char current_filename[64]; +} DataStorageStats_t; + +// 数据存储句柄 +typedef struct { + FIL file; + uint8_t buffer[DATA_STORAGE_BUFFER_SIZE]; + uint16_t buffer_index; + DataStorageStats_t stats; + uint8_t initialized; +} DataStorageHandle_t; + +// 函数声明 +HAL_StatusTypeDef DataStorage_Init(DataStorageHandle_t *handle); +HAL_StatusTypeDef DataStorage_StartRecording(DataStorageHandle_t *handle); +HAL_StatusTypeDef DataStorage_StopRecording(DataStorageHandle_t *handle); +HAL_StatusTypeDef DataStorage_WriteData(DataStorageHandle_t *handle, const DataPacket_t *packet); +HAL_StatusTypeDef DataStorage_WriteCorrectedData(DataStorageHandle_t *handle, const CorrectionResult_t *result); +HAL_StatusTypeDef DataStorage_Flush(DataStorageHandle_t *handle); +void DataStorage_GetStats(DataStorageHandle_t *handle, DataStorageStats_t *stats); +HAL_StatusTypeDef DataStorage_CreateNewFile(DataStorageHandle_t *handle); + +#endif // DATA_STORAGE_H \ No newline at end of file diff --git a/User/ltc2508_driver.c b/User/ltc2508_driver.c index 817faa1..68c7577 100644 --- a/User/ltc2508_driver.c +++ b/User/ltc2508_driver.c @@ -6,6 +6,9 @@ volatile uint16_t g_adc_data[NUM_LTC2508][LTC2508_DATA_LEN] = {0}; volatile uint8_t g_adc_data_ready_flag = 0; volatile uint8_t g_dma_complete_count = 0; +// 错误统计信息 +LTC2508_StatsTypeDef g_ltc2508_stats = {0}; + // SPI 句柄指针 static SPI_HandleTypeDef *g_hspi1 = NULL; static SPI_HandleTypeDef *g_hspi2 = NULL; @@ -16,55 +19,82 @@ static SPI_HandleTypeDef *g_hspi3 = NULL; * @param hspi1: SPI1 句柄指针 * @param hspi2: SPI2 句柄指针 * @param hspi3: SPI3 句柄指针 - * @retval None + * @retval LTC2508_StatusTypeDef */ -void LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_HandleTypeDef *hspi3) +LTC2508_StatusTypeDef LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_HandleTypeDef *hspi3) { + // 参数检查 + if (hspi1 == NULL || hspi2 == NULL || hspi3 == NULL) { + g_ltc2508_stats.error_count++; + g_ltc2508_stats.last_error = LTC2508_ERROR_INIT; + return LTC2508_ERROR_INIT; + } + g_hspi1 = hspi1; g_hspi2 = hspi2; g_hspi3 = hspi3; g_adc_data_ready_flag = 0; g_dma_complete_count = 0; memset((void*)g_adc_data, 0, sizeof(g_adc_data)); + + // 重置统计信息 + memset(&g_ltc2508_stats, 0, sizeof(g_ltc2508_stats)); // 可以在这里添加对 LTC2508 的配置,如果需要通过 SPI 发送配置字 // 例如:HAL_SPI_Transmit(g_hspi1, &config_word, 1, 100); + + return LTC2508_OK; } /** * @brief 触发三路 SPI 通过 DMA 读取数据 * @param None - * @retval None + * @retval LTC2508_StatusTypeDef */ -void LTC2508_TriggerDmaRead(void) +LTC2508_StatusTypeDef LTC2508_TriggerDmaRead(void) { + // 检查SPI句柄是否有效 + if (g_hspi1 == NULL || g_hspi2 == NULL || g_hspi3 == NULL) { + g_ltc2508_stats.error_count++; + g_ltc2508_stats.last_error = LTC2508_ERROR_INIT; + return LTC2508_ERROR_INIT; + } + if (g_adc_data_ready_flag == 0 && g_dma_complete_count == 0) // 确保上次数据已处理且 DMA 未在进行 { g_dma_complete_count = 0; // 重置计数 -// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); -// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); - // SPI2 和 SPI3 作为从机只接收 - if (HAL_SPI_Receive_DMA(g_hspi2, (uint8_t*)g_adc_data[1], LTC2508_DATA_LEN) != HAL_OK) - { - Error_Handler(); - } + if (HAL_SPI_Receive_DMA(g_hspi2, (uint8_t*)g_adc_data[1], LTC2508_DATA_LEN * 2) != HAL_OK) + { + g_ltc2508_stats.dma_error_count++; + g_ltc2508_stats.error_count++; + g_ltc2508_stats.last_error = LTC2508_ERROR_DMA; + return LTC2508_ERROR_DMA; + } - if (HAL_SPI_Receive_DMA(g_hspi3, (uint8_t*)g_adc_data[2], LTC2508_DATA_LEN) != HAL_OK) - { - Error_Handler(); - } + if (HAL_SPI_Receive_DMA(g_hspi3, (uint8_t*)g_adc_data[2], LTC2508_DATA_LEN * 2) != HAL_OK) + { + g_ltc2508_stats.dma_error_count++; + g_ltc2508_stats.error_count++; + g_ltc2508_stats.last_error = LTC2508_ERROR_DMA; + return LTC2508_ERROR_DMA; + } // SPI1 作为主机收发,先发一个 dummy 数据触发时钟 uint16_t dummy_tx[LTC2508_DATA_LEN] = {0}; // 可以是任意值 - if (HAL_SPI_TransmitReceive_DMA(g_hspi1, (uint8_t*)dummy_tx, (uint8_t*)g_adc_data[0], LTC2508_DATA_LEN) != HAL_OK) + if (HAL_SPI_TransmitReceive_DMA(g_hspi1, (uint8_t*)dummy_tx, (uint8_t*)g_adc_data[0], LTC2508_DATA_LEN * 2) != HAL_OK) { - Error_Handler(); + g_ltc2508_stats.dma_error_count++; + g_ltc2508_stats.error_count++; + g_ltc2508_stats.last_error = LTC2508_ERROR_DMA; + return LTC2508_ERROR_DMA; } - + return LTC2508_OK; } + + return LTC2508_ERROR_TIMEOUT; // 上次数据未处理完成 } /** @@ -76,32 +106,76 @@ void LTC2508_DmaComplete_Callback(SPI_HandleTypeDef *hspi) { if (hspi == g_hspi1 || hspi == g_hspi2 || hspi == g_hspi3) { - g_dma_complete_count = NUM_LTC2508; - if (g_dma_complete_count == NUM_LTC2508) + g_dma_complete_count++; + if (g_dma_complete_count >= NUM_LTC2508) { g_adc_data_ready_flag = 1; g_dma_complete_count = 0; // 为下一次读取做准备 + g_ltc2508_stats.total_samples++; } } } -// 需要在 stm32g4xx_it.c 中正确地调用 HAL_SPI_IRQHandler -// 并在 stm32g4xx_hal_spi.c 或 stm32g4xx_it.c 中添加以下回调函数的弱定义, -// 如果它们还没有被定义的话: -/* -__weak void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) +/** + * @brief SPI DMA 传输错误回调函数 + * @param hspi: SPI 句柄指针 + * @retval None + */ +void LTC2508_ErrorCallback(SPI_HandleTypeDef *hspi) { - LTC2508_DmaComplete_Callback(hspi); + if (hspi == g_hspi1 || hspi == g_hspi2 || hspi == g_hspi3) + { + g_ltc2508_stats.dma_error_count++; + g_ltc2508_stats.error_count++; + g_ltc2508_stats.last_error = LTC2508_ERROR_DMA; + + // 重置DMA状态 + g_dma_complete_count = 0; + g_adc_data_ready_flag = 0; + } } -__weak void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) +/** + * @brief 验证ADC数据有效性 + * @param channel: ADC通道 (0-2) + * @retval LTC2508_StatusTypeDef + */ +LTC2508_StatusTypeDef LTC2508_ValidateData(uint8_t channel) { - LTC2508_DmaComplete_Callback(hspi); + if (channel >= NUM_LTC2508) { + return LTC2508_ERROR_DATA_INVALID; + } + + // 检查数据是否为全0或全1 (可能的错误状态) + uint32_t combined_data = ((uint32_t)g_adc_data[channel][0] << 16) | g_adc_data[channel][1]; + + if (combined_data == 0x00000000 || combined_data == 0xFFFFFFFF) { + g_ltc2508_stats.error_count++; + g_ltc2508_stats.last_error = LTC2508_ERROR_DATA_INVALID; + return LTC2508_ERROR_DATA_INVALID; + } + + return LTC2508_OK; } -__weak void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) +/** + * @brief 获取统计信息 + * @param stats: 统计信息结构体指针 + * @retval None + */ +void LTC2508_GetStats(LTC2508_StatsTypeDef *stats) { - // Handle error - Error_Handler(); + if (stats != NULL) { + memcpy(stats, &g_ltc2508_stats, sizeof(LTC2508_StatsTypeDef)); + } +} + +/** + * @brief 重置统计信息 + * @param None + * @retval None + */ +void LTC2508_ResetStats(void) +{ + memset(&g_ltc2508_stats, 0, sizeof(LTC2508_StatsTypeDef)); } -*/ diff --git a/User/ltc2508_driver.h b/User/ltc2508_driver.h index ccce94f..24fd1c2 100644 --- a/User/ltc2508_driver.h +++ b/User/ltc2508_driver.h @@ -9,14 +9,39 @@ // 假设我们有3个 LTC2508 #define NUM_LTC2508 3 +// LTC2508错误状态定义 +typedef enum { + LTC2508_OK = 0, + LTC2508_ERROR_INIT, + LTC2508_ERROR_SPI, + LTC2508_ERROR_DMA, + LTC2508_ERROR_TIMEOUT, + LTC2508_ERROR_DATA_INVALID +} LTC2508_StatusTypeDef; + +// LTC2508统计信息 +typedef struct { + uint32_t total_samples; + uint32_t error_count; + uint32_t timeout_count; + uint32_t dma_error_count; + uint8_t last_error; +} LTC2508_StatsTypeDef; + // 用于存储三路 ADC 数据的全局变量 (每个 ADC 2个 16-bit 数据) extern volatile uint16_t g_adc_data[NUM_LTC2508][LTC2508_DATA_LEN]; // ADC 数据准备就绪标志 extern volatile uint8_t g_adc_data_ready_flag; +// 错误统计信息 +extern LTC2508_StatsTypeDef g_ltc2508_stats; // 函数原型 -void LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_HandleTypeDef *hspi3); -void LTC2508_TriggerDmaRead(void); +LTC2508_StatusTypeDef LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_HandleTypeDef *hspi3); +LTC2508_StatusTypeDef LTC2508_TriggerDmaRead(void); void LTC2508_DmaComplete_Callback(SPI_HandleTypeDef *hspi); +void LTC2508_ErrorCallback(SPI_HandleTypeDef *hspi); +LTC2508_StatusTypeDef LTC2508_ValidateData(uint8_t channel); +void LTC2508_GetStats(LTC2508_StatsTypeDef *stats); +void LTC2508_ResetStats(void); #endif // LTC2508_DRIVER_H \ No newline at end of file diff --git a/User/system_monitor.c b/User/system_monitor.c new file mode 100644 index 0000000..d00b751 --- /dev/null +++ b/User/system_monitor.c @@ -0,0 +1,113 @@ +#include "system_monitor.h" +#include + +// 静态变量 +static SystemMonitorStats_t g_system_stats = {0}; +static uint32_t g_last_update_tick = 0; + +/** + * @brief 初始化系统监控模块 + * @param None + * @retval None + */ +void SystemMonitor_Init(void) +{ + memset(&g_system_stats, 0, sizeof(SystemMonitorStats_t)); + g_system_stats.current_state = SYSTEM_STATE_INIT; + g_last_update_tick = HAL_GetTick(); +} + +/** + * @brief 更新系统监控状态 + * @param None + * @retval None + */ +void SystemMonitor_Update(void) +{ + uint32_t current_tick = HAL_GetTick(); + + // 更新运行时间 + if (current_tick >= g_last_update_tick) { + g_system_stats.uptime_seconds = current_tick / 1000; + } + + // 获取LTC2508统计信息 + LTC2508_StatsTypeDef ltc_stats; + LTC2508_GetStats(<c_stats); + g_system_stats.total_samples = ltc_stats.total_samples; + + // 检查ADC错误 + if (ltc_stats.error_count > 0) { + SystemMonitor_ReportError(SYSTEM_ERROR_ADC); + } + + g_last_update_tick = current_tick; +} + +/** + * @brief 获取当前系统状态 + * @param None + * @retval SystemState_t + */ +SystemState_t SystemMonitor_GetState(void) +{ + return g_system_stats.current_state; +} + +/** + * @brief 设置系统状态 + * @param new_state: 新的系统状态 + * @retval None + */ +void SystemMonitor_SetState(SystemState_t new_state) +{ + g_system_stats.current_state = new_state; +} + +/** + * @brief 报告系统错误 + * @param error: 错误类型 + * @retval None + */ +void SystemMonitor_ReportError(SystemError_t error) +{ + g_system_stats.last_error = error; + g_system_stats.error_count++; + + // 根据错误类型设置系统状态 + if (error == SYSTEM_ERROR_CRITICAL) { + g_system_stats.current_state = SYSTEM_STATE_ERROR; + } +} + +/** + * @brief 获取系统统计信息 + * @param stats: 统计信息结构体指针 + * @retval None + */ +void SystemMonitor_GetStats(SystemMonitorStats_t *stats) +{ + if (stats != NULL) { + memcpy(stats, &g_system_stats, sizeof(SystemMonitorStats_t)); + } +} + +/** + * @brief 检查系统健康状态 + * @param None + * @retval uint8_t: 1-健康, 0-异常 + */ +uint8_t SystemMonitor_IsHealthy(void) +{ + // 检查系统状态 + if (g_system_stats.current_state == SYSTEM_STATE_ERROR) { + return 0; + } + + // 检查错误计数 + if (g_system_stats.error_count > 10) { + return 0; + } + + return 1; // 系统健康 +} \ No newline at end of file diff --git a/User/system_monitor.h b/User/system_monitor.h new file mode 100644 index 0000000..84a8834 --- /dev/null +++ b/User/system_monitor.h @@ -0,0 +1,51 @@ +#ifndef SYSTEM_MONITOR_H +#define SYSTEM_MONITOR_H + +#include "main.h" +#include "ltc2508_driver.h" +#include "data_storage.h" +#include + +// 系统状态定义 +typedef enum { + SYSTEM_STATE_INIT = 0, + SYSTEM_STATE_IDLE, + SYSTEM_STATE_SAMPLING, + SYSTEM_STATE_RECORDING, + SYSTEM_STATE_ERROR, + SYSTEM_STATE_MAINTENANCE +} SystemState_t; + +// 系统错误类型 +typedef enum { + SYSTEM_ERROR_NONE = 0, + SYSTEM_ERROR_ADC, + SYSTEM_ERROR_STORAGE, + SYSTEM_ERROR_USB, + SYSTEM_ERROR_COMMUNICATION, + SYSTEM_ERROR_MEMORY, + SYSTEM_ERROR_CRITICAL +} SystemError_t; + +// 系统监控统计信息 +typedef struct { + SystemState_t current_state; + SystemError_t last_error; + uint32_t uptime_seconds; + uint32_t total_samples; + uint32_t error_count; + uint32_t memory_usage; + uint8_t cpu_usage_percent; + uint8_t temperature_celsius; +} SystemMonitorStats_t; + +// 函数声明 +void SystemMonitor_Init(void); +void SystemMonitor_Update(void); +SystemState_t SystemMonitor_GetState(void); +void SystemMonitor_SetState(SystemState_t new_state); +void SystemMonitor_ReportError(SystemError_t error); +void SystemMonitor_GetStats(SystemMonitorStats_t *stats); +uint8_t SystemMonitor_IsHealthy(void); + +#endif // SYSTEM_MONITOR_H \ No newline at end of file