本帖最后由 michael91 于 2017-8-19 19:26 编辑
@正点原子 原子哥,各位大神帮忙看一下 USATR1串口用DMA接收, 数据错误,网上的方法都试过了,也请教了别人,但是还是无法解决
左边是循环发送8字节数据帧,右边是接收的数据帧,前两个字节FF, FE和后两个字节FF,FE是我自己加的帧头和帧尾,右边第1行是复位后的第一次正确接收,从第2行开始出现错误,第3行往后错误相同,都是第8个字节跑到了第1个字节的位置。
DMA配置的正常模式,不是循环模式。循环模式好像会出现这样的问题
#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接收
}
}
一周热门 更多>