Fork me on GitHub

随笔 - 997  文章 - 5  评论 - 181  阅读 - 300万 

一 引言
最近在调试stm32的多串口。没想到居然遇到那么多的问题。这里做一个总结,还是非常有必要的。
二 问题
这里先弄清楚几个问题。
1 串口有必要使用DMA吗?
DMA可以在串口高速的时候不占用CMU的资源,这在多任务系统中非常重要。无论是串口还是i2C,SPI,都是非常有必要使用DMA的,这里基础的概念东西搞清楚即可。
2 DMA的主要函数有哪些?
DMA的初始化要记得,这个千万不要漏了。不过一般是标注的,不想要你改动什么的。
复制代码
/**
  * Enable DMA controller clock
  */
void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
  /* DMA1_Channel6_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 8, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
  /* DMA2_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Channel4_IRQn, 6, 0);
  HAL_NVIC_EnableIRQ(DMA2_Channel4_IRQn);
  /* DMA2_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Channel5_IRQn, 6, 0);
  HAL_NVIC_EnableIRQ(DMA2_Channel5_IRQn);

}
复制代码

 

hdma_usart3_rx这里需要在这个中断注册:这个很关键
 
 
复制代码
/**
  * @brief This function handles DMA1 channel6 global interrupt.
  */
void DMA1_Channel6_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */

  /* USER CODE END DMA1_Channel6_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_usart3_rx);
  /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */

  /* USER CODE END DMA1_Channel6_IRQn 1 */
}
复制代码

 

DMA的核心函数有两个,已经被封装的很好了。一个是DMA发送的,一个是DMA接收数据的。
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
3 DMA和串口的链接是怎么样子呢?

 

3 DMA和串口的链接是怎么样子呢?
其实,串口和DMA建立链接很容易的,只需要把DMA发送的第一个入参数填入对应的串口句柄即可。实例如下所示:
 
4 串口使用DMA的基本流程是什么?
首先初始化的时候
复制代码
    if (HAL_DMA_Init(&hdma_usart3_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart3_rx);

    /* USART3 interrupt Init */
    HAL_NVIC_SetPriority(USART3_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART3_IRQn);
  /* USER CODE BEGIN USART3_MspInit 1 */
     __HAL_UART_CLEAR_IDLEFLAG(&huart3);
     HAL_UART_Receive_DMA(&huart3, GPS_RX_BUFF, GPS_RX_BUFF_SIZE);
     __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);
复制代码

 

 
其次在串口中断的中的读取这块要注意:
复制代码
/**
  * @brief This function handles USART3 global interrupt.
  */
void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
    uint16_t  temp;
    if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart3);
        //HAL_UART_DMAStop(&huart3);
        //temp=huart3.hdmarx->Instance->CNDTR;
        // if(temp<LCD_RX_Buffer_Size-1)
        //     LCD_Rx_Flag=String_Flag;
        // else
        //     LCD_Rx_Flag=Byte_Flag;
    gps_recive_flag++;
        __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);

        HAL_UART_Receive_DMA(&huart3, GPS_RX_BUFF, GPS_RX_BUFF_SIZE);

        //osSemaphoreRelease(myBinarySem_LCDHandle);
    }
  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */

  /* USER CODE END USART3_IRQn 1 */
}
复制代码

 

 
三 总结
其实,虽然函数简单,其实,这里涉及的知识点还是非常多的。对这些底层的代码阅读和反复使用,才能了然于心。
 
 
posted on   虚生  阅读(201)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
历史上的今天:
2017-12-05 python修改文件中字符串并写入
2017-12-05 蓝牙5芯片出来了!收好这份厂商名单
点击右上角即可分享
微信分享提示