本帖最后由 聪聪哥哥 于 2025-5-16 19:38 编辑
#申请原创# 前言:昨天使用DMA和空闲中断实现了串口接收不定长的数据功能,今天使用HAL库函数实现一下上述功能。
串口的空闲中断:顾名思义,就是当串口在一定的时间内没有接收到数据时,触发控制状态,从而产生空闲中断;一般来说,STM32在数据交互时,传输字节之间的间隔很短,然后再一个字节的通讯时间内,没有收到数据时,意味着程序进入了空闲中断,所以在程序的初始化后,我们只需要开启空闲中断后,然后在串口的回调函数中,进行数据迁移就可以,这里为了方便验证,将数据做回传处理。一:cube MX配置和昨天的配置相同,这里就不做介绍
二:HAL库函数几个重要的函数分享:
2.1 :
- HAL_UARTEx_ReceiveToIdle_DMA
函数原型如下:- HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
- {
- HAL_StatusTypeDef status;
- /* Check that a Rx process is not already ongoing */
- if (huart->RxState == HAL_UART_STATE_READY)
- {
- if ((pData == NULL) || (Size == 0U))
- {
- return HAL_ERROR;
- }
- /* In case of 9bits/No Parity transfer, pData buffer provided as input parameter
- should be aligned on a uint16_t frontier, as data copy from RDR will be
- handled by DMA from a uint16_t frontier. */
- if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
- {
- if ((((uint32_t)pData) & 1U) != 0U)
- {
- return HAL_ERROR;
- }
- }
- /* Set Reception type to reception till IDLE Event*/
- huart->ReceptionType = HAL_UART_RECEPTION_TOIDLE;
- huart->RxEventType = HAL_UART_RXEVENT_TC;
- status = UART_Start_Receive_DMA(huart, pData, Size);
- /* Check Rx process has been successfully started */
- if (status == HAL_OK)
- {
- if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
- {
- __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_IDLEF);
- ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
- }
- else
- {
- /* In case of errors already pending when reception is started,
- Interrupts may have already been raised and lead to reception abortion.
- (Overrun error for instance).
- In such case Reception Type has been reset to HAL_UART_RECEPTION_STANDARD. */
- status = HAL_ERROR;
- }
- }
- return status;
- }
- else
- {
- return HAL_BUSY;
- }
- }
调用UART_Start_Receive_DMA(),启用DMA将接收到的数据放在指针 pData 指向的位置。
这里我们重新编写一下回调函数的如下所示:
定义一下一些串口2的变量:
- uint8_t SendBuffer2[sendlength2] ;
- uint8_t RecBuffer2[reclength2] ;
- uint8_t usart2_rx_len; //串口2接收数据长度
- uint8_t Usart2_DEAL_RX_Buf[reclength2]; //串口2处理接收缓冲
- uint8_t usart2_Flag; //串口2接收完整数据包指令
串口的接收回调函数和接收错误的回调函数如下:
- void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
- {
- if(huart == &huart2)
- {
- // __HAL_DMA_DISABLE(&hdma_usart2_rx);
- // HAL_UARTEx_ReceiveToIdle_DMA(&huart2,RecBuffer2,256);
- // __HAL_DMA_ENABLE(&hdma_usart2_rx);
- HAL_UARTEx_ReceiveToIdle_DMA(&huart2, RecBuffer2, 256); // 接收完毕后重启
- HAL_UART_Transmit(&huart2, RecBuffer2, Size, 0xffff); // 将接收到的数据再发出
- __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT); // 手动关闭DMA_IT_HT中断
- memset(RecBuffer2, 0, 32); // 清除接收缓存
- // mcudRxLength = Size;
- // LocalSlaveProcess(mcudRxLength,GetLocalAddr());
- }
- }
- void HAL_UART_ErrorCallback(UART_HandleTypeDef * huart)
- {
- if(huart->Instance == USART2)
- {
- HAL_UARTEx_ReceiveToIdle_DMA(&huart2, RecBuffer2, 256); // 接收发生错误后重启
- __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT); // 手动关闭DMA_IT_HT中断
- memset(RecBuffer2, 0, 32); // 清除接收缓存
- }
- }
实物验证图片如下:
可以看到串口在接收到大概几个毫秒内就可以将数据返回,可见DMA接收和发送的效率!!!!实测在50ms的通讯速率情况,发送了共计100多W的字节长度,没有发生字节错乱的情况。
测试demo如下:
LED0.zip
(9.47 KB, 下载次数: 0)
|