3回答

0收藏

Cube下实现串口+DMA+空闲中断接收不定长数据

其他 其他 1406 人阅读 | 3 人回复 | 2020-07-01

一直困惑怎么在Cube上实现串口+DMA+空闲中断接收不定长数据。
使用下来发现Cube好的地方就是你按照图形画方式配置后会帮你省掉很多初始化的工作。但是从标准库走过来略有点别扭,可能用用就习惯了。
想把这几天搞的跟大家聊聊,有不对的地方请指正啊。同时感谢网友baifernlover对本菜的指导。
USART1+DMA配置如下图:

生成工程后,在主函数里添加:
  • __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);    //使能空闲中断
  •   while (1)
  •   {
  •         if(recv_end_flag ==1)                                           //recv_end_flag 结束标志
  •         {
  •                 printf("rx_len=%d\r\n",rx_len);                    //rx_len 此次接收到了多少数据
  •                 for(i=0;i<rx_len;i++)
  •                 {
  •                                 printf("%x\r\n",rx_buffer);
  •                 }
  •                 rx_len=0;
  •                 recv_end_flag=0;
  •         }
  •         HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
  •   }

[color=rgb(51, 102, 153) !important]复制代码


中断函数里面:
  • void USART1_IRQHandler(void)
  • {
  •         uint32_t tmp_flag = 0;
  •         uint32_t temp;
  •         tmp_flag =  __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
  •         if((tmp_flag != RESET))
  •        {
  •                 __HAL_UART_CLEAR_IDLEFLAG(&huart1);
  •                 temp = huart1.Instance->SR;
  •                 temp = huart1.Instance->DR;
  •                 HAL_UART_DMAStop(&huart1);
  •                 temp  = hdma_usart1_rx.Instance->NDTR;
  •                 rx_len =  BUFFER_SIZE - temp;
  •                  recv_end_flag = 1;
  •          }
  • }

[color=rgb(51, 102, 153) !important]复制代码


之前看到帖子说HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)和HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)接收需要指定接收Size长度值,但是这两个函数的Size有所区别。
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)主要做了两件事:
1.   huart->pRxBuffPtr = pData;       /*!< Pointer to UART Rx transfer Buffer */
      huart->RxXferSize = Size;           /*!< UART Rx Transfer size              */        这个赋值好像没什么用
     huart->RxXferCount = Size;        /*!< UART Rx Transfer Counter           */
2.使能中断
/* Enable the UART Data Register not empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
在中断处理函数中,去判断中断标志位;然后再根据相应的中断标志位去处理:
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
  /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_Receive_IT(huart);
  }

UART_Receive_IT函数里感觉做了两件事:
1.*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);  //存数据
2.if(--huart->RxXferCount == 0)                                          //之前赋值的 huart->RxXferCount = Size;
   {
         __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);     //最后一个数据接收完了就关闭中断
    }
   HAL_UART_RxCpltCallback(huart);                                     //调用接收完成回调函数
整个过程中,来一个数据,huart->RxXferCount做一次减法,直到等于0,去调用回调函数。


HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)中:
1. HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);--->
2.DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);这里的DataLength就是之前的Size吧---->
3. /* Configure DMA Stream data length */
   hdma->Instance->NDTR = DataLength;   
对NDTR寄存器描述:This register can be written only
when the stream is disabled. When the stream is enabled, this register is read-only,
indicating the remaining data items to be transmitted. This register decrements after each
DMA transfer.

这里的定义的Size赋给了DMA_SxNDTR。使能之后,只能读取,表示还有多少字节需要被“传送”。所以空闲中断里面
temp  = hdma_usart1_rx.Instance->NDTR;  //读取还没有被传送的个数            
rx_len =  BUFFER_SIZE - temp;                    //DMA缓存大小减去没有被传送的个数,就等于已经被传送的个数,也就是接收到的个数。

先这样子理解了。所以感觉如果是DMA接收,即使外部过来的数据个数不等于设定的Size,那么数据也还是被接收到了指定的buffer中。
DMA中断处理函数HAL_DMA_IRQHandler里面会判断DMA传输的状态,完了去调用各自的回调函数。比如传输完成的话会去调用UART_DMAReceiveCplt()--->HAL_UART_RxCpltCallback(huart);最后还是调用了HAL_UART_RxCpltCallback(huart)函数。

最后附上工程文件,欢迎大家多多讨论。



游客,如果您要查看本帖隐藏内容请回复




分享到:
回复

使用道具 举报

回答|共 3 个

倒序浏览

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条