STM32 串口接收大量數據導致死機


http://blog.csdn.net/origin333/article/details/49992383

以下文章出自上面的鏈接。感謝原創作者的分享。

在一項目中,使用STM32作為主控,程序運行一段時間后概率出現主循環卡死現象。

 

問題分析如下:

1、程序USART2不停接收並處理串口數據,波特率115200;

2、主循環卡死;

3、USART1中斷及TIM2中斷響應函數運行正常;(USART1及TIM2中斷優先級均比USART2高)

4、出現現象后,拔掉USART2的接收數據線,現象不能回復正常;

5、出現現象后,拔掉后再插入USART2的接收數據線,現象不能回復正常;

6、並未出現HardFault現象;

 

基於以上4點,可能原因如下:

1、USART2接收中斷標志沒有清除;

2、堆棧數據溢出,導致程序異常;

        3、USART2中斷重入導致異常;

4、USART2中斷函數被異常響應;

        5、USART2中斷ERR;

 

對於以上可能原因一一分析:

1、中斷接收標志清楚問題:

(1)USART2接收中斷響應函數如下:

 1 void USART2_Istr(void)
 2 {  
 3     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
 4     {   
 5         USART_ClearFlag(USART2, USART_FLAG_RXNE);
 6         USART_ClearITPendingBit(USART2, USART_IT_RXNE);
 7         Data = USART_ReceiveData(USART2);
 8         //Process Data
 9     }
10 }

(2)出現現象后,通過Usart1中斷獲取到如下信息:

a. USART_GetITStatus(USART2,  USART_IT_RXNE)  == RESET

b. USART_GetFlagStatus(USART2,  USART_FLAG_RXNE)  == RESET

c. 執行USART_ClearFlag(USART2, USART_FLAG_RXNE)及 USART_ClearITPendingBit(USART2, USART_IT_RXNE)后無法恢復正常;

 結論:與USART2 RXNE中斷標志無關。

 

2、堆棧數據溢出,導致程序異常;

(1)使用2倍棧空間,問題存在,概率不會降低;

(2)使用0.5倍棧空間,問題存在,概率不會提高;

(3)使用0.25倍棧空間,程序運行進入HardFault;

結論:與堆棧無關。

 

3、USART2中斷重入導致異常;

(1)使用標志法,確認出現問題時,中斷響應函數沒有重入;

結論:中斷響應函數沒有重入。

 

4、USART2中斷函數被異常響應;

(1)USART2中斷函數可以被正常調用,只是不停進入中斷響應函數,卡死主循環;

(2)檢查程序Map,沒發現與中斷響應函數地址相同的函數;

(3)檢查中斷向量表,沒發現異常;

結論:中斷函數沒有被異常調用;

 

5、USART2中斷ERR;

(1)關閉USART2中斷,主循環恢復正常;

(2)啟動USART2中斷,主循環卡死;

(3)獲取到DR=0x0000;

(4)USART_GetITStatus取到:RXNE=0,PE=0,TXE=0,TC=0,IDLE=0,LBD=0,CTS=0,ERR=0,ORE=0,NE=0,FE=0;

(5)通過USART_ClearITPendingBit清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均無法恢復正常;

(6)通過USART_GetFlagStatus:

  a.第一次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=1,ORE=1,NE=0,FE=0,PE=0

b.第二次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0

c.第三次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0

(7)通過USART_ClearFlag清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均無法恢復正常;

分析:

(1)為什么通過USART_GetITStatus獲取了所有中斷標志,均為RESET(TC、TXE中斷沒開),還會進中斷?

(2)為什么通過USART_ClearITPendingBit清除了所有中斷標志,還會進入中斷?

(3)為什么關閉USART2中斷后再次啟動它還會進入卡死狀態?

(4)為什么通過USART_GetFlagStatus第一次和第二次讀的不一樣?而且USART_ClearFlag清掉所有Flag,也沒法恢復正常?

 

帶着以上幾個疑問,查看了參考手冊,才恍然大悟!如下:

(1)打開RXNEIE,默認會同時打開RXNE和ORE中斷。

(2)必須第一時間清零RXNE,如沒及時清零,下一幀數據過來時就會產生Overrun error!

(3)錯誤就是ORE導致的

出現錯誤時,讀了RXNE=0,出錯應該是上圖打勾的情況,如下

 

(4)如文檔說明,要清除ORE中斷需要按順序讀取USART_SR和USART_DR寄存器!

那就是說USART_ClearFlag清掉所有Flag后,還必須讀一遍USART_DR寄存器!

      經過測試出現問題后依次讀讀取USART_SR和USART_DR,程序回復正常!

 

(5)那還有一個問題,為什么USART_GetITStatus讀不到ORE中斷標志?

讀USART_GetITStatus函數就知道了,只有CR3的EIE置1且SR的ORE置1,讀出來USART_GetITStatus(USART2,  USART_IT_ORE)  才是 SET。

見CR3的EIE位說明。

 

解決辦法,出現通過接收時,通過USART_GetFlagStatus讀取ORE,若不為RESET,則讀取DR數據丟棄。

修改如下:

 

 1 void USART2_NewIstr(void)
 2 {  
 3     if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)
 4    {
 5        USART_ReceiveData(USART2);
 6      USART_ClearFlag(USART2, USART_FLAG_PE);
 7    }
 8     
 9    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
10    {
11        USART_ReceiveData(USART2);
12      USART_ClearFlag(USART2, USART_FLAG_ORE);
13    }
14     
15     if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)
16    {
17        USART_ReceiveData(USART2);
18       USART_ClearFlag(USART2, USART_FLAG_FE);
19    }
20     
21     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
22     {   
23         USART_ClearFlag(USART2, USART_FLAG_RXNE);
24         USART_ClearITPendingBit(USART2, USART_IT_RXNE);
25         Data = USART_ReceiveData(USART2);
26     }
27 }

總結:

1、看文檔!看文檔!還是看文檔!(重要的事情要說3遍)

2、庫函數用的時候,也要注意其實現,稍有不慎就可能用錯。

3、注意USART_GetFlagStatus與USART_GetITStatus的區別,還有中斷響應機制。

4、任意時候都要考慮出錯處理。

 

查了一下 ,也有人遇到了相同的情況,可參考:

http://blog.csdn.net/love_maomao/article/details/8234039


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM