feat(adc): implement comprehensive ADC data acquisition and processing system
Add complete data acquisition pipeline with LTC2508 ADC drivers, correction algorithms, data storage, and system monitoring. Includes ARM DSP optimized matrix operations for sensor calibration, SD card data logging with USB mass storage, and robust error handling with validation throughout the processing chain. - Add LTC2508 multi-channel SPI driver with DMA support and error recovery - Implement correction module with ARM DSP matrix operations for sensor calibration - Add data storage system with SD card logging and configurable file management - Integrate system monitor for health tracking and error reporting - Enhance data packet structure with CRC validation and timestamps - Add USB mass storage interface for SD card access - Implement comprehensive error handling and statistics collection
This commit is contained in:
parent
8d9bcd092b
commit
6297f3044d
110
Core/Src/main.c
110
Core/Src/main.c
@ -32,6 +32,9 @@
|
|||||||
#include "ltc2508_driver.h"
|
#include "ltc2508_driver.h"
|
||||||
#include "rs485_driver.h"
|
#include "rs485_driver.h"
|
||||||
#include "data_packet.h"
|
#include "data_packet.h"
|
||||||
|
#include "correction.h"
|
||||||
|
#include "data_storage.h"
|
||||||
|
#include "system_monitor.h"
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
@ -52,8 +55,15 @@
|
|||||||
/* Private variables ---------------------------------------------------------*/
|
/* Private variables ---------------------------------------------------------*/
|
||||||
|
|
||||||
/* USER CODE BEGIN PV */
|
/* USER CODE BEGIN PV */
|
||||||
//CorrectionParams_t g_correction_params;
|
// 校正参数
|
||||||
|
CorrectionParams_t g_correction_params;
|
||||||
|
// 数据包
|
||||||
DataPacket_t g_data_packet;
|
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 */
|
/* USER CODE END PV */
|
||||||
|
|
||||||
/* Private function prototypes -----------------------------------------------*/
|
/* Private function prototypes -----------------------------------------------*/
|
||||||
@ -107,12 +117,32 @@ int main(void)
|
|||||||
MX_USB_DEVICE_Init();
|
MX_USB_DEVICE_Init();
|
||||||
MX_USART3_UART_Init();
|
MX_USART3_UART_Init();
|
||||||
/* USER CODE BEGIN 2 */
|
/* 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);
|
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);
|
// 初始化校正参数
|
||||||
|
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_SET);
|
||||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
|
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
|
||||||
/* USER CODE END 2 */
|
/* USER CODE END 2 */
|
||||||
@ -124,39 +154,65 @@ int main(void)
|
|||||||
/* USER CODE END WHILE */
|
/* USER CODE END WHILE */
|
||||||
|
|
||||||
/* USER CODE BEGIN 3 */
|
/* 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)
|
if (g_adc_data_ready_flag)
|
||||||
{
|
{
|
||||||
g_adc_data_ready_flag = 0; // <20><><EFBFBD><EFBFBD><EFBFBD>־
|
g_adc_data_ready_flag = 0; // 清除标志
|
||||||
|
SystemMonitor_SetState(SYSTEM_STATE_SAMPLING);
|
||||||
|
|
||||||
// 1. <20>ϲ<EFBFBD><CFB2><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD>16λ<36><CEBB>ǰ)
|
// 1. 合并数据 (高位16位在前)
|
||||||
int32_t raw_adc[NUM_LTC2508];
|
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[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[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]);
|
raw_adc[2] = (int32_t)(((uint32_t)g_adc_data[2][0] << 16) | g_adc_data[2][1]);
|
||||||
|
|
||||||
#if 0
|
// 2. 验证数据有效性
|
||||||
// 2. У<><D0A3>
|
for (uint8_t i = 0; i < NUM_LTC2508; i++) {
|
||||||
float corrected_x, corrected_y, corrected_z;
|
if (LTC2508_ValidateData(i) != LTC2508_OK) {
|
||||||
Apply_Correction(raw_adc[0], raw_adc[1], raw_adc[2],
|
SystemMonitor_ReportError(SYSTEM_ERROR_ADC);
|
||||||
&corrected_x, &corrected_y, &corrected_z,
|
continue; // 跳过无效数据
|
||||||
&g_correction_params);
|
|
||||||
|
|
||||||
// 3. <20><>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD> float תΪ int32_t (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|
||||||
int32_t final_adc1 = (int32_t)(corrected_x);
|
|
||||||
int32_t final_adc2 = (int32_t)(corrected_y);
|
|
||||||
int32_t final_adc3 = (int32_t)(corrected_z);
|
|
||||||
|
|
||||||
// 4. <20><><EFBFBD>
|
|
||||||
PackData(&g_data_packet, (uint32_t)final_adc1, (uint32_t)final_adc2, (uint32_t)final_adc3);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 4. <20><><EFBFBD>
|
|
||||||
PackData(&g_data_packet, raw_adc[0] , raw_adc[1] , raw_adc[2]);
|
|
||||||
|
|
||||||
// 5. <20><><EFBFBD><EFBFBD>
|
|
||||||
RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 发送数据包
|
||||||
|
if (RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t)) != HAL_OK) {
|
||||||
|
SystemMonitor_ReportError(SYSTEM_ERROR_COMMUNICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 */
|
/* USER CODE END 3 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,8 @@
|
|||||||
#include "usbd_storage_if.h"
|
#include "usbd_storage_if.h"
|
||||||
|
|
||||||
/* USER CODE BEGIN INCLUDE */
|
/* USER CODE BEGIN INCLUDE */
|
||||||
|
#include "fatfs.h"
|
||||||
|
#include "ff.h"
|
||||||
/* USER CODE END INCLUDE */
|
/* USER CODE END INCLUDE */
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
@ -31,7 +32,11 @@
|
|||||||
|
|
||||||
/* USER CODE BEGIN PV */
|
/* USER CODE BEGIN PV */
|
||||||
/* Private variables ---------------------------------------------------------*/
|
/* Private variables ---------------------------------------------------------*/
|
||||||
|
extern SD_HandleTypeDef hsd;
|
||||||
|
extern FATFS SDFatFS;
|
||||||
|
extern char SDPath[4];
|
||||||
|
|
||||||
|
static uint8_t sd_initialized = 0;
|
||||||
/* USER CODE END PV */
|
/* USER CODE END PV */
|
||||||
|
|
||||||
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
|
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
|
||||||
@ -179,6 +184,17 @@ int8_t STORAGE_Init_FS(uint8_t lun)
|
|||||||
/* USER CODE BEGIN 2 */
|
/* 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);
|
return (USBD_OK);
|
||||||
/* USER CODE END 2 */
|
/* USER CODE END 2 */
|
||||||
}
|
}
|
||||||
@ -195,8 +211,19 @@ int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_
|
|||||||
/* USER CODE BEGIN 3 */
|
/* USER CODE BEGIN 3 */
|
||||||
UNUSED(lun);
|
UNUSED(lun);
|
||||||
|
|
||||||
|
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_num = STORAGE_BLK_NBR;
|
||||||
*block_size = STORAGE_BLK_SIZ;
|
*block_size = STORAGE_BLK_SIZ;
|
||||||
|
}
|
||||||
|
|
||||||
return (USBD_OK);
|
return (USBD_OK);
|
||||||
/* USER CODE END 3 */
|
/* USER CODE END 3 */
|
||||||
}
|
}
|
||||||
@ -211,7 +238,16 @@ int8_t STORAGE_IsReady_FS(uint8_t lun)
|
|||||||
/* USER CODE BEGIN 4 */
|
/* USER CODE BEGIN 4 */
|
||||||
UNUSED(lun);
|
UNUSED(lun);
|
||||||
|
|
||||||
|
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_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (USBD_FAIL);
|
||||||
/* USER CODE END 4 */
|
/* USER CODE END 4 */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,9 +277,14 @@ int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t bl
|
|||||||
{
|
{
|
||||||
/* USER CODE BEGIN 6 */
|
/* USER CODE BEGIN 6 */
|
||||||
UNUSED(lun);
|
UNUSED(lun);
|
||||||
UNUSED(buf);
|
|
||||||
UNUSED(blk_addr);
|
if (!sd_initialized || buf == NULL) {
|
||||||
UNUSED(blk_len);
|
return (USBD_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, HAL_MAX_DELAY) != HAL_OK) {
|
||||||
|
return (USBD_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
return (USBD_OK);
|
return (USBD_OK);
|
||||||
/* USER CODE END 6 */
|
/* USER CODE END 6 */
|
||||||
@ -261,9 +302,14 @@ int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t b
|
|||||||
{
|
{
|
||||||
/* USER CODE BEGIN 7 */
|
/* USER CODE BEGIN 7 */
|
||||||
UNUSED(lun);
|
UNUSED(lun);
|
||||||
UNUSED(buf);
|
|
||||||
UNUSED(blk_addr);
|
if (!sd_initialized || buf == NULL) {
|
||||||
UNUSED(blk_len);
|
return (USBD_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, HAL_MAX_DELAY) != HAL_OK) {
|
||||||
|
return (USBD_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
return (USBD_OK);
|
return (USBD_OK);
|
||||||
/* USER CODE END 7 */
|
/* USER CODE END 7 */
|
||||||
|
|||||||
@ -1,102 +1,157 @@
|
|||||||
#include "correction.h"
|
#include "correction.h"
|
||||||
//#include "fmac.h"
|
#include <string.h>
|
||||||
//#include "cordic.h"
|
#include "stddef.h"
|
||||||
|
|
||||||
// 外部的 FMAC 和 CORDIC 句柄
|
static float input_vector[3];
|
||||||
//extern FMAC_HandleTypeDef hfmac;
|
static float output_vector[3];
|
||||||
//extern CORDIC_HandleTypeDef hcordic;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 初始化校正参数(示例)
|
* @brief 初始化校正参数为默认值
|
||||||
* @param params: 参数结构体指针
|
* @param params: 参数结构体指针
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void Init_CorrectionParams(CorrectionParams_t *params)
|
void Init_CorrectionParams(CorrectionParams_t *params)
|
||||||
{
|
{
|
||||||
// --- 请在这里填充你从校准中得到的实际参数 ---
|
if (params == NULL) return;
|
||||||
// 偏移
|
|
||||||
|
// 初始化偏移为0
|
||||||
params->offset_x = 0.0f;
|
params->offset_x = 0.0f;
|
||||||
params->offset_y = 0.0f;
|
params->offset_y = 0.0f;
|
||||||
params->offset_z = 0.0f;
|
params->offset_z = 0.0f;
|
||||||
|
|
||||||
// 灵敏度/非正交矩阵 (这里假设为单位矩阵)
|
// 初始化为单位矩阵
|
||||||
params->scale_xx = 1.0f; params->scale_xy = 0.0f; params->scale_xz = 0.0f;
|
memset(params->correction_matrix, 0, sizeof(params->correction_matrix));
|
||||||
params->scale_yx = 0.0f; params->scale_yy = 1.0f; params->scale_yz = 0.0f;
|
params->correction_matrix[0] = 1.0f; // [0,0]
|
||||||
params->scale_zx = 0.0f; params->scale_zy = 0.0f; params->scale_zz = 1.0f;
|
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 应用三分量校正
|
* @brief 设置校正矩阵
|
||||||
* @param raw_x, raw_y, raw_z: 原始 ADC 数据
|
* @param params: 参数结构体指针
|
||||||
* @param corrected_x, corrected_y, corrected_z: 校正后数据的指针
|
* @param matrix: 3x3校正矩阵(行优先存储)
|
||||||
* @param params: 校正参数
|
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void Apply_Correction(int32_t raw_x, int32_t raw_y, int32_t raw_z,
|
void Set_CorrectionMatrix(CorrectionParams_t *params, const float *matrix)
|
||||||
float *corrected_x, float *corrected_y, float *corrected_z,
|
|
||||||
CorrectionParams_t *params)
|
|
||||||
{
|
{
|
||||||
// 1. 将原始数据转换为浮点数
|
if (params == NULL || matrix == NULL) return;
|
||||||
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. 灵敏度/非正交校正 (矩阵乘法)
|
memcpy(params->correction_matrix, matrix, sizeof(params->correction_matrix));
|
||||||
// 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;
|
#if USE_ARM_DSP
|
||||||
temp_y = params->scale_yx * x_f + params->scale_yy * y_f + params->scale_yz * z_f;
|
// 重新初始化ARM DSP矩阵实例
|
||||||
temp_z = params->scale_zx * x_f + params->scale_zy * y_f + params->scale_zz * z_f;
|
arm_mat_init_f32(¶ms->matrix_inst, 3, 3, params->correction_matrix);
|
||||||
|
#endif
|
||||||
// 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 完成
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,51 @@
|
|||||||
#ifndef CORRECTION_H
|
#ifndef CORRECTION_H
|
||||||
#define CORRECTION_H
|
#define CORRECTION_H
|
||||||
|
|
||||||
#include "main.h" // For CORDIC and FMAC handles
|
#include "main.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// 假设的校正参数结构体,你需要填充实际参数
|
// 使用ARM DSP库进行矩阵运算
|
||||||
|
#ifdef ARM_MATH_CM4
|
||||||
|
#include "arm_math.h"
|
||||||
|
#define USE_ARM_DSP 1
|
||||||
|
#else
|
||||||
|
#define USE_ARM_DSP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 校正参数结构体
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
// 偏移参数
|
||||||
float offset_x, offset_y, offset_z;
|
float offset_x, offset_y, offset_z;
|
||||||
float scale_xx, scale_xy, scale_xz;
|
|
||||||
float scale_yx, scale_yy, scale_yz;
|
// 3x3校正矩阵 (行优先存储)
|
||||||
float scale_zx, scale_zy, scale_zz;
|
float correction_matrix[9];
|
||||||
|
|
||||||
|
// ARM DSP矩阵实例
|
||||||
|
#if USE_ARM_DSP
|
||||||
|
arm_matrix_instance_f32 matrix_inst;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 校正参数有效标志
|
||||||
|
uint8_t params_valid;
|
||||||
} CorrectionParams_t;
|
} CorrectionParams_t;
|
||||||
|
|
||||||
void Init_CorrectionParams(CorrectionParams_t *params); // 初始化参数
|
// 校正结果结构体
|
||||||
void Apply_Correction(int32_t raw_x, int32_t raw_y, int32_t raw_z,
|
typedef struct {
|
||||||
float *corrected_x, float *corrected_y, float *corrected_z,
|
float corrected_x;
|
||||||
CorrectionParams_t *params);
|
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
|
#endif // CORRECTION_H
|
||||||
@ -1,7 +1,9 @@
|
|||||||
#include "data_packet.h"
|
#include "data_packet.h"
|
||||||
|
#include "stddef.h"
|
||||||
|
#include "stm32f4xx_hal.h"
|
||||||
|
|
||||||
// CRC16-MODBUS
|
// CRC16-MODBUS算法实现
|
||||||
uint16_t Calculate_CRC16(uint8_t *data, uint16_t len) {
|
uint16_t Calculate_CRC16(const uint8_t *data, uint16_t len) {
|
||||||
uint16_t crc = 0xFFFF;
|
uint16_t crc = 0xFFFF;
|
||||||
for (uint16_t i = 0; i < len; i++) {
|
for (uint16_t i = 0; i < len; i++) {
|
||||||
crc ^= data[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)
|
void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3)
|
||||||
{
|
{
|
||||||
// packet->start_byte = PACKET_START_BYTE; // Incorrect assignment
|
if (packet == NULL) return;
|
||||||
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
|
|
||||||
|
|
||||||
// MCU 原生字节序 (小端)
|
// 设置包头
|
||||||
|
packet->start_byte = PACKET_START_BYTE;
|
||||||
|
|
||||||
|
// 设置时间戳
|
||||||
|
packet->timestamp = HAL_GetTick();
|
||||||
|
|
||||||
|
// 设置ADC数据
|
||||||
packet->adc_data1 = adc1;
|
packet->adc_data1 = adc1;
|
||||||
packet->adc_data2 = adc2;
|
packet->adc_data2 = adc2;
|
||||||
packet->adc_data3 = adc3;
|
packet->adc_data3 = adc3;
|
||||||
|
|
||||||
// 计算校验和 (只计算 ADC 数据部分)
|
// 计算校验和 (不包括校验和字段本身和包尾)
|
||||||
// uint16_t checksum = Calculate_CRC16((uint8_t*)&packet->adc_data1, sizeof(uint32_t) * 3);
|
uint16_t checksum = Calculate_CRC16((uint8_t*)packet,
|
||||||
// packet->checksum = checksum; // 校验和也用小端
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,19 +4,35 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define PACKET_START_BYTE 0xFFFFFFFF
|
#define PACKET_START_BYTE 0xFFFFFFFF
|
||||||
#define PACKET_END_BYTE 0x55
|
#define PACKET_END_BYTE 0x0000
|
||||||
|
|
||||||
// 数据包结构
|
// 数据包结构 - 启用校验和和包尾
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint8_t start_byte[4]; // 包头
|
uint32_t start_byte; // 包头 (4字节)
|
||||||
int32_t adc_data1; // ADC1 数据 (高位在前)
|
uint32_t timestamp; // 时间戳 (4字节)
|
||||||
int32_t adc_data2; // ADC2 数据 (高位在前)
|
int32_t adc_data1; // ADC1 数据 (4字节)
|
||||||
int32_t adc_data3; // ADC3 数据 (高位在前)
|
int32_t adc_data2; // ADC2 数据 (4字节)
|
||||||
// uint16_t checksum; // 校验和 (例如 CRC16, 高位在前)
|
int32_t adc_data3; // ADC3 数据 (4字节)
|
||||||
// uint8_t end_byte; // 包尾
|
uint16_t checksum; // CRC16校验和 (2字节)
|
||||||
|
uint16_t end_byte; // 包尾 (2字节)
|
||||||
} DataPacket_t;
|
} 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 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
|
#endif // DATA_PACKET_H
|
||||||
|
|||||||
195
User/data_storage.c
Normal file
195
User/data_storage.c
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
#include "data_storage.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
54
User/data_storage.h
Normal file
54
User/data_storage.h
Normal file
@ -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 <stdint.h>
|
||||||
|
|
||||||
|
// 数据存储配置
|
||||||
|
#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
|
||||||
@ -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_adc_data_ready_flag = 0;
|
||||||
volatile uint8_t g_dma_complete_count = 0;
|
volatile uint8_t g_dma_complete_count = 0;
|
||||||
|
|
||||||
|
// 错误统计信息
|
||||||
|
LTC2508_StatsTypeDef g_ltc2508_stats = {0};
|
||||||
|
|
||||||
// SPI 句柄指针
|
// SPI 句柄指针
|
||||||
static SPI_HandleTypeDef *g_hspi1 = NULL;
|
static SPI_HandleTypeDef *g_hspi1 = NULL;
|
||||||
static SPI_HandleTypeDef *g_hspi2 = NULL;
|
static SPI_HandleTypeDef *g_hspi2 = NULL;
|
||||||
@ -16,10 +19,17 @@ static SPI_HandleTypeDef *g_hspi3 = NULL;
|
|||||||
* @param hspi1: SPI1 句柄指针
|
* @param hspi1: SPI1 句柄指针
|
||||||
* @param hspi2: SPI2 句柄指针
|
* @param hspi2: SPI2 句柄指针
|
||||||
* @param hspi3: SPI3 句柄指针
|
* @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_hspi1 = hspi1;
|
||||||
g_hspi2 = hspi2;
|
g_hspi2 = hspi2;
|
||||||
g_hspi3 = hspi3;
|
g_hspi3 = hspi3;
|
||||||
@ -27,44 +37,64 @@ void LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_Handle
|
|||||||
g_dma_complete_count = 0;
|
g_dma_complete_count = 0;
|
||||||
memset((void*)g_adc_data, 0, sizeof(g_adc_data));
|
memset((void*)g_adc_data, 0, sizeof(g_adc_data));
|
||||||
|
|
||||||
|
// 重置统计信息
|
||||||
|
memset(&g_ltc2508_stats, 0, sizeof(g_ltc2508_stats));
|
||||||
|
|
||||||
// 可以在这里添加对 LTC2508 的配置,如果需要通过 SPI 发送配置字
|
// 可以在这里添加对 LTC2508 的配置,如果需要通过 SPI 发送配置字
|
||||||
// 例如:HAL_SPI_Transmit(g_hspi1, &config_word, 1, 100);
|
// 例如:HAL_SPI_Transmit(g_hspi1, &config_word, 1, 100);
|
||||||
|
|
||||||
|
return LTC2508_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 触发三路 SPI 通过 DMA 读取数据
|
* @brief 触发三路 SPI 通过 DMA 读取数据
|
||||||
* @param None
|
* @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 未在进行
|
if (g_adc_data_ready_flag == 0 && g_dma_complete_count == 0) // 确保上次数据已处理且 DMA 未在进行
|
||||||
{
|
{
|
||||||
g_dma_complete_count = 0; // 重置计数
|
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 作为从机只接收
|
// SPI2 和 SPI3 作为从机只接收
|
||||||
if (HAL_SPI_Receive_DMA(g_hspi2, (uint8_t*)g_adc_data[1], LTC2508_DATA_LEN) != HAL_OK)
|
if (HAL_SPI_Receive_DMA(g_hspi2, (uint8_t*)g_adc_data[1], 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAL_SPI_Receive_DMA(g_hspi3, (uint8_t*)g_adc_data[2], LTC2508_DATA_LEN) != HAL_OK)
|
if (HAL_SPI_Receive_DMA(g_hspi3, (uint8_t*)g_adc_data[2], 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI1 作为主机收发,先发一个 dummy 数据触发时钟
|
// SPI1 作为主机收发,先发一个 dummy 数据触发时钟
|
||||||
uint16_t dummy_tx[LTC2508_DATA_LEN] = {0}; // 可以是任意值
|
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)
|
if (hspi == g_hspi1 || hspi == g_hspi2 || hspi == g_hspi3)
|
||||||
{
|
{
|
||||||
g_dma_complete_count = NUM_LTC2508;
|
g_dma_complete_count++;
|
||||||
if (g_dma_complete_count == NUM_LTC2508)
|
if (g_dma_complete_count >= NUM_LTC2508)
|
||||||
{
|
{
|
||||||
g_adc_data_ready_flag = 1;
|
g_adc_data_ready_flag = 1;
|
||||||
g_dma_complete_count = 0; // 为下一次读取做准备
|
g_dma_complete_count = 0; // 为下一次读取做准备
|
||||||
|
g_ltc2508_stats.total_samples++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 需要在 stm32g4xx_it.c 中正确地调用 HAL_SPI_IRQHandler
|
/**
|
||||||
// 并在 stm32g4xx_hal_spi.c 或 stm32g4xx_it.c 中添加以下回调函数的弱定义,
|
* @brief SPI DMA 传输错误回调函数
|
||||||
// 如果它们还没有被定义的话:
|
* @param hspi: SPI 句柄指针
|
||||||
/*
|
* @retval None
|
||||||
__weak void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
|
*/
|
||||||
|
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
|
if (stats != NULL) {
|
||||||
Error_Handler();
|
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));
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
@ -9,14 +9,39 @@
|
|||||||
// 假设我们有3个 LTC2508
|
// 假设我们有3个 LTC2508
|
||||||
#define NUM_LTC2508 3
|
#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 数据)
|
// 用于存储三路 ADC 数据的全局变量 (每个 ADC 2个 16-bit 数据)
|
||||||
extern volatile uint16_t g_adc_data[NUM_LTC2508][LTC2508_DATA_LEN];
|
extern volatile uint16_t g_adc_data[NUM_LTC2508][LTC2508_DATA_LEN];
|
||||||
// ADC 数据准备就绪标志
|
// ADC 数据准备就绪标志
|
||||||
extern volatile uint8_t g_adc_data_ready_flag;
|
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);
|
LTC2508_StatusTypeDef LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_HandleTypeDef *hspi3);
|
||||||
void LTC2508_TriggerDmaRead(void);
|
LTC2508_StatusTypeDef LTC2508_TriggerDmaRead(void);
|
||||||
void LTC2508_DmaComplete_Callback(SPI_HandleTypeDef *hspi);
|
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
|
#endif // LTC2508_DRIVER_H
|
||||||
113
User/system_monitor.c
Normal file
113
User/system_monitor.c
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#include "system_monitor.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// 静态变量
|
||||||
|
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; // 系统健康
|
||||||
|
}
|
||||||
51
User/system_monitor.h
Normal file
51
User/system_monitor.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef SYSTEM_MONITOR_H
|
||||||
|
#define SYSTEM_MONITOR_H
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "ltc2508_driver.h"
|
||||||
|
#include "data_storage.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// 系统状态定义
|
||||||
|
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
|
||||||
Loading…
x
Reference in New Issue
Block a user