使用串口1接收GPS模块(BZ121)的信号,解析UBX PVT协议。在开源的minifly上面写GPS串口通讯程序,不能printf出来,所以通过设置标志位发送到匿名上位机,来判断。得到,初始化正常运行,DMA配置完成,空闲中断标志位,每次触发一次空闲中断后,标志位翻转,可以得到空闲中断在触发。后来通过读取dmabuff中的数据,发现数据不是在帧头帧尾处开始空闲接收,猜测是否是因为115200的波特率太高了?等原因导致误触发。
/FreeRTOS相关头文件/
include "FreeRTOS.h"
include "queue.h"
include "semphr.h"
include "sys.h"
include <string.h>
include "config.h"
include "uart1.h"
include "debug_assert.h"
include "config.h"
include <stdlib.h>
include <stdio.h>
//Ublox协议相关定义
define UBLOX_SYNC1 0xB5
define UBLOX_SYNC2 0x62
define UBLOX_NAV_CLASS 0x01
define UBLOX_NAV_PVT 0x07
// DMA缓冲区大小
define DMA_BUFFER_SIZE 256
define RING_BUFFER_SIZE 512
// DMA接收缓冲区
static volatile uint8_t dmaBuffer[DMA_BUFFER_SIZE];
static volatile uint16_t dmaReceived = 0;
// 环形缓冲区
typedef struct {
uint8_t buffer[RING_BUFFER_SIZE];
volatile uint16_t head;
volatile uint16_t tail;
volatile uint16_t count;
} RingBuffer_t;
//全局变量
static bool isInit = false;
static UBLOX_t ubloxData;
static GPS_t gpsData;
static xQueueHandle uart1queue;
static UbloxParser_t ubloxParser;
static RingBuffer_t rxRingBuffer;
//函数声明
static void parseUbloxPVT(uint8_t *payload);
static void processUbloxData(uint8_t data);
static void DMA_Config(void);
static void USART_Config(u32 baudrate);
void uart1Init(u32 baudrate)
{
if(isInit) return;
// 初始化数据结构
uart1_debug_flags.uart_init_flag = 1; // 标记初始化开始
memset(&ubloxData, 0, sizeof(ubloxData));
memset(&gpsData, 0, sizeof(gpsData));
memset(&ubloxParser, 0, sizeof(ubloxParser));
memset(&rxRingBuffer, 0, sizeof(rxRingBuffer));// 配置USART和DMA
USART_Config(baudrate);isInit = true;
}
static void USART_Config(u32 baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
USART_InitTypeDef USART_InitStructure;/* 使能GPIO和USART1时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);/* 配置USART引脚 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; // TX
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(GPIOA, &GPIO_InitStructure);/* 引脚复用映射 */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_USART1);/* USART初始化 */
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1, &USART_InitStructure);/* 使能空闲中断 */
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); // 禁用 RXNE 中断/* 配置中断优先级 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);USART_Cmd(USART1, ENABLE);
uart1_debug_flags.uart_init_flag = 2; // 标记串口配置完成
}
{
DMA_InitTypeDef DMA_InitStructure;/* 使能DMA2时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);/* 先禁用DMA */
DMA_Cmd(DMA2_Stream2, DISABLE);/* 配置DMA */
DMA_InitStructure.DMA_Channel = DMA_Channel_4; // USART1_RX使用Channel4
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dmaBuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = DMA_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;/* 清除所有中断标志 */
DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2 | DMA_IT_HTIF2 | DMA_IT_TEIF2 | DMA_IT_DMEIF2 | DMA_IT_FEIF2);DMA_Init(DMA2_Stream2, &DMA_InitStructure);/* USART DMA使能 */
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);/* 启动DMA */
DMA_Cmd(DMA2_Stream2, ENABLE);
uart1_debug_flags.dma_config_flag = 1; // 标记DMA配置完成
}
if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) {
uart1_debug_flags.idle_int_flag ^= 1; // 空闲中断触发时翻转标志
USART_ReceiveData(USART1); // 读取SR寄存器清除IDLE标志
USART_ClearITPendingBit(USART1, USART_IT_IDLE);uint16_t received = DMA_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA2_Stream2);
uart1_debug_flags.receivedatanum=received;
/* 4. 检查接收数据长度是否合理 */
if(received > 0 && received <= DMA_BUFFER_SIZE)
{
/* 5. 更新环形缓冲区并处理 Ublox 数据 */
for(uint16_t i = 0; i < received; i++) {
uint16_t next_head = (rxRingBuffer.head + 1) % RING_BUFFER_SIZE;// 检查缓冲区是否已满
if(next_head != rxRingBuffer.tail) {
rxRingBuffer.buffer[rxRingBuffer.head] = dmaBuffer[i];
rxRingBuffer.head = next_head;
rxRingBuffer.count++;
uart1_debug_flags.onebyte=dmaBuffer[5];
uart1_debug_flags.twobyte=dmaBuffer[6];
uart1_debug_flags.threebyte=dmaBuffer[7];
uart1_debug_flags.fourbyte=dmaBuffer[8];
uart1_debug_flags.fivebyte=dmaBuffer[9];
processUbloxData(dmaBuffer[i]);
/* 直接处理每个字节 */
processUbloxData(dmaBuffer[i]);
} else {
// 缓冲区溢出处理
break;
}
}
}
// 清除 IDLE 标志并重启 DMDMA_Cmd(DMA2_Stream2, DISABLE);
DMA_SetCurrDataCounter(DMA2_Stream2, DMA_BUFFER_SIZE); // 重置计数器
DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2 | DMA_FLAG_HTIF2 | DMA_FLAG_TEIF2 | DMA_FLAG_DMEIF2 | DMA_FLAG_FEIF2);
DMA_Cmd(DMA2_Stream2, ENABLE);
}
// /* 6. 溢出错误处理 */
// if(USART_GetFlagStatus(USART1, USART_FLAG_ORE))
// {
// uart1_debug_flags.shujuyichu=6;
// USART_ReceiveData(USART1);
// USART_ClearFlag(USART1, USART_FLAG_ORE);
// }
}///* USART1 中断服务函数 */
//void USART1_IRQHandler(void)
//{
// /* 1. 检查 IDLE 中断(接收完成) */
// if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
// {
// uart1_debug_flags.idle_int_flag ^= 1; // 空闲中断触发时翻转标志
// /* 2. 计算 DMA 接收的字节数 */
// uint16_t received = DMA_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA2_Stream2);
// uart1_debug_flags.receivedatanum=received;
// /* 3. 更新环形缓冲区并处理 Ublox 数据 */
// for(uint16_t i = 0; i < received; i++) {
// rxRingBuffer.buffer[rxRingBuffer.head] = dmaBuffer[i];
// rxRingBuffer.head = (rxRingBuffer.head + 1) % RING_BUFFER_SIZE;
// uart1_debug_flags.onebyte=dmaBuffer[0];
// uart1_debug_flags.twobyte=dmaBuffer[1];
// uart1_debug_flags.threebyte=dmaBuffer[2];
// uart1_debug_flags.fourbyte=dmaBuffer[3];
// uart1_debug_flags.fivebyte=dmaBuffer[4];
// /* 直接处理每个字节 */
// processUbloxData(dmaBuffer[i]);
// }
//// printf("接收到一帧数据,字节数: %d\n", received); // 添加成功接收的打印
// /* 4. 清除 IDLE 中断标志 */
// USART_ReceiveData(USART1);
//
// /* 5. 重启 DMA 传输 */
// DMA_Cmd(DMA2_Stream2, DISABLE);
// DMA2_Stream2->NDTR = DMA_BUFFER_SIZE; // F4 系列用 NDTR
// DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2 | DMA_FLAG_HTIF2 | DMA_FLAG_TEIF2);
// DMA_Cmd(DMA2_Stream2, ENABLE);
// }
//
// /* 6. 溢出错误处理 */
// if(USART_GetFlagStatus(USART1, USART_FLAG_ORE))
// {
// uart1_debug_flags.shujuyichu=6;
// USART_ReceiveData(USART1);
// USART_ClearFlag(USART1, USART_FLAG_ORE);
// }
//}
static void parseUbloxPVT(uint8_t *payload) {
// 解析PVT消息
ubloxData.time = (float)(*(uint32_t*)(payload + 4)) / 1000.0f; // iTOW转换为秒// 经纬度 (1e-7度 -> 度)
ubloxData.longitude = (double)(*(int32_t*)(payload + 24)) * 1e-7;
ubloxData.latitude = (double)(*(int32_t*)(payload + 28)) * 1e-7;// 高度 (mm -> m)
ubloxData.altitude = (float)(*(int32_t*)(payload + 36)) * 0.001f;// 速度 (mm/s -> cm/s)
ubloxData.velN = *(int32_t*)(payload + 48) / 10;
ubloxData.velE = *(int32_t*)(payload + 52) / 10;
ubloxData.velD = *(int32_t*)(payload + 56) / 10;
ubloxData.speed = *(int32_t*)(payload + 60) / 10; // 地面速度// 航向 (1e-5度 -> 度)
ubloxData.heading = (float)(*(int32_t*)(payload + 64)) * 1e-5f;// 精度 (mm -> m)
ubloxData.hAcc = (float)(*(uint32_t*)(payload + 40)) * 0.001f;
ubloxData.vAcc = (float)(*(uint32_t*)(payload + 44)) * 0.001f;
ubloxData.sAcc = (float)(*(uint32_t*)(payload + 68)) * 0.001f;
ubloxData.cAcc = (float)(*(uint32_t*)(payload + 72)) * 1e-5f;// 定位状态和卫星数
ubloxData.fixStatus = *(uint8_t*)(payload + 20);
ubloxData.numSV = *(uint8_t*)(payload + 23);
}/* 处理Ublox协议数据 */
static void processUbloxData(uint8_t data) {
switch (ubloxParser.state) {
case 0: // 等待同步字符1
if (data == UBLOX_SYNC1) {
ubloxParser.state = 1;
uart1_debug_flags.pvt_parse_flag = 1;
}
break;case 1: // 等待同步字符2
if (data == UBLOX_SYNC2) {
ubloxParser.state = 2; uart1_debug_flags.pvt_parse_flag = 2;
ubloxParser.ck_a = 0;
ubloxParser.ck_b = 0;
} else {
ubloxParser.state = 0; uart1_debug_flags.pvt_parse_flag = 0;
}
break;case 2: // 读取消息类
ubloxParser.class = data;
ubloxParser.ck_a += data;
ubloxParser.ck_b += ubloxParser.ck_a;
ubloxParser.state = 3; uart1_debug_flags.pvt_parse_flag = 3;
break;case 3: // 读取消息ID
ubloxParser.id = data;
ubloxParser.ck_a += data;
ubloxParser.ck_b += ubloxParser.ck_a;
ubloxParser.state = 4; uart1_debug_flags.pvt_parse_flag = 4;
break;case 4: // 读取长度低字节
ubloxParser.length = data;
ubloxParser.ck_a += data;
ubloxParser.ck_b += ubloxParser.ck_a;
ubloxParser.state = 5; uart1_debug_flags.pvt_parse_flag = 5;
break;case 5: // 读取长度高字节
ubloxParser.length |= (data << 8);
ubloxParser.ck_a += data;
ubloxParser.ck_b += ubloxParser.ck_a;if (ubloxParser.length > sizeof(ubloxParser.payload)) {
ubloxParser.state = 0; // 长度过长,重置
} else if (ubloxParser.length > 0) {
ubloxParser.count = 0;
ubloxParser.state = 6; // 读取负载
uart1_debug_flags.pvt_parse_flag = 6;
} else {
ubloxParser.state = 7; // 无负载,直接校验
uart1_debug_flags.pvt_parse_flag = 7;
}
break;
case 6: // 读取负载数据
ubloxParser.payload[ubloxParser.count++] = data;
ubloxParser.ck_a += data;
ubloxParser.ck_b += ubloxParser.ck_a;if (ubloxParser.count >= ubloxParser.length) {
ubloxParser.state = 7;
uart1_debug_flags.pvt_parse_flag = 7;
}
break;
case 7: // 校验A
if (data == ubloxParser.ck_a) {
ubloxParser.state = 8;
uart1_debug_flags.pvt_parse_flag = 8;
} else {
ubloxParser.state = 0; // 校验失败
}
break;case 8: // 校验B
if (data == ubloxParser.ck_b) {
// 完整消息接收完毕
if (ubloxParser.class == UBLOX_NAV_CLASS &&
ubloxParser.id == UBLOX_NAV_PVT) {// 解析PVT消息
parseUbloxPVT(ubloxParser.payload);
uart1_debug_flags.pvt_parse_flag = 9; // 标记PVT解析成功
// printf("成功解析PVT数据:\n");
// printf("经度: %f, 纬度: %f, 高度: %f, 速度: %.2f, 航向: %f\n", ubloxData.longitude, ubloxData.latitude, ubloxData.altitude,(float)ubloxData.velN, // 转换为float
// (float)ubloxData.velE); // 转换为float
}
}
ubloxParser.state = 0; // 无论校验成功与否都重置状态
break;```
```default:
ubloxParser.state = 0;
break;}
}/* 获取GPS数据 */
void getGPSdata(GPS_t *data) {
if (data == NULL) {
return;
}
gpsData.lastlatitude =gpsData.latitude ;
gpsData.lastLongitude = gpsData.longitude;
//当前经纬度
gpsData.latitude = ubloxData.latitude;
gpsData.longitude = ubloxData.longitude;
// 速度 (cm/s)
gpsData.velocity.x = (float)ubloxData.velN;
gpsData.velocity.y = (float)ubloxData.velE;
gpsData.velocity.z = (float)ubloxData.velD;
}