USATR1串口的DMA接收错误问题

2019-07-20 12:30发布

本帖最后由 michael91 于 2017-8-19 19:26 编辑

@正点原子  原子哥,各位大神帮忙看一下 USATR1串口用DMA接收, 数据错误,网上的方法都试过了,也请教了别人,但是还是无法解决
左边是循环发送8字节数据帧,右边是接收的数据帧,前两个字节FF, FE和后两个字节FF,FE是我自己加的帧头和帧尾,右边第1行是复位后的第一次正确接收,从第2行开始出现错误,第3行往后错误相同,都是第8个字节跑到了第1个字节的位置。DMA配置的正常模式,不是循环模式。循环模式好像会出现这样的问题
小Q截图-20170819190627.png

#include "delay.h"
#include "RS232_DMA_RX.h"
#include "RS232_DMA_TX.h"
u8 USART1_Rec_Cnt=0;
u8 DMA2_Rece_Buf[12];
//
void USART1_Init(u32 bound)
{
    //
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);  //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //使能USART1时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
  //串口1引脚复用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);   //GPIOA9复用为USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1

//USART1   
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9 10

//USART1 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1


//USART1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;  //响应优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能
NVIC_Init(&NVIC_InitStructure);         //根据指定的参数初始化NVIC寄存器


USART_ITConfig(USART1,USART_IT_IDLE, ENABLE); //开启空闲中断
    //相应的DMA配置
while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE){};  //等待DMA可配置
DMA_DeInit(DMA2_Stream5);   //将DMA2的通道5寄存器重设为缺省值,对应的串口1接收

DMA_InitStructure.DMA_BufferSize= DMA2_Rec_Len;  //长度8字节
    DMA_InitStructure.DMA_Channel=DMA_Channel_4;     //对应串口1接收
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;   //外设到存储器
DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;    //非FIFO模式
DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_1QuarterFull;
DMA_InitStructure.DMA_Memory0BaseAddr=(u32)&DMA2_Rece_Buf[2];  //数据存储地址
DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;     //单次模式
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;  //宽度8位
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;     //存储器地址递增
DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;             //正常模式
DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&USART1->DR;   //外设地址,串口1
DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;   //单次模式
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte; //宽度8位
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;     //外设地址不增
DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;       //优先级中
DMA_Init(DMA2_Stream5,&DMA_InitStructure);   
// DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);    //没用DMA传输完成中断,用了USART_IT_IDLE总线空闲中断  
// DMA_ClearITPendingBit(DMA2_Stream5, DMA_IT_TCIF5);
    DMA_Cmd(DMA2_Stream5, ENABLE);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);    //使能串口1 DMA接收

USART_Cmd(USART1, ENABLE);  //使能串口1
}
void USART1_IRQHandler(void)         //串口中断      
{
if(USART_GetITStatus(USART1,USART_IT_IDLE)!= RESET)   //总线空闲中断
{
  USART_Cmd(USART1, DISABLE);    //关闭串口接收
  USART1->SR;
  USART1->DR;  //先读这两个才能清除标志位
  USART_ClearITPendingBit(USART1,USART_IT_IDLE); //清除标志位
  DMA_Cmd(DMA2_Stream5, DISABLE);  //关闭DMA传输
  DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5); //清除标志位
  
  USART1_Rec_Cnt=DMA2_Rec_Len-DMA_GetCurrDataCounter(DMA2_Stream5);  //DMA2_Rec_Len=8,接受完8字节
  if(USART1_Rec_Cnt==8)
  {
   USART1_Rec_Cnt=0;
   DMA2_Rece_Buf[0]=0xFF;  DMA2_Rece_Buf[1]=0xFE;   //收到的数据加上两个字节的帧头
   DMA2_Rece_Buf[10]=0xFF; DMA2_Rece_Buf[11]=0xFE;  //收到的数据加上两个字节的帧尾
   USART3_SendData(DMA2_Rece_Buf,12);       //将数据发送到串口3
  }
  
  while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE); //确保DMA可以被设置   
  DMA_SetCurrDataCounter(DMA2_Stream5,DMA2_Rec_Len);  //数据传输量 DMA2_Rec_Len =8
  DMA_Cmd(DMA2_Stream5,ENABLE);   //开启DMA传输
  USART_Cmd(USART1, ENABLE);         //开启串口1接收
}
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
2条回答
michael91
1楼-- · 2019-07-20 16:25
 精彩回答 2  元偷偷看……
michael91
2楼-- · 2019-07-20 20:27
改成单个数据帧循环发送,结果是这样
小Q截图-20170819201804.png

一周热门 更多>