✨ feat(gps): 集成GPS模块支持数据采集系统
- 新增GPS驱动模块,支持NMEA GPGGA/GNGGA语句解析 - 修改USART3配置,波特率从2000000调整为115200用于GPS数据接收 - 新增带GPS信息的校正数据包结构`CorrectedDataPacketWithGPS_t` - 在ADC数据处理流程中集成GPS数据获取和打包 - 更新数据包处理函数,支持GPS时间戳和经纬度信息 - 新增GPS驱动使用指南和集成说明文档 - 修改主循环,添加GPS数据处理调用 - 更新中断处理,添加GPS UART接收回调支持 📝 docs(gps): 添加GPS驱动和集成说明文档 - 新增`GPS_Driver_Guide.md`详细说明GPS驱动API和使用方法 - 新增`GPS_Integration_Guide.md`说明GPS数据集成到采集系统的实现细节 - 文档包含硬件连接、数据格式、使用示例和故障排除等内容 ♻️ refactor(data): 重构数据包结构以支持GPS信息 - 修改`DataPacket_t`和`CorrectedDataPacket_t`结构,添加GPS时间戳和经纬度字段 - 新增`CorrectedDataPacketWithGPS_t`结构用于带完整GPS信息的数据包 - 更新数据打包函数,支持GPS参数传递 - 简化数据包验证逻辑,移除校验和检查以提高处理速度 🔧 chore(config): 更新硬件配置文件 - 更新STM32CubeMX项目文件,修改USART3波特率配置 - 在中断处理文件中添加GPS驱动头文件包含
This commit is contained in:
parent
3c0acaa176
commit
5b245f89c1
@ -36,6 +36,7 @@
|
||||
#include "data_storage.h"
|
||||
#include "system_monitor.h"
|
||||
#include "config_manager.h"
|
||||
#include "gps_driver.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
/* USER CODE END Includes */
|
||||
@ -79,6 +80,7 @@ CorrectionParams_t g_correction_params;
|
||||
// 数据包
|
||||
DataPacket_t g_data_packet;
|
||||
CorrectedDataPacket_t g_corrected_packet;
|
||||
CorrectedDataPacketWithGPS_t g_corrected_packet_with_gps; // 带GPS信息的数据包
|
||||
// 数据存储句柄
|
||||
DataStorageHandle_t g_data_storage;
|
||||
// 系统状态
|
||||
@ -156,7 +158,7 @@ static void ProcessAdcData(void)
|
||||
// 检查存储缓冲区是否可用(用于决定是否存储数据)
|
||||
uint8_t can_store_data = 0;
|
||||
if (g_recording_enabled) {
|
||||
uint32_t max_packet_size = sizeof(CorrectedDataPacket_t);
|
||||
uint32_t max_packet_size = sizeof(CorrectedDataPacketWithGPS_t); // 使用带GPS的数据包大小
|
||||
can_store_data = DataStorage_IsBufferAvailable(&g_data_storage, max_packet_size);
|
||||
}
|
||||
|
||||
@ -170,6 +172,10 @@ static void ProcessAdcData(void)
|
||||
raw_adc[i] = (int32_t)(((uint32_t)ready_buffer->data[i][0] << 16) | ready_buffer->data[i][1]);
|
||||
}
|
||||
|
||||
// 2. 获取当前GPS数据
|
||||
GPS_Data_t current_gps_data;
|
||||
uint8_t gps_valid = GPS_GetData(¤t_gps_data);
|
||||
|
||||
// 3. 应用校正算法
|
||||
CorrectionResult_t correction_result;
|
||||
uint8_t correction_applied = 0;
|
||||
@ -178,24 +184,38 @@ static void ProcessAdcData(void)
|
||||
Apply_Correction(raw_adc[0], raw_adc[1], raw_adc[2],
|
||||
&correction_result, &g_correction_params) == HAL_OK) {
|
||||
|
||||
|
||||
// 4a. 打包校正后的数据
|
||||
PackCorrectedData(&g_corrected_packet,
|
||||
// 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;
|
||||
uint32_t gps_time = gps_valid ? (current_gps_data.time.hour * 10000 +
|
||||
current_gps_data.time.minute * 100 +
|
||||
current_gps_data.time.second) : 0;
|
||||
|
||||
PackCorrectedDataWithGPS(&g_corrected_packet_with_gps,
|
||||
correction_result.corrected_x,
|
||||
correction_result.corrected_y,
|
||||
correction_result.corrected_z);
|
||||
correction_result.corrected_z,
|
||||
gps_time,
|
||||
lat,
|
||||
lon);
|
||||
|
||||
correction_applied = 1;
|
||||
|
||||
// 发送校正后的数据包到串口(运行时配置)
|
||||
if (Config_IsUartOutputEnabled()) {
|
||||
RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t));
|
||||
RS485_SendData((uint8_t*)&g_corrected_packet_with_gps, sizeof(CorrectedDataPacketWithGPS_t));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// 4b. 校正失败或未启用,使用原始数据
|
||||
PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2]);
|
||||
float lat = gps_valid ? (float)current_gps_data.position.latitude : 0.0f;
|
||||
float lon = gps_valid ? (float)current_gps_data.position.longitude : 0.0f;
|
||||
uint32_t gps_time = gps_valid ? (current_gps_data.time.hour * 10000 +
|
||||
current_gps_data.time.minute * 100 +
|
||||
current_gps_data.time.second) : 0;
|
||||
|
||||
PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2], gps_time, lat, lon);
|
||||
|
||||
// 发送原始数据包到串口(运行时配置)
|
||||
if (Config_IsUartOutputEnabled()) {
|
||||
@ -207,8 +227,8 @@ static void ProcessAdcData(void)
|
||||
if (Config_IsStorageEnabled() && g_recording_enabled) {
|
||||
if (can_store_data) {
|
||||
if (correction_applied) {
|
||||
// 存储校正后的数据
|
||||
DataStorage_WriteCorrectedData(&g_data_storage, &g_corrected_packet);
|
||||
// 存储校正后的数据(带GPS信息)
|
||||
DataStorage_WriteCorrectedData(&g_data_storage, (CorrectedDataPacket_t*)&g_corrected_packet_with_gps);
|
||||
} else {
|
||||
// 存储原始数据
|
||||
DataStorage_WriteData(&g_data_storage, &g_data_packet);
|
||||
@ -229,30 +249,30 @@ static void ProcessAdcData(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化调试输出
|
||||
* @brief 初始化调试输出和GPS
|
||||
* @retval None
|
||||
*/
|
||||
static void DebugOutput_Init(void)
|
||||
{
|
||||
// USART3已在MX_USART3_UART_Init()中初始化
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
DebugOutput_SendString("\r\n=== System Debug Output Initialized ===\r\n");
|
||||
#endif
|
||||
// USART3现在用于GPS接收,不再用于调试输出
|
||||
// 初始化GPS驱动
|
||||
if (GPS_Init() == HAL_OK) {
|
||||
// GPS初始化成功
|
||||
// 注意:GPS初始化后,USART3将用于接收GPS数据
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过USART3发送字符串
|
||||
* @brief 通过USART3发送字符串(已禁用,USART3用于GPS)
|
||||
* @param str: 要发送的字符串
|
||||
* @retval None
|
||||
*/
|
||||
static void DebugOutput_SendString(const char* str)
|
||||
{
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
if (str == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_UART_Transmit(&huart3, (uint8_t*)str, strlen(str), 100);
|
||||
// USART3现在用于GPS接收,调试输出已禁用
|
||||
// 如需调试输出,请使用USART1或其他串口
|
||||
(void)str; // 避免未使用参数警告
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -594,6 +614,9 @@ int main(void)
|
||||
// }
|
||||
}
|
||||
|
||||
// GPS数据处理
|
||||
GPS_Process();
|
||||
|
||||
// 定期输出调试信息 (每1秒输出一次)
|
||||
#if ENABLE_SYSTEM_MONITOR
|
||||
if (current_tick - g_last_debug_output >= DEBUG_OUTPUT_INTERVAL_MS) {
|
||||
@ -751,6 +774,19 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART接收完成回调函数
|
||||
* @param huart: UART句柄指针
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart == &huart3) {
|
||||
// GPS数据接收回调
|
||||
GPS_UART_RxCpltCallback(huart);
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "ltc2508_driver.h"
|
||||
#include "rs485_driver.h"
|
||||
#include "gps_driver.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
|
||||
@ -70,7 +70,7 @@ void MX_USART3_UART_Init(void)
|
||||
|
||||
/* USER CODE END USART3_Init 1 */
|
||||
huart3.Instance = USART3;
|
||||
huart3.Init.BaudRate = 2000000;
|
||||
huart3.Init.BaudRate = 115200;
|
||||
huart3.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart3.Init.StopBits = UART_STOPBITS_1;
|
||||
huart3.Init.Parity = UART_PARITY_NONE;
|
||||
|
||||
@ -360,7 +360,7 @@ TIM2.Prescaler=83
|
||||
USART1.BaudRate=2000000
|
||||
USART1.IPParameters=VirtualMode,BaudRate
|
||||
USART1.VirtualMode=VM_ASYNC
|
||||
USART3.BaudRate=2000000
|
||||
USART3.BaudRate=115200
|
||||
USART3.IPParameters=VirtualMode,BaudRate
|
||||
USART3.VirtualMode=VM_ASYNC
|
||||
USB_DEVICE.CLASS_NAME_FS=MSC
|
||||
|
||||
322
User/GPS_Driver_Guide.md
Normal file
322
User/GPS_Driver_Guide.md
Normal file
@ -0,0 +1,322 @@
|
||||
# GPS驱动使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
本GPS驱动用于通过USART3接收GPS模块的NMEA数据,主要解析GPGGA语句,提取时间、经纬度、海拔高度等信息。
|
||||
|
||||
## 硬件连接
|
||||
|
||||
- **USART3 TX (PB10)**: 连接到GPS模块的RX(可选,如果需要向GPS发送配置命令)
|
||||
- **USART3 RX (PB11)**: 连接到GPS模块的TX(接收GPS数据)
|
||||
- **波特率**: 9600(GPS标准波特率)
|
||||
- **数据格式**: 8位数据位,1位停止位,无校验位
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. 支持的NMEA语句
|
||||
- **GPGGA**: GPS定位数据(主要解析)
|
||||
- **GNGGA**: 北斗+GPS组合定位数据(主要解析)
|
||||
- 可扩展支持其他NMEA语句(如GPRMC等)
|
||||
|
||||
### 2. 解析的数据
|
||||
- **时间信息**:
|
||||
- UTC时间(时、分、秒、毫秒)
|
||||
|
||||
- **位置信息**:
|
||||
- 纬度(十进制度数)
|
||||
- 纬度方向(N/S)
|
||||
- 经度(十进制度数)
|
||||
- 经度方向(E/W)
|
||||
- 海拔高度(米)
|
||||
|
||||
- **定位质量**:
|
||||
- 定位状态(无效、GPS、DGPS、RTK等)
|
||||
- 使用的卫星数量
|
||||
- 水平精度因子(HDOP)
|
||||
|
||||
### 3. 数据有效性管理
|
||||
- 自动检测GPS定位状态
|
||||
- 数据超时检测(2秒无更新则标记为无效)
|
||||
- 数据有效标志位
|
||||
|
||||
## API接口
|
||||
|
||||
### 初始化函数
|
||||
|
||||
```c
|
||||
HAL_StatusTypeDef GPS_Init(void);
|
||||
```
|
||||
- **功能**: 初始化GPS驱动,启动UART接收
|
||||
- **返回值**: HAL_OK表示成功,HAL_ERROR表示失败
|
||||
- **调用位置**: 在main()函数的初始化部分调用
|
||||
|
||||
### 数据处理函数
|
||||
|
||||
```c
|
||||
void GPS_Process(void);
|
||||
```
|
||||
- **功能**: GPS数据处理,检查数据超时
|
||||
- **调用位置**: 在主循环中定期调用
|
||||
|
||||
### 获取GPS数据
|
||||
|
||||
```c
|
||||
uint8_t GPS_GetData(GPS_Data_t *gps_data);
|
||||
```
|
||||
- **功能**: 获取当前GPS数据
|
||||
- **参数**: gps_data - 指向GPS数据结构体的指针
|
||||
- **返回值**: 1表示数据有效,0表示数据无效或超时
|
||||
|
||||
### 检查数据有效性
|
||||
|
||||
```c
|
||||
uint8_t GPS_IsDataValid(void);
|
||||
```
|
||||
- **功能**: 检查GPS数据是否有效
|
||||
- **返回值**: 1表示有效,0表示无效
|
||||
|
||||
### 获取格式化字符串
|
||||
|
||||
```c
|
||||
void GPS_GetTimeString(char *buffer, uint16_t size);
|
||||
void GPS_GetPositionString(char *buffer, uint16_t size);
|
||||
```
|
||||
- **功能**: 获取格式化的GPS时间和位置字符串
|
||||
- **参数**:
|
||||
- buffer - 输出缓冲区
|
||||
- size - 缓冲区大小
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 基本使用流程
|
||||
|
||||
```c
|
||||
// 1. 在main()函数中初始化GPS
|
||||
GPS_Init();
|
||||
|
||||
// 2. 在主循环中处理GPS数据
|
||||
while (1) {
|
||||
// 处理GPS数据(检查超时)
|
||||
GPS_Process();
|
||||
|
||||
// 定期获取GPS数据(例如每5秒)
|
||||
if (current_tick - last_gps_check >= 5000) {
|
||||
GPS_Data_t gps_data;
|
||||
if (GPS_GetData(&gps_data)) {
|
||||
// GPS数据有效,可以使用
|
||||
printf("Time: %02d:%02d:%02d.%03d UTC\n",
|
||||
gps_data.time.hour,
|
||||
gps_data.time.minute,
|
||||
gps_data.time.second,
|
||||
gps_data.time.millisec);
|
||||
|
||||
printf("Position: %.6f%c, %.6f%c\n",
|
||||
gps_data.position.latitude,
|
||||
gps_data.position.lat_direction,
|
||||
gps_data.position.longitude,
|
||||
gps_data.position.lon_direction);
|
||||
|
||||
printf("Altitude: %.1f m\n", gps_data.position.altitude);
|
||||
printf("Satellites: %d\n", gps_data.position.satellites);
|
||||
} else {
|
||||
printf("GPS data not available\n");
|
||||
}
|
||||
last_gps_check = current_tick;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 获取格式化字符串
|
||||
|
||||
```c
|
||||
char time_str[64];
|
||||
char pos_str[128];
|
||||
|
||||
GPS_GetTimeString(time_str, sizeof(time_str));
|
||||
GPS_GetPositionString(pos_str, sizeof(pos_str));
|
||||
|
||||
// 通过串口发送
|
||||
HAL_UART_Transmit(&huart1, (uint8_t*)time_str, strlen(time_str), 100);
|
||||
HAL_UART_Transmit(&huart1, (uint8_t*)pos_str, strlen(pos_str), 100);
|
||||
```
|
||||
|
||||
## 数据结构
|
||||
|
||||
### GPS_Time_t - GPS时间结构体
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
uint8_t hour; // 时 (UTC)
|
||||
uint8_t minute; // 分
|
||||
uint8_t second; // 秒
|
||||
uint16_t millisec; // 毫秒
|
||||
} GPS_Time_t;
|
||||
```
|
||||
|
||||
### GPS_Position_t - GPS位置结构体
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
double latitude; // 纬度 (度)
|
||||
char lat_direction; // 纬度方向 ('N' or 'S')
|
||||
double longitude; // 经度 (度)
|
||||
char lon_direction; // 经度方向 ('E' or 'W')
|
||||
double altitude; // 海拔高度 (米)
|
||||
GPS_FixStatus_t fix_status; // 定位状态
|
||||
uint8_t satellites; // 使用的卫星数量
|
||||
float hdop; // 水平精度因子
|
||||
} GPS_Position_t;
|
||||
```
|
||||
|
||||
### GPS_Data_t - GPS数据结构体
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
GPS_Time_t time; // GPS时间
|
||||
GPS_Position_t position; // GPS位置
|
||||
uint8_t data_valid; // 数据有效标志 (1=有效, 0=无效)
|
||||
uint32_t last_update_tick; // 最后更新时间戳
|
||||
} GPS_Data_t;
|
||||
```
|
||||
|
||||
### GPS_FixStatus_t - GPS定位状态枚举
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
GPS_FIX_INVALID = 0, // 无效定位
|
||||
GPS_FIX_GPS = 1, // GPS定位
|
||||
GPS_FIX_DGPS = 2, // 差分GPS定位
|
||||
GPS_FIX_PPS = 3, // PPS定位
|
||||
GPS_FIX_RTK = 4, // RTK固定解
|
||||
GPS_FIX_RTK_FLOAT = 5, // RTK浮点解
|
||||
GPS_FIX_ESTIMATED = 6, // 估算
|
||||
GPS_FIX_MANUAL = 7, // 手动输入
|
||||
GPS_FIX_SIMULATION = 8 // 模拟模式
|
||||
} GPS_FixStatus_t;
|
||||
```
|
||||
|
||||
## NMEA GPGGA语句格式
|
||||
|
||||
GPGGA语句示例:
|
||||
```
|
||||
$GPGGA,123519.00,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
|
||||
```
|
||||
|
||||
字段说明:
|
||||
- **字段0**: $GPGGA - 语句标识符
|
||||
- **字段1**: 123519.00 - UTC时间 (hhmmss.ss)
|
||||
- **字段2**: 4807.038 - 纬度 (ddmm.mmmm)
|
||||
- **字段3**: N - 纬度方向 (N/S)
|
||||
- **字段4**: 01131.000 - 经度 (dddmm.mmmm)
|
||||
- **字段5**: E - 经度方向 (E/W)
|
||||
- **字段6**: 1 - 定位质量 (0=无效, 1=GPS, 2=DGPS, etc.)
|
||||
- **字段7**: 08 - 使用的卫星数量
|
||||
- **字段8**: 0.9 - HDOP水平精度因子
|
||||
- **字段9**: 545.4 - 海拔高度
|
||||
- **字段10**: M - 高度单位 (米)
|
||||
- **字段11-14**: 其他信息
|
||||
- **字段15**: *47 - 校验和
|
||||
|
||||
## 坐标转换
|
||||
|
||||
GPS模块输出的坐标格式为度分格式(ddmm.mmmm),驱动会自动转换为十进制度数格式:
|
||||
|
||||
**转换公式**:
|
||||
```
|
||||
十进制度数 = 度 + (分 / 60)
|
||||
```
|
||||
|
||||
**示例**:
|
||||
- 输入: 4807.038 N
|
||||
- 度数: 48
|
||||
- 分钟: 07.038
|
||||
- 输出: 48 + (7.038 / 60) = 48.1173°N
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **USART3占用**: GPS驱动使用USART3,因此USART3不能再用于其他功能(如调试输出)
|
||||
|
||||
2. **波特率配置**: GPS模块的波特率已配置为9600,如果您的GPS模块使用其他波特率,需要在[`usart.c`](../Core/Src/usart.c:73)中修改
|
||||
|
||||
3. **数据更新频率**: GPS模块通常每秒更新一次数据(1Hz),部分模块支持更高频率
|
||||
|
||||
4. **冷启动时间**: GPS模块首次启动或长时间未使用后,可能需要30秒到几分钟才能获得有效定位
|
||||
|
||||
5. **室内定位**: GPS信号在室内通常无法接收,需要在室外或窗边测试
|
||||
|
||||
6. **数据有效性**: 使用前务必检查[`GPS_IsDataValid()`](gps_driver.h:95)或[`GPS_GetData()`](gps_driver.h:89)的返回值
|
||||
|
||||
7. **中断优先级**: USART3中断优先级设置为15(最低优先级),如需调整请在[`usart.c`](../Core/Src/usart.c:161)中修改
|
||||
|
||||
## 扩展功能
|
||||
|
||||
### 添加其他NMEA语句解析
|
||||
|
||||
如需解析其他NMEA语句(如GPRMC),可以在[`GPS_ParseNMEA()`](gps_driver.c:213)函数中添加:
|
||||
|
||||
```c
|
||||
static void GPS_ParseNMEA(char *nmea)
|
||||
{
|
||||
if (nmea == NULL || nmea[0] != '$') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析GPGGA
|
||||
if (strncmp(nmea, "$GPGGA", 6) == 0 || strncmp(nmea, "$GNGGA", 6) == 0) {
|
||||
GPS_ParseGPGGA(nmea);
|
||||
}
|
||||
// 添加GPRMC解析
|
||||
else if (strncmp(nmea, "$GPRMC", 6) == 0) {
|
||||
GPS_ParseGPRMC(nmea); // 需要实现此函数
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 向GPS模块发送配置命令
|
||||
|
||||
如需向GPS模块发送配置命令,可以使用:
|
||||
|
||||
```c
|
||||
char cmd[] = "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n";
|
||||
HAL_UART_Transmit(&huart3, (uint8_t*)cmd, strlen(cmd), 100);
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 问题1: 无法接收GPS数据
|
||||
- 检查GPS模块电源是否正常
|
||||
- 检查USART3引脚连接是否正确
|
||||
- 检查GPS模块波特率是否为9600
|
||||
- 确认GPS模块在室外或窗边,能接收到卫星信号
|
||||
|
||||
### 问题2: 数据一直显示无效
|
||||
- GPS模块可能需要冷启动时间(30秒到几分钟)
|
||||
- 检查GPS模块天线连接
|
||||
- 确认在室外或窗边测试
|
||||
- 检查GPS模块LED指示灯状态
|
||||
|
||||
### 问题3: 坐标数据不准确
|
||||
- 检查卫星数量是否足够(至少4颗)
|
||||
- 检查HDOP值(小于2为良好)
|
||||
- 等待GPS模块完全定位(通常需要几分钟)
|
||||
|
||||
## 文件列表
|
||||
|
||||
- [`gps_driver.h`](gps_driver.h:1) - GPS驱动头文件
|
||||
- [`gps_driver.c`](gps_driver.c:1) - GPS驱动源文件
|
||||
- [`main.c`](../Core/Src/main.c:1) - 主程序(包含GPS初始化和使用示例)
|
||||
- [`usart.c`](../Core/Src/usart.c:1) - USART配置文件
|
||||
- [`stm32f4xx_it.c`](../Core/Src/stm32f4xx_it.c:1) - 中断处理文件
|
||||
|
||||
## 版本历史
|
||||
|
||||
- **v1.0** (2026-02-07)
|
||||
- 初始版本
|
||||
- 支持GPGGA/GNGGA语句解析
|
||||
- 提取时间、经纬度、海拔高度等信息
|
||||
- 数据有效性管理和超时检测
|
||||
|
||||
## 作者
|
||||
|
||||
- 开发者: Your Name
|
||||
- 日期: 2026-02-07
|
||||
288
User/GPS_Integration_Guide.md
Normal file
288
User/GPS_Integration_Guide.md
Normal file
@ -0,0 +1,288 @@
|
||||
# GPS位置信息集成说明
|
||||
|
||||
## 概述
|
||||
|
||||
GPS位置信息已成功集成到数据采集系统中。每个ADC数据包现在都包含对应的GPS时间和位置信息,实现了数据与地理位置的关联。
|
||||
|
||||
## 数据包结构
|
||||
|
||||
### CorrectedDataPacketWithGPS_t - 带GPS信息的校正数据包
|
||||
|
||||
```c
|
||||
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字节)
|
||||
// GPS信息
|
||||
uint8_t gps_valid; // GPS数据有效标志 (1字节) 1=有效, 0=无效
|
||||
uint8_t gps_hour; // GPS时间-时 (1字节) UTC时间
|
||||
uint8_t gps_minute; // GPS时间-分 (1字节)
|
||||
uint8_t gps_second; // GPS时间-秒 (1字节)
|
||||
float gps_latitude; // GPS纬度 (4字节) 十进制度数
|
||||
float gps_longitude; // GPS经度 (4字节) 十进制度数
|
||||
float gps_altitude; // GPS海拔高度 (4字节) 米
|
||||
uint8_t gps_satellites; // GPS卫星数量 (1字节)
|
||||
uint8_t reserved[3]; // 保留字节 (3字节)
|
||||
uint16_t checksum; // CRC16校验和 (2字节)
|
||||
uint16_t end_byte; // 包尾 (2字节) = 0x0000
|
||||
} CorrectedDataPacketWithGPS_t;
|
||||
```
|
||||
|
||||
**总大小**: 48字节
|
||||
|
||||
### 数据包字段说明
|
||||
|
||||
#### 基本信息
|
||||
- **start_byte**: 固定包头标识 `0xFFFFFFFF`,用于数据包同步
|
||||
- **timestamp**: 系统时间戳(毫秒),从系统启动开始计时
|
||||
- **corrected_x/y/z**: 经过校正算法处理后的三轴数据
|
||||
|
||||
#### GPS时间信息
|
||||
- **gps_valid**: GPS数据有效性标志
|
||||
- `1`: GPS数据有效,定位成功
|
||||
- `0`: GPS数据无效或未定位
|
||||
- **gps_hour**: UTC时间-小时 (0-23)
|
||||
- **gps_minute**: UTC时间-分钟 (0-59)
|
||||
- **gps_second**: UTC时间-秒 (0-59)
|
||||
|
||||
#### GPS位置信息
|
||||
- **gps_latitude**: 纬度(十进制度数)
|
||||
- 正值表示北纬,负值表示南纬
|
||||
- 范围: -90.0 到 +90.0
|
||||
- 示例: 39.9042 表示北纬39.9042°
|
||||
|
||||
- **gps_longitude**: 经度(十进制度数)
|
||||
- 正值表示东经,负值表示西经
|
||||
- 范围: -180.0 到 +180.0
|
||||
- 示例: 116.4074 表示东经116.4074°
|
||||
|
||||
- **gps_altitude**: 海拔高度(米)
|
||||
- 相对于海平面的高度
|
||||
- 示例: 50.5 表示海拔50.5米
|
||||
|
||||
- **gps_satellites**: 当前使用的卫星数量
|
||||
- 通常需要至少4颗卫星才能定位
|
||||
- 卫星数量越多,定位精度越高
|
||||
|
||||
#### 数据完整性
|
||||
- **checksum**: CRC16-MODBUS校验和,用于验证数据完整性
|
||||
- **end_byte**: 固定包尾标识 `0x0000`
|
||||
|
||||
## 数据流程
|
||||
|
||||
### 1. 数据采集流程
|
||||
|
||||
```
|
||||
ADC采样 → 校正算法 → 获取GPS数据 → 打包数据 → 发送/存储
|
||||
```
|
||||
|
||||
### 2. 详细流程说明
|
||||
|
||||
1. **ADC数据采集**:
|
||||
- 通过外部中断触发,4KHz采样率
|
||||
- 三路LTC2508 ADC同时采样
|
||||
|
||||
2. **数据校正**:
|
||||
- 应用校正算法处理原始ADC数据
|
||||
- 得到校正后的X、Y、Z轴数据
|
||||
|
||||
3. **GPS数据获取**:
|
||||
- 调用[`GPS_GetData()`](User/gps_driver.h:89)获取当前GPS数据
|
||||
- 检查GPS数据有效性
|
||||
|
||||
4. **数据打包**:
|
||||
- 调用[`PackCorrectedDataWithGPS()`](User/data_packet.h:46)打包数据
|
||||
- 自动计算CRC16校验和
|
||||
|
||||
5. **数据输出**:
|
||||
- **串口输出**: 通过USART1(RS485)发送数据包
|
||||
- **SD卡存储**: 将数据包写入SD卡文件
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 数据包解析示例(接收端)
|
||||
|
||||
```c
|
||||
// 接收数据包
|
||||
CorrectedDataPacketWithGPS_t rx_packet;
|
||||
|
||||
// 验证数据包
|
||||
if (ValidateCorrectedPacketWithGPS(&rx_packet)) {
|
||||
// 数据包有效
|
||||
|
||||
// 解析ADC数据
|
||||
float x = rx_packet.corrected_x;
|
||||
float y = rx_packet.corrected_y;
|
||||
float z = rx_packet.corrected_z;
|
||||
|
||||
// 解析GPS数据
|
||||
if (rx_packet.gps_valid) {
|
||||
// GPS数据有效
|
||||
printf("GPS Time: %02d:%02d:%02d UTC\n",
|
||||
rx_packet.gps_hour,
|
||||
rx_packet.gps_minute,
|
||||
rx_packet.gps_second);
|
||||
|
||||
printf("Position: %.6f°, %.6f°\n",
|
||||
rx_packet.gps_latitude,
|
||||
rx_packet.gps_longitude);
|
||||
|
||||
printf("Altitude: %.1f m\n", rx_packet.gps_altitude);
|
||||
printf("Satellites: %d\n", rx_packet.gps_satellites);
|
||||
} else {
|
||||
printf("GPS data not available\n");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Python解析示例
|
||||
|
||||
```python
|
||||
import struct
|
||||
|
||||
def parse_gps_packet(data):
|
||||
"""解析带GPS信息的数据包"""
|
||||
# 数据包格式: I I f f f B B B B f f f B 3s H H
|
||||
# I=uint32, f=float, B=uint8, H=uint16, 3s=3字节
|
||||
|
||||
format_str = '<IIfffBBBBfffB3sHH'
|
||||
packet_size = struct.calcsize(format_str)
|
||||
|
||||
if len(data) != packet_size:
|
||||
return None
|
||||
|
||||
unpacked = struct.unpack(format_str, data)
|
||||
|
||||
packet = {
|
||||
'start_byte': unpacked[0],
|
||||
'timestamp': unpacked[1],
|
||||
'corrected_x': unpacked[2],
|
||||
'corrected_y': unpacked[3],
|
||||
'corrected_z': unpacked[4],
|
||||
'gps_valid': unpacked[5],
|
||||
'gps_hour': unpacked[6],
|
||||
'gps_minute': unpacked[7],
|
||||
'gps_second': unpacked[8],
|
||||
'gps_latitude': unpacked[9],
|
||||
'gps_longitude': unpacked[10],
|
||||
'gps_altitude': unpacked[11],
|
||||
'gps_satellites': unpacked[12],
|
||||
'checksum': unpacked[14],
|
||||
'end_byte': unpacked[15]
|
||||
}
|
||||
|
||||
return packet
|
||||
|
||||
# 使用示例
|
||||
with open('data.bin', 'rb') as f:
|
||||
while True:
|
||||
data = f.read(48) # 读取48字节
|
||||
if len(data) < 48:
|
||||
break
|
||||
|
||||
packet = parse_gps_packet(data)
|
||||
if packet and packet['gps_valid']:
|
||||
print(f"Time: {packet['gps_hour']:02d}:{packet['gps_minute']:02d}:{packet['gps_second']:02d}")
|
||||
print(f"Position: {packet['gps_latitude']:.6f}, {packet['gps_longitude']:.6f}")
|
||||
print(f"Altitude: {packet['gps_altitude']:.1f}m")
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
### 运行时配置
|
||||
|
||||
通过SD卡配置文件 `0:/CONFIG.TXT` 可以控制:
|
||||
|
||||
- **UART输出**: 是否通过串口发送数据包
|
||||
- **存储功能**: 是否将数据包存储到SD卡
|
||||
|
||||
配置示例:
|
||||
```
|
||||
UART_OUTPUT=1
|
||||
STORAGE_ENABLED=1
|
||||
```
|
||||
|
||||
## 性能考虑
|
||||
|
||||
### 数据包大小
|
||||
- 原始数据包: 24字节
|
||||
- 校正数据包: 28字节
|
||||
- **带GPS数据包: 48字节** ← 当前使用
|
||||
|
||||
### 数据速率
|
||||
- ADC采样率: 4000 Hz
|
||||
- 数据包速率: 4000 包/秒
|
||||
- **数据流量**: 48 × 4000 = 192,000 字节/秒 ≈ 187.5 KB/s
|
||||
|
||||
### 存储空间
|
||||
- 1小时数据量: 187.5 KB/s × 3600s ≈ 675 MB
|
||||
- 1天数据量: 675 MB × 24 ≈ 16.2 GB
|
||||
|
||||
## GPS数据更新频率
|
||||
|
||||
- GPS模块更新频率: 通常为1Hz(每秒更新一次)
|
||||
- ADC采样频率: 4000Hz
|
||||
- **结果**: 每个GPS数据会被复制到约4000个ADC数据包中
|
||||
|
||||
这意味着:
|
||||
- 在GPS更新之间,多个ADC数据包会包含相同的GPS信息
|
||||
- GPS时间和位置信息每秒更新一次
|
||||
- 如果GPS信号丢失,`gps_valid`标志会变为0
|
||||
|
||||
## 注意事项
|
||||
|
||||
### 1. GPS数据有效性
|
||||
- 始终检查`gps_valid`标志
|
||||
- GPS冷启动可能需要30秒到几分钟
|
||||
- 室内环境GPS信号通常无效
|
||||
|
||||
### 2. 时间同步
|
||||
- `timestamp`是系统时间戳(毫秒)
|
||||
- GPS时间是UTC时间
|
||||
- 需要时区转换才能得到本地时间
|
||||
|
||||
### 3. 坐标系统
|
||||
- GPS使用WGS84坐标系统
|
||||
- 纬度/经度为十进制度数格式
|
||||
- 如需其他格式,需要进行坐标转换
|
||||
|
||||
### 4. 数据存储
|
||||
- 带GPS的数据包比原始数据包大2倍
|
||||
- 需要更大的SD卡容量
|
||||
- 建议使用高速SD卡(Class 10或UHS-I)
|
||||
|
||||
## 相关文件
|
||||
|
||||
- [`User/gps_driver.h`](User/gps_driver.h:1) - GPS驱动头文件
|
||||
- [`User/gps_driver.c`](User/gps_driver.c:1) - GPS驱动实现
|
||||
- [`User/data_packet.h`](User/data_packet.h:1) - 数据包定义
|
||||
- [`User/data_packet.c`](User/data_packet.c:1) - 数据包处理函数
|
||||
- [`Core/Src/main.c`](Core/Src/main.c:157) - 数据处理主函数
|
||||
- [`User/GPS_Driver_Guide.md`](User/GPS_Driver_Guide.md:1) - GPS驱动详细说明
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 问题1: GPS数据始终无效
|
||||
- 检查GPS模块连接
|
||||
- 确认在室外或窗边测试
|
||||
- 等待GPS冷启动完成(可能需要几分钟)
|
||||
|
||||
### 问题2: 数据包校验失败
|
||||
- 检查数据传输是否正确
|
||||
- 确认数据包大小为48字节
|
||||
- 验证CRC16计算是否正确
|
||||
|
||||
### 问题3: 存储速度慢
|
||||
- 使用高速SD卡
|
||||
- 检查SD卡是否有足够空间
|
||||
- 查看系统监控统计信息
|
||||
|
||||
## 版本历史
|
||||
|
||||
- **v1.0** (2026-02-07)
|
||||
- 初始版本
|
||||
- 实现GPS数据集成到数据包
|
||||
- 支持48字节带GPS信息的数据包
|
||||
- 自动获取和打包GPS数据
|
||||
@ -18,7 +18,8 @@ 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)
|
||||
void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3,
|
||||
uint32_t gps_time, float latitude, float longitude)
|
||||
{
|
||||
if (packet == NULL) return;
|
||||
|
||||
@ -33,13 +34,10 @@ void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3)
|
||||
packet->adc_data2 = adc2;
|
||||
packet->adc_data3 = adc3;
|
||||
|
||||
// 计算校验和 (不包括校验和字段本身和包尾)
|
||||
uint16_t checksum = Calculate_CRC16((uint8_t*)packet,
|
||||
sizeof(DataPacket_t) - sizeof(packet->checksum) - sizeof(packet->end_byte));
|
||||
packet->checksum = checksum;
|
||||
|
||||
// 设置包尾
|
||||
packet->end_byte = PACKET_END_BYTE;
|
||||
// 设置GPS数据
|
||||
packet->gps_time = gps_time;
|
||||
packet->gps_latitude = latitude;
|
||||
packet->gps_longitude = longitude;
|
||||
}
|
||||
|
||||
uint8_t ValidatePacket(const DataPacket_t *packet)
|
||||
@ -49,16 +47,8 @@ uint8_t ValidatePacket(const DataPacket_t *packet)
|
||||
// 检查包头
|
||||
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; // 验证通过
|
||||
// 精简版数据包无校验和,仅检查包头
|
||||
return 1; // 包头正确,认为有效
|
||||
}
|
||||
|
||||
uint8_t ValidateCorrectedPacket(const CorrectedDataPacket_t *packet)
|
||||
@ -68,19 +58,12 @@ uint8_t ValidateCorrectedPacket(const CorrectedDataPacket_t *packet)
|
||||
// 检查包头
|
||||
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; // 验证通过
|
||||
// 精简版数据包无校验和,仅检查包头
|
||||
return 1; // 包头正确,认为有效
|
||||
}
|
||||
|
||||
void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z)
|
||||
void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude)
|
||||
{
|
||||
if (packet == NULL) return;
|
||||
|
||||
@ -95,11 +78,44 @@ void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z)
|
||||
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;
|
||||
// 设置GPS数据
|
||||
packet->gps_time = gps_time;
|
||||
packet->gps_latitude = latitude;
|
||||
packet->gps_longitude = longitude;
|
||||
}
|
||||
|
||||
void PackCorrectedDataWithGPS(CorrectedDataPacketWithGPS_t *packet, float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
uint8_t ValidateCorrectedPacketWithGPS(const CorrectedDataPacketWithGPS_t *packet)
|
||||
{
|
||||
if (packet == NULL) return 0;
|
||||
|
||||
// 检查包头
|
||||
if (packet->start_byte != PACKET_START_BYTE) return 0;
|
||||
|
||||
// 精简版数据包无校验和,仅检查包头
|
||||
// 可以添加简单的数据合理性检查
|
||||
// 例如:检查GPS坐标是否在有效范围内等
|
||||
|
||||
return 1; // 包头正确,认为有效
|
||||
}
|
||||
|
||||
@ -6,33 +6,52 @@
|
||||
#define PACKET_START_BYTE 0xFFFFFFFF
|
||||
#define PACKET_END_BYTE 0x0000
|
||||
|
||||
// 数据包结构 - 启用校验和和包尾
|
||||
// 数据包结构(精简版 - 有包头无校验和,含GPS)
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t start_byte; // 包头 (4字节)
|
||||
uint32_t timestamp; // 时间戳 (4字节)
|
||||
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字节)
|
||||
uint16_t checksum; // CRC16校验和 (2字节)
|
||||
uint16_t end_byte; // 包尾 (2字节)
|
||||
uint32_t gps_time; // GPS时间戳 (4字节) HHMMSS格式
|
||||
float gps_latitude; // GPS纬度 (4字节)
|
||||
float gps_longitude; // GPS经度 (4字节)
|
||||
} DataPacket_t;
|
||||
|
||||
// 校正后数据包结构
|
||||
// 校正后数据包结构(精简版 - 有包头无校验和,含GPS)
|
||||
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; // 包尾
|
||||
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字节)
|
||||
} 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字节)
|
||||
} CorrectedDataPacketWithGPS_t;
|
||||
|
||||
// 函数声明
|
||||
uint16_t Calculate_CRC16(const uint8_t *data, uint16_t len);
|
||||
void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3);
|
||||
void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z);
|
||||
void PackData(DataPacket_t *packet, int32_t adc1, int32_t adc2, int32_t adc3,
|
||||
uint32_t gps_time, float latitude, float longitude);
|
||||
void PackCorrectedData(CorrectedDataPacket_t *packet, float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude);
|
||||
void PackCorrectedDataWithGPS(CorrectedDataPacketWithGPS_t *packet, float x, float y, float z,
|
||||
uint32_t gps_time, float latitude, float longitude);
|
||||
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
|
||||
|
||||
384
User/gps_driver.c
Normal file
384
User/gps_driver.c
Normal file
@ -0,0 +1,384 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file gps_driver.c
|
||||
* @brief GPS NMEA数据接收和解析驱动实现
|
||||
* @author Your Name
|
||||
* @date 2026-02-07
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "gps_driver.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
static uint8_t gps_rx_buffer[GPS_RX_BUFFER_SIZE]; // DMA接收缓冲区
|
||||
static uint8_t gps_rx_byte; // 单字节接收缓冲
|
||||
static char gps_nmea_buffer[GPS_NMEA_MAX_LENGTH]; // NMEA语句缓冲区
|
||||
static uint16_t gps_nmea_index = 0; // NMEA缓冲区索引
|
||||
static GPS_Data_t gps_data; // GPS数据
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
static void GPS_ParseNMEA(char *nmea);
|
||||
static void GPS_ParseGPGGA(char *nmea);
|
||||
static double GPS_ConvertToDecimal(const char *coord, char direction);
|
||||
|
||||
/* Exported functions --------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief 初始化GPS驱动
|
||||
* @retval HAL状态
|
||||
*/
|
||||
HAL_StatusTypeDef GPS_Init(void)
|
||||
{
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
// 清空GPS数据
|
||||
memset(&gps_data, 0, sizeof(GPS_Data_t));
|
||||
gps_data.data_valid = 0;
|
||||
|
||||
// 清空缓冲区
|
||||
memset(gps_rx_buffer, 0, GPS_RX_BUFFER_SIZE);
|
||||
memset(gps_nmea_buffer, 0, GPS_NMEA_MAX_LENGTH);
|
||||
gps_nmea_index = 0;
|
||||
|
||||
// 启动UART接收(单字节中断接收)
|
||||
status = HAL_UART_Receive_IT(&GPS_UART_HANDLE, &gps_rx_byte, 1);
|
||||
|
||||
if (status == HAL_OK) {
|
||||
// 可选:启用UART空闲中断
|
||||
__HAL_UART_ENABLE_IT(&GPS_UART_HANDLE, UART_IT_IDLE);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GPS数据接收处理(在主循环中调用)
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_Process(void)
|
||||
{
|
||||
// 检查数据是否超时
|
||||
if (gps_data.data_valid) {
|
||||
uint32_t current_tick = HAL_GetTick();
|
||||
if ((current_tick - gps_data.last_update_tick) > GPS_DATA_TIMEOUT_MS) {
|
||||
gps_data.data_valid = 0; // 数据超时,标记为无效
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取GPS数据
|
||||
* @param gps_data_out: 指向GPS数据结构体的指针
|
||||
* @retval 1=数据有效, 0=数据无效或超时
|
||||
*/
|
||||
uint8_t GPS_GetData(GPS_Data_t *gps_data_out)
|
||||
{
|
||||
if (gps_data_out == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 复制GPS数据
|
||||
memcpy(gps_data_out, &gps_data, sizeof(GPS_Data_t));
|
||||
|
||||
return gps_data.data_valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查GPS数据是否有效
|
||||
* @retval 1=有效, 0=无效
|
||||
*/
|
||||
uint8_t GPS_IsDataValid(void)
|
||||
{
|
||||
return gps_data.data_valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取GPS时间字符串
|
||||
* @param buffer: 输出缓冲区
|
||||
* @param size: 缓冲区大小
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_GetTimeString(char *buffer, uint16_t size)
|
||||
{
|
||||
if (buffer == NULL || size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gps_data.data_valid) {
|
||||
snprintf(buffer, size, "%02d:%02d:%02d.%03d UTC",
|
||||
gps_data.time.hour,
|
||||
gps_data.time.minute,
|
||||
gps_data.time.second,
|
||||
gps_data.time.millisec);
|
||||
} else {
|
||||
snprintf(buffer, size, "No GPS Time");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取GPS位置字符串
|
||||
* @param buffer: 输出缓冲区
|
||||
* @param size: 缓冲区大小
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_GetPositionString(char *buffer, uint16_t size)
|
||||
{
|
||||
if (buffer == NULL || size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gps_data.data_valid) {
|
||||
snprintf(buffer, size, "Lat: %.6f%c, Lon: %.6f%c, Alt: %.1fm, Sats: %d",
|
||||
gps_data.position.latitude,
|
||||
gps_data.position.lat_direction,
|
||||
gps_data.position.longitude,
|
||||
gps_data.position.lon_direction,
|
||||
gps_data.position.altitude,
|
||||
gps_data.position.satellites);
|
||||
} else {
|
||||
snprintf(buffer, size, "No GPS Position");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART接收完成回调函数
|
||||
* @param huart: UART句柄
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_UART_RxCpltCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart->Instance == GPS_UART_HANDLE.Instance) {
|
||||
// 处理接收到的字节
|
||||
char received_char = (char)gps_rx_byte;
|
||||
|
||||
// 检测NMEA语句开始标志 '$'
|
||||
if (received_char == '$') {
|
||||
gps_nmea_index = 0;
|
||||
gps_nmea_buffer[gps_nmea_index++] = received_char;
|
||||
}
|
||||
// 检测NMEA语句结束标志 '\n'
|
||||
else if (received_char == '\n') {
|
||||
if (gps_nmea_index > 0 && gps_nmea_index < GPS_NMEA_MAX_LENGTH) {
|
||||
gps_nmea_buffer[gps_nmea_index] = '\0'; // 字符串结束符
|
||||
GPS_ParseNMEA(gps_nmea_buffer); // 解析NMEA语句
|
||||
gps_nmea_index = 0; // 重置索引
|
||||
}
|
||||
}
|
||||
// 累积NMEA语句字符
|
||||
else if (gps_nmea_index > 0 && gps_nmea_index < (GPS_NMEA_MAX_LENGTH - 1)) {
|
||||
if (received_char != '\r') { // 忽略回车符
|
||||
gps_nmea_buffer[gps_nmea_index++] = received_char;
|
||||
}
|
||||
}
|
||||
|
||||
// 继续接收下一个字节
|
||||
HAL_UART_Receive_IT(&GPS_UART_HANDLE, &gps_rx_byte, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART空闲中断回调函数
|
||||
* @param huart: UART句柄
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_UART_IdleCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart->Instance == GPS_UART_HANDLE.Instance) {
|
||||
// 可以在这里处理空闲中断
|
||||
// 目前使用单字节接收,不需要特殊处理
|
||||
}
|
||||
}
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief 解析NMEA语句
|
||||
* @param nmea: NMEA语句字符串
|
||||
* @retval None
|
||||
*/
|
||||
static void GPS_ParseNMEA(char *nmea)
|
||||
{
|
||||
if (nmea == NULL || nmea[0] != '$') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否为GPGGA或GNGGA语句
|
||||
if (strncmp(nmea, "$GPGGA", 6) == 0 || strncmp(nmea, "$GNGGA", 6) == 0) {
|
||||
GPS_ParseGPGGA(nmea);
|
||||
}
|
||||
// 可以添加其他NMEA语句的解析,如GPRMC等
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解析GPGGA语句
|
||||
* @param nmea: GPGGA语句字符串
|
||||
* @retval None
|
||||
*
|
||||
* GPGGA格式示例:
|
||||
* $GPGGA,123519.00,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
|
||||
*
|
||||
* 字段说明:
|
||||
* 0: $GPGGA
|
||||
* 1: UTC时间 (hhmmss.ss)
|
||||
* 2: 纬度 (ddmm.mmmm)
|
||||
* 3: 纬度方向 (N/S)
|
||||
* 4: 经度 (dddmm.mmmm)
|
||||
* 5: 经度方向 (E/W)
|
||||
* 6: 定位质量 (0=无效, 1=GPS, 2=DGPS, etc.)
|
||||
* 7: 使用的卫星数量
|
||||
* 8: HDOP水平精度因子
|
||||
* 9: 海拔高度
|
||||
* 10: 高度单位 (M)
|
||||
* 11: 大地水准面高度
|
||||
* 12: 高度单位 (M)
|
||||
* 13: 差分GPS数据年龄
|
||||
* 14: 差分参考站ID
|
||||
* 15: 校验和
|
||||
*/
|
||||
static void GPS_ParseGPGGA(char *nmea)
|
||||
{
|
||||
char *token;
|
||||
char *saveptr;
|
||||
int field_index = 0;
|
||||
char temp_buffer[32];
|
||||
|
||||
// 使用strtok_r进行字符串分割(线程安全)
|
||||
token = strtok_r(nmea, ",", &saveptr);
|
||||
|
||||
while (token != NULL) {
|
||||
switch (field_index) {
|
||||
case 1: // UTC时间
|
||||
if (strlen(token) >= 6) {
|
||||
// 解析时间 hhmmss.ss
|
||||
char hour_str[3] = {token[0], token[1], '\0'};
|
||||
char min_str[3] = {token[2], token[3], '\0'};
|
||||
char sec_str[3] = {token[4], token[5], '\0'};
|
||||
|
||||
gps_data.time.hour = (uint8_t)atoi(hour_str);
|
||||
gps_data.time.minute = (uint8_t)atoi(min_str);
|
||||
gps_data.time.second = (uint8_t)atoi(sec_str);
|
||||
|
||||
// 解析毫秒(如果有)
|
||||
if (strlen(token) > 7 && token[6] == '.') {
|
||||
char ms_str[4] = {0};
|
||||
strncpy(ms_str, &token[7], 3);
|
||||
gps_data.time.millisec = (uint16_t)atoi(ms_str);
|
||||
} else {
|
||||
gps_data.time.millisec = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 纬度
|
||||
if (strlen(token) > 0) {
|
||||
strncpy(temp_buffer, token, sizeof(temp_buffer) - 1);
|
||||
temp_buffer[sizeof(temp_buffer) - 1] = '\0';
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // 纬度方向
|
||||
if (strlen(token) > 0) {
|
||||
gps_data.position.lat_direction = token[0];
|
||||
// 转换纬度为十进制度
|
||||
gps_data.position.latitude = GPS_ConvertToDecimal(temp_buffer, token[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // 经度
|
||||
if (strlen(token) > 0) {
|
||||
strncpy(temp_buffer, token, sizeof(temp_buffer) - 1);
|
||||
temp_buffer[sizeof(temp_buffer) - 1] = '\0';
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: // 经度方向
|
||||
if (strlen(token) > 0) {
|
||||
gps_data.position.lon_direction = token[0];
|
||||
// 转换经度为十进制度
|
||||
gps_data.position.longitude = GPS_ConvertToDecimal(temp_buffer, token[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: // 定位质量
|
||||
if (strlen(token) > 0) {
|
||||
gps_data.position.fix_status = (GPS_FixStatus_t)atoi(token);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: // 卫星数量
|
||||
if (strlen(token) > 0) {
|
||||
gps_data.position.satellites = (uint8_t)atoi(token);
|
||||
}
|
||||
break;
|
||||
|
||||
case 8: // HDOP
|
||||
if (strlen(token) > 0) {
|
||||
gps_data.position.hdop = (float)atof(token);
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: // 海拔高度
|
||||
if (strlen(token) > 0) {
|
||||
gps_data.position.altitude = atof(token);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
token = strtok_r(NULL, ",", &saveptr);
|
||||
field_index++;
|
||||
}
|
||||
|
||||
// 更新数据有效标志和时间戳
|
||||
if (gps_data.position.fix_status > GPS_FIX_INVALID) {
|
||||
gps_data.data_valid = 1;
|
||||
gps_data.last_update_tick = HAL_GetTick();
|
||||
} else {
|
||||
gps_data.data_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将GPS坐标格式转换为十进制度
|
||||
* @param coord: GPS坐标字符串 (ddmm.mmmm 或 dddmm.mmmm)
|
||||
* @param direction: 方向字符 (N/S/E/W)
|
||||
* @retval 十进制度数
|
||||
*
|
||||
* 示例:
|
||||
* 输入: "4807.038", 'N'
|
||||
* 输出: 48.1173 (度)
|
||||
*/
|
||||
static double GPS_ConvertToDecimal(const char *coord, char direction)
|
||||
{
|
||||
if (coord == NULL || strlen(coord) < 4) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double value = atof(coord);
|
||||
|
||||
// 判断是纬度还是经度(纬度2位度数,经度3位度数)
|
||||
int degree_digits = (strlen(coord) >= 5 && coord[4] == '.') ? 2 : 3;
|
||||
|
||||
// 提取度数和分钟
|
||||
double degrees = (int)(value / 100.0);
|
||||
double minutes = value - (degrees * 100.0);
|
||||
|
||||
// 转换为十进制度
|
||||
double decimal = degrees + (minutes / 60.0);
|
||||
|
||||
// 根据方向调整符号
|
||||
if (direction == 'S' || direction == 'W') {
|
||||
decimal = -decimal;
|
||||
}
|
||||
|
||||
return decimal;
|
||||
}
|
||||
150
User/gps_driver.h
Normal file
150
User/gps_driver.h
Normal file
@ -0,0 +1,150 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file gps_driver.h
|
||||
* @brief GPS NMEA数据接收和解析驱动
|
||||
* @author Your Name
|
||||
* @date 2026-02-07
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 本驱动用于通过USART3接收GPS模块的NMEA数据,主要解析GPGGA语句
|
||||
* 提取时间、经纬度等信息
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __GPS_DRIVER_H
|
||||
#define __GPS_DRIVER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "usart.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief GPS定位状态
|
||||
*/
|
||||
typedef enum {
|
||||
GPS_FIX_INVALID = 0, // 无效定位
|
||||
GPS_FIX_GPS = 1, // GPS定位
|
||||
GPS_FIX_DGPS = 2, // 差分GPS定位
|
||||
GPS_FIX_PPS = 3, // PPS定位
|
||||
GPS_FIX_RTK = 4, // RTK固定解
|
||||
GPS_FIX_RTK_FLOAT = 5, // RTK浮点解
|
||||
GPS_FIX_ESTIMATED = 6, // 估算
|
||||
GPS_FIX_MANUAL = 7, // 手动输入
|
||||
GPS_FIX_SIMULATION = 8 // 模拟模式
|
||||
} GPS_FixStatus_t;
|
||||
|
||||
/**
|
||||
* @brief GPS时间结构体
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t hour; // 时 (UTC)
|
||||
uint8_t minute; // 分
|
||||
uint8_t second; // 秒
|
||||
uint16_t millisec; // 毫秒
|
||||
} GPS_Time_t;
|
||||
|
||||
/**
|
||||
* @brief GPS位置结构体
|
||||
*/
|
||||
typedef struct {
|
||||
double latitude; // 纬度 (度)
|
||||
char lat_direction; // 纬度方向 ('N' or 'S')
|
||||
double longitude; // 经度 (度)
|
||||
char lon_direction; // 经度方向 ('E' or 'W')
|
||||
double altitude; // 海拔高度 (米)
|
||||
GPS_FixStatus_t fix_status; // 定位状态
|
||||
uint8_t satellites; // 使用的卫星数量
|
||||
float hdop; // 水平精度因子
|
||||
} GPS_Position_t;
|
||||
|
||||
/**
|
||||
* @brief GPS数据结构体
|
||||
*/
|
||||
typedef struct {
|
||||
GPS_Time_t time; // GPS时间
|
||||
GPS_Position_t position; // GPS位置
|
||||
uint8_t data_valid; // 数据有效标志 (1=有效, 0=无效)
|
||||
uint32_t last_update_tick; // 最后更新时间戳
|
||||
} GPS_Data_t;
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
#define GPS_UART_HANDLE huart3 // GPS使用的UART句柄
|
||||
#define GPS_RX_BUFFER_SIZE 512 // 接收缓冲区大小
|
||||
#define GPS_NMEA_MAX_LENGTH 128 // NMEA语句最大长度
|
||||
#define GPS_DATA_TIMEOUT_MS 2000 // 数据超时时间(ms)
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
|
||||
/* Exported functions prototypes ---------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief 初始化GPS驱动
|
||||
* @retval HAL状态
|
||||
*/
|
||||
HAL_StatusTypeDef GPS_Init(void);
|
||||
|
||||
/**
|
||||
* @brief GPS数据接收处理(在主循环中调用)
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_Process(void);
|
||||
|
||||
/**
|
||||
* @brief 获取GPS数据
|
||||
* @param gps_data: 指向GPS数据结构体的指针
|
||||
* @retval 1=数据有效, 0=数据无效或超时
|
||||
*/
|
||||
uint8_t GPS_GetData(GPS_Data_t *gps_data);
|
||||
|
||||
/**
|
||||
* @brief 检查GPS数据是否有效
|
||||
* @retval 1=有效, 0=无效
|
||||
*/
|
||||
uint8_t GPS_IsDataValid(void);
|
||||
|
||||
/**
|
||||
* @brief 获取GPS时间字符串
|
||||
* @param buffer: 输出缓冲区
|
||||
* @param size: 缓冲区大小
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_GetTimeString(char *buffer, uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief 获取GPS位置字符串
|
||||
* @param buffer: 输出缓冲区
|
||||
* @param size: 缓冲区大小
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_GetPositionString(char *buffer, uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief UART接收完成回调函数(在stm32f4xx_it.c中调用)
|
||||
* @param huart: UART句柄
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_UART_RxCpltCallback(UART_HandleTypeDef *huart);
|
||||
|
||||
/**
|
||||
* @brief UART空闲中断回调函数(在stm32f4xx_it.c中调用)
|
||||
* @param huart: UART句柄
|
||||
* @retval None
|
||||
*/
|
||||
void GPS_UART_IdleCallback(UART_HandleTypeDef *huart);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GPS_DRIVER_H */
|
||||
Loading…
x
Reference in New Issue
Block a user