RXNE中斷響應(yīng)過程方法(1)
在USART1串口控制流水燈的實驗中,http://www.reibang.com/p/48817b329231,串口助手發(fā)送“mode_1#”命令字后懦底,STM32的USART1 DR寄存器接收到1個字符之后,就會進入到中斷服務(wù)函數(shù);總結(jié)中斷執(zhí)行的過程:
(1)使能中斷標志位逝钥,CR1寄存器的標志位RXNEIE被置1隘弊; 此函數(shù)調(diào)用之后,會直接配置CR1寄存器的RXNEIE=1;
__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
(2)響應(yīng)中斷的入口函數(shù)
在使能了中斷之后送悔,DR數(shù)據(jù)寄存器只要接收到1個字符慢显,例如,發(fā)送命令字“mode_1#”,DR寄存器先接收到一個字符“m”,就會產(chǎn)生中斷欠啤;USART1_IRQHandler()函數(shù)是USART1中斷服務(wù)的入口荚藻,其中&huart1是訪問串口句柄UART_HandleTypeDef,可以通過huart1.TxXferSize,調(diào)用結(jié)構(gòu)體定義的成員洁段,
void USART1_IRQHandler(void)//中斷響應(yīng)的入口
{
USER_UART_IRQHandler(&huart1);
}
串口句柄的定義內(nèi)容应狱,包含了(發(fā)送或接收的)數(shù)據(jù)緩存、數(shù)據(jù)指針祠丝、串口 DMA 相關(guān)的變量疾呻、各種標志位等等要在整個項目流程中都要設(shè)置的各個成員除嘹。還有中斷服務(wù)程序中的回調(diào)函數(shù);這樣我們在整個程序中就可以方便調(diào)用岸蜗;
UART_HandleTypeDef huart1;
typedef struct __UART_HandleTypeDef
{
USART_TypeDef *Instance; /*!< UART registers base address */
UART_InitTypeDef Init; /*!< UART communication parameters */
uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
uint16_t TxXferSize; /*!< UART Tx Transfer size */
__IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
__IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /*!< Locking object */
__IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
and also related to Tx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO uint32_t ErrorCode; /*!< UART Error code */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Half Complete Callback */
void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Complete Callback */
void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Half Complete Callback */
void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */
void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */
void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */
void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */
void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
} UART_HandleTypeDef;
(3)用戶重寫中斷服務(wù)函數(shù)
此次項目中憾赁,我們注釋掉了HAL庫原本的HAL_UART_IRQHandler(&huart1);然后重新定義了USER_UART_IRQHandler(&huart1);在中斷入口響應(yīng)函數(shù) USART1_IRQHandler(void)執(zhí)行以后,我們就直接調(diào)用USER_UART_IRQHandler(&huart1)散吵;在main.c中對函數(shù)進行定義龙考;
void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
{
if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET))//接收一個字節(jié)就會產(chǎn)生中斷
{
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
uart1RxBuff[uart1RxCounter] = (uint8_t)(huart1.Instance->DR & (uint8_t)0x00ff);
uart1RxCounter++;
__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE);
}
if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))//接收一組數(shù)據(jù)/一幀數(shù)據(jù)就會中斷
{
__HAL_UART_DISABLE_IT(&huart1,UART_IT_IDLE);
uart1RxState = 1;
}
}
這種方式與我們之前學(xué)習(xí)的標準庫方法比較相似,在中斷服務(wù)入口函數(shù)里矾睦,判斷標志位晦款,然后做讀/寫操作,最后清除標志位枚冗;沒有使用調(diào)用HAL庫的回調(diào)函數(shù)缓溅,程序代碼思路比較簡潔;
(4)判斷標志位赁温,將數(shù)據(jù)寄存器DR中接收的低8位字符讀取到自己定義的數(shù)組中坛怪;同時,完成清除標志位RXNE股囊;代碼中uart1RxBuff是我們在C語言代碼中定義好的數(shù)組袜匿,準備將DR寄存器的數(shù)值讀入到數(shù)組中;通過在線調(diào)試稚疹,我們可以看到變化居灯;
從DR寄存器讀取數(shù)據(jù)之后,RXNE會自動被清零内狗;
if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET))
uart1RxBuff[uart1RxCounter] = (uint8_t)(huart1.Instance->DR & (uint8_t)0x0i0ff);
uart1RxCounter++;
當RDR移位寄存器中的數(shù)據(jù)被轉(zhuǎn)移到USART_DR寄存器中怪嫌,該位被硬件置位。如果USART_CR1寄存器中的RXNEIE為1柳沙,則產(chǎn)生中斷岩灭。對USART_DR的讀操作可以將該位清零。
(5)使能IDLE中斷赂鲤,本次項目在RXNE中斷響應(yīng)函數(shù)中噪径,開啟了IDLE中斷,IDLE是空閑線路檢測標志位蛤袒,當一幀數(shù)據(jù)發(fā)送完熄云,下一幀數(shù)據(jù)還沒有發(fā)送之前膨更,會有空閑狀態(tài)妙真;IDLE標志位用于檢測一幀數(shù)據(jù)是否發(fā)送完成;在本例中荚守,IDLE使能的代碼是:
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
在中斷服務(wù)函數(shù)中又使能了一個新的中斷珍德,可能對于初學(xué)者有很多疑問练般;這里注意不屬于中斷嵌套,IDLE標志位也只有在接收數(shù)據(jù)的狀態(tài)下锈候,才可能發(fā)生薄料,因為RXNE接收一個字符就會發(fā)生中斷,而IDLE是接收一幀數(shù)據(jù)才會發(fā)生中斷泵琳,這里兩個狀態(tài)是可以在一次接收數(shù)據(jù)的過程中按代碼順序先后發(fā)生摄职;所以不存在中斷嵌套問題;如果初學(xué)者對這里覺得難以理解获列,也可以將IDLE的使能谷市,在main.c全局變量中進行使能;
(6)產(chǎn)生IDLE中斷
當檢測到總線空閑時击孩,IDLE位被硬件置位,因為已經(jīng)開啟了USART_CR1中的IDLEIE為’1’迫悠,則產(chǎn)生中斷;條件判斷成立巩梢,接收數(shù)據(jù)狀態(tài)字置uart1RxState=1创泄;
if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))//接收一組數(shù)據(jù)/一幀數(shù)據(jù)就會中斷
{
__HAL_UART_DISABLE_IT(&huart1,UART_IT_IDLE);
uart1RxState = 1;
}
IDLE的狀態(tài)位受到RXNE狀態(tài)位的影響,先有RXNE狀態(tài)位置1括蝠,檢測到IDLE狀態(tài)情況下鞠抑,才會進入IDLE的中斷響應(yīng);表示一幀數(shù)據(jù)已經(jīng)接收完成忌警;
(7)禁用IDLE中斷碍拆;__HAL_UART_DISABLE_IT(&huart1,UART_IT_IDLE);
總結(jié):通過此篇分析,是幫助同學(xué)們理解串口接收中斷函數(shù)的執(zhí)行流程慨蓝;使能函數(shù)__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE) 與用戶自定義的中斷服務(wù)函數(shù) USER_UART_IRQHandler(UART_HandleTypeDef *huart)感混,配合使用。完成數(shù)據(jù)接收礼烈;此篇沒有用到接收中斷的回調(diào)函數(shù)弧满。我們在下篇方法二中進行介紹。