F407板子 DMA接收串口数据问题

2019-07-20 01:44发布

我的板子是探索者F407,前几天看到使用串口1配合DMA接收不定长数据,大大减轻CPU载荷这篇帖子,觉得不错,想拿来做实验,结果出问题了,代码反复看了,总是找不出问题,拜托各位大神帮帮忙,我菜鸟一只!!!使用串口1配合DMA接收不定长数据,大大减轻CPU载荷。此贴的描述说明。

最近经常看见坛友在论坛上问串口接收的问题,我之前刚好由于项目需要用到PLC的PPI协议,需要不停地利用串口接收数据,一开始的时候采用单字节中断的方式接收判断。但是用来做通信的时候需要不停的产生串口接收中断,会严重影响主程序的运行。后来采用DMA接收的方式,但是一般情况下配置的DMA都是接定长的串口数据,对于未知长度的串口数据接收并不适用。后来在网上发现了一种方法可以利用串口的空闲中断+DMA接收的方法完美解决此类问题,特别适用于不需要每个就收字节都判断的串口数据接收,下面说一下事实现思路和程序。

实现思路:采用STM32F103的串口1,并配置成空闲中断模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数据的时候,假设这帧数据长度是100个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理。


帖子上使用的是103芯片,我是用F407芯片的,不知道是不是两个芯片的DMA模块上使用有区别,我都是照帖子的程序照搬过来的。


MYDMA_Enable(DMA2_Stream5,SEND_BUF_SIZE);                   //恢复DMA指针,等待下一次接受

//开启一次DMA传输
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{

        DMA_Cmd(DMA_Streamx, DISABLE);                     
       
        while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}       
               
        DMA_SetCurrDataCounter(DMA_Streamx,ndtr);         

        DMA_Cmd(DMA_Streamx, ENABLE);                     
}

觉得可能是上面这几段代码有问题,感觉DMA指针没有恢复的样子







友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
9条回答
八度空间
2019-07-20 12:54
奔跑的蟑螂 发表于 2016-9-6 22:21
我发现单片机只能接收到一次数据 是因为少了DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5);//清除传输完成 ...

不要在中断服务函数中使用printf(个人建议),操作步骤大体相当
我的发送函数
void HAL_Submcu_uart_dma_Transmit(uint16_t Size)
{
        DMA1_Channel2->CNDTR = (uint16_t)Size;
        DMA_Cmd(DMA1_Channel2, ENABLE);  //开始传输
}

中断服务函数
void USART3_IRQHandler(void)
{
#if MB_SUB_USER_DMA_EN
        if (USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)  //产生了空闲中断
        {
                if ((usart_dma_dev.MB_SUB_USART_Flag & MB_SUB_USART_Flag_TC) != 0)
                {
                        DMA_Cmd(DMA1_Channel3, DISABLE);  //先关闭,预防干扰
                        usart_dma_dev.MB_SUB_USART_RX_Index = usart_dma_dev.MB_SUB_USART_RX_Length - DMA_GetCurrDataCounter(DMA1_Channel3);  //获取当前接收到的数据长度
                        DMA1_Channel3->CNDTR = (uint16_t)usart_dma_dev.MB_SUB_USART_RX_Length;  //重新配置接收长度
                        DMA_Cmd(DMA1_Channel3, ENABLE);
                        (void)USART_ReceiveData(USART3);
                        usart_dma_dev.MB_SUB_USART_Flag |= MB_SUB_USART_Flag_RXE;
//                        printf("usart dma rcv ok %d ", usart_dma_dev.MB_SUB_USART_RX_Index);
                }
        }
        /* ==================== STM32F30x Series chips ==================== */
        #if __STM32xx == 0x03  //STM32F30x
        USART_ClearITPendingBit(USART3, USART_IT_IDLE);
        #endif
#else
        uint8_t res=0;            
       
        if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收到数据
        {
                res = USART_ReceiveData(USART3);  //读取接收到的数据
                if (HAL_UART_RXCount < HAL_UART_RXD_Num)
                {
                        HAL_UART_RXBuf[HAL_UART_RXCount] = res;  //记录接收到的值
                        HAL_UART_RXCount++;                  //接收数据增加1
                }
        }
#endif
}

一周热门 更多>