整个接收的过程:
(1)启动UART的DMA接收(这里面还定义了DMA回调函数):HAL_UART_Receive_DMA
(2)接收完成后,请求DMA中断(判断中断的类型):HAL_DMA_IRQHandler
(3)DMA接收完成回调函数(同时关闭了DMA接收):UART_DMAReceiveCplt
(4)UART接收回调函数(处理数据,启动DMA接收):HAL_UART_RxCpltCallback
流程图如下:
(1)UART的DMA接收
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
这个函数的参数有三个:UART的结构体 、接收数据的数组指针、接收数据的多少
主要实现的功能是:
将自定义的数组和size赋值给huart结构体,这样数据就会存储到我们定义的数组中
然后自定义DMA接收完成的回调函数(通过函数指针的方式)
同时使能UART DMA数据流,可以接收UART发送过来的数据。
(2)DMA中断请求函数,每一种外设都有很多类型的中断,但是只有一个中断请求的入口
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
这个函数里面处理了DMA所有的中断请求,肯定要查询一遍寄存器,进来的是哪个中断,然后对症下药,我们用到的是DMA接收UART数据完成的中断。
(3)DMA接收完成回调函数,主要实现两个任务:关闭DMA的接收,调用UART接收回调函数
static void UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode*/
if ((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
{
huart->RxXferCount = 0U;
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Disable the DMA transfer for the receiver request by setting the DMAR bit
in the UART CR3 register */
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
}
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx complete callback*/
huart->RxCpltCallback(huart);
#else
/*Call legacy weak Rx complete callback*/
HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
在这个函数中有一段条件编译,(USE_HAL_UART_REGISTER_CALLBACKS == 1)
这是说允许用户动态编写回调函数,在UART部分没有自定义回调函数,所以执行else,系统默认会有一个回调弱函数,不过我们会重新写这个函数,所以会转到执行我们写的HAL_UART_RxCpltCallback。
(4)UART接收回调函数(由我们重写),完成数据处理和开启下次DMA接收的任务
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
RemoteDateProcess(rData);//数据处理
HAL_UART_Receive_DMA(&huart1, rData, 18);//开启下次串口DMA的接收
}