【STM32C092RC 测评】+05 优化DMA+空闲中断的数据回传功能
本帖最后由 聪聪哥哥 于 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)
{
returnHAL_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 ;
uint8_t RecBuffer2 ;
uint8_t usart2_rx_len; //串口2接收数据长度
uint8_t Usart2_DEAL_RX_Buf; //串口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如下:
页:
[1]