中斷分類
STM32的EXTI控制器支持19 個(gè)外部中斷/ 事件請(qǐng)求。每個(gè)中斷設(shè)有狀態(tài)位,每個(gè)中斷/ 事件都有獨(dú)立的觸發(fā)和屏蔽設(shè)置。
STM32的19個(gè)外部中斷對(duì)應(yīng)著19路中斷線,分別是EXTI_Line0-EXTI_Line18:
線0~15:對(duì)應(yīng)外部 IO口的輸入中斷。
線16:連接到 PVD 輸出。
線17:連接到 RTC 鬧鐘事件。
線18:連接到 USB 喚醒事件。
觸發(fā)方式:STM32 的外部中斷是通過(guò)邊沿來(lái)觸發(fā)的,不支持電平觸發(fā)。
外部中斷分組:STM32 的每一個(gè)GPIO都能配置成一個(gè)外部中斷觸發(fā)源,STM32 通過(guò)根據(jù)引腳的序號(hào)不同將眾多中斷觸發(fā)源分成不同的組,比如:PA0,PB0,PC0,PD0,PE0,PF0,PG0為第一組,那么依此類推,我們能得出一共有16 組,STM32 規(guī)定,每一組中同時(shí)只能有一個(gè)中斷觸發(fā)源工作,那么,最多工作的也就是16個(gè)外部中斷。
寄存器組
EXTICR寄存器組,總共有4
個(gè),因?yàn)榫幾g器的寄存器組都是從0 開(kāi)始編號(hào)的,所以EXTICR[0]~ EXTICR[3],對(duì)應(yīng)《STM32參考手冊(cè)》里的
EXTICR1~ EXTICR 4(查了好久才搞明白這個(gè)數(shù)組的含義!!)。每個(gè)
EXTICR只用了其低16 位。
EXTICR[0]
~EXTICR[3]的分配如下:
EXTI寄存器的結(jié)構(gòu)體:
typedef struct
{
vu32 IMR;
vu32 EMR;
vu32 RTSR;
vu32 FTSR;
vu32 SWIER;
vu32 PR;
} EXTI_TypeDef;
IMR:中斷屏蔽寄存器
這是一個(gè) 32 寄存器。但是只有前 19 位有效。當(dāng)位 x 設(shè)置為1 時(shí),則開(kāi)啟這個(gè)線上的中斷,否則關(guān)閉該線上的中斷。
EMR:事件屏蔽寄存器
同IMR ,只是該寄存器是針對(duì)事件的屏蔽和開(kāi)啟。
RTSR:上升沿觸發(fā)選擇寄存器
該寄存器同IMR ,也是一個(gè)32為的寄存器,只有前 19位有效。位 x 對(duì)應(yīng)線x 上的上升沿觸發(fā),如果設(shè)置為 1 ,則是允許上升沿觸發(fā)中斷/ 事件。否則,不允許。
FTSR:下降沿觸發(fā)選擇寄存器
同 PTSR,不過(guò)這個(gè)寄存器是設(shè)置下降沿的。下降沿和上升沿可以被同時(shí)設(shè)置,這樣就變成了任意電平觸發(fā)了。
SWIER:軟件中斷事件寄存器
通過(guò)向該寄存器的位x 寫(xiě)入 1 ,在未設(shè)置 IMR 和EMR的時(shí)候,將設(shè)置PR中相應(yīng)位掛起。如果設(shè)置了IMR 和EMR時(shí)將產(chǎn)生一次中斷。被設(shè)置的SWIER位,將會(huì)在PR中的對(duì)應(yīng)位清除后清除。
PR:掛起寄存器
0 ,表示對(duì)應(yīng)線上沒(méi)有發(fā)生觸發(fā)請(qǐng)求。
1,表示外部中斷線上發(fā)生了選擇的邊沿事件。通過(guò)向該寄存器的對(duì)應(yīng)位寫(xiě)入
1 可以清除該位。
在中斷服務(wù)函數(shù)里面經(jīng)常會(huì)要向該寄存器的對(duì)應(yīng)位寫(xiě)1 來(lái)清除中斷請(qǐng)求。
Ex_NVIC_Config基本是按照這個(gè)結(jié)構(gòu)來(lái)編寫(xiě)的
中斷配置步驟
STM32的每個(gè)IO口都可以作為中斷輸入,這點(diǎn)很好用。要把IO口作為外部中斷輸入,有以下幾個(gè)步驟:
1)初始化IO口為輸入。
這一步設(shè)置你要作為外部中斷輸入的IO口的狀態(tài),可以設(shè)置為上拉/下拉輸入,也可以設(shè)置為浮空輸入,但浮空的時(shí)候外部一定要帶上拉,或者下拉電阻。否則可能導(dǎo)致中斷不停的觸發(fā)。在干擾較大的地方,就算使用了上拉/下拉,也建議使用外部上拉/下拉電阻,這樣可以一定程度防止外部干擾帶來(lái)的影響。
2)開(kāi)啟IO口復(fù)用時(shí)鐘,設(shè)置IO口與中斷線的映射關(guān)系。
STM32的IO口與中斷線的對(duì)應(yīng)關(guān)系需要配置外部中斷配置寄存器EXTICR,這樣我們要先開(kāi)啟復(fù)用時(shí)鐘,然后配置IO口與中斷線的對(duì)應(yīng)關(guān)系。才能把外部中斷與中斷線連接起來(lái)。
3)開(kāi)啟與該IO口相對(duì)的線上中斷/事件,設(shè)置觸發(fā)條件。
這一步,我們要配置中斷產(chǎn)生的條件,STM32可以配置成上升沿觸發(fā),下降沿觸發(fā),或者任意電平變化觸發(fā),但是不能配置成高電平觸發(fā)和低電平觸發(fā)。這里根據(jù)自己的實(shí)際情況來(lái)配置。同時(shí)要開(kāi)啟中斷線上的中斷,這里需要注意的是:如果使用外部中斷,并設(shè)置該中斷的EMR位的話,會(huì)引起軟件仿真不能跳到中斷,而硬件上是可以的。而不設(shè)置EMR,軟件仿真就可以進(jìn)入中斷服務(wù)函數(shù),并且硬件上也是可以的。建議不要配置EMR位。
4)配置中斷分組(NVIC),并使能中斷。
這一步,我們就是配置中斷的分組,以及使能,對(duì)STM32的中斷來(lái)說(shuō),只有配置了NVIC的設(shè)置,并開(kāi)啟才能被執(zhí)行,否則是不會(huì)執(zhí)行到中斷服務(wù)函數(shù)里面去的。關(guān)于NVIC的詳細(xì)介紹,請(qǐng)參考前面章節(jié)。
5)編寫(xiě)中斷服務(wù)函數(shù)。
這是中斷設(shè)置的最后一步,中斷服務(wù)函數(shù),是必不可少的,如果在代碼里面開(kāi)啟了中斷,但是沒(méi)編寫(xiě)中斷服務(wù)函數(shù),就可能引起硬件錯(cuò)誤,從而導(dǎo)致程序崩潰!所以在開(kāi)啟了某個(gè)中斷后,一定要記得為該中斷編寫(xiě)服務(wù)函數(shù)。在中斷服務(wù)函數(shù)里面編寫(xiě)你要執(zhí)行的中斷后的操作。
實(shí)驗(yàn)4--外部中斷實(shí)驗(yàn)exit.c函數(shù)如下:
- #include "exti.h"
- #include "led.h"
- #include "key.h"
- #include "delay.h"
- #include "usart.h"
-
- //外部中斷0服務(wù)程序
- void EXTI0_IRQHandler(void)
- {
- delay_ms(10);//消抖
- if(KEY2==1) //按鍵2
- {
- LED0=!LED0;
- LED1=!LED1;
- }
- EXTI->PR=1<<0; //清除LINE0上的中斷標(biāo)志位
- }
-
- //外部中斷15~10服務(wù)程序
- void EXTI15_10_IRQHandler(void)
- {
- delay_ms(10); //消抖
- if(KEY0==0) //按鍵0
- {
- LED0=!LED0;
- }else if(KEY1==0)//按鍵1
- {
- LED1=!LED1;
- }
- EXTI->PR=1<<13; //清除LINE13上的中斷標(biāo)志位
- EXTI->PR=1<<15; //清除LINE15上的中斷標(biāo)志位
- }
- //外部中斷初始化程序
- //初始化PA0,PA13,PA15為中斷輸入.
- void EXTIX_Init(void)
- {
- RCC->APB2ENR|=1<<2; //使能PORTA時(shí)鐘
- JTAG_Set(JTAG_SWD_DISABLE);//關(guān)閉JTAG和SWD
-
- GPIOA->CRL&=0XFFFFFFF0;//PA0設(shè)置成輸入
- GPIOA->CRL|=0X00000008;
- GPIOA->CRH&=0X0F0FFFFF;//PA13,15設(shè)置成輸入
- GPIOA->CRH|=0X80800000;
- GPIOA->ODR|=1<<13; //PA13上拉,PA0默認(rèn)下拉
- GPIOA->ODR|=1<<15; //PA15上拉
-
- Ex_NVIC_Config(GPIO_A,0,RTIR); //上升沿觸發(fā)
- Ex_NVIC_Config(GPIO_A,13,FTIR);//下降沿觸發(fā)
- Ex_NVIC_Config(GPIO_A,15,FTIR);//下降沿觸發(fā)
-
- MY_NVIC_Init(2,2,EXTI0_IRQChannel,2); //搶占2,子優(yōu)先級(jí)2,組2
- MY_NVIC_Init(2,1,EXTI15_10_IRQChannel,2);//搶占2,子優(yōu)先級(jí)1,組2
- }
其中的兩個(gè)函數(shù):Ex_NVIC_Config(GPIO_A,0,RTIR);和MY_NVIC_Init(2,2,EXTI0_IRQChannel,2);這兩個(gè)函數(shù)都是在sys.c里定義,分別完成了步驟2、3、4.函數(shù)原型如下:
- //外部中斷配置函數(shù)
- //只針對(duì)GPIOA~G;不包括PVD,RTC和USB喚醒這三個(gè)
- //參數(shù):GPIOx:0~6,代表GPIOA~G;BITx:需要使能的位;TRIM:觸發(fā)模式,1,下升沿;2,上降沿;3,任意電平觸發(fā)
- //該函數(shù)一次只能配置1個(gè)IO口,多個(gè)IO口,需多次調(diào)用
- //該函數(shù)會(huì)自動(dòng)開(kāi)啟對(duì)應(yīng)中斷,以及屏蔽線
- //待測(cè)試...
- void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)
- {
- u8 EXTADDR;
- u8 EXTOFFSET;
- EXTADDR=BITx/4;//得到中斷寄存器組的編號(hào)
- EXTOFFSET=(BITx%4)*4;
-
- RCC->APB2ENR|=0x01;//使能io復(fù)用時(shí)鐘
-
- AFIO->EXTICR[EXTADDR]&=~(0x000F<<EXTOFFSET);//清除原來(lái)設(shè)置!??!
- AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET;//EXTI.BITx映射到GPIOx.BITx
-
- //自動(dòng)設(shè)置
- EXTI->IMR|=1<<BITx;// 開(kāi)啟line BITx上的中斷
- //EXTI->EMR|=1<<BITx;//不屏蔽line BITx上的事件 (如果不屏蔽這句,在硬件上是可以的,但是在軟件仿真的時(shí)候無(wú)法進(jìn)入中斷!)
- if(TRIM&0x01)EXTI->FTSR|=1<<BITx;//line BITx上事件下降沿觸發(fā)
- if(TRIM&0x02)EXTI->RTSR|=1<<BITx;//line BITx上事件上升降沿觸發(fā)
- }
這個(gè)函數(shù)完成了兩個(gè)步驟:
2、開(kāi)啟IO口復(fù)用時(shí)鐘,設(shè)置IO口與中斷線的映射關(guān)系
3、開(kāi)啟與該IO口相對(duì)的線上的中斷/時(shí)間,設(shè)置觸發(fā)條件
- //設(shè)置NVIC
- //NVIC_PreemptionPriority:搶占優(yōu)先級(jí)
- //NVIC_SubPriority :響應(yīng)優(yōu)先級(jí)
- //NVIC_Channel :中斷編號(hào)
- //NVIC_Group :中斷分組 0~4
- //注意優(yōu)先級(jí)不能超過(guò)設(shè)定的組的范圍!否則會(huì)有意想不到的錯(cuò)誤
- //組劃分:
- //組0:0位搶占優(yōu)先級(jí),4位響應(yīng)優(yōu)先級(jí)
- //組1:1位搶占優(yōu)先級(jí),3位響應(yīng)優(yōu)先級(jí)
- //組2:2位搶占優(yōu)先級(jí),2位響應(yīng)優(yōu)先級(jí)
- //組3:3位搶占優(yōu)先級(jí),1位響應(yīng)優(yōu)先級(jí)
- //組4:4位搶占優(yōu)先級(jí),0位響應(yīng)優(yōu)先級(jí)
- //NVIC_SubPriority和NVIC_PreemptionPriority的原則是,數(shù)值越小,越優(yōu)先
- //CHECK OK
- //100329
- void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)
- {
- u32 temp;
- u8 IPRADDR=NVIC_Channel/4; //每組只能存4個(gè),得到組地址
- u8 IPROFFSET=NVIC_Channel%4;//在組內(nèi)的偏移
- IPROFFSET=IPROFFSET*8+4; //得到偏移的確切位置
- MY_NVIC_PriorityGroupConfig(NVIC_Group);//設(shè)置分組
- temp=NVIC_PreemptionPriority<<(4-NVIC_Group);
- temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
- temp&=0xf;//取低四位
-
- if(NVIC_Channel<32)NVIC->ISER[0]|=1<<NVIC_Channel;//使能中斷位(要清除的話,相反操作就OK)
- else NVIC->ISER[1]|=1<<(NVIC_Channel-32);
- NVIC->IPR[IPRADDR]|=temp<<IPROFFSET;//設(shè)置響應(yīng)優(yōu)先級(jí)和搶斷優(yōu)先級(jí)
這個(gè)函數(shù)完成了:
4、配置中斷分組(NVIC),并使能中斷
補(bǔ)充
在實(shí)驗(yàn)18--觸摸屏實(shí)驗(yàn)中,中斷初始化沒(méi)有調(diào)用這個(gè)函數(shù),它是這樣配置的:
- MY_NVIC_Init(2,0,EXTI1_IRQChannel,2);
- RCC->APB2ENR|=0x01; //使能io復(fù)用時(shí)鐘
- AFIO->EXTICR[0]|=0X0020; //EXTI1映射到PC1(這句原子的程序里注釋錯(cuò)了搞成了EXTI13)
- EXTI->IMR|=1<<1; //開(kāi)啟line1上的中斷
- EXTI->EMR|=1<<1; //不屏蔽line1上的事件
- EXTI->FTSR|=1<<1; //line1上事件下降沿觸發(fā)
RCC->APB2ENR|=0x01; 這一句是開(kāi)啟復(fù)用時(shí)鐘,什么時(shí)候需要開(kāi)啟復(fù)用時(shí)鐘?手冊(cè)有這樣一段:
也就是說(shuō)只要操作EVCR、EXTICRX、MAPR的時(shí)候,就必須開(kāi)啟復(fù)用功能時(shí)鐘,即當(dāng)你要配置stm32的事件輸出、外部中斷、重映射的時(shí)候.就必須開(kāi)啟復(fù)用時(shí)鐘。
AFIO->EXTICR[0]|=0X0020; //EXTI1映射到PC1
這一句設(shè)置中斷映射,如上文所說(shuō)EXTICR[0]~ EXTICR[3] 對(duì)應(yīng) EXTICR1~ EXTICR4,舉例:
AFIO->EXTICR[3] &= 0xFFFFFF0F;
AFIO->EXTICR[3] |= 0xFFFFFF0F; //EXTI13映射到PA13,0(即0x00)代表A口,1(即0x01)代表B口,依次類推,6(即0x0110)代表G口.
AFIO->EXTICR[3] &= 0xFFFFFF0F;
AFIO->EXTICR[3] |= 0xFFFFFF2F; //EXIT13映射到PC13,2(0x0010)代表C口
外部中斷函數(shù)不能進(jìn)入的原因分析分析,可能為以下幾個(gè)方面:
1)GPIO或者AFIO的時(shí)鐘沒(méi)有開(kāi)啟;
2)GPIO和配置的中斷線路不匹配;
3)中斷觸發(fā)方式和實(shí)際不相符合;
4)中斷處理函數(shù)用庫(kù)函數(shù)時(shí),寫(xiě)錯(cuò),經(jīng)常可能出現(xiàn)數(shù)字和字母之間沒(méi)有下劃線;
5)外部中斷是沿觸發(fā),有可能檢測(cè)不到沿,比如中斷線是低電平(浮空輸入),觸發(fā)是下降沿觸發(fā),可能會(huì)出現(xiàn)一直是低電平,高電平的時(shí)候是一樣的情況,電平持續(xù) 為高電平;
6)沒(méi)有用軟件中斷來(lái)觸發(fā)外部中斷,調(diào)用函數(shù)EXTI_GenerateSWInterrupt;,因?yàn)檐浖袛嘞扔谶呇刂袛嗵幚怼?/span>
|