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);
}