✨ feat(optic_mag): 集成光泵磁力仪驱动并重构数据包架构
- 新增光泵磁力仪驱动模块,通过 USART2 中断接收 BCD 编码数据,采样率 115200bps - 重构数据包架构:引入标准包与扩展包(含光泵数据)两种类型,通过帧头魔数区分 - 新增 DataPacketWithOptic_t、CorrectedDataPacketWithOptic_t 两种扩展数据包类型 - 数据存储改为通用字节流写入(方案Y),支持任意包类型混流存储 - 将编译期配置集中到 app_config.h,包括 UART 输出、SD 存储、GPS 位置等开关 - 移除 ADC_SYNC GPIO 引脚配置,释放 PA2 用于 USART2_TX - 主循环 ProcessAdcData 改为按需选择数据包类型,光泵数据快照在 ADC 中断前完成 - 新增 USART2 错误回调处理,支持接收异常时自动恢复
This commit is contained in:
parent
4f8feccc06
commit
bc37e14fba
49
CLAUDE.md
Normal file
49
CLAUDE.md
Normal file
@ -0,0 +1,49 @@
|
||||
# STM_ATEM_F405 项目说明
|
||||
|
||||
## 项目概述
|
||||
STM32F405 航空电磁接收机固件,基于 STM32CubeIDE + HAL 库开发。
|
||||
|
||||
**核心功能:** ADC 采集(LTC2508)→ 数据校正 → SD 卡存储 / UART 输出
|
||||
|
||||
## 目录结构
|
||||
- `Core/` — CubeMX 生成代码(main.c、外设初始化),**不要手动修改生成区域**
|
||||
- `User/` — 业务逻辑(驱动、数据包、存储、GPS、配置管理等)
|
||||
- `Drivers/` — HAL 驱动库(不修改)
|
||||
- `Middlewares/` — FatFs、USB(不修改)
|
||||
|
||||
## 关键模块
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `ltc2508_driver` | SPI ADC 采集驱动 |
|
||||
| `data_packet` | 数据包格式定义与封包 |
|
||||
| `data_storage` | FatFs SD 卡文件写入 |
|
||||
| `correction` | ADC 校正参数应用 |
|
||||
| `app_config` | 编译期配置(UART 输出、SD 存储开关)|
|
||||
| `config_manager` | 配置运行时访问层,默认值来自 `app_config.h` |
|
||||
| `gps_driver` | GPS NMEA 解析(UART)|
|
||||
| `rs485_driver` | RS485 通信 |
|
||||
| `optic_mag_driver` | 光学磁传感器 |
|
||||
| `system_monitor` | 系统状态统计与诊断 |
|
||||
|
||||
## 通信接口
|
||||
| 接口 | 用途 | 波特率 | 备注 |
|
||||
|------|------|--------|------|
|
||||
| USART1 (PA9/PA10) | RS485 数据输出 | 2 000 000 | TX DMA;DE/RE 控制脚 PC7 |
|
||||
| USART2 (PA3) | 光泵磁力仪接收 | 115 200 | 仅 RX,DMA 循环;PA2 已改为普通 GPIO |
|
||||
| USART3 (PB10/PB11) | GPS NMEA 接收 | 115 200 | TX/RX,单字节中断接收 |
|
||||
| SPI1/2/3 | LTC2508 ADC 采集 | — | 三路 SPI 同时驱动三片 ADC |
|
||||
| SDIO | SD 卡(FatFs) | — | 与 USB MSC 共用,采样期间独占 |
|
||||
| USB | MSC 大容量存储 | — | 供 PC 直接访问 SD 卡 |
|
||||
|
||||
## 开发规范
|
||||
- 每次修改代码后,判断是否影响模块职责、接口用途、配置项或注意事项,若有则同步更新 CLAUDE.md 对应部分
|
||||
|
||||
- 业务代码只放 `User/` 目录;CubeMX 生成区域(`USER CODE BEGIN/END`)内写用户代码
|
||||
- 函数命名:`模块名_功能()` 如 `DataStorage_StartRecording()`
|
||||
- 全局变量加 `g_` 前缀,静态变量加 `s_` 前缀
|
||||
- 不添加无意义注释;注释用中文说明 **为什么**,不说明是什么
|
||||
|
||||
## 注意事项
|
||||
- 修改 `.ioc` 文件后重新生成代码会覆盖 `Core/` 文件,需手动恢复用户代码
|
||||
- USB MSC 与 FatFs 共享 SD 卡,采样期间需卸载再挂载
|
||||
- 配置在 `User/app_config.h` 中以 `#define` 编译期确定;若需恢复 CONFIG.TXT 运行时加载,在 `main.c` 挂载 SD 后重新调用 `Config_Load()` 即可
|
||||
@ -60,8 +60,6 @@ void Error_Handler(void);
|
||||
#define ADC_DRY_Pin GPIO_PIN_1
|
||||
#define ADC_DRY_GPIO_Port GPIOA
|
||||
#define ADC_DRY_EXTI_IRQn EXTI1_IRQn
|
||||
#define ADC_SYNC_Pin GPIO_PIN_2
|
||||
#define ADC_SYNC_GPIO_Port GPIOA
|
||||
#define RS485_CTL_Pin GPIO_PIN_7
|
||||
#define RS485_CTL_GPIO_Port GPIOC
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@ void DMA1_Stream0_IRQHandler(void);
|
||||
void DMA1_Stream3_IRQHandler(void);
|
||||
void TIM2_IRQHandler(void);
|
||||
void USART1_IRQHandler(void);
|
||||
void USART2_IRQHandler(void);
|
||||
void USART3_IRQHandler(void);
|
||||
void SDIO_IRQHandler(void);
|
||||
void DMA2_Stream0_IRQHandler(void);
|
||||
|
||||
@ -34,6 +34,8 @@ extern "C" {
|
||||
|
||||
extern UART_HandleTypeDef huart1;
|
||||
|
||||
extern UART_HandleTypeDef huart2;
|
||||
|
||||
extern UART_HandleTypeDef huart3;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
@ -41,6 +43,7 @@ extern UART_HandleTypeDef huart3;
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_USART1_UART_Init(void);
|
||||
void MX_USART2_UART_Init(void);
|
||||
void MX_USART3_UART_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
@ -51,9 +51,6 @@ void MX_GPIO_Init(void)
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(ADC_SYNC_GPIO_Port, ADC_SYNC_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(RS485_CTL_GPIO_Port, RS485_CTL_Pin, GPIO_PIN_RESET);
|
||||
|
||||
@ -69,13 +66,6 @@ void MX_GPIO_Init(void)
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(ADC_DRY_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : ADC_SYNC_Pin */
|
||||
GPIO_InitStruct.Pin = ADC_SYNC_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(ADC_SYNC_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : RS485_CTL_Pin */
|
||||
GPIO_InitStruct.Pin = RS485_CTL_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
|
||||
167
Core/Src/main.c
167
Core/Src/main.c
@ -37,6 +37,7 @@
|
||||
#include "system_monitor.h"
|
||||
#include "config_manager.h"
|
||||
#include "gps_driver.h"
|
||||
#include "optic_mag_driver.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
/* USER CODE END Includes */
|
||||
@ -48,15 +49,10 @@
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
// 监控功能宏开关(统一控制串口输出和文件存储)
|
||||
#define ENABLE_SYSTEM_MONITOR 1 // 系统监控开关
|
||||
#define DEBUG_OUTPUT_INTERVAL_MS 30000 // 调试输出间隔(毫秒)
|
||||
#define MONITOR_SAVE_INTERVAL_MS 30000 // 监控状态保存间隔(毫秒) - 30秒
|
||||
|
||||
// 数据输出模式选择(运行时配置,从SD卡加载)
|
||||
// 注意:DATA_OUTPUT_MODE_UART 和 DATA_OUTPUT_MODE_STORAGE 已改为运行时配置
|
||||
// 使用 Config_IsUartOutputEnabled() 和 Config_IsStorageEnabled() 来检查状态
|
||||
// 配置文件:0:/CONFIG.TXT
|
||||
// 以下宏从 app_config.h 引入,此处仅做别名映射,保持内部代码不变
|
||||
#define ENABLE_SYSTEM_MONITOR CFG_ENABLE_SYSTEM_MONITOR
|
||||
#define DEBUG_OUTPUT_INTERVAL_MS CFG_DEBUG_OUTPUT_INTERVAL_MS
|
||||
#define MONITOR_SAVE_INTERVAL_MS CFG_MONITOR_SAVE_INTERVAL_MS
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
@ -73,14 +69,17 @@ extern SPI_HandleTypeDef hspi2;
|
||||
extern SPI_HandleTypeDef hspi3;
|
||||
extern TIM_HandleTypeDef htim2;
|
||||
extern UART_HandleTypeDef huart1;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
extern UART_HandleTypeDef huart3;
|
||||
|
||||
// 校正参数
|
||||
CorrectionParams_t g_correction_params;
|
||||
// 数据包
|
||||
// 数据包(标准包 / 扩展包各一份,ProcessAdcData按需选用)
|
||||
DataPacket_t g_data_packet;
|
||||
DataPacketWithOptic_t g_data_packet_with_optic;
|
||||
CorrectedDataPacket_t g_corrected_packet;
|
||||
CorrectedDataPacketWithGPS_t g_corrected_packet_with_gps; // 带GPS信息的数据包
|
||||
CorrectedDataPacketWithGPS_t g_corrected_packet_with_gps;
|
||||
CorrectedDataPacketWithOptic_t g_corrected_packet_with_optic;
|
||||
// 数据存储句柄
|
||||
DataStorageHandle_t g_data_storage;
|
||||
// 系统状态
|
||||
@ -151,110 +150,99 @@ static void StopRecording(void)
|
||||
*/
|
||||
static void ProcessAdcData(void)
|
||||
{
|
||||
// 检查ADC数据是否准备就绪
|
||||
LTC2508_BufferTypeDef *ready_buffer = NULL;
|
||||
if (LTC2508_GetReadyBuffer(&ready_buffer) == LTC2508_OK && ready_buffer != NULL)
|
||||
{
|
||||
// 检查存储缓冲区是否可用(用于决定是否存储数据)
|
||||
if (LTC2508_GetReadyBuffer(&ready_buffer) != LTC2508_OK || ready_buffer == NULL) return;
|
||||
|
||||
// 快照光泵数据:USART2中断优先级(10) < TIM2优先级(3),此处不会被抢占,无需关中断
|
||||
uint8_t optic_fresh = g_optic_mag_fresh;
|
||||
uint32_t optic_val = g_optic_mag_value;
|
||||
if (optic_fresh) g_optic_mag_fresh = 0;
|
||||
|
||||
// 检查存储缓冲区是否可用(取最大包长为基准)
|
||||
uint8_t can_store_data = 0;
|
||||
if (g_recording_enabled) {
|
||||
uint32_t max_packet_size = sizeof(CorrectedDataPacketWithGPS_t); // 使用带GPS的数据包大小
|
||||
can_store_data = DataStorage_IsBufferAvailable(&g_data_storage, max_packet_size);
|
||||
can_store_data = DataStorage_IsBufferAvailable(&g_data_storage,
|
||||
sizeof(CorrectedDataPacketWithOptic_t));
|
||||
}
|
||||
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
SystemMonitor_IncrementSampleCount();
|
||||
#endif
|
||||
|
||||
// 1. 从双缓冲区获取数据并合并 (高位16位在前)
|
||||
// 1. 合并三路ADC原始数据(高16位在前)
|
||||
int32_t raw_adc[NUM_LTC2508];
|
||||
for (uint8_t i = 0; i < NUM_LTC2508; i++) {
|
||||
raw_adc[i] = (int32_t)(((uint32_t)ready_buffer->data[i][0] << 16) | ready_buffer->data[i][1]);
|
||||
}
|
||||
|
||||
// 2. 获取当前GPS数据
|
||||
// 2. 获取GPS数据(时间戳始终使用,位置字段受ENABLE_GPS_POSITION控制)
|
||||
GPS_Data_t current_gps_data;
|
||||
uint8_t gps_valid = GPS_GetData(¤t_gps_data);
|
||||
uint32_t gps_time = gps_valid ? (current_gps_data.time.hour * 10000u +
|
||||
current_gps_data.time.minute * 100u +
|
||||
current_gps_data.time.second) : 0u;
|
||||
float lat = (float)current_gps_data.position.latitude;
|
||||
float lon = (float)current_gps_data.position.longitude;
|
||||
float alt = (float)current_gps_data.position.altitude;
|
||||
|
||||
// 3. 决定发送哪种包(校正×是否有光泵 = 4种组合)
|
||||
const uint8_t *send_ptr;
|
||||
uint16_t send_size;
|
||||
|
||||
// 3. 应用校正算法
|
||||
CorrectionResult_t correction_result;
|
||||
uint8_t correction_applied = 0;
|
||||
|
||||
if (g_correction_params.params_valid &&
|
||||
Apply_Correction(raw_adc[0], raw_adc[1], raw_adc[2],
|
||||
&correction_result, &g_correction_params) == HAL_OK) {
|
||||
|
||||
// 4a. 打包校正后的数据(带GPS关键信息:仅经纬度)
|
||||
// float lat = gps_valid ? (float)current_gps_data.position.latitude : 0.0f;
|
||||
// float lon = gps_valid ? (float)current_gps_data.position.longitude : 0.0f;
|
||||
// float alt = gps_valid ? (float)current_gps_data.position.altitude : 0.0f;
|
||||
float lat = (float)current_gps_data.position.latitude;
|
||||
float lon = (float)current_gps_data.position.longitude;
|
||||
float alt = (float)current_gps_data.position.altitude;
|
||||
uint32_t gps_time = gps_valid ? (current_gps_data.time.hour * 10000 +
|
||||
current_gps_data.time.minute * 100 +
|
||||
current_gps_data.time.second) : 0;
|
||||
|
||||
if (optic_fresh) {
|
||||
PackCorrectedDataWithOptic(&g_corrected_packet_with_optic,
|
||||
correction_result.corrected_x, correction_result.corrected_y,
|
||||
correction_result.corrected_z, gps_time, lat, lon, alt, optic_val);
|
||||
send_ptr = (const uint8_t *)&g_corrected_packet_with_optic;
|
||||
send_size = sizeof(CorrectedDataPacketWithOptic_t);
|
||||
} else {
|
||||
PackCorrectedDataWithGPS(&g_corrected_packet_with_gps,
|
||||
correction_result.corrected_x,
|
||||
correction_result.corrected_y,
|
||||
correction_result.corrected_z,
|
||||
gps_time,
|
||||
lat,
|
||||
lon,
|
||||
alt);
|
||||
|
||||
correction_applied = 1;
|
||||
|
||||
// 发送校正后的数据包到串口(运行时配置)
|
||||
if (Config_IsUartOutputEnabled()) {
|
||||
RS485_SendData((uint8_t*)&g_corrected_packet_with_gps, sizeof(CorrectedDataPacketWithGPS_t));
|
||||
correction_result.corrected_x, correction_result.corrected_y,
|
||||
correction_result.corrected_z, gps_time, lat, lon, alt);
|
||||
send_ptr = (const uint8_t *)&g_corrected_packet_with_gps;
|
||||
send_size = sizeof(CorrectedDataPacketWithGPS_t);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// 4b. 校正失败或未启用,使用原始数据
|
||||
// float lat = gps_valid ? (float)current_gps_data.position.latitude : 0.0f;
|
||||
// float lon = gps_valid ? (float)current_gps_data.position.longitude : 0.0f;
|
||||
// float alt = gps_valid ? (float)current_gps_data.position.altitude : 0.0f;
|
||||
float lat = (float)current_gps_data.position.latitude;
|
||||
float lon = (float)current_gps_data.position.longitude;
|
||||
float alt = (float)current_gps_data.position.altitude;
|
||||
uint32_t gps_time = gps_valid ? (current_gps_data.time.hour * 10000 +
|
||||
current_gps_data.time.minute * 100 +
|
||||
current_gps_data.time.second) : 0;
|
||||
if (optic_fresh) {
|
||||
PackDataWithOptic(&g_data_packet_with_optic,
|
||||
raw_adc[0], raw_adc[1], raw_adc[2],
|
||||
gps_time, lat, lon, alt, optic_val);
|
||||
send_ptr = (const uint8_t *)&g_data_packet_with_optic;
|
||||
send_size = sizeof(DataPacketWithOptic_t);
|
||||
} else {
|
||||
PackData(&g_data_packet,
|
||||
raw_adc[0], raw_adc[1], raw_adc[2],
|
||||
gps_time, lat, lon, alt);
|
||||
send_ptr = (const uint8_t *)&g_data_packet;
|
||||
send_size = sizeof(DataPacket_t);
|
||||
}
|
||||
}
|
||||
|
||||
PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2], gps_time, lat, lon, alt);
|
||||
|
||||
// 发送原始数据包到串口(运行时配置)
|
||||
// 4. 发送到RS485串口
|
||||
if (Config_IsUartOutputEnabled()) {
|
||||
RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t));
|
||||
}
|
||||
RS485_SendData((uint8_t *)send_ptr, send_size);
|
||||
}
|
||||
|
||||
// 6. 存储数据到SD卡 (如果启用记录且缓冲区可用,运行时配置)
|
||||
// 5. 存储到SD卡(方案Y:直接写原始字节流,与串口格式一致)
|
||||
if (Config_IsStorageEnabled() && g_recording_enabled) {
|
||||
if (can_store_data) {
|
||||
if (correction_applied) {
|
||||
// 存储校正后的数据(带GPS信息)
|
||||
DataStorage_WriteCorrectedData(&g_data_storage, (CorrectedDataPacket_t*)&g_corrected_packet_with_gps);
|
||||
DataStorage_WriteRawBytes(&g_data_storage, send_ptr, send_size);
|
||||
} else {
|
||||
// 存储原始数据
|
||||
DataStorage_WriteData(&g_data_storage, &g_data_packet);
|
||||
}
|
||||
} else {
|
||||
// 缓冲区满,数据被丢弃
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
SystemMonitor_ReportDataDropped();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 释放已处理的缓冲区
|
||||
// 6. 释放已处理的缓冲区
|
||||
LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer());
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -536,6 +524,7 @@ int main(void)
|
||||
MX_USART3_UART_Init();
|
||||
MX_TIM2_Init();
|
||||
MX_TIM1_Init();
|
||||
MX_USART2_UART_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
// 初始化系统监控
|
||||
@ -543,9 +532,12 @@ int main(void)
|
||||
SystemMonitor_Init();
|
||||
#endif
|
||||
|
||||
// 初始化调试输出
|
||||
// 初始化调试输出(含GPS)
|
||||
DebugOutput_Init();
|
||||
|
||||
// 初始化光泵磁力仪接收(USART2 RX,115200)
|
||||
OpticMag_Init(&huart2);
|
||||
|
||||
// 初始化配置管理器(设置默认值)
|
||||
Config_Init();
|
||||
|
||||
@ -562,13 +554,9 @@ int main(void)
|
||||
if (!g_usb_connected) {
|
||||
// USB未连接,挂载文件系统用于数据采集
|
||||
if (MountFileSystemForSampling() == HAL_OK) {
|
||||
// 从SD卡加载配置
|
||||
if (Config_Load() == HAL_OK) {
|
||||
DebugOutput_SendString("Config loaded from SD card\r\n");
|
||||
} else {
|
||||
DebugOutput_SendString("Using default config\r\n");
|
||||
}
|
||||
|
||||
#if CFG_LOAD_FROM_FILE
|
||||
Config_Load();
|
||||
#endif
|
||||
// 初始化数据存储
|
||||
if (DataStorage_Init(&g_data_storage) == HAL_OK) {
|
||||
// 开始数据记录(如果存储功能已启用)
|
||||
@ -812,8 +800,21 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
|
||||
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart == &huart3) {
|
||||
// GPS数据接收回调
|
||||
GPS_UART_RxCpltCallback(huart);
|
||||
} else if (huart == &huart2) {
|
||||
OpticMag_UART_RxCpltCallback(huart);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART错误回调函数
|
||||
* @param huart: UART句柄指针
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart == &huart2) {
|
||||
OpticMag_UART_ErrorCallback(huart);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "ltc2508_driver.h"
|
||||
#include "rs485_driver.h"
|
||||
#include "gps_driver.h"
|
||||
#include "optic_mag_driver.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
@ -69,12 +70,12 @@ extern DMA_HandleTypeDef hdma_spi3_rx;
|
||||
extern TIM_HandleTypeDef htim2;
|
||||
extern DMA_HandleTypeDef hdma_usart1_tx;
|
||||
extern UART_HandleTypeDef huart1;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
extern UART_HandleTypeDef huart3;
|
||||
/* USER CODE BEGIN EV */
|
||||
extern SPI_HandleTypeDef hspi1;
|
||||
extern SPI_HandleTypeDef hspi2;
|
||||
extern SPI_HandleTypeDef hspi3;
|
||||
extern UART_HandleTypeDef huart1;
|
||||
/* USER CODE END EV */
|
||||
|
||||
/******************************************************************************/
|
||||
@ -285,6 +286,20 @@ void USART1_IRQHandler(void)
|
||||
/* USER CODE END USART1_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles USART2 global interrupt.
|
||||
*/
|
||||
void USART2_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_IRQn 0 */
|
||||
|
||||
/* USER CODE END USART2_IRQn 0 */
|
||||
HAL_UART_IRQHandler(&huart2);
|
||||
/* USER CODE BEGIN USART2_IRQn 1 */
|
||||
|
||||
/* USER CODE END USART2_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles USART3 global interrupt.
|
||||
*/
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
/* USER CODE END 0 */
|
||||
|
||||
UART_HandleTypeDef huart1;
|
||||
UART_HandleTypeDef huart2;
|
||||
UART_HandleTypeDef huart3;
|
||||
DMA_HandleTypeDef hdma_usart1_tx;
|
||||
|
||||
@ -56,6 +57,35 @@ void MX_USART1_UART_Init(void)
|
||||
|
||||
/* USER CODE END USART1_Init 2 */
|
||||
|
||||
}
|
||||
/* USART2 init function */
|
||||
|
||||
void MX_USART2_UART_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN USART2_Init 0 */
|
||||
|
||||
/* USER CODE END USART2_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN USART2_Init 1 */
|
||||
|
||||
/* USER CODE END USART2_Init 1 */
|
||||
huart2.Instance = USART2;
|
||||
huart2.Init.BaudRate = 115200;
|
||||
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart2.Init.StopBits = UART_STOPBITS_1;
|
||||
huart2.Init.Parity = UART_PARITY_NONE;
|
||||
huart2.Init.Mode = UART_MODE_RX;
|
||||
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
if (HAL_UART_Init(&huart2) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN USART2_Init 2 */
|
||||
|
||||
/* USER CODE END USART2_Init 2 */
|
||||
|
||||
}
|
||||
/* USART3 init function */
|
||||
|
||||
@ -137,6 +167,40 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
|
||||
|
||||
/* USER CODE END USART1_MspInit 1 */
|
||||
}
|
||||
else if(uartHandle->Instance==USART2)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_MspInit 0 */
|
||||
|
||||
/* USER CODE END USART2_MspInit 0 */
|
||||
/* USART2 clock enable */
|
||||
__HAL_RCC_USART2_CLK_ENABLE();
|
||||
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
/**USART2 GPIO Configuration
|
||||
PA2 ------> USART2_TX
|
||||
PA3 ------> USART2_RX
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USART2 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART2_IRQn, 7, 0);
|
||||
HAL_NVIC_EnableIRQ(USART2_IRQn);
|
||||
/* USER CODE BEGIN USART2_MspInit 1 */
|
||||
/* 覆盖PA2为普通GPIO输出:CubeMX将其初始化为USART2_TX(AF7),
|
||||
此处重新配置以供其他功能使用,PA3(RX)保持AF7不变 */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_2;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = 0;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
/* USER CODE END USART2_MspInit 1 */
|
||||
}
|
||||
else if(uartHandle->Instance==USART3)
|
||||
{
|
||||
/* USER CODE BEGIN USART3_MspInit 0 */
|
||||
@ -192,6 +256,26 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
|
||||
|
||||
/* USER CODE END USART1_MspDeInit 1 */
|
||||
}
|
||||
else if(uartHandle->Instance==USART2)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END USART2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_USART2_CLK_DISABLE();
|
||||
|
||||
/**USART2 GPIO Configuration
|
||||
PA2 ------> USART2_TX
|
||||
PA3 ------> USART2_RX
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
|
||||
|
||||
/* USART2 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(USART2_IRQn);
|
||||
/* USER CODE BEGIN USART2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END USART2_MspDeInit 1 */
|
||||
}
|
||||
else if(uartHandle->Instance==USART3)
|
||||
{
|
||||
/* USER CODE BEGIN USART3_MspDeInit 0 */
|
||||
|
||||
BIN
Doc/注意事项.jpg
Normal file
BIN
Doc/注意事项.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
@ -111,9 +111,10 @@ Mcu.IP0=DMA
|
||||
Mcu.IP1=FATFS
|
||||
Mcu.IP10=TIM2
|
||||
Mcu.IP11=USART1
|
||||
Mcu.IP12=USART3
|
||||
Mcu.IP13=USB_DEVICE
|
||||
Mcu.IP14=USB_OTG_FS
|
||||
Mcu.IP12=USART2
|
||||
Mcu.IP13=USART3
|
||||
Mcu.IP14=USB_DEVICE
|
||||
Mcu.IP15=USB_OTG_FS
|
||||
Mcu.IP2=NVIC
|
||||
Mcu.IP3=RCC
|
||||
Mcu.IP4=SDIO
|
||||
@ -122,42 +123,43 @@ Mcu.IP6=SPI2
|
||||
Mcu.IP7=SPI3
|
||||
Mcu.IP8=SYS
|
||||
Mcu.IP9=TIM1
|
||||
Mcu.IPNb=15
|
||||
Mcu.IPNb=16
|
||||
Mcu.Name=STM32F405RGTx
|
||||
Mcu.Package=LQFP64
|
||||
Mcu.Pin0=PH0-OSC_IN
|
||||
Mcu.Pin1=PH1-OSC_OUT
|
||||
Mcu.Pin10=PB13
|
||||
Mcu.Pin11=PB15
|
||||
Mcu.Pin12=PC7
|
||||
Mcu.Pin13=PC8
|
||||
Mcu.Pin14=PC9
|
||||
Mcu.Pin15=PA8
|
||||
Mcu.Pin16=PA9
|
||||
Mcu.Pin17=PA10
|
||||
Mcu.Pin18=PA11
|
||||
Mcu.Pin19=PA12
|
||||
Mcu.Pin10=PB11
|
||||
Mcu.Pin11=PB13
|
||||
Mcu.Pin12=PB15
|
||||
Mcu.Pin13=PC7
|
||||
Mcu.Pin14=PC8
|
||||
Mcu.Pin15=PC9
|
||||
Mcu.Pin16=PA8
|
||||
Mcu.Pin17=PA9
|
||||
Mcu.Pin18=PA10
|
||||
Mcu.Pin19=PA11
|
||||
Mcu.Pin2=PC3
|
||||
Mcu.Pin20=PA13
|
||||
Mcu.Pin21=PA14
|
||||
Mcu.Pin22=PC10
|
||||
Mcu.Pin23=PC11
|
||||
Mcu.Pin24=PC12
|
||||
Mcu.Pin25=PD2
|
||||
Mcu.Pin26=PB3
|
||||
Mcu.Pin27=PB5
|
||||
Mcu.Pin28=VP_FATFS_VS_SDIO
|
||||
Mcu.Pin29=VP_SYS_VS_Systick
|
||||
Mcu.Pin20=PA12
|
||||
Mcu.Pin21=PA13
|
||||
Mcu.Pin22=PA14
|
||||
Mcu.Pin23=PC10
|
||||
Mcu.Pin24=PC11
|
||||
Mcu.Pin25=PC12
|
||||
Mcu.Pin26=PD2
|
||||
Mcu.Pin27=PB3
|
||||
Mcu.Pin28=PB5
|
||||
Mcu.Pin29=VP_FATFS_VS_SDIO
|
||||
Mcu.Pin3=PA1
|
||||
Mcu.Pin30=VP_TIM2_VS_ClockSourceINT
|
||||
Mcu.Pin31=VP_USB_DEVICE_VS_USB_DEVICE_MSC_FS
|
||||
Mcu.Pin30=VP_SYS_VS_Systick
|
||||
Mcu.Pin31=VP_TIM2_VS_ClockSourceINT
|
||||
Mcu.Pin32=VP_USB_DEVICE_VS_USB_DEVICE_MSC_FS
|
||||
Mcu.Pin4=PA2
|
||||
Mcu.Pin5=PA5
|
||||
Mcu.Pin6=PA6
|
||||
Mcu.Pin7=PA7
|
||||
Mcu.Pin8=PB10
|
||||
Mcu.Pin9=PB11
|
||||
Mcu.PinsNb=32
|
||||
Mcu.Pin5=PA3
|
||||
Mcu.Pin6=PA5
|
||||
Mcu.Pin7=PA6
|
||||
Mcu.Pin8=PA7
|
||||
Mcu.Pin9=PB10
|
||||
Mcu.PinsNb=33
|
||||
Mcu.ThirdPartyNb=0
|
||||
Mcu.UserConstants=
|
||||
Mcu.UserName=STM32F405RGTx
|
||||
@ -185,6 +187,7 @@ NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.SysTick_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:false
|
||||
NVIC.TIM2_IRQn=true\:3\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.USART1_IRQn=true\:11\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.USART2_IRQn=true\:7\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.USART3_IRQn=true\:15\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
PA1.GPIOParameters=GPIO_Label
|
||||
@ -201,10 +204,10 @@ PA13.Mode=Serial_Wire
|
||||
PA13.Signal=SYS_JTMS-SWDIO
|
||||
PA14.Mode=Serial_Wire
|
||||
PA14.Signal=SYS_JTCK-SWCLK
|
||||
PA2.GPIOParameters=GPIO_Label
|
||||
PA2.GPIO_Label=ADC_SYNC
|
||||
PA2.Locked=true
|
||||
PA2.Signal=GPIO_Output
|
||||
PA2.Mode=Asynchronous
|
||||
PA2.Signal=USART2_TX
|
||||
PA3.Mode=Asynchronous
|
||||
PA3.Signal=USART2_RX
|
||||
PA5.Mode=Full_Duplex_Master
|
||||
PA5.Signal=SPI1_SCK
|
||||
PA6.Mode=Full_Duplex_Master
|
||||
@ -299,7 +302,7 @@ ProjectManager.ToolChainLocation=
|
||||
ProjectManager.UAScriptAfterPath=
|
||||
ProjectManager.UAScriptBeforePath=
|
||||
ProjectManager.UnderRoot=true
|
||||
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_SDIO_SD_Init-SDIO-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI2_Init-SPI2-false-HAL-true,7-MX_SPI3_Init-SPI3-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_FATFS_Init-FATFS-false-HAL-false,10-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-false,11-MX_USART3_UART_Init-USART3-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true
|
||||
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_SDIO_SD_Init-SDIO-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI2_Init-SPI2-false-HAL-true,7-MX_SPI3_Init-SPI3-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_FATFS_Init-FATFS-false-HAL-false,10-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-false,11-MX_USART3_UART_Init-USART3-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true,13-MX_TIM1_Init-TIM1-false-HAL-true,14-MX_USART2_UART_Init-USART2-false-HAL-true
|
||||
RCC.48MHZClocksFreq_Value=48000000
|
||||
RCC.AHBFreq_Value=168000000
|
||||
RCC.APB1CLKDivider=RCC_HCLK_DIV4
|
||||
@ -371,6 +374,9 @@ TIM2.Prescaler=83
|
||||
USART1.BaudRate=2000000
|
||||
USART1.IPParameters=VirtualMode,BaudRate
|
||||
USART1.VirtualMode=VM_ASYNC
|
||||
USART2.IPParameters=VirtualMode,Mode
|
||||
USART2.Mode=MODE_RX
|
||||
USART2.VirtualMode=VM_ASYNC
|
||||
USART3.BaudRate=115200
|
||||
USART3.IPParameters=VirtualMode,BaudRate
|
||||
USART3.VirtualMode=VM_ASYNC
|
||||
|
||||
84
User/app_config.h
Normal file
84
User/app_config.h
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef APP_CONFIG_H
|
||||
#define APP_CONFIG_H
|
||||
|
||||
// ============================================================
|
||||
// 系统编译期配置总入口
|
||||
// 所有可调参数集中在此文件,修改后重新编译生效。
|
||||
// 若需恢复 SD 卡运行时加载,将 CFG_LOAD_FROM_FILE 置 1,
|
||||
// 其余编译期值将作为加载失败时的 fallback 默认值。
|
||||
// ============================================================
|
||||
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// 配置加载方式
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// 是否在启动时从 SD 卡 CONFIG.TXT 加载配置
|
||||
// 1 = 运行时加载(文件内容覆盖以下编译期值)
|
||||
// 0 = 仅使用以下编译期值,不读取文件(安全,可重复)
|
||||
#define CFG_LOAD_FROM_FILE 0
|
||||
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// 数据输出控制
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// RS485 串口输出开关
|
||||
// 1 = 每帧 ADC 数据通过 USART1 以 2Mbps 发送
|
||||
// 0 = 禁用串口输出,降低功耗和 CPU 占用
|
||||
#define CFG_UART_OUTPUT_ENABLED 1
|
||||
|
||||
// SD 卡数据存储开关
|
||||
// 1 = 每帧数据写入 SD 卡 DATA/SESSION_xxx/ 目录下的文件
|
||||
// 0 = 禁用存储,SD 卡仅用于 USB MSC 访问
|
||||
#define CFG_STORAGE_ENABLED 1
|
||||
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// 功能模块开关
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// 系统监控统计模块
|
||||
// 1 = 启用:统计采样次数、丢帧数、SD 写入量、串口发送量,
|
||||
// 并定期输出到调试串口 / 写入 LOG.TXT
|
||||
// 0 = 禁用:相关代码被条件编译剔除,节省 Flash 和运行时开销
|
||||
#define CFG_ENABLE_SYSTEM_MONITOR 0
|
||||
|
||||
// 数据包中包含 GPS 经纬度和海拔字段
|
||||
// 1 = 每帧包含 latitude(float) + longitude(float) + altitude(float),包体增大 12 字节
|
||||
// 0 = 仅保留 GPS 时间戳(gps_time),包体更小,适合不需要位置信息的场景
|
||||
#define CFG_ENABLE_GPS_POSITION 0
|
||||
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// 调试与监控定时参数
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// 调试信息通过 RS485 输出的时间间隔(毫秒)
|
||||
// 控制 DebugOutput_PrintSystemStats() 的调用频率
|
||||
// 建议范围:5000(5秒)~ 60000(1分钟)
|
||||
#define CFG_DEBUG_OUTPUT_INTERVAL_MS 30000
|
||||
|
||||
// 监控统计数据写入 SD 卡 LOG.TXT 的时间间隔(毫秒)
|
||||
// 间隔越短日志越详细,但 SD 卡写入操作越频繁
|
||||
// 建议范围:10000(10秒)~ 300000(5分钟)
|
||||
#define CFG_MONITOR_SAVE_INTERVAL_MS 30000
|
||||
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// SD 卡存储参数
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// SD 卡写入双缓冲区单个缓冲区大小(字节)
|
||||
// 更大的缓冲区可减少写入次数,提升吞吐量,但占用更多 RAM
|
||||
// STM32F405 RAM 为 192KB,建议不超过 65536(64KB)
|
||||
// 典型值:32768(32KB) / 65536(64KB)
|
||||
#define CFG_STORAGE_BUFFER_SIZE 32768
|
||||
|
||||
// 单个数据文件的最大大小(字节),超过后自动创建新文件
|
||||
// 较小的文件便于传输和分析,较大的文件减少文件切换开销
|
||||
// 典型值:100MB / 500MB / 1024MB
|
||||
#define CFG_STORAGE_FILE_MAX_SIZE (100 * 1024 * 1024)
|
||||
|
||||
|
||||
#endif // APP_CONFIG_H
|
||||
@ -2,6 +2,7 @@
|
||||
#define CONFIG_MANAGER_H
|
||||
|
||||
#include "main.h"
|
||||
#include "app_config.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// 配置文件路径
|
||||
@ -17,8 +18,8 @@ typedef struct {
|
||||
} SystemConfig_t;
|
||||
|
||||
// 默认配置值
|
||||
#define DEFAULT_UART_OUTPUT_ENABLED 1
|
||||
#define DEFAULT_STORAGE_ENABLED 0
|
||||
#define DEFAULT_UART_OUTPUT_ENABLED CFG_UART_OUTPUT_ENABLED
|
||||
#define DEFAULT_STORAGE_ENABLED CFG_STORAGE_ENABLED
|
||||
#define CONFIG_VERSION 0x00010000 // 版本 1.0.0
|
||||
|
||||
// 函数声明
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
#include "stddef.h"
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
// CRC16-MODBUS算法实现
|
||||
uint16_t Calculate_CRC16(const uint8_t *data, uint16_t len) {
|
||||
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,107 +18,91 @@ uint16_t Calculate_CRC16(const uint8_t *data, uint16_t len) {
|
||||
return crc;
|
||||
}
|
||||
|
||||
void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3,
|
||||
// ─── 内部辅助宏:填充GPS位置字段(仅在宏开启时) ─────────────────────────────
|
||||
#ifdef ENABLE_GPS_POSITION
|
||||
#define FILL_GPS_POSITION(pkt, lat, lon, alt) \
|
||||
do { (pkt)->gps_latitude = (lat); (pkt)->gps_longitude = (lon); (pkt)->gps_altitude = (alt); } while(0)
|
||||
#else
|
||||
#define FILL_GPS_POSITION(pkt, lat, lon, alt) // 空操作
|
||||
#endif
|
||||
|
||||
// ─── 原始ADC数据包 ────────────────────────────────────────────────────────────
|
||||
|
||||
void PackData(DataPacket_t *packet,
|
||||
int32_t adc1, int32_t adc2, int32_t adc3,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude)
|
||||
{
|
||||
if (packet == NULL) return;
|
||||
|
||||
// 设置包头
|
||||
packet->start_byte = PACKET_START_BYTE;
|
||||
|
||||
// 设置时间戳
|
||||
// packet->timestamp = HAL_GetTick();
|
||||
|
||||
// 设置ADC数据
|
||||
packet->start_byte = PACKET_TYPE_STANDARD;
|
||||
packet->adc_data1 = adc1;
|
||||
packet->adc_data2 = adc2;
|
||||
packet->adc_data3 = adc3;
|
||||
|
||||
// 设置GPS数据
|
||||
packet->gps_time = gps_time;
|
||||
packet->gps_latitude = latitude;
|
||||
packet->gps_longitude = longitude;
|
||||
packet->gps_altitude = altitude;
|
||||
FILL_GPS_POSITION(packet, latitude, longitude, altitude);
|
||||
}
|
||||
|
||||
void PackDataWithOptic(DataPacketWithOptic_t *packet,
|
||||
int32_t adc1, int32_t adc2, int32_t adc3,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude,
|
||||
uint32_t optical_mag)
|
||||
{
|
||||
if (packet == NULL) return;
|
||||
packet->start_byte = PACKET_TYPE_WITH_OPTIC;
|
||||
packet->adc_data1 = adc1;
|
||||
packet->adc_data2 = adc2;
|
||||
packet->adc_data3 = adc3;
|
||||
packet->gps_time = gps_time;
|
||||
FILL_GPS_POSITION(packet, latitude, longitude, altitude);
|
||||
packet->optical_mag = optical_mag;
|
||||
}
|
||||
|
||||
// ─── 校正数据包 ───────────────────────────────────────────────────────────────
|
||||
|
||||
void PackCorrectedData(CorrectedDataPacket_t *packet,
|
||||
float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude)
|
||||
{
|
||||
PackCorrectedDataWithGPS(packet, x, y, z, gps_time, latitude, longitude, altitude);
|
||||
}
|
||||
|
||||
void PackCorrectedDataWithGPS(CorrectedDataPacketWithGPS_t *packet,
|
||||
float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude)
|
||||
{
|
||||
if (packet == NULL) return;
|
||||
packet->start_byte = PACKET_TYPE_STANDARD;
|
||||
packet->corrected_x = x;
|
||||
packet->corrected_y = y;
|
||||
packet->corrected_z = z;
|
||||
packet->gps_time = gps_time;
|
||||
FILL_GPS_POSITION(packet, latitude, longitude, altitude);
|
||||
}
|
||||
|
||||
void PackCorrectedDataWithOptic(CorrectedDataPacketWithOptic_t *packet,
|
||||
float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude,
|
||||
uint32_t optical_mag)
|
||||
{
|
||||
if (packet == NULL) return;
|
||||
packet->start_byte = PACKET_TYPE_WITH_OPTIC;
|
||||
packet->corrected_x = x;
|
||||
packet->corrected_y = y;
|
||||
packet->corrected_z = z;
|
||||
packet->gps_time = gps_time;
|
||||
FILL_GPS_POSITION(packet, latitude, longitude, altitude);
|
||||
packet->optical_mag = optical_mag;
|
||||
}
|
||||
|
||||
// ─── 验证函数 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
uint8_t ValidatePacket(const DataPacket_t *packet)
|
||||
{
|
||||
if (packet == NULL) return 0;
|
||||
|
||||
// 检查包头
|
||||
if (packet->start_byte != PACKET_START_BYTE) return 0;
|
||||
|
||||
// 精简版数据包无校验和,仅检查包头
|
||||
return 1; // 包头正确,认为有效
|
||||
return (packet->start_byte == PACKET_TYPE_STANDARD) ? 1 : 0;
|
||||
}
|
||||
|
||||
uint8_t ValidateCorrectedPacket(const CorrectedDataPacket_t *packet)
|
||||
{
|
||||
if (packet == NULL) return 0;
|
||||
|
||||
// 检查包头
|
||||
if (packet->start_byte != PACKET_START_BYTE) return 0;
|
||||
|
||||
// 精简版数据包无校验和,仅检查包头
|
||||
return 1; // 包头正确,认为有效
|
||||
}
|
||||
|
||||
void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude)
|
||||
{
|
||||
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;
|
||||
|
||||
// 设置GPS数据
|
||||
packet->gps_time = gps_time;
|
||||
packet->gps_latitude = latitude;
|
||||
packet->gps_longitude = longitude;
|
||||
packet->gps_altitude = altitude;
|
||||
}
|
||||
|
||||
void PackCorrectedDataWithGPS(CorrectedDataPacketWithGPS_t *packet, float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude)
|
||||
{
|
||||
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;
|
||||
|
||||
// 设置GPS数据
|
||||
packet->gps_time = gps_time;
|
||||
packet->gps_latitude = latitude;
|
||||
packet->gps_longitude = longitude;
|
||||
packet->gps_altitude = altitude;
|
||||
}
|
||||
|
||||
uint8_t ValidateCorrectedPacketWithGPS(const CorrectedDataPacketWithGPS_t *packet)
|
||||
{
|
||||
if (packet == NULL) return 0;
|
||||
|
||||
// 检查包头
|
||||
if (packet->start_byte != PACKET_START_BYTE) return 0;
|
||||
|
||||
// 精简版数据包无校验和,仅检查包头
|
||||
// 可以添加简单的数据合理性检查
|
||||
// 例如:检查GPS坐标是否在有效范围内等
|
||||
|
||||
return 1; // 包头正确,认为有效
|
||||
return (packet->start_byte == PACKET_TYPE_STANDARD) ? 1 : 0;
|
||||
}
|
||||
|
||||
@ -2,59 +2,109 @@
|
||||
#define DATA_PACKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "app_config.h"
|
||||
|
||||
#define PACKET_START_BYTE 0xFFFFFFFF
|
||||
#define PACKET_END_BYTE 0x0000
|
||||
// 帧同步魔数(高3字节固定),低字节为类型标志
|
||||
#define PACKET_TYPE_STANDARD 0xFFFFFFFFUL // 标准包(无光泵)
|
||||
#define PACKET_TYPE_WITH_OPTIC 0xFFFFFFFEUL // 扩展包(含光泵,末尾追加 optical_mag)
|
||||
#define PACKET_SYNC_MASK 0xFFFFFF00UL // 同步检测掩码
|
||||
|
||||
// 兼容旧代码
|
||||
#define PACKET_START_BYTE PACKET_TYPE_STANDARD
|
||||
|
||||
// GPS位置字段由 app_config.h 中 CFG_ENABLE_GPS_POSITION 控制
|
||||
#if CFG_ENABLE_GPS_POSITION
|
||||
#define ENABLE_GPS_POSITION
|
||||
#endif
|
||||
|
||||
// ─── 原始ADC数据包 ────────────────────────────────────────────────────────────
|
||||
|
||||
// 数据包结构(精简版 - 有包头无校验和,含GPS)
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t start_byte; // 包头 (4字节) = 0xFFFFFFFF
|
||||
// uint32_t timestamp; // 系统时间戳 (4字节)
|
||||
int32_t adc_data1; // ADC1 数据 (4字节)
|
||||
int32_t adc_data2; // ADC2 数据 (4字节)
|
||||
int32_t adc_data3; // ADC3 数据 (4字节)
|
||||
uint32_t gps_time; // GPS时间戳 (4字节) HHMMSS格式
|
||||
float gps_latitude; // GPS纬度 (4字节)
|
||||
float gps_longitude; // GPS经度 (4字节)
|
||||
float gps_altitude; // GPS海拔 (4字节)
|
||||
uint32_t start_byte; // PACKET_TYPE_STANDARD
|
||||
int32_t adc_data1;
|
||||
int32_t adc_data2;
|
||||
int32_t adc_data3;
|
||||
uint32_t gps_time; // HHMMSS格式,始终存在
|
||||
#ifdef ENABLE_GPS_POSITION
|
||||
float gps_latitude;
|
||||
float gps_longitude;
|
||||
float gps_altitude;
|
||||
#endif
|
||||
} DataPacket_t;
|
||||
|
||||
// 校正后数据包结构(精简版 - 有包头无校验和,含GPS)
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t start_byte; // 包头 (4字节) = 0xFFFFFFFF
|
||||
// uint32_t timestamp; // 系统时间戳 (4字节)
|
||||
float corrected_x; // 校正后X轴数据 (4字节)
|
||||
float corrected_y; // 校正后Y轴数据 (4字节)
|
||||
float corrected_z; // 校正后Z轴数据 (4字节)
|
||||
uint32_t gps_time; // GPS时间戳 (4字节) HHMMSS格式
|
||||
float gps_latitude; // GPS纬度 (4字节)
|
||||
float gps_longitude; // GPS经度 (4字节)
|
||||
float gps_altitude; // GPS海拔 (4字节)
|
||||
uint32_t start_byte; // PACKET_TYPE_WITH_OPTIC
|
||||
int32_t adc_data1;
|
||||
int32_t adc_data2;
|
||||
int32_t adc_data3;
|
||||
uint32_t gps_time;
|
||||
#ifdef ENABLE_GPS_POSITION
|
||||
float gps_latitude;
|
||||
float gps_longitude;
|
||||
float gps_altitude;
|
||||
#endif
|
||||
uint32_t optical_mag; // 单位 0.0001 nT,例如 123456789 = 12345.6789 nT
|
||||
} DataPacketWithOptic_t;
|
||||
|
||||
// ─── 校正数据包 ───────────────────────────────────────────────────────────────
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t start_byte; // PACKET_TYPE_STANDARD
|
||||
float corrected_x;
|
||||
float corrected_y;
|
||||
float corrected_z;
|
||||
uint32_t gps_time;
|
||||
#ifdef ENABLE_GPS_POSITION
|
||||
float gps_latitude;
|
||||
float gps_longitude;
|
||||
float gps_altitude;
|
||||
#endif
|
||||
} CorrectedDataPacket_t;
|
||||
|
||||
// 带GPS信息的校正数据包结构(精简版 - 有包头无校验和)
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t start_byte; // 包头 (4字节) = 0xFFFFFFFF
|
||||
// uint32_t timestamp; // 系统时间戳 (4字节)
|
||||
float corrected_x; // 校正后X轴数据 (4字节)
|
||||
float corrected_y; // 校正后Y轴数据 (4字节)
|
||||
float corrected_z; // 校正后Z轴数据 (4字节)
|
||||
uint32_t gps_time; // GPS时间戳 (4字节) HHMMSS格式
|
||||
float gps_latitude; // GPS纬度 (4字节)
|
||||
float gps_longitude; // GPS经度 (4字节)
|
||||
float gps_altitude; // GPS海拔 (4字节)
|
||||
} CorrectedDataPacketWithGPS_t;
|
||||
// 与 CorrectedDataPacket_t 相同,保留别名兼容旧代码
|
||||
typedef CorrectedDataPacket_t CorrectedDataPacketWithGPS_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t start_byte; // PACKET_TYPE_WITH_OPTIC
|
||||
float corrected_x;
|
||||
float corrected_y;
|
||||
float corrected_z;
|
||||
uint32_t gps_time;
|
||||
#ifdef ENABLE_GPS_POSITION
|
||||
float gps_latitude;
|
||||
float gps_longitude;
|
||||
float gps_altitude;
|
||||
#endif
|
||||
uint32_t optical_mag; // 单位 0.0001 nT
|
||||
} CorrectedDataPacketWithOptic_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,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude);
|
||||
void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z,
|
||||
|
||||
void PackDataWithOptic(DataPacketWithOptic_t *packet,
|
||||
int32_t adc1, int32_t adc2, int32_t adc3,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude,
|
||||
uint32_t optical_mag);
|
||||
|
||||
void PackCorrectedData(CorrectedDataPacket_t *packet,
|
||||
float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude);
|
||||
void PackCorrectedDataWithGPS(CorrectedDataPacketWithGPS_t *packet, float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float , float altitude);
|
||||
|
||||
void PackCorrectedDataWithGPS(CorrectedDataPacketWithGPS_t *packet,
|
||||
float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude);
|
||||
|
||||
void PackCorrectedDataWithOptic(CorrectedDataPacketWithOptic_t *packet,
|
||||
float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude, float altitude,
|
||||
uint32_t optical_mag);
|
||||
|
||||
uint8_t ValidatePacket(const DataPacket_t *packet);
|
||||
uint8_t ValidateCorrectedPacket(const CorrectedDataPacket_t *packet);
|
||||
uint8_t ValidateCorrectedPacketWithGPS(const CorrectedDataPacketWithGPS_t *packet);
|
||||
|
||||
#endif // DATA_PACKET_H
|
||||
|
||||
@ -113,6 +113,41 @@ HAL_StatusTypeDef DataStorage_WriteData(DataStorageHandle_t *handle, const DataP
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通用字节流写入,支持任意包长度(方案Y混流存储)
|
||||
* @param handle: 数据存储句柄指针
|
||||
* @param data: 数据缓冲区指针
|
||||
* @param size: 写入字节数
|
||||
* @retval HAL_StatusTypeDef
|
||||
*/
|
||||
HAL_StatusTypeDef DataStorage_WriteRawBytes(DataStorageHandle_t *handle, const uint8_t *data, uint16_t size)
|
||||
{
|
||||
if (handle == NULL || data == NULL || !handle->initialized || size == 0) {
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if (handle->stats.state != DATA_STORAGE_RECORDING) {
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
DataBuffer_t *active_buf = &handle->buffers[handle->active_buffer];
|
||||
|
||||
if (active_buf->index + size > DATA_STORAGE_BUFFER_SIZE) {
|
||||
if (DataStorage_SwitchBuffer(handle) != HAL_OK) {
|
||||
handle->stats.error_count++;
|
||||
return HAL_ERROR;
|
||||
}
|
||||
active_buf = &handle->buffers[handle->active_buffer];
|
||||
}
|
||||
|
||||
memcpy(&active_buf->data[active_buf->index], data, size);
|
||||
active_buf->index += size;
|
||||
active_buf->state = BUFFER_WRITING;
|
||||
handle->stats.total_samples++;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 写入校正后的数据包到存储
|
||||
* @param handle: 数据存储句柄指针
|
||||
|
||||
@ -2,15 +2,16 @@
|
||||
#define DATA_STORAGE_H
|
||||
|
||||
#include "main.h"
|
||||
#include "app_config.h"
|
||||
#include "fatfs.h"
|
||||
#include "ff.h"
|
||||
#include "data_packet.h"
|
||||
#include "correction.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// 数据存储配置
|
||||
#define DATA_STORAGE_BUFFER_SIZE 32768 // 缓冲区大小(字节)
|
||||
#define DATA_STORAGE_FILE_MAX_SIZE (100*1024*1024) // 单个文件最大100MB
|
||||
// 数据存储配置(数值由 app_config.h 中 CFG_* 统一管理)
|
||||
#define DATA_STORAGE_BUFFER_SIZE CFG_STORAGE_BUFFER_SIZE
|
||||
#define DATA_STORAGE_FILE_MAX_SIZE CFG_STORAGE_FILE_MAX_SIZE
|
||||
#define DATA_STORAGE_BASE_PATH "0:/DATA" // 数据存储基础路径
|
||||
#define DATA_STORAGE_FILE_PREFIX "/ADC_DATA_" // 文件名前缀
|
||||
#define DATA_STORAGE_FOLDER_PREFIX "SESSION_" // 文件夹名前缀
|
||||
@ -87,4 +88,7 @@ void DataStorage_ProcessBackgroundTasks(DataStorageHandle_t *handle);
|
||||
// 缓冲区可用性检查函数
|
||||
uint8_t DataStorage_IsBufferAvailable(DataStorageHandle_t *handle, uint32_t required_size);
|
||||
|
||||
// 通用字节流写入(支持任意包类型,方案Y混流存储)
|
||||
HAL_StatusTypeDef DataStorage_WriteRawBytes(DataStorageHandle_t *handle, const uint8_t *data, uint16_t size);
|
||||
|
||||
#endif // DATA_STORAGE_H
|
||||
|
||||
70
User/optic_mag_driver.c
Normal file
70
User/optic_mag_driver.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include "optic_mag_driver.h"
|
||||
|
||||
volatile uint32_t g_optic_mag_value = 0;
|
||||
volatile uint8_t g_optic_mag_fresh = 0;
|
||||
|
||||
typedef enum {
|
||||
OPTIC_STATE_IDLE = 0,
|
||||
OPTIC_STATE_COLLECTING,
|
||||
OPTIC_STATE_WAIT_END,
|
||||
} OpticState_t;
|
||||
|
||||
static UART_HandleTypeDef *s_huart;
|
||||
static uint8_t s_rx_byte;
|
||||
static uint8_t s_bcd_buf[OPTIC_MAG_DATA_BYTES];
|
||||
static uint8_t s_data_count;
|
||||
static OpticState_t s_state;
|
||||
|
||||
void OpticMag_Init(UART_HandleTypeDef *huart)
|
||||
{
|
||||
s_huart = huart;
|
||||
s_state = OPTIC_STATE_IDLE;
|
||||
s_data_count = 0;
|
||||
HAL_UART_Receive_IT(s_huart, &s_rx_byte, 1);
|
||||
}
|
||||
|
||||
void OpticMag_UART_RxCpltCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart != s_huart) return;
|
||||
|
||||
uint8_t byte = s_rx_byte;
|
||||
|
||||
switch (s_state) {
|
||||
case OPTIC_STATE_IDLE:
|
||||
if (byte == OPTIC_MAG_FRAME_START) {
|
||||
s_data_count = 0;
|
||||
s_state = OPTIC_STATE_COLLECTING;
|
||||
}
|
||||
break;
|
||||
|
||||
case OPTIC_STATE_COLLECTING:
|
||||
s_bcd_buf[s_data_count++] = byte;
|
||||
if (s_data_count == OPTIC_MAG_DATA_BYTES) {
|
||||
s_state = OPTIC_STATE_WAIT_END;
|
||||
}
|
||||
break;
|
||||
|
||||
case OPTIC_STATE_WAIT_END:
|
||||
if (byte == OPTIC_MAG_FRAME_END) {
|
||||
// 取前9位BCD数字(忽略第10位),每字节低nibble为有效数字
|
||||
uint32_t value = 0;
|
||||
for (uint8_t i = 0; i < 9; i++) {
|
||||
value = value * 10u + (s_bcd_buf[i] & 0x0Fu);
|
||||
}
|
||||
g_optic_mag_value = value;
|
||||
g_optic_mag_fresh = 1;
|
||||
}
|
||||
// 无论结束字节是否合法,均回到IDLE(非法帧直接丢弃)
|
||||
s_state = OPTIC_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
HAL_UART_Receive_IT(s_huart, &s_rx_byte, 1);
|
||||
}
|
||||
|
||||
void OpticMag_UART_ErrorCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart != s_huart) return;
|
||||
s_state = OPTIC_STATE_IDLE;
|
||||
HAL_UART_Receive_IT(s_huart, &s_rx_byte, 1);
|
||||
}
|
||||
20
User/optic_mag_driver.h
Normal file
20
User/optic_mag_driver.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef OPTIC_MAG_DRIVER_H
|
||||
#define OPTIC_MAG_DRIVER_H
|
||||
|
||||
#include "main.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define OPTIC_MAG_FRAME_START 0x5A
|
||||
#define OPTIC_MAG_FRAME_END 0xA5
|
||||
#define OPTIC_MAG_DATA_BYTES 10
|
||||
|
||||
// 单位 0.0001 nT,忽略末位BCD数字,取前9位
|
||||
// 例如 123456789 表示 12345.6789 nT
|
||||
extern volatile uint32_t g_optic_mag_value;
|
||||
extern volatile uint8_t g_optic_mag_fresh;
|
||||
|
||||
void OpticMag_Init(UART_HandleTypeDef *huart);
|
||||
void OpticMag_UART_RxCpltCallback(UART_HandleTypeDef *huart);
|
||||
void OpticMag_UART_ErrorCallback(UART_HandleTypeDef *huart);
|
||||
|
||||
#endif // OPTIC_MAG_DRIVER_H
|
||||
Loading…
x
Reference in New Issue
Block a user