思路:首先cubemax生成工程后,在用户代码中,使用空闲中断+手动调用HAL_UART_RxCpltCallback的方式来实现调用,然后处理完数据后清除空闲中断。
代码:
实现手动调用完成函数,因为DMA只会在接收完整后才能自动调用,比如期望400个字节,只收到100个是不会调用完成的,一个数据包长度不够就不会调用。
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
HAL_UART_RxCpltCallback(&huart1);
/* USER CODE END USART1_IRQn 1 */
}
开启空闲中断和DMA接收,开启空闲中断后,可以用来实现数据包接收完成就产生中断,而不是DMA全部接收完成才产生中断,也不是每个字节都产生中断
__HAL_UART_ENABLE_IT(&LOAD_UART, UART_IT_IDLE);
while(__HAL_UART_GET_FLAG(&LOAD_UART,UART_FLAG_IDLE)==RESET)
{}
HAL_UART_Receive_DMA(&LOAD_UART, aucLoad_DMABuf, LOAD_DMA_SIZE);
在这个函数里清除空闲中断标志,否则会导致中断无法退出而死机,然后通过RxXferSize -CNDTR计算出实际收到的字节数量。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint32_t temp;
if (&LOAD_UART == huart)
{
HAL_UART_DMAStop(&LOAD_UART);
__HAL_UART_CLEAR_IDLEFLAG(&LOAD_UART); //清除标志位
temp = LOAD_UART.Instance->ISR; //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
temp = LOAD_UART.Instance->RDR; //读取数据寄存器中的数据
temp = LOAD_UART.hdmarx->Instance->CNDTR; //获取DMA中未传输的数据个数,NDTR寄存器分析见下面
usLoad_Length = LOAD_UART.RxXferSize - temp;
bLoad_Prase = TRUE;
}
}