你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

串口空闲+DMA接收GPS信号,空闲中断触发时间不对。

[复制链接]
。。。。,,, 提问时间:2025-8-8 23:15 / 未解决

使用串口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;
}
收藏 评论0 发布时间:2025-8-8 23:15

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版