一、查詢模式
1.
二、中斷模式
1.中斷接收。
1.1先看中斷接收的流程(以 USART2 為例)
在啟動文件中找到中斷向量
USART2_IRQHandler
找到USART2_IRQHandler的函數定義
可以看到這里又轉到另一個函數里去了,再找下去:
該函數的源碼:
/** * @brief This function handles UART interrupt request. * @param huart: pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @retval None */ void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) { uint32_t isrflags = READ_REG(huart->Instance->SR); uint32_t cr1its = READ_REG(huart->Instance->CR1); uint32_t cr3its = READ_REG(huart->Instance->CR3); uint32_t errorflags = 0x00U; uint32_t dmarequest = 0x00U; /* If no error occurs */ errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE)); if(errorflags == RESET) { /* UART in mode Receiver -------------------------------------------------*/ if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) { UART_Receive_IT(huart); return; } } /* If some errors occur */ if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET))) { /* UART parity error interrupt occurred ----------------------------------*/ if(((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_PE; } /* UART noise error interrupt occurred -----------------------------------*/ if(((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_NE; } /* UART frame error interrupt occurred -----------------------------------*/ if(((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_FE; } /* UART Over-Run interrupt occurred --------------------------------------*/ if(((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_ORE; } /* Call UART Error Call back function if need be --------------------------*/ if(huart->ErrorCode != HAL_UART_ERROR_NONE) { /* UART in mode Receiver -----------------------------------------------*/ if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) { UART_Receive_IT(huart); } /* If Overrun error occurs, or if any error occurs in DMA mode reception, consider error as blocking */ dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR); if(((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest) { /* Blocking error : transfer is aborted Set the UART state ready to be able to start again the process, Disable Rx Interrupts, and disable Rx DMA request, if ongoing */ UART_EndRxTransfer(huart); /* Disable the UART DMA Rx request if enabled */ if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) { CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); /* Abort the UART DMA Rx channel */ if(huart->hdmarx != NULL) { /* Set the UART DMA Abort callback : will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */ huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError; if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK) { /* Call Directly XferAbortCallback function in case of error */ huart->hdmarx->XferAbortCallback(huart->hdmarx); } } else { /* Call user error callback */ HAL_UART_ErrorCallback(huart); } } else { /* Call user error callback */ HAL_UART_ErrorCallback(huart); } } else { /* Non Blocking error : transfer could go on. Error is notified to user through user error callback */ HAL_UART_ErrorCallback(huart); huart->ErrorCode = HAL_UART_ERROR_NONE; } } return; } /* End if some error occurs */ /* UART in mode Transmitter ------------------------------------------------*/ if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET)) { UART_Transmit_IT(huart); return; } /* UART in mode Transmitter end --------------------------------------------*/ if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET)) { UART_EndTransmit_IT(huart); return; } }
也就是說,當串口中斷觸發以后,幾經周轉到了這里,該函數功能是讀取寄存器的幾個狀態,判斷無誤后再轉到另一個函數,就是上圖小矩形框出來的UART_Receive_IT(huart);
然后我們再去看UART_Receive_IT(huart)這個函數原型:
回調函數就在這個UART_Receive_IT(huart)函數里:
在回調函數上邊有兩行很重要的代碼:
這兩行代碼的作用是關閉串口接收中斷,也就是說,在一次串口中斷接收過程的最后,即串口接收完一組數據之后會關閉串口接收中斷。(這個后面還會再講,先記住)。
總結一下,串口中斷接收的流程:
USART2_IRQHandler(void) -> HAL_UART_IRQHandler(UART_HandleTypeDef *huart) -> UART_Receive_IT(UART_HandleTypeDef *huart) -> HAL_UART_RxCpltCallback(huart);
Callback函數就是用戶要重寫在main.c里的回調函數。
再說明一下一個很重要的問題:STM32的每個串口中斷有好幾個(發送接收等),但是只要是與串口相關的中斷發生系統都會先調用同一個函數,也就是中斷向量表中的那個,比如usart2的話就是USART2_IRQHandler(void),然后這個函數再調用HAL_UART_IRQHandler,在HAL_UART_IRQHandler中去讀取寄存器判斷究竟是那幾個位被置為1,確定好是哪個中斷之后(接收還是發送)再調用不同的回調函數。
1.2如何使用接收中斷。
在cube中配置完了之后並沒有使能串口中斷(有一個串口初始化函數,但是在這個函數中並未使能串口中斷)需要用戶手動使能。使能代碼如下:
HAL_UART_Receive_IT(&huart2, (uint8_t *)kRxBuffer, 10);
什么意思呢?
HAL庫的串口接收思路是這樣的:用戶你可以隨便定義一個緩存區,大小隨意,然后通過上邊這個函數把這個緩存區對應到串口的接收,上面函數的意思就是把kRxBuffer(這是一個數組)作為緩存區,指定大小為10。然后usart2接收數據的時候就防到kRxBuffer這個數組中,只有當接收到10個數據之后才調用一次callback函數(回調函數)。當然不要忘了該函數的使能串口接收中斷功能, 在:二、中斷模式 的1.1節中說到了串口接收完數據后會關閉使能,所以,在回調函數中一定要再寫一次HAL_UART_Receive_IT(&huart2, (uint8_t *)kRxBuffer, 10),使能接收中斷。
小小的總結下串口中斷接收怎么用:
(1)指定一個緩存區(串口接收到的數據會全部堆到這個緩存區)
(2)使能串口接收中斷,並把緩存區對應到串口
(3)在回調函數中實現接收到數據之后的操作(比如處理數據)並再次使能串口接收中斷。
所以更具體一下串口接收的流程就是這樣的:
(1)串口一個接一個的接收到數據填充到緩存區
(2)緩存區滿(大小是用戶定義的)程序幾經輾轉最后會調用到回調函數。
(3)執行用戶在回調函數中實現的功能。
2.中斷發送。
2.1發送中斷的觸發流程。
由於在STM32中usart2的入口中斷只有一個:
就是上圖的中斷向量表中紅框標出來的。其他的所有中斷其實都是從這里出發的,我們再和捋接收一樣捋一遍發送。
首先是USART2_IRQHandler,找到這個函數原型(這一步和接收完全一樣):
再找HAL_UART_IRQHandler(&huart2);原型:
到這里還是和接收完全一樣,注意是完全一樣,源碼也就是上面接收貼出來的一樣。這次我們主要注意該函數最后幾行(可以翻上去看源碼):
把中間代碼收起來以后看最后紅框,這就很明顯了,這里觸發了發送中斷(軟件觸發)
接着去找這個UART_EndTransmit_IT(huart)的函數原型:
第一個紅框里清除了發送中斷使能(同接收一樣,在用完之后就關掉,但是不同於接收,發送完成就不用再在回調函數中使能了,因為在中斷發送的時候就會使能),第二個紅框調用回調函數。
2.2如何使用發送中斷。
中斷發送的意思,非常類似於中斷接收,但其中有一些不同,看下面這個函數:
HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
一個非常類似於中斷接收使能的函數。接收中斷使能函數的作用是綁定接收緩存區並使能接收中斷,但是對於發送,該函數的作用是發送指定長度的指定數據並使能發送中斷。
比如有一個unsigned char 數組a[10],HAL_UART_Transmit_IT(&huart2, a, 10),這一句的意思是用usart2(串口2)發送a數組中的10個數據,然后使能發送中斷。
當發送完成之后(或者發送一半,發送一半也有個中斷)就會執行回調函數。
總結一下發送中斷:
使用HAL_UART_Transmit_IT函數發送指定長度的數據,並使能發送中斷,發送到一半和發送結束會觸發中斷(相關的回調函數是HAL_UART_TxHalfCpltCallback()和HAL_UART_TxCpltCallback())中斷觸發后發送中斷使能會被清除,然后調用回調函數,回調函數執行完成之后結束本次發送。