整个接收的过程:
    (1)启动UART的DMA接收(这里面还定义了DMA回调函数):HAL_UART_Receive_DMA
    (2)接收完成后,请求DMA中断(判断中断的类型):HAL_DMA_IRQHandler
    (3)DMA接收完成回调函数(同时关闭了DMA接收):UART_DMAReceiveCplt
    (4)UART接收回调函数(处理数据,启动DMA接收):HAL_UART_RxCpltCallback

    流程图如下:
    HAL库学习(三)---DMA - 图1
    (1)UART的DMA接收

    1. HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

    这个函数的参数有三个:UART的结构体 、接收数据的数组指针、接收数据的多少
    主要实现的功能是:
    将自定义的数组和size赋值给huart结构体,这样数据就会存储到我们定义的数组中
    然后自定义DMA接收完成的回调函数(通过函数指针的方式)
    同时使能UART DMA数据流,可以接收UART发送过来的数据。

    (2)DMA中断请求函数,每一种外设都有很多类型的中断,但是只有一个中断请求的入口

    1. HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

    这个函数里面处理了DMA所有的中断请求,肯定要查询一遍寄存器,进来的是哪个中断,然后对症下药,我们用到的是DMA接收UART数据完成的中断。

    (3)DMA接收完成回调函数,主要实现两个任务:关闭DMA的接收,调用UART接收回调函数

    1. static void UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
    2. {
    3. UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
    4. /* DMA Normal mode*/
    5. if ((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
    6. {
    7. huart->RxXferCount = 0U;
    8. /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
    9. CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
    10. CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    11. /* Disable the DMA transfer for the receiver request by setting the DMAR bit
    12. in the UART CR3 register */
    13. CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    14. /* At end of Rx process, restore huart->RxState to Ready */
    15. huart->RxState = HAL_UART_STATE_READY;
    16. }
    17. #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
    18. /*Call registered Rx complete callback*/
    19. huart->RxCpltCallback(huart);
    20. #else
    21. /*Call legacy weak Rx complete callback*/
    22. HAL_UART_RxCpltCallback(huart);
    23. #endif /* USE_HAL_UART_REGISTER_CALLBACKS */

    在这个函数中有一段条件编译,(USE_HAL_UART_REGISTER_CALLBACKS == 1)
    这是说允许用户动态编写回调函数,在UART部分没有自定义回调函数,所以执行else,系统默认会有一个回调弱函数,不过我们会重新写这个函数,所以会转到执行我们写的HAL_UART_RxCpltCallback。

    (4)UART接收回调函数(由我们重写),完成数据处理开启下次DMA接收的任务

    1. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    2. {
    3. RemoteDateProcess(rData);//数据处理
    4. HAL_UART_Receive_DMA(&huart1, rData, 18);//开启下次串口DMA的接收
    5. }