先看一段代碼:
while(1)
{
if(EXTI_Sign==1)
{
HAL_Delay(Period);
HAL_NVIC_EnableIRQ(EXTI2_3_IRQn);
HAL_NVIC_EnableIRQ(EXTI2_3_IRQn);
EXTI_Sign=0;
。。。。。。
}
}
有人使用STM32G0系列的芯片開發(fā)產(chǎn)品,有段功能測試驗(yàn)證代碼如上所示,相同的函數(shù)必須調(diào)用2次才能正常運(yùn)行,調(diào)用2次倒也罷了,關(guān)鍵是必須!頗為納悶。
這里開啟了PA3的外部中斷功能,上下沿均可觸發(fā)。PA3接收外來報警信號,類似于煙感報警器。報警信號是一串脈沖信號,報警信號過來時存在多次抖動問題??蛻粝肓藗€方法消抖,只要報警端口有電平變化就觸發(fā)中斷然后把中斷Disable,并設(shè)置報警標(biāo)志再回到主程序。
主程序里識別到報警有效標(biāo)志后延時幾分鐘再Enable剛才Disable掉的外部中斷。但是,他發(fā)現(xiàn)再次使能外部中斷時需要連續(xù)兩次調(diào)用使能中斷的代碼才可以響應(yīng)新的報警信號?!敬颂幬淖忠罁?jù)反饋者的文字描述組織而成】
下面MX_GPIO_Init(void)是經(jīng)CubeMx配置后自動生成的,里面有EXTI相關(guān)NVIC配置。相關(guān)代碼如下:
static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); 。。。。。。 /*Configure GPIO pin : PA3 */ GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI2_3_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI2_3_IRQn); } 基于上沿觸發(fā)的中斷服務(wù)程序如下[基于下沿觸發(fā)的此處省略】: EXTI ISR(): { __HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_PIN_3);//清中斷申請標(biāo)志; HAL_NVIC_DisableIRQ(EXTI2_3_IRQn);//關(guān)閉中斷響應(yīng) EXIT_Sign=1;//表示收到報警信號 } 主循環(huán)代碼像下面書寫才能讓程序正常運(yùn)行:【略去了其它代碼】 while (1) { if(EXTI_Sign ==1) { HAL_Delay(Period); MX_GPIO_Init();//客戶無意中發(fā)現(xiàn)加這句有用 HAL_NVIC_EnableIRQ(EXTI2_3_IRQn); EXTI_Sign =0; 。。。。。。 } }
現(xiàn)在的疑問是在EXTI中斷服務(wù)程序運(yùn)行HAL_NVIC_DisableIRQ(EXTI2_3_IRQn)后,到主循環(huán)代碼里再次使能外部中斷時,為何還要額外運(yùn)行一次MX_GPIO_Init()函數(shù)才能讓程序正常運(yùn)行。最終發(fā)現(xiàn)運(yùn)行該函數(shù)的實(shí)質(zhì)就是將HAL_NVIC_EnableIRQ(EXTI2_3_IRQn)多運(yùn)行一次。
換句話說,上面的主循環(huán)代碼要改成下面樣子才可以讓程序正常運(yùn)行:
while(1)
{
if(EXTI_Sign==1)
{//報警有效,即發(fā)生過報警時,代碼進(jìn)到這里。
HAL_Delay(Period);
HAL_NVIC_EnableIRQ(EXTI2_3_IRQn);//1
HAL_NVIC_EnableIRQ(EXTI2_3_IRQn);//2
EXTI_Sign=0; //清除報警標(biāo)志,準(zhǔn)備監(jiān)測新的警情
。。。。。。
}
}
說到底,問題就是主循環(huán)里為何要兩次重復(fù)運(yùn)行HAL_NVIC_EnableIRQ(EXTI2_3_IRQn)函數(shù)后才能響應(yīng)新的報警信號呢?
可以肯定,理論上講,開啟某個中斷響應(yīng)無須2次運(yùn)行相關(guān)函數(shù)。我們來一起找找原因。為了便于查看代碼,我把中斷服務(wù)程序和主程序代碼截圖放在一起。
在中斷服務(wù)程序里就是清除中斷請求標(biāo)志,關(guān)閉PA3的外部中斷響應(yīng),并設(shè)置警情標(biāo)志EXTI_Sign為1。
這里有沒有問題呢?
他使用的HAL_NVIC_EnableIRQ(EXTI2_3_IRQn)函數(shù),關(guān)閉的是內(nèi)核對該中斷請求的響應(yīng),盡管他剛才在進(jìn)中斷時做外部中斷請求標(biāo)志的清零,但并不能保證他這個清零操作之后不會再產(chǎn)生外部中斷請求。事實(shí)上,結(jié)合目前的使用場景,由于報警信號是一串跳變脈沖,即使一進(jìn)中斷就先做了個中斷請求標(biāo)志的清零,在中斷退出甚至還未完全退出時大概率還會產(chǎn)生新的中斷請求,但又由于他在中斷服務(wù)程序里把中斷響應(yīng)關(guān)閉了,中斷不能得到及時響應(yīng),請求只能懸著【Pending】跟隨程序來到主循環(huán)。
主循環(huán)代碼首先檢查報警標(biāo)志是否生效,生效則進(jìn)入循環(huán)體,先靜靜地歇會兒【HAL_Delay(Period)】,讓剛才的報警信號完全消停下來,然后再調(diào)用第一個HAL_NVIC_EnableIRQ(EXTI2_3_IRQn)函數(shù)打開中斷響應(yīng)。這下可好,剛才候著的中斷請求得到響應(yīng)機(jī)會了,則馬上去執(zhí)行中斷服務(wù)程序。這次在中斷服務(wù)程序里的操作跟上次完全一樣,即在中斷服務(wù)程序里,又調(diào)用中斷響應(yīng)關(guān)閉函數(shù),做了跟剛才主循環(huán)里第一個HAL_NVIC_EnableIRQ(EXTI2_3_IRQn)函數(shù)完全相反的功能。即到這個點(diǎn)的時候,中斷響應(yīng)被關(guān)閉了。
如果中斷返回后沒有使用第2句HAL_NVIC_EnableIRQ(EXTI2_3_IRQn)函數(shù)打開中斷響應(yīng),而只是執(zhí)行那句清零報警標(biāo)志然后退出循環(huán)體。由于中斷響應(yīng)已經(jīng)關(guān)閉,不管外部怎么報警都不會得到響應(yīng),報警標(biāo)志也就永遠(yuǎn)不會被置1,這樣主循環(huán)體也進(jìn)不了內(nèi)循環(huán)來開啟中斷響應(yīng)。
如果有了第2句HAL_NVIC_EnableIRQ(EXTI2_3_IRQn)函數(shù)在循環(huán)體內(nèi),它就可以扭轉(zhuǎn)剛才在中斷服務(wù)程序里關(guān)閉外部中斷響應(yīng)的局面,即把它扳回來。這樣的話功能上至少能正常運(yùn)轉(zhuǎn)了。
原因基本就大致這么回事?;诂F(xiàn)有代碼寫法,如何破除這個連寫2次的搞法呢。其實(shí),我們只需要在主循環(huán)體內(nèi)開啟外部中斷響應(yīng)的函數(shù)前,延時等待函數(shù)之后加上對相關(guān)中斷請求標(biāo)志位的清零即可解決當(dāng)前困惑。
比如像下面這樣【其中DSB是個數(shù)據(jù)同步隔離指令,保障它前面的指令執(zhí)行完畢后才執(zhí)行它后面的】,在主循環(huán)內(nèi)開啟中斷響應(yīng)前,先做中斷請求標(biāo)志的清零。
while(1)
{
if(EXTI_Sign==1)
{
HAL_Delay(Period);
__HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_PIN_3); __HAL_GPIO_EXTI_CLEAR_FALLING_IT(GPIO_PIN_3);
__DSB();
HAL_NVIC_EnableIRQ(EXTI2_3_IRQn);
EXTI_Sign=0;
。。。。。。
}
}
OK,本話題就聊到這里,愿君有所獲。類似問題不論STM32新手還是老手都可能不期而遇,祝君好運(yùn)!
-
STM32
+關(guān)注
關(guān)注
2270文章
10904瀏覽量
356367 -
中斷
+關(guān)注
關(guān)注
5文章
899瀏覽量
41529 -
程序
+關(guān)注
關(guān)注
117文章
3788瀏覽量
81105 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4333瀏覽量
62699 -
代碼
+關(guān)注
關(guān)注
30文章
4791瀏覽量
68694
原文標(biāo)題:聊聊一個STM32中斷處理問題
文章出處:【微信號:stmcu832,微信公眾號:茶話MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論