- 概要
- RXNE中斷響應過程方法(2)
(一)概要
中斷響應過程需要實現(xiàn)的關鍵代碼是由兩部分組成:
使能中斷標志位+完善中斷服務入口函數(shù)选调,這就像一個固定的套餐組合理盆,缺一不可逝段;
在上一篇http://www.reibang.com/p/f2d4095c9def介紹RXNE的中斷響應過程膏燃,是用HAL庫函數(shù)
__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);使能中斷滥搭,配合中斷響應服務入口函數(shù)USER_UART_IRQHandler(&huart1);共同實現(xiàn)了接收到一個字符的中斷響應過程;
(二)RXNE中斷響應過程方法(2)
2.1 簡介
第二種方法判导,是我們繼續(xù)沿用HAL庫自定義的回調(diào)函數(shù)來實現(xiàn)中斷服務入口程序嫉父,依然是使能中斷 標志位+補充中斷響應服務函數(shù),方法二提供的套餐組合為HAL_UART_Receive_IT() 和HAL_UART_RxCpltCallback()
使能RXNE中斷標志位的函數(shù)聲明是:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
中斷響應服務函數(shù)是HAL庫定義的回調(diào)函數(shù)( Callback):
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
回調(diào)函數(shù)是一種弱函數(shù)眼刃,
weak 顧名思義是“弱”的意思绕辖,如果函數(shù)名稱前面加上__weak 修飾符,我們一般稱這個函數(shù)為“弱函數(shù)”擂红。加上了__weak 修飾符的函數(shù)仪际,用戶可以在用戶文件中重新定義一個同名函數(shù)围小,最終編譯器編譯的時候,會選擇用戶定義的函數(shù)树碱,如果用戶沒重新定義這個函數(shù)肯适,那么編譯器就會執(zhí)行__weak 聲明的函數(shù),并且編譯器不會報錯成榜。
具備weak屬性的函數(shù)框舔,就像是穿了一件隱身衣,當用戶沒有在文件中定義時赎婚,它對于編譯器是不可見的隱身狀態(tài)刘绣,只有當被用戶重新定義之后,它作為中斷響應的服務函數(shù)挣输,會按照用戶定義實現(xiàn)其功能纬凤;回調(diào)函數(shù)在HAL庫中非常常見,它既可以被全局結構體變量句柄調(diào)用撩嚼,也可以成為中斷響應的服務函數(shù)停士;用戶需要清晰理解不同外設的回調(diào)函數(shù)實現(xiàn)功能,才能方便高效的應用完丽;
2.2 代碼實現(xiàn)步驟
在USART1串口控制流水燈的實驗中恋技,http://www.reibang.com/p/48817b329231,串口助手發(fā)送“mode_1#”命令字后舰涌,STM32的USART1 pRxBuffPtr連續(xù)接收到9個字符之后猖任,就會進入到中斷服務回調(diào)函數(shù); HAL_UART_RxCpltCallback(huart)瓷耙;我們在main.c中重新定義回調(diào)函數(shù)朱躺,即可實現(xiàn)同樣的效果;接下來分析中斷使能到中斷響應的全過程搁痛;
中斷使能:HAL_UART_Receive_IT
中斷響應:SART1_IRQHandler()——HAL_UART_IRQHandler—— UART_Receive_IT——當RxXferCount計數(shù)器自減到0长搀,調(diào)用回調(diào)函數(shù)HAL_UART_RxCpltCallback();
(1)使能中斷標志位
1.1 調(diào)用函數(shù)HAL_UART_Receive_IT允許RXNE標志位產(chǎn)生中斷,該函數(shù)
在mian.c主函數(shù)USART1初始化操作之后鸡典,調(diào)用此函數(shù)源请,目的是開啟RXNE標志位,因為命令字“mode_1#\r\n”是9個字符彻况,當DR數(shù)據(jù)寄存器接收到來自串口助手發(fā)送的9個字符之后谁尸,就會產(chǎn)生響應中斷服務函數(shù);
HAL_UART_Receive_IT(&huart1,uart1RxBuff,9);
從該函數(shù)定義可以得知:該函數(shù)功能是:
1.使能PE(奇偶校驗錯誤)中斷標志位纽甘,ERR(錯誤數(shù)據(jù))中斷標志位良蛮,RXNE(數(shù)據(jù)寄存器不為空)中斷標志位;
2.給串口句柄huart1的三個全局變量*pRxBuffPtr,RxXferSize和RxXferCount賦初值悍赢;
pRxBuffPtr 指向用戶自定義的接收數(shù)組的首地址决瞳;
RxXferSize; 接收數(shù)據(jù)的長度货徙;
RxXferCount:接收數(shù)據(jù)的計數(shù)器;
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pRxBuffPtr = pData;//指向用戶自定義的接收數(shù)組
huart->RxXferSize = Size;//設定接收到的字符串個數(shù)
huart->RxXferCount = Size;//設定計數(shù)器的初值
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Parity Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);//使能PE標志位
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);//使能ERR標志位
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);//使能RXNE標志位
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
(2)中斷響應的執(zhí)行過程
2.1 中斷入口函數(shù): 在文件stm32f1xx_it.c中皮胡,找到IRQHandler函數(shù)
void USART1_IRQHandler(void)//中斷響應的入口
{
HAL_UART_IRQHandler(&huart1);
}
2.2 執(zhí)行 HAL_UART_IRQHandler(&huart1);: 從函數(shù)定義可知痴颊,當使能RXNE標志位之后,條件語句成立屡贺,則調(diào)用UART_Receive_IT(huart);
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;
}
}
2.3 執(zhí)行函數(shù) UART_Receive_IT(huart);蠢棱。該函數(shù)功能
1.判斷一次接收的有效數(shù)據(jù)位是8個字節(jié)還是9個字節(jié);是否必須包含奇偶校驗位甩栈;
2.從DR數(shù)據(jù)寄存器中讀取有效數(shù)據(jù)位存放到用戶自定義的數(shù)組中裳扯;
3.移動指針pRxBuffPtr;
4判斷uarRxXferCount計數(shù)器自減為0之后谤职,就調(diào)用回調(diào)函數(shù) HAL_UART_RxCpltCallback(huart);
5.條件成立,函數(shù)返回HAL_OK亿鲜;
函數(shù) UART_Receive_IT()的作用是把每次中斷接收到的字符保存在串口句柄的緩存指針 pRxBuffPtr 中允蜈,同時每次接收一個字符,其計數(shù)器 RxXferCount 減 1蒿柳,直到接收完成 RxXferSize 個字符之后 RxXferCount 設置為0饶套,同時調(diào)用接收完成回調(diào)函數(shù) HAL_UART_RxCpltCallback 進行處理;
2.4 用戶在main.c中重寫回調(diào)函數(shù)HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)垒探,在回調(diào)函數(shù)中只需要判斷是否USART1的產(chǎn)生的中斷妓蛮,用戶自定義的全局變量 uart1RxState賦值1,則說明數(shù)據(jù)已經(jīng)接收圾叼;此外蛤克,因為上一步在調(diào)用回調(diào)函數(shù)之前,已經(jīng)關閉了中斷__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE)夷蚊;所以需要重新開啟中斷构挤,調(diào)用函數(shù)HAL_UART_Receive_IT(&huart1,uart1RxBuff,9);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//當RXcounter自減到0 惕鼓,才進入回調(diào)函數(shù)
{
if(huart->Instance==USART1)
{
uart1RxState =1;
}
HAL_UART_Receive_IT(&huart1,uart1RxBuff,9);//重新開啟中斷
}
總結:
串口中斷是我們總結了第二種方法筋现。與第一種方法不同,我們采用了HAL自定義的中斷服務函數(shù)箱歧,且通過重新定義回調(diào)函數(shù)的方法矾飞。實現(xiàn)了與方法一相同的功能;無論是采取之前庫函數(shù)的思想呀邢,重寫中斷服務響應函數(shù)洒沦;還是采取HAL的邏輯,運用HAL幫我們自定義好的函數(shù)驼鹅;我們都需要充分理解中斷執(zhí)行過程微谓;通過單步運行反復調(diào)試代碼森篷,閱讀參考手冊和英文文檔注釋,幫助我們更好的理解串口異步通信豺型;