usart1实现DMA的发送和接收功能,出现的接收问题

2020-01-01 17:36发布

小弟刚上手stm32不久,我现在搞了一个用usart1实现了DMA的发送和接收功能。已经成功了,但是我设置的是一次接收32

个字符,如果接收的超过或者少于32个字符,就会出现问题,就无法接收了(我们实现的是用ZigBee无线传输,一次定义32

个字符为一个数据包,但是就怕zigbee的接收的问题,使得DMA无法收到定义好的32个字符,这样就会无法完成后续的任务



我的思路是这样的:
1.先配置USART1的时钟以及相应的GPIO,初始化USART1,使能USART1;
2.0使能DMA时钟
2.1配置DMA发送:
----配置DMA发送中断(DMA1_Channel4)
----DMA发送设置,DMA_BufferSize设为32,都是8bit(DMA_PeripheralDataSize_Byte,DMA_MemoryDataSize_Byte),DMA_Mode为循环模式,然后:
        DMA_Cmd (DMA1_Channel4,ENABLE);       
        DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
2.2配置DMA接收:
----配置DMA接收中断(DMA1_Channel5)
----DMA接收设置,DMA_BufferSize设为32,都是8bit(DMA_PeripheralDataSize_Byte,DMA_MemoryDataSize_Byte),DMA_Mode为循环模式,然后:
        DMA_Cmd (DMA1_Channel5,ENABLE);       
        DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);
2.3串口向 DMA发出请求(先让DMA接收,接收到了在发送)
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
3.1在DMA接收中断函数中(void DMA1_Channel5_IRQHandler(void))
----如果接收完成 //if(DMA_GetFlagStatus(DMA1_FLAG_TC5)==SET)
----就先给一个全局变量flag=1(为了在main函数中的循环里识别)
----再关闭串口的DMA接收请求  //USART_DMACmd(USART1, USART_DMAReq_Rx, DISABLE);
----清除标志        //DMA_ClearFlag(DMA1_FLAG_TC5);
3.2在main函数的while循环中 如果发现flag==1,说明接收完成,可以传想要传输的数据了;
----于是,打开串口的DMA发送请求  //USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);       
----同时flag=0
3.3在DMA发送中断函数中(void DMA1_Channel4_IRQHandler(void))
----如果发送完成  //if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET)
----就关闭串口的DMA发送请求,再打开串口的DMA接收请求:
        USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);
        USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
----清除标志        //DMA_ClearFlag(DMA1_FLAG_TC4);
//////////////////////////////////////////////////////////////////////////////////////////////
这就是整个函数,函数实现的很好,接了32个字符(PC给stm32 发送32个字符),马上就发回32个字符,看似已经ok,但是遇到两种蛋疼的情况:

1.pc给stm32 发送的字符少于32个;
2.发送的多于32个;
这样都会导致,stm32无法在继续接收和发送字符了,即使我在向stm32发送正确的32个字符,必须复位才行,这样的话,我们的stm32就无法接收后续的数据了,这怎么办,我想了让它在先关闭串口的DMA请求,在打开,可惜还是不行,请求高人解答。
希望高人谈一下引起这种情况的原因,以及详细的解答方案,最好能有关键性的代码和解释。
谢谢。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
26条回答
20061002838
1楼-- · 2020-01-03 04:35
humanking7 发表于 2013-3-12 23:11
您说的是检测usart是否空闲,然后做出判断?您有没有合适的代码,一些东西还是不太清楚,有源码更好一点 ...

这需要什么源码
STM32硬件支持总线空闲中断了

直接使能这个中断(已经设置好接收DMA,且DMA接收长度大于等于实际数据长度);
STM32检测到总线空闲就会进入中断,中断里面读取数据、重新初始化DMA(你要是用大的环形缓冲的话连重新初始化DMA都不用)就行了

好好看看STM32的参考手册吧
humanking7
2楼-- · 2020-01-03 09:19
20061002838 发表于 2013-3-12 23:26
这需要什么源码
STM32硬件支持总线空闲中断了

谢谢您,其他都好办,就是初始化dma每次都不行,我估计我是对dma的操作认识的不够彻底,就是卡在这里了,希望您能给一个dma初始化的思路(真心不怕被您笑话)
20061002838
3楼-- · 2020-01-03 10:56
humanking7 发表于 2013-3-13 12:12
谢谢您,其他都好办,就是初始化dma每次都不行,我估计我是对dma的操作认识的不够彻底,就是卡在这里了, ...
  1. #define  UART_RXD_BUF_SIZE 100

  2. static uint8_t UART_ReceiveBuffer[UART_RXD_BUF_SIZE];
  3. static uint8_t UART_RXD_Str[80];

  4. volatile uint32_t Flag_UART_RXD = 0;

  5. static void USART_RXD_DMA_Configuration(void)
  6. {

  7.     DMA_InitTypeDef DMA_InitStructure;

  8.     RCC_AHBPeriphClockCmd(UART_DMA_CLK, ENABLE);

  9.     /* DMA1 channel1 configuration ----------------------------------------------*/
  10.     DMA_DeInit(UART_DMA_RXD);

  11.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (UART_NUM->DR);
  12.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)UART_ReceiveBuffer;
  13.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  14.     DMA_InitStructure.DMA_BufferSize = UART_RXD_BUF_SIZE;
  15.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  16.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  17.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  18.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  19.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  20.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  21.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  22.     DMA_Init(UART_DMA_RXD, &DMA_InitStructure);

  23.     DMA_ITConfig(UART_DMA_RXD, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE, DISABLE);

  24.     DMA_Cmd(UART_DMA_RXD, ENABLE);
  25. }
复制代码初始化DMA的
  1. char TXD_Buffer[200];

  2. void UART_IRQ_Handler(void)
  3. {
  4.     unsigned long len;
  5.     char *str;

  6.     if(UART_NUM->SR & USART_FLAG_IDLE)   //总线空闲中断
  7.     {
  8.         USART_ClearFlag(UART_NUM, USART_FLAG_RXNE);        //清除空闲中断标志位
  9.         len = USART_ReceiveData(UART_NUM);

  10.         len = UART_RXD_BUF_SIZE - DMA_GetCurrDataCounter(UART_DMA_RXD);   //获得接收字符串长度

  11.         memcpy_a(UART_RXD_Str, UART_ReceiveBuffer, len);
  12.         UART_RXD_Str[len] = 0;

  13.         USART_RXD_DMA_Configuration();

  14.         str = User_Cmd(UART_RXD_Str, &len);

  15.         USART_SendStr_DMA(str, len);
  16.     }
  17. }
复制代码中断
humanking7
4楼-- · 2020-01-03 12:08
20061002838 发表于 2013-3-13 12:52
初始化DMA的中断

最近比较忙,还没试,我的原程序用中断实现了,谁让不是所想,但是安全可靠,您的这个代码对我以后研究大有裨益,再谢
wsfry
5楼-- · 2020-01-03 12:27
 精彩回答 2  元偷偷看……
wsfry
6楼-- · 2020-01-03 16:52
humanking7 发表于 2013-3-16 03:13
最近比较忙,还没试,我的原程序用中断实现了,谁让不是所想,但是安全可靠,您的这个代码对我以后研究大 ...

上面的大侠提供的方法你有没有试一下呀,效果如何?

一周热门 更多>