STM32-高速串口,基于DMA的空闲中断

STM32发送,接收说明

串口接收数据的方式,有两种,
1,poll
2,int

中断又分为一次接收一个数据,和DMA一次接收多个数据。
考虑到数据的高速情况,我们这里当然是选择DMA了,

但是DMA有一个不好的点就是中断触发机制,要么是half,要么是接收完毕,
那么就有一个很难受的问题,一帧数据,基本上会被切断,所以对于那些对帧的完整性有较高要求的场景,DMA的这种中断就很难使用。

常用的解决办法就是实现一个判空机制,判断上一次中断和当前时间是否timeout,如果timeout,就认为一帧结束,把DMA的数据获取并拼包之后使用。

但是这个办法没办法准确判定timeout的时间,因为poll的时间差,或者是帧与帧时间的时间差,导致很难判定成功。

这个时候,STM32的一个牛掰的机制就来了,中断有一个IDLE中断源,就是串口进入空闲时,触发一个中断。那DMA+IDLE结合, 就可以很完美的实现快速接受和帧数据分离。

下面是代码

void UsartReceive_IDLE(UART_HandleTypeDef *huart)
{
stuUartRevFifo *revinfo;
for(int32_t i = 0 ; i < ZQ_UARTINFO_COUNT ; i ++)
{
if(huart == sg_uartRevFifoBuff[i].uart && sg_uartRevFifoBuff[i].revCmd == UART_REV_DMA)
{
// is you
revinfo = &(sg_uartRevFifoBuff[i]);
}
}
uint32_t temp = 0;
if((__HAL_UART_GET_FLAG(revinfo->uart,UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(revinfo->uart);
HAL_UART_DMAStop(revinfo->uart);
temp = revinfo->uart->hdmarx->Instance->NDTR;
//rev data count
if(revinfo->revFunc != NULL)
{
revinfo->revFunc(revinfo->revBuff,ZQ_UARTINFO_SIZE - temp);
}
//memset(revinfo->revBuff,0,ZQ_UARTINFO_SIZE);
HAL_UART_Receive_DMA(revinfo->uart,revinfo->revBuff,ZQ_UARTINFO_SIZE);
}
}

这是中断代码,这个代码放在it.c文件的串口中断中执行。

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	UsartReceive_IDLE(&huart1);
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
}

你可能感兴趣的:(STM32)