DMA 局限性
DMA 傳輸完成會產(chǎn)生中斷告知 CPU,這對于固定長度的數(shù)據(jù)是沒什么問題的。但是對于不定長的數(shù)據(jù)就不行了,DMA 一定要接收到足夠多(設(shè)定的長度)的數(shù)據(jù)時才產(chǎn)生完成中斷,如果接收到的數(shù)據(jù)量小于設(shè)定的長度,這個時候 CPU 就無法通過中斷方式取處理這點(diǎn)數(shù)據(jù)了。那 CPU 怎樣優(yōu)化這個缺陷呢?那就是使用輪詢的方式,主動獲取 DMA 當(dāng)前收到了多少字節(jié)數(shù)據(jù),然后決定要不要處理這些數(shù)據(jù)。但是,一旦使用輪詢方式就背離了 DMA 原有的設(shè)計意圖(為 CPU 減負(fù))。
那還有什么辦法可以優(yōu)雅地解決這個問題嗎?那就是使用串口空閑中斷。
串口空閑中斷
這里是轉(zhuǎn)變了一個思路,單純從 DMA 角度解決問題貌似找不到很好的答案,那就轉(zhuǎn)換到串口上來。因為本身的工作是串口 DMA 接收任意長度數(shù)據(jù)。
串口有個空閑中斷,大概是串口總線在一個字節(jié)的時間內(nèi)沒有再接收到數(shù)據(jù),認(rèn)為一幀數(shù)據(jù)傳輸完畢了,就會產(chǎn)生串口空閑中斷。
這樣我們就不使用 DMA 中斷了,只使用串口空閑中斷,即在串口空閑中斷中獲取 DMA 接收的數(shù)據(jù)并處理,然后再開啟下次 DMA 接收。
關(guān)鍵代碼
使能串口空閑中斷
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
添加串口空閑中斷處理函數(shù)
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 */
UART_IRQHandler_IDLE(&huart1); // 串口空閑中斷處理函數(shù)
/* USER CODE END USART1_IRQn 1 */
}
/* USER CODE BEGIN 1 */
void UART_IRQHandler_IDLE(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET)
{
HAL_UART_DMAStop(&huart1);
uint8_t data_length = sizeof(recv_buf) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_Transmit(&huart1, recv_buf, data_length, 100);
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
__HAL_UART_CLEAR_OREFLAG(&huart1);
HAL_UART_Receive_DMA(&huart1, recv_buf, sizeof(recv_buf));
}
}
}
/* USER CODE END 1 */
避坑
在使用串口中斷時,一定記得要清除 ORE flag,不然中斷會出各種意想不到的異常,比如串口發(fā)送數(shù)據(jù)會觸發(fā)串口接收中斷。
__HAL_UART_CLEAR_OREFLAG(&huart1);
測試
文章來源:http://www.zghlxwxcb.cn/news/detail-671523.html
完整代碼
https://download.csdn.net/download/lyndon_li/88054148
對應(yīng)硬件:STM32F107VCT6文章來源地址http://www.zghlxwxcb.cn/news/detail-671523.html
到了這里,關(guān)于STM32 串口 DMA 接收任意長度數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!