- 前言
- 一、 HAL 庫串口收發(fā)
- 1.1 串口發(fā)送
- 1.2 串口接收
- 二、 收發(fā)同時串口卡死?
- 2.1 問題說明
- 2.2 嘗試的處理方式
- 結語
前言
對于 STM32 串口的使用,確實很簡單使用 STM32CubeMX 做好初始化,就可以直接使用了。
但是最近在某些產(chǎn)品上使用串口同時收發(fā)的時候,發(fā)現(xiàn)有時候串口會收不到數(shù)據(jù)了,但是發(fā)送正常,而且這個問題再數(shù)據(jù)量大的時候很容易出現(xiàn),于是乎進行了好幾天的問題測試……
一、 HAL 庫串口收發(fā)
先簡單回顧一下 STM32 HAL庫串口收發(fā)是如何使用的。
1.1 串口發(fā)送
對于 STM32 來說,串口發(fā)送有3中方式:
- 輪詢發(fā)送;
- 中斷發(fā)送;
- DMA發(fā)送;
在實際產(chǎn)品上,大部分項目中都用的是 輪詢 方式發(fā)送,本次出現(xiàn)接收卡死的問題的產(chǎn)品也是采用的輪詢發(fā)送,所以我簡單的說明一下輪詢發(fā)送,其他兩種方式為 STM32 學習的基礎問題,這里就不過多討論。
發(fā)送相對簡單,在 HAL 庫實際都是使用HAL_UART_Transmit
函數(shù):
在這里插入圖片描述
不管是哪個串口發(fā)送,都做了個簡單的發(fā)送函數(shù):
在這里插入圖片描述
發(fā)送沒什么好說的,簡單易用。
1.2 串口接收
和串口發(fā)送一樣,串口接收有3中方式:
- 輪詢接收;
- 中斷接收;
- DMA接收;
在我們正常的項目使用中,一般都是 中斷接收 或者 DMA 接收,基本上不會使用 輪詢接收的方式。
那么對于本次出問題的產(chǎn)品,我采用的是 中斷接收的方式。
但是相比較發(fā)送,在 HAL 庫中 使用中斷接收的方式就有點 “五花八門” 的感覺。
1.2.1 標準庫接收
在標準庫的時候,我們經(jīng)常這么用,在串口初始化的時候使用下面的語句使能中斷:
//在串口初始化代碼之后加上中斷使能
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
如果需要自動判斷一幀數(shù)據(jù),我們再開啟一下 IDLE 中斷:
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);
然后在對應的中斷處理函數(shù)中,直接讀取 DR 寄存器(STM32F103 而言為 DR,STM32L051 為RDR),然后當 IDLE 中斷產(chǎn)生,也可以處理一下標志位:
//自己用的,用到了 USART_IT_IDLE 標志位,有時候不合適
void USART3_IRQHandler(void) //串口3中斷服務程序
{
u8 clear3=clear3; //消除編譯器沒有用到的提醒
// u8 Res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
USART_Enocean_BUF[Enocean_Data++] = USART3- >DR;
USART3_RX_BUF[USART3_Data++] = USART_ReceiveData(USART3);
// Res= USART_ReceiveData(USART3);
// USART_SendData(USART1,Res);while(!(USART1- >SR&USART_FLAG_TXE));
}
else if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)
{
clear3=USART3- >SR; //讀SR寄存器 可以清空寄存器
clear3=USART3- >DR; //讀DR寄存器(先讀SR寄存器,再讀DR,為了清除IDLE中斷)
USART3_RX_STA=1; //標記接收到了一幀數(shù)據(jù)
//USART3_Data=0;
} //enocean是不是讀不到一幀數(shù)據(jù),不用一幀數(shù)據(jù)測試一下
}
1.2.1 HAL庫接收
HAL庫接收方式一
在 HAL 庫函數(shù)接收的時候,其實也可以使用標準庫上一樣的中斷標志使能:
MX_LPUART1_UART_Init();
__HAL_UART_ENABLE_IT(&hlpuart1,UART_IT_RXNE);
IDLE 中斷使能:
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
這種方式的處理方式,可以和標準庫差不多。
在 HAL 庫中,外設的中斷的入口函數(shù)都放在stm32l0xx_it.c
這個文件夾中( 以STM32L051 為例),在這個文件中可以找到和標準庫一樣的 中斷入口函數(shù),我們可以進行如下處理:
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_RXNE) == SET){
// USART_Enocean_BUF[Enocean_Data++] = huart2.Instance- >RDR
// RXNE 數(shù)據(jù)處理,直接讀取數(shù)據(jù)
}
if((__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IT(&huart2,UART_CLEAR_IDLEF); //??3y?D??
// ReceiveState = 1;
// IDLE 數(shù)據(jù)處理,一幀數(shù)據(jù)接收標志位置位
}
}
HAL庫接收方式二
但是在于 HAL 中,還有一種比較常用的開啟中斷方法,不是直接使能中斷,而是通過調(diào)用 HAL 庫函數(shù) HAL_UART_Receive_IT
:
在這里插入圖片描述
一般的使用方式步驟:
在這里插入圖片描述
對于本次需要說明的問題,就是使用了 HAL_UART_Receive_IT
函數(shù)導致的,下文我們會說明,這里列出了基本的使用步驟。
二、 收發(fā)同時串口卡死?
2.1 問題說明
最近測試部反饋,產(chǎn)品有些時候的下行沒反應,這里所說的下行,其實就是串口接收。
霹靂扒拉一大堆多余的省略 ... ... 只說幾個重點:
出問題的最后現(xiàn)象就是串口發(fā)送正常,但是永遠接收不到數(shù)據(jù)了,其他程序正常運行。
出問題只存在于串口又有接收,又有發(fā)送的產(chǎn)品上。
產(chǎn)品發(fā)送一般是周期性的,但是接收是隨機的,無線信號串口接收,所以產(chǎn)品的出問題的情況也是隨機的,但是數(shù)據(jù)量大起來肯定就會出現(xiàn)永遠接收不到的問題。
2.2 嘗試的處理方式
因為所有的一些都是按照正常流程設計的,按理來說實在是不知道為什么會這樣,所以網(wǎng)上查詢測試了好久,現(xiàn)在我把嘗試的處理方式以及步驟記錄說明一下:
2.2.1 清除錯誤標志位
在使用 HAL 庫的時候,有4個錯誤 flag,如下圖:
在這里插入圖片描述
期初還以為是某些異常錯誤導致的,經(jīng)過網(wǎng)上的的一些查詢,剛開始是添加了清除錯誤標志位:
__HAL_UART_CLEAR_FLAG(&hlpuart1, UART_FLAG_PE);//清標志
__HAL_UART_CLEAR_FLAG(&hlpuart1, UART_FLAG_FE);
__HAL_UART_CLEAR_FLAG(&hlpuart1, UART_FLAG_NE);
__HAL_UART_CLEAR_FLAG(&hlpuart1, UART_FLAG_ORE);
在需要的地方加上錯誤標志位清除,我是在清除串口緩存中處理的:
在這里插入圖片描述
2.2.2 串口溢出錯誤
其實串口溢出錯誤在上面的已經(jīng)清除過標志位,因為這個問題著實搞得我頭有點大,所以看到網(wǎng)上前人的處理方式和上面直接清除不一樣,還是試了一把。
這里簡單說明一下,我還特意去看了下自己的 CubeMX 設置,在設置的時候 有一個 Overrun 錯誤標志位,平時我們設置都不一定往下拉著看 = =!:
在這里插入圖片描述
然后確定了開啟了串口溢出錯誤檢測以后,我根據(jù)網(wǎng)上的方式,加了一個HAL_UART_ErrorCallback
函數(shù),其實就類似于HAL_UART_RxCpltCallback
函數(shù):
在這里插入圖片描述
自己加了一個 出錯處理函數(shù),其實現(xiàn)在看來,當然也是沒有用的。
2.2.3 HAL庫的半雙工處理?
折騰了好長一段時間,其實一開始就知道問題在于 同時收發(fā)會出問題的情況,那么繼續(xù)上網(wǎng)找問題。
最終確定了一個問題就是:
我們都知道 STM32 串口是全雙工的, STM32 HAL庫在處理接收的時候會鎖一下串口一會,導致變成某個短時間的“半雙工”。
這個時候如果同時收發(fā)就會出現(xiàn)問題,最后解決的辦法在這篇文章中看到了:STM32 F103串口同時收發(fā)出現(xiàn)死鎖問題解決辦法
問題在于我們使用的HAL_UART_Receive_IT
函數(shù)中,有對串口加鎖的操作:
雖然在后面有解鎖:
在這里插入圖片描述
但是根據(jù)后期的解決方式來說,確實就是這個HAL_UART_Receive_IT
函數(shù)的問題,最后使用的方式為,在產(chǎn)生一次中斷以后開啟的時候手動解鎖:
在這里插入圖片描述
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart- >Instance == LPUART1){
Enocean_Data++;
if(Enocean_Data > 98)Enocean_Data = 0;
while(HAL_UART_Receive_IT(&hlpuart1, (uint8_t *)&USART_Enocean_BUF[Enocean_Data], 1) != HAL_OK){
hlpuart1.RxState = HAL_UART_STATE_READY;
__HAL_UNLOCK(&hlpuart1);
}
}
else if(huart- >Instance==USART1)
{
}
}
終于,串口不再卡死 , 成功!
結語
沒想到和 EEPROM 一樣,一個簡單的芯片,一個熟悉的串口 ,出了這種問題 = =!還好最后解決了問題。
踩過的坑都是積累與經(jīng)驗,加油。
-
STM32
+關注
關注
2270文章
10895瀏覽量
355721 -
串口
+關注
關注
14文章
1551瀏覽量
76421 -
HAL
+關注
關注
2文章
70瀏覽量
12607
發(fā)布評論請先 登錄
相關推薦
評論