1、情景描述:
最近在做一個項目,X86的上位機通過串口控制MCU,使用串口中斷接收上位機數據時,MCU在上電的情況下燒錄程序,可以正常接收上位機的數據,在斷電重啟后,一直進入不了中斷回調函數,上電的情況是X86上電,MCU也同時上電。
2、原因分析:
造成這個的原因是因為硬件上電的時候,因為X86跟MCU是同時上電的,上電后會把串口的電平拉高,這個高電平觸發了MCU的串口中斷,導致MCU的串口中斷誤以為接收到了一個數據,例如 HAL_UART_Receive_IT(&huart1, (uint8_t *)Rx_buff, 5) 這里,上電后MCU誤以為接收了一個數據,還剩下4個數據沒有接收,然后上位機每次發送5個數據過來后MCU中斷數據接收個數錯誤,所以一直無法進入中斷回調函數。
我們看到 HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart) ,里面的 RxXferCount 是告訴我們中斷要接收的剩余數據量大小,根據上面舉例子的話,上電時因為那個高電平的原因導致 RxXferCount 變成了4,如下圖打印信息所示

接着我們重新看回 HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart) 函數里的調用回調函數部分,下圖所示,發現 RxXferCount 要為0的時候才會調用中斷回調函數,依舊以上面例子說明,當MCU誤以為上電時的高電平為數據時,上位機再發送5個數據下來,RxXferCount 就永遠無法變成0,所以導致一直進入不了中斷回調函數。

3、解決方法:
3.1軟件解決方法
軟件解決的時候,我們要知道導致這個問題的根源是 RxXferCount 這個值被誤判了,所以我們只需要在上電的時候,對這個值進行修正即可;
首先我們定義一個標志位,用來標志MCU的狀態是剛上電的狀態
char uart_error_flag=0;
接着我們編寫函數對 RxXferCoun 值進行處理
/*** 函數名:void uart_error(void) 說 明:解決剛上電時,由於串口電平拉高,導致串口中斷誤以為接收到了一個字節, 導致后面接收數據個數一直錯誤,無法進入中斷回調函數問題 傳入值:無 傳出值:無 **/ void uart_error(void) { if( (huart1.RxXferCount < Rxdsize) && (uart_error_flag==0) ) { /*RxXferCount 告訴我們剩余空間大小,如果剩余空間和總空間不一樣,則說明中斷收到數據了*/ printf("huart1.RxXferCount = %d\r\n",huart1.RxXferCount); uart_error_flag = 1; huart1.RxXferCount = 5; //修改剩余空間,防止無法進入回調 } }
最后我們在 main 函數里的 while 循環前調用即可
int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART2_UART_Init(); //初始化打印信息串口 MX_USART1_UART_Init(); //初始化中斷接收串口 HAL_UART_Receive_IT(&huart1, (uint8_t *)Rx_buff, Rxdsize); //打開串口中斷接收 uart_error(); //處理上電時串口中斷誤判的問題 while (1) { /* 注意要在中斷回調函數里重新打開串口中斷接收,否則串口中斷接收只能接收一次 */ } }
3.2 硬件解決方法
硬件解決方法比較粗暴,就是做一個電源延時電路,等X86重新上電后,再給MCU上電。
補充說明:
使用DMA接收時候不會出現這種情況,不過使用DMA接收,如果上位機發送數據過快,會出現數據粘包現象,例如上位機發送是數據一包是5個數據,如果上位機發送數據過快(20ms以內),MCU就好會把接收到的好幾包數據當做一包數據來處理,例如把3包數據當做1包數據來處理,這樣MCU就會誤以為一包數據的15個了,出現誤判的情況,不過它接收的數據是准確的,就是分包能力沒有串口中斷強。
