STM32F103 串口+DMA+双缓冲接收不定长数据的问题

2019-08-13 21:21发布

在液晶屏上显示一副彩 {MOD}图片(320*240)约为150K字节,图片数据是从串口接收,然后存储到外部FLASH(W25Q64)中,查了一些资料,打算使用串口+DMA+双缓冲的方式接收处理数据,串口波特率为57600,串口使用空闲中断的方式来判断DMA接收完成。  DMA定义了两个数据,大小为4096。串口一直在接收数据,应该是接收到4096字节的时候,进入DMA中断,然后DMA中断切换为另一个缓冲接收数据,当接收到最后的2048个字节后进入串口空闲中断,表示图片数据已经接收完全了。

但是现在遇到一个问题,还没接收到4096字节的时候,串口就进入到了空闲中断,请问这是什么问题啊?我的程序如下:
void uart_init(u32 bound)
{
        //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        //配置时钟
        //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE) ;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE) ;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE) ;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE) ;
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);        // JTAG Disable,SWD Enable

    USART_DeInit(USART2);  //复位串口2

        //USART1_TX        GPIOA.2
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;        //PA.2
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                //复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
        //USART1_RX        GPIOA.3
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;        //PA.3
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3  

        //485_Enable        GPIOA.15
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;        //PA.15
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //推挽输出

        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
        RS485_Pin=0;        //开机默认接收

        ////////////////////////////////////////////////////////////////////////////////

        //Usart2 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级1
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                //子优先级0
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器

        //USART 初始化设置
        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(USART2, &USART_InitStructure); //初始化串口2

        //中断配置
        USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);        //开启接收空闲中断
        USART_Cmd(USART2, ENABLE);                                                //使能串口2
}



/***********************  配置RX_DMA  ************************/
void USART2_DMA_RX(void)
{
        //串口接收DMA配置
        //DMA_InitTypeDef DMA_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//启动DMA时钟

        USART_DMACmd(USART2,USART_DMAReq_Rx,DISABLE);

        DMA_DeInit(DMA1_Channel6);        // 串口2 接收 DMA传输通道是通道6
        DMA_InitStructure.DMA_PeripheralBaseAddr = ((u32)(&(USART2->DR)));        //DMA外设基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART2_DMA_RX_Buf1;//DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;        //数据传输方向:从外设读取发送到内存
        DMA_InitStructure.DMA_BufferSize = USART2_RX_Buf_Len;        //DMA通道的DMA缓存的大小
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度为8位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//数据宽度为8位
        //DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//工作在正常缓存模式
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作在循环模式
        //DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//DMA通道x拥有最高优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA1_Channel6 , &DMA_InitStructure); //初始化DMA的通道
        DMA_ClearFlag(DMA1_FLAG_TC6); //清除DMA接收完成标志
        DMA_Cmd(DMA1_Channel6 , ENABLE) ;


        DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);//使能DMA传输完成中断

        USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);        //使能串口2 DMA接收

        //Free_Buf_No=BUF_NO2; //因为 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART2_DMA_RX_Buf1;
        Free_Buf_No=BUF_NO1;
    Buf_Ok=0; //此时没有数据准备完成 当然FALSE

        //配置NVIC        配置串口DMA的中断优先级
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn ;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0 ;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE ;
        NVIC_Init(&NVIC_InitStructure);
}



/*************** 串口2中断服务程序 *********************/
void USART2_IRQHandler(void)
{
        u32 temp = 0;

        if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)  //判断是否真的空闲帧来了
        {
                //USART_ClearFlag(USART2,USART_IT_IDLE);
                temp = USART2->SR;        //先读SR,然后读DR才能清除
                temp = USART2->DR;        //清USART_IT_IDLE标志
                DMA_Cmd(DMA1_Channel6,DISABLE);   //关闭DMA接收,防止其间还有数据过来

                temp = USART2_RX_Buf_Len - DMA_GetCurrDataCounter(DMA1_Channel6); //计算接收的字节数

                //Usart2_RX_Cou = temp;        //保存接收到的字节数,main中处理后要清零
                Buf_Ok = 1;        //串口2一个数据包接收完成,标志置一,main中处理后要清零

                DMA_SetCurrDataCounter(DMA1_Channel6,USART2_RX_Buf_Len);//设置传输数据长度,重装填,并让接收地址偏址从0开始
                DMA_Cmd(DMA1_Channel6,ENABLE);  //打开DMA接收
        }
}



//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
        DMA_Cmd(DMA_CHx, ENABLE);      
}
//关闭一次DMA传输
void MYDMA_Disable(DMA_Channel_TypeDef*DMA_CHx)
{
        DMA_Cmd(DMA_CHx, DISABLE);
}


void DMA1_Channel6_IRQHandler(void)
{
        if(DMA_GetITStatus(DMA1_IT_TC6)) //通道6传输完成中断TC 还有传输 过半中断HT 错误中断TE 全局中断GL
        {
                MYDMA_Disable(DMA1_Channel6);

                //DataCounter = DMA_GetCurrDataCounter(DMA1_Channel6);//获取剩余长度,一般都为0,调试用
                DMA_ClearITPendingBit(DMA1_IT_GL6);    //清除全部中断标志
                //DMA_InitStructure.DMA_BufferSize = (u16)200;
                DMA_InitStructure.DMA_BufferSize = (u16)USART2_RX_Buf_Len;
                       
                //转换可操作BUF
                if(Free_Buf_No==BUF_NO1) //如果BUF1空闲,将DMA接收数据赋值给BUF1   
                {   
                        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART2_DMA_RX_Buf1;
                        DMA_Init(DMA1_Channel6, &DMA_InitStructure);
                        Free_Buf_No=BUF_NO2;
                }
                else  //如果BUF2空闲,将DMA接收数据赋值给BUF2   
                {
                        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART2_DMA_RX_Buf2;
                        DMA_Init(DMA1_Channel6, &DMA_InitStructure);
                        Free_Buf_No=BUF_NO1;
                }

                Buf_Ok=1; //有准备好的数据了

               
                MYDMA_Enable(DMA1_Channel6);   
        }
}



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
6条回答
阳光2260
1楼-- · 2019-08-14 01:27
有些不太明白了,应该是最后一次不足4096字节的数据进入空闲中断的,但是为什么中间会进入串口空闲中断啊?
请各位大侠帮忙看看问题出在哪里。
阳光2260
2楼-- · 2019-08-14 05:27
 精彩回答 2  元偷偷看……
正点原子
3楼-- · 2019-08-14 10:41
说明你发送的内容不是连续发送的。检查发送端代码。
阳光2260
4楼-- · 2019-08-14 16:15
正点原子 发表于 2017-9-28 20:46
说明你发送的内容不是连续发送的。检查发送端代码。

是在电脑上使用串口调试助手发送的,没有代码。
正点原子
5楼-- · 2019-08-14 20:22
阳光2260 发表于 2017-9-29 09:10
是在电脑上使用串口调试助手发送的,没有代码。

换串口调试助手,试试
阳光2260
6楼-- · 2019-08-14 23:41
正点原子 发表于 2017-10-9 01:04
换串口调试助手,试试

应该是电脑上的串口调试助手发送数据的时间不稳定,所以造成这样的情况。

一周热门 更多>