案例代碼及相關(guān)資料下載鏈接:
鏈接:https://pan.baidu.com/s/1hsIibEmsB91xFclJd-YTYA?pwd=jauj?
提取碼:jauj??
1?中斷系統(tǒng)
1.1??中斷的概念
中斷系統(tǒng)的定義:中斷是指在主程序運(yùn)行過(guò)程中,出現(xiàn)了特定的中斷觸發(fā)條件(中斷源),使得CPU暫停當(dāng)前正在運(yùn)行的程序,轉(zhuǎn)而去處理中斷程序,處理完成后又返回原來(lái)被暫停的位置繼續(xù)運(yùn)行。
通俗來(lái)講中斷就是主程序在正常運(yùn)行時(shí),出現(xiàn)了中斷觸發(fā)條件,而中斷觸發(fā)的條件有很多:對(duì)于外部中斷來(lái)講可能是引腳的電平發(fā)生變化;對(duì)于定時(shí)器來(lái)講可能是定時(shí)的時(shí)間到了;對(duì)于串口通信來(lái)講可能是接收到了數(shù)據(jù),當(dāng)以上事件發(fā)生時(shí),程序的執(zhí)行就會(huì)從主程序中跳到中斷程序中來(lái)執(zhí)行中斷程序,直到中斷程序執(zhí)行完成之后才會(huì)重新執(zhí)行主程序。而使用中斷系統(tǒng)最大的作用就是能夠極大的提升程序的運(yùn)行效率。
中斷優(yōu)先級(jí):中斷優(yōu)先級(jí)建立在有多個(gè)中斷源的時(shí)候,當(dāng)有多個(gè)中斷源出現(xiàn)時(shí),CPU就要考慮率先執(zhí)行哪個(gè)中斷,中斷就像做一件事的輕重比例,當(dāng)有很多事情堆到眼前時(shí)候,通常先做情況最緊急的,再做稍次一點(diǎn)的,這樣就會(huì)給中斷確立執(zhí)行的先后順序,而多個(gè)中斷的執(zhí)行順序的先后就被叫做中斷優(yōu)先級(jí)。
中斷嵌套:當(dāng)一個(gè)中斷程序正在運(yùn)行時(shí),又有新的更高優(yōu)先級(jí)的中斷源申請(qǐng)中斷,CPU再次暫停當(dāng)前中斷程序,轉(zhuǎn)而去處理新的中斷程序,處理完成后依次進(jìn)行返回,而中斷嵌套的執(zhí)行通常是由中斷優(yōu)先級(jí)來(lái)確定的。中斷嵌套可以理解將一堆要做的事慢慢一個(gè)一個(gè)拋給你,而你要根據(jù)每個(gè)事情的緊急程度來(lái)決定在已經(jīng)有的事情里先做哪一個(gè)。
中斷執(zhí)行的流程如下圖所示:
在我們學(xué)習(xí)的STM32?中有68個(gè)可屏蔽中斷通道(中斷源),包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多個(gè)外設(shè)(68個(gè)中斷源是F1系列中最多的,而對(duì)于某個(gè)具體型號(hào)可能并沒(méi)有這么多,所以中斷源的數(shù)量以單片機(jī)的數(shù)據(jù)手冊(cè)為準(zhǔn)),這些中斷源都使用NVIC統(tǒng)一管理中斷,每個(gè)中斷通道都擁有16個(gè)可編程的優(yōu)先等級(jí),可對(duì)優(yōu)先級(jí)進(jìn)行分組,進(jìn)一步設(shè)置搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)。(具體中斷源如下表所示灰色部分為內(nèi)核中斷,不是灰色部分的為STM32的外設(shè)中斷,具體圖標(biāo)手冊(cè)中有)
NVIC結(jié)構(gòu):
基本結(jié)構(gòu)圖如下圖所示:
NVIC的全稱是Nested vectoredinterrupt controller,即嵌套向量中斷控制器,在STM32中NVIC用來(lái)統(tǒng)一分配中斷優(yōu)先級(jí)和管理中斷的,他是單片機(jī)內(nèi)核外設(shè),是用來(lái)幫助CPU處理中斷分配和配置中斷優(yōu)先級(jí)的地方(為了讓CPU高速運(yùn)行),因?yàn)镹VIC有多個(gè)輸入口,所以能將單片機(jī)的外設(shè)中斷都來(lái)接到NVIC上,而NVIC只有一個(gè)輸出口這樣就能通過(guò)對(duì)中斷優(yōu)先級(jí)的設(shè)置,來(lái)輸出中斷優(yōu)先級(jí)高的,然后交給CPU讓CPU優(yōu)先執(zhí)行中斷優(yōu)先級(jí)高的程序,這就是NVIC的基本作用。
NVIC優(yōu)先級(jí)分組:
為了處理不同形式的優(yōu)先級(jí),NVIC會(huì)有優(yōu)先級(jí)進(jìn)行分組,而NVIC的中斷優(yōu)先級(jí)由優(yōu)先級(jí)寄存器的4位(0~15)決定,這4位可以進(jìn)行切分,分為高n位的搶占優(yōu)先級(jí)和低4-n位的響應(yīng)優(yōu)先級(jí),其屬性編號(hào)越小,表明它的優(yōu)先級(jí)別越高。搶占優(yōu)先級(jí),是指打斷其他中斷的屬性,即因?yàn)榫哂羞@個(gè)屬性會(huì)出現(xiàn)嵌套中斷(在執(zhí)行中斷服務(wù)函數(shù)A 的過(guò)程中被中斷B 打斷,執(zhí)行完中斷服務(wù)函數(shù)B 再繼續(xù)執(zhí)行中斷服務(wù)函數(shù)A),搶占屬性由NVIC 的參數(shù)配置。而響應(yīng)屬性則應(yīng)用在搶占屬性相同的情況下,當(dāng)兩個(gè)中斷向量的搶占優(yōu)先級(jí)相同時(shí),如果兩個(gè)中斷同時(shí)到達(dá), 則先處理響應(yīng)優(yōu)先級(jí)高的中斷,搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)均相同的按中斷號(hào)排隊(duì),數(shù)字小的先響應(yīng)。(中斷號(hào)是指上圖中優(yōu)先級(jí)的序號(hào))
優(yōu)先級(jí)的分組方式如下圖所示:
注意在配置好NVIC的分組方式之后,配置優(yōu)先級(jí)時(shí),取值不能超過(guò)對(duì)應(yīng)NVIC分組的取值范圍。
1.2??外部中斷的簡(jiǎn)介與配置
外部中斷簡(jiǎn)介:
EXTI(Extern Interrupt)外部中斷,EXTI可以監(jiān)測(cè)指定GPIO口的電平信號(hào),當(dāng)其指定的GPIO口產(chǎn)生電平變化時(shí),EXTI將立即向NVIC發(fā)出中斷申請(qǐng),經(jīng)過(guò)NVIC裁決后即可中斷CPU主程序,使CPU執(zhí)行EXTI對(duì)應(yīng)的中斷程序。
其觸發(fā)方式有上升沿,下降沿,雙邊沿,軟件觸發(fā)四種。EXTI支持所有的GPIO口都可以觸發(fā)中斷,但是相同的Pin_不可以同時(shí)觸發(fā)中斷,例如PA1與PB1不能同時(shí)觸發(fā)中斷。EXTI有20個(gè)通道數(shù),說(shuō)明EXTI可以有20個(gè)中斷源,其中包括16個(gè)GPIO_Pin,外加PVD輸出、RTC鬧鐘、USB喚醒、以太網(wǎng)喚
醒;而EXTI響應(yīng)方式有中斷響應(yīng)(申請(qǐng)中斷讓CPU執(zhí)行中斷函數(shù)),事件響應(yīng)(中斷響應(yīng)時(shí),外部中斷信號(hào)不會(huì)傳向CPU而是給到單片機(jī)外設(shè),讓單片機(jī)外設(shè)響應(yīng)一個(gè)事件)。
外部中斷的基本結(jié)構(gòu):
結(jié)構(gòu)圖如下圖所示:
最左邊是GPIO口的外設(shè),由于每個(gè)GPIO都有16個(gè)通道當(dāng)每個(gè)GPIO的引腳都占用一個(gè)那么EXTI的通道就會(huì)不夠用,為了讓相同的Pin_不同時(shí)觸發(fā)中斷,所以就有AFIO用來(lái)進(jìn)行中斷引腳的選擇,相當(dāng)于一個(gè)數(shù)據(jù)選擇器,他可以從前面N個(gè)GPIO的16個(gè)引腳中選擇其中一個(gè)接到后面的EXTI通道里面,所以就會(huì)有上面說(shuō)的相同的Pin_不可以同時(shí)觸發(fā)中斷,因?yàn)閷?duì)于相同的Pin_在經(jīng)過(guò)AFIO之后只會(huì)有一個(gè)Pin_接到后面的EXTI通道上,例如:PA0,PB0,PC0,PD0,只有一個(gè)Pin_0可以接到EXTI的通道0上。而以上GPIO引腳通過(guò)EXTI上之后,就會(huì)分為兩種輸出,一種接到NVIC上,一種接到單片機(jī)外設(shè)上(也是對(duì)應(yīng)的事件響應(yīng)),這里EXTI的輸出本來(lái)為20個(gè)但是由于ST公司想要節(jié)省引腳口,所以EXTI4之后的中斷被五個(gè)為一組分在同一個(gè)通道里,所以EXTI5~9會(huì)觸發(fā)同一個(gè)中斷函數(shù),EXTI10~15觸發(fā)同一個(gè)中斷函數(shù),但是基于Hal庫(kù)開(kāi)發(fā)的STM32將這些中斷函數(shù)寫在了一起,所以所有中斷通道都可以寫在同一個(gè)中斷函數(shù)里面,但是標(biāo)準(zhǔn)庫(kù)必須根據(jù)不同的中斷通道來(lái)判斷到底能不能寫在一起。
AFIO口的結(jié)構(gòu)圖如下:
此圖原理就是將輸入的不同GPIO相同的Pin_通過(guò)數(shù)據(jù)選擇器來(lái)進(jìn)行選擇,最后只選擇一個(gè)Pin_來(lái)接到EXTI通道上,具體如何選擇就是通過(guò)配置AFIO_EXTRCRX寄存器的EXTIx位來(lái)進(jìn)行選擇,每個(gè)位代表不同的GPIO,這樣就能以確定的位來(lái)確定是哪個(gè)GPIO的引腳會(huì)接到EXTIX的通道上面。
AFIO主要用于引腳復(fù)用功能的選擇和重定義(數(shù)據(jù)選擇器),在STM32中,AFIO主要完成兩個(gè)任務(wù):復(fù)用功能引腳重映射、中斷引腳選擇。
?EXTI結(jié)構(gòu)圖
電平經(jīng)過(guò)AFIO之后進(jìn)入EXTI,首先要對(duì)該中斷源的觸發(fā)方式進(jìn)行選擇(上升沿觸發(fā)/下降沿觸發(fā)/雙邊沿觸發(fā))進(jìn)入或門的輸入,這里用或門進(jìn)行輸入的原因是因?yàn)橛|發(fā)方式也可以選擇是軟件觸發(fā),然后就會(huì)分成兩路,接到NVIC中斷控制器的是觸發(fā)中斷的,而接到脈沖發(fā)生器的是用來(lái)觸發(fā)事件的。
先看觸發(fā)中斷這一路的,這里接的請(qǐng)求掛起寄存器相當(dāng)于中斷標(biāo)志位,通過(guò)讀取這個(gè)寄存器判斷是哪個(gè)通道發(fā)出中斷請(qǐng)求,如果給請(qǐng)求掛起寄存器置1,那么就會(huì)和中斷屏蔽寄存器進(jìn)入一個(gè)與門,然后進(jìn)入NVIC中斷控制器,這里與門和這個(gè)中斷屏蔽寄存器相當(dāng)于一個(gè)開(kāi)關(guān)的作用,因?yàn)榕c門是如果輸入有一個(gè)為0,那么輸出一定為0,所以會(huì)通過(guò)控制中斷屏蔽寄存器來(lái)控制是否響應(yīng)中斷。
事件觸發(fā)這一路與中斷觸發(fā)大同小異,這里事件屏蔽寄存器和與門也充當(dāng)開(kāi)關(guān)的作用,通過(guò)與門之后接一個(gè)脈沖發(fā)生器,這個(gè)脈沖發(fā)生器的作用就是給一個(gè)電平脈沖是用來(lái)觸發(fā)其他外設(shè)的。
上圖中畫斜杠寫20的表示這里可以接20根線,連接20個(gè)通道,而APB總線和外設(shè)接口,單片機(jī)對(duì)于寄存器的訪問(wèn)就是借助APB總線來(lái)進(jìn)行。
2實(shí)驗(yàn)演示
2.1??旋轉(zhuǎn)編碼器的簡(jiǎn)介
旋轉(zhuǎn)編碼器:用來(lái)測(cè)量位置、速度或旋轉(zhuǎn)方向的裝置,當(dāng)其旋轉(zhuǎn)軸旋轉(zhuǎn)時(shí),其輸出端可以輸出與旋轉(zhuǎn)速度和方向?qū)?yīng)的方波信號(hào),讀取方波信號(hào)的頻率和相位信息即可得知旋轉(zhuǎn)軸的速度和方向,通常有以下幾種類型:機(jī)械觸點(diǎn)式/霍爾傳感器式/光柵式。
實(shí)物圖如下:
左邊第一個(gè)不能判斷不能判斷旋轉(zhuǎn)方向,只能測(cè)位置和速度所以不經(jīng)常使用,而剩下的就是我們本開(kāi)發(fā)板自帶的旋轉(zhuǎn)編碼器,由第三個(gè)拆解圖可得他內(nèi)部是通過(guò)金屬觸點(diǎn)來(lái)進(jìn)行通斷的,所以為機(jī)械式編碼器,有左右兩部分開(kāi)關(guān)觸點(diǎn),其中左右兩部分內(nèi)側(cè)較細(xì)的觸點(diǎn)是連接在引腳B上,而剩下外側(cè)的觸點(diǎn)分別連在引腳A和C上,而中間的圓點(diǎn)為一個(gè)普通的按鍵,然后來(lái)看這個(gè)編碼盤也是一系列像光柵一樣的東西,但也是金屬觸點(diǎn),在旋轉(zhuǎn)時(shí)依次接通和斷開(kāi)兩邊的觸點(diǎn),而金屬盤的位置也是經(jīng)過(guò)設(shè)計(jì)可以讓兩側(cè)觸點(diǎn)的通斷有九十度的相位差,
具體輸出波形如下方兩圖所示(上圖為正轉(zhuǎn)時(shí),下圖為反轉(zhuǎn)時(shí))以下這樣的正交波形就可以用來(lái)區(qū)別方向。
?硬件電路圖如下
2.2??對(duì)射式紅外傳感器計(jì)次
?接線圖如下:
實(shí)物圖如下:
實(shí)驗(yàn)內(nèi)容
本實(shí)驗(yàn)是對(duì)對(duì)射式紅外傳感的傳感次數(shù)進(jìn)行計(jì)次,通過(guò)用遮光片遮擋來(lái)對(duì)紅外傳感器傳輸進(jìn)行計(jì)次,然后通過(guò)OLED屏幕來(lái)顯示傳感次數(shù)。并且對(duì)于中斷觸發(fā)方式的不同,計(jì)次方式也不同。
首先,配置STMCube MX
將GPIO口用來(lái)實(shí)現(xiàn)外部中斷的配置為中斷模式即PB14,由于OLED也要繼續(xù)使用所以對(duì)OLED的引腳繼續(xù)配置為輸出模式即可:
在NVIC中勾選EXTI line[15:10] interrupts
對(duì)NVIC的中斷分組方式選擇方式2(哪一個(gè)隨自己選擇)
在GPIO這里對(duì)中斷觸發(fā)方式進(jìn)行選擇:
其他配置不變,生成工程即可。
代碼部分:
HAL庫(kù)關(guān)于外部中斷的函數(shù)只有一個(gè):
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
具體模板用法如下:
HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
? if(GPIO_Pin==GPIO_PIN_1)//判斷是哪個(gè)中斷源
? {
? //執(zhí)行中斷函數(shù)
? __HAL_GPIO_EXTI_CLEAR_IT ( GPIO_Pin);
//中斷結(jié)束標(biāo)志必須有不然會(huì)卡在中斷中不能進(jìn)入主程序
? }
//Hal庫(kù)中所有的中斷函數(shù)都在這一個(gè)函數(shù)中進(jìn)行
? if(GPIO_Pin==GPIO_PIN_3)
? {
? }
}
CountSensor部分代碼
#include "main.h"
#include "gpio.h"
uint16_t Consensor_count;
uint16_t ?CountSensor_Get(void)
{
? return Consensor_count;
}
/**
?* 函數(shù)功能: 外部中斷回調(diào)函數(shù)
?* 輸入?yún)?shù): GPIO_Pin:中斷引腳
?* 返 回 值: 無(wú)
?* 說(shuō) ? ?明: 無(wú)
?*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
?if(GPIO_Pin==CountSensor_Pin)
?{
? ?if(HAL_GPIO_ReadPin(CountSensor_GPIO_Port,CountSensor_Pin)== 1 ?)//下降沿有效計(jì)次即可
? ?{
? ? ?Consensor_count++;
? ?}
? ?__HAL_GPIO_EXTI_CLEAR_IT ( CountSensor_Pin);
?}
}
主函數(shù)部分代碼
OLED_Init ();
OLED_ShowString (1,1,"Count:");
while (1)
{
?OLED_ShowNum (1,7,CountSensor_Get (),5);//如果有新的下降沿出現(xiàn)直接覆蓋上一次的數(shù)字
}
2.3??旋轉(zhuǎn)編碼計(jì)次
接線圖如下圖所示:
實(shí)驗(yàn)內(nèi)容:
對(duì)旋轉(zhuǎn)編碼器旋轉(zhuǎn)進(jìn)行計(jì)次,正轉(zhuǎn)加加愛(ài),反轉(zhuǎn)減減,計(jì)得次數(shù)通過(guò)OLED來(lái)不斷刷新。
STM32CubeMX配置:
對(duì)旋轉(zhuǎn)編碼器連接的引腳PB0與PB1配置為外部中斷模式,給OLED連接的引腳PB8與PB9配置為輸出模式,在NVIC選擇分組方式,然后在下面勾選
EXTI line0 interrupt? ?EXTI line1 interrupt?。
然后在GPIO里配置IO口的觸發(fā)中斷方式與輸出模式,根據(jù)自身習(xí)慣來(lái)對(duì)IO口進(jìn)行宏定義。
配置完成后,生成工程。
代碼部分:
Encoder部分代碼:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-703861.html
#include "main.h"
#include "gpio.h"
uint16_t Encoder_Count;
uint16_t ?Encoder_Get(void)
{
? uint16_t Temp;
? Temp = Encoder_Count ;
? Encoder_Count = 0;
? return Temp ;
}
/**
?* 函數(shù)功能: 外部中斷回調(diào)函數(shù)
?* 輸入?yún)?shù): GPIO_Pin:中斷引腳
?* 返 回 值: 無(wú)
?* 說(shuō) ? ?明: 無(wú)
?*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
?if(GPIO_Pin==Count_Increase_Pin)//讀取中斷源
?{
? if(HAL_GPIO_ReadPin(Count_Increase_GPIO_Port ?, Count_Increase_Pin)==0 )
? {
? if(HAL_GPIO_ReadPin(Count_Decrease_GPIO_Port ?, Count_Decrease_Pin)== 0 )//旋轉(zhuǎn)編碼器向左轉(zhuǎn)時(shí)
? ? ?Encoder_Count--;
? ?}
? ?__HAL_GPIO_EXTI_CLEAR_IT ( Count_Increase_Pin);//消除中斷標(biāo)志,由中斷進(jìn)入主函數(shù)
?}
?else if(GPIO_Pin==Count_Decrease_Pin)
?{
? ? if(HAL_GPIO_ReadPin(Count_Decrease_GPIO_Port ?, Count_Decrease_Pin)== 0)
? ?{
? ? if(HAL_GPIO_ReadPin(Count_Increase_GPIO_Port ?, Count_Increase_Pin)== 0 )//旋轉(zhuǎn)編碼器向右轉(zhuǎn)時(shí)
? ? Encoder_Count++;
? ?}
? ?__HAL_GPIO_EXTI_CLEAR_IT ( Count_Decrease_Pin);//消除中斷標(biāo)志,由中斷進(jìn)入主函數(shù)
}
主函數(shù)部分代碼:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-703861.html
in16_t Num;
OLED_Init();
OLED_ShowString (1,1,"Count:");
while (1)
{
? /* USER CODE END WHILE */
? /* USER CODE BEGIN 3 */
? Num+=Encoder_Get();//時(shí)刻刷新計(jì)次
? OLED_ShowSignedNum(1,7,Num,5);
}
}
到了這里,關(guān)于【STM32教程】第四章 STM32的外部中斷EXTI的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!