onlycook 发表于 2025-8-15 15:00

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

使用串口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 0xB5define UBLOX_SYNC2 0x62define UBLOX_NAV_CLASS 0x01define UBLOX_NAV_PVT 0x07// DMA缓冲区大小define DMA_BUFFER_SIZE 256define RING_BUFFER_SIZE 512// DMA接收缓冲区 static volatile uint8_t dmaBuffer; static volatile uint16_t dmaReceived = 0;// 环形缓冲区 typedef struct { uint8_t buffer; 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和DMAUSART_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;// RXGPIO_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; // TXGPIO_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使用Channel4DMA_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 = dmaBuffer;rxRingBuffer.head = next_head;rxRingBuffer.count++;uart1_debug_flags.onebyte=dmaBuffer;uart1_debug_flags.twobyte=dmaBuffer;uart1_debug_flags.threebyte=dmaBuffer;uart1_debug_flags.fourbyte=dmaBuffer;uart1_debug_flags.fivebyte=dmaBuffer;processUbloxData(dmaBuffer);/* 直接处理每个字节 */processUbloxData(dmaBuffer);} 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 = dmaBuffer;//            rxRingBuffer.head = (rxRingBuffer.head + 1) % RING_BUFFER_SIZE;//            uart1_debug_flags.onebyte=dmaBuffer;//                  uart1_debug_flags.twobyte=dmaBuffer;//                  uart1_debug_flags.threebyte=dmaBuffer;//                  uart1_debug_flags.fourbyte=dmaBuffer;//                  uart1_debug_flags.fivebyte=dmaBuffer;//            /* 直接处理每个字节 *///            processUbloxData(dmaBuffer);//      }////         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: // 等待同步字符1if (data == UBLOX_SYNC1) {ubloxParser.state = 1;uart1_debug_flags.pvt_parse_flag = 1;}break;case 1: // 等待同步字符2if (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: // 读取消息IDubloxParser.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 = 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: // 校验Aif (data == ubloxParser.ck_a) {ubloxParser.state = 8;uart1_debug_flags.pvt_parse_flag = 8;} else {ubloxParser.state = 0; // 校验失败}break;case 8: // 校验Bif (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;}
页: [1]
查看完整版本: 串口空闲+DMA接收GPS信号,空闲中断触发时间不对。