NVIC和EXTI

NVICNest Vector Interrupt Controller,嵌套中斷向量控制器,是用來管理中斷嵌套的,核心任務在於其優先級的管理。NVIC給每個中斷賦予先佔優先級(搶佔優先級)和次佔優先級(響應優先級)。

CM3 內核支持256箇中斷,其中包含了16個內核中斷和240個外部中斷,並且具有256級的可編程中斷設置。但STM32並沒有使用CM3內核的全部東西,而是隻用了它的一部分,STM3276 箇中斷,包括16 個內核中斷和60 個可屏蔽中斷,具有16級可編程的中斷優先級。而我們常用的就是這60個可屏蔽中斷。

STM32CM3內核的中斷向量表進行了重新編排,將編號-36的中斷向量定義爲系統異常,編號爲負的內核異常不能被設置優先級,從編號7開始爲外部中斷,這些中斷優先級都是可以自行設置的。

EXTIExternal Interrupt,外部中斷,通過GPIO檢查輸入脈衝,引起中斷時間,打斷原來的代碼執行流程,進入到中斷服務函數中進行處理,處理完後再返回中斷之前的代碼中執行。

STM32 EXTI控制器支持19個外部中斷/事件請求。每個中斷設有狀態位,每個中斷/事件都有獨立的觸發和屏蔽設置。STM3219 個外部中斷爲 :
0~15:對應外部IO口的輸入中斷。
16:連接到PVD輸出。
17:連接到RTC鬧鐘事件。
18:連接到USB喚醒事件。

 

EXTI中斷步驟:

① 配置端口爲輸入模式

② 開啓與該IO口相對應的線上中斷/事件,並設置觸發條件

③ 配置中斷分組(NVIC)並使能中斷

④ 中斷函數

 

一、配置端口爲輸入模式

void GPIOA_Init(void)

{

   GPIO_DeInit(GPIOA);

RCC->APB2ENR|=1<<2;     //使能PORTA時鐘

GPIOA->CRL&=0XFFFFFFF0;//PA0設置成上拉輸入   

GPIOA->CRL|=0X00000008;   

}

在對端口進行任何操作之前,必須打開對應的時鐘信號,其設置才能生效。這裏使

用了GPIOA.00 端口作爲中斷0輸入,作爲輸入時一般我們設置爲上拉輸入,如果要

設置成浮空輸入的話,外部一定要加上拉電阻,這樣對於過濾輸入波動很有益處(

設在電壓在3.3-2.0之間進行波動,時間上沒嘗試按鍵操作,因爲一旦有按鍵,就應

該爲0,那麼接了上拉的話,除非產生了低電平,否則小波動都會被拉高過濾掉)

 

二、開啓與該IO口相對應的線上中斷/事件,並設置觸發條件

這一步封裝在函數void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)中,可以直接調用,例如:Ex_NVIC_Config(GPIO_A,0,RTIR); //設置PA0上升沿觸發

  Ex_NVIC_Config(GPIO_A,13,FTIR);//設置PA13)下降沿觸發

該函數爲 Ex_NVIC_Config,該函數有3個參數:GPIOxGPIOA~G0~6),在sys.h裏面有定義。代表要配置的IO口。BITx則代表這個IO口的第幾位。TRIM爲觸發方式,低2位有效(0x01代表下降觸發;0x02代表上升沿觸發;0x03代表任意電平觸發)。其代碼如下:
/**************************

該函數只針對GPIOA~G;不包括PVDRTCUSB喚醒這三個,參數:GPIOA~G0~6),代表GPIOA~G;BITx:需要使能的位;TRIM:觸發模式,1,上升沿;2,下降沿;3,任意電平觸發;該函數一次只能配置1IO 口,多個IO 口,需多次調用,該函數會自動開啓對應中斷,以及屏蔽線

***************************/

void Ex_NVIC_Config(u8 GPIOxu8 BITxu8 TRIM)
{

u8 EXTADDR;
u8 EXTOFFSET;
EXTADDR=BITx/4;//得到中斷寄存器組的編號
EXTOFFSET=(BITx%4)*4;
RCC->APB2ENR|=0x01;//使能IO複用時鐘
AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET;//EXTI.BITx映射到GPIOx.BITx
//自動設置
EXTI->IMR|=1<<BITx;//開啓line BITx上的中斷
EXTI->EMR|=1<<BITx;//不屏蔽lineBITx上的事件
if(TRIM&0x01)EXTI->FTSR|=1<<BITx;//lineBITx 上事件下降沿觸發
if(TRIM&0x02)EXTI->RTSR|=1<<BITx;//lineBITx 上事件上升降沿觸發
}

EXTICR(External interrupt configuration register)即外部中斷配置寄存器。

因爲STM32 任何一個IO口都可以配置成中斷輸入口,但是IO口的數目遠大於中斷線數(16個),所以我們需要選擇哪一個中斷是經由那個IO口輸入的。於是STM32就這樣設計,GPIOA~GPIOG[15:0]分別對應中斷線15~0。這樣每個中斷線對應了最多7IO 口,以線0爲例:它對應了GPIOA.0PIOB.0GPIOC.0GPIOD.0GPIOE.0GPIOF.0GPIOG.0。而中斷線每次只能連接到1IO 口上,這樣就需要EXTICR來決定對應的中斷線配置到哪個GPIO上了。寄存器EXTIR有四組,在書寫時要注意。具體對應關係如下:0000: PA[x] pin0001: PB[x] pin0010: PC[x] pin0011: PD[x] pin0100: PE[x] pin0101: PF[x] pin0110: PG[x] pin。假設我們需要設定外部中斷0GPIOA_0來控制,那麼我就可以寫成AFIO->EXTIR[0] |=0X00;  


Ex_NVIC_Config,首先根據GPIOx的位得到中斷寄存器組的編號,即EXTICR的編號,在EXTICR裏面配置中斷線應該配置到GPIOx的哪個位。然後使能該位的中斷及事件,最後配置觸發方式。這樣就完成了外部中斷的的配置了。從代碼中可以看到該函數默認是開啓中斷和事件的。其次還要注意的一點就是該函數一次只能配置一個IO口,如果你有多個IO口需要配置,則多次調用這個函數就可以了。

三、配置中斷分組(NVIC)並使能中斷

這一步封裝在函數void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)裏面可以直接調用,例如

MY_NVIC_Init(2,2,EXTI0_IRQChannel,2);    //搶佔2,子優先級2,組2
    NVIC 設置函數MY_NVIC_Init,該函數有4個參數,分別爲:NVIC_PreemptionPriorityNVIC_SubPriorityNVIC_ChannelNVIC_Group。第一個參數NVIC_PreemptionPriority爲中斷搶佔優先級數值,第二個參數NVIC_SubPriority爲中斷子優先級數值,前兩個參數的值必須在規定範圍內,否則也可能產生意想不到的錯誤。第三個參數NVIC_Channel爲中斷的編號(範圍爲0~59),最後一個參數NVIC_Group爲中斷分組設置(範圍爲0~4)。

/********************設置NVIC****************
*NVIC_PreemptionPriority:搶佔優先級
*//NVIC_SubPriority :響應優先級
*NVIC_Channel :中斷編號
*NVIC_Group :中斷分組 0~4
*注意優先級不能超過設定的組的範圍!否則會有意想不到的錯誤
*組劃分:
*0:0 位搶佔優先級,4 位響應優先級
*1:1 位搶佔優先級,3 位響應優先級
*2:2 位搶佔優先級,2 位響應優先級
*3:3 位搶佔優先級,1 位響應優先級
*4:4 位搶佔優先級,0 位響應優先級
*NVIC_SubPriority NVIC_PreemptionPriority的原則是,數值越小,越優先

************************************/
void MY_NVIC_Init(u8 NVIC_PreemptionPriorityu8 NVIC_SubPriorityu8NVIC_Channelu8 NVIC_Group)
{
  u32 temp;
  u8 IPRADDR=NVIC_Channel/4; //每組只能存4個,得到組地址
  u8 IPROFFSET=NVIC_Channel%4;//在組內的偏移
  IPROFFSET=IPROFFSET*8+4; //得到偏移的確切位置
  MY_NVIC_PriorityGroupConfig(NVIC_Group);//設置分組
  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;//設置響應優先級和搶斷優先級
}

MY_NVIC_PriorityGroupConfigNVIC的分組函數,該函數的參數NVIC_Group爲要設置的分組號,可選範圍爲0~4,總共5組:EXTI0EXTI1EXTI2EXTI3EXTI4Line0~Line4EXTI15_10Line15~Line10EXTI9_5Line9~Line5。如果參數非法,將可能導致不可預料的結果。

/***************設置NVIC分組*****************
*NVIC_Group:NVIC 分組 0~4總共5

************************************/

void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
{
  u32 temptemp1;
  temp1=(~NVIC_Group)&0x07;//取後三位

temp1<<=8;

temp=SCB->AIRCR; //讀取先前的設置

temp&=0X0000F8FF; //清空先前分組

temp|=0X05FA0000; //寫入鑰匙

temp|=temp1;

SCB->AIRCR=temp; //設置分組
}

MY_NVIC_PriorityGroupConfig 函數設置中斷優先級分組的思路:STM325 個分組是通過設置SCB->AIRCRBIT[10:8]來實現的,SCB->AIRCR的修改需要通過在高16位寫入0X05FA這個密鑰才能修改的,故在設置AIRCR之前,應該把密鑰加入到要寫入的內容的高16位,以保證能正常的寫入AIRCR。在修改AIRCR的時候,我們一般採用讀->->寫的步驟,來實現不改變AIRCR原來的其他設置。MY_NVIC_PriorityGroupConfig分組函數在每個系統裏面只要設置一次就夠了,設置多次,則是以最後的那一次爲準。但是隻要多次設置的組號都是一樣,就沒事。否則前面設置的中斷會因爲後面組的變化優先級會發生改變,這點在使用的時候要特別注意!一個系統代碼裏面,所有的中斷分組都要統一,以上代碼對要配置的中斷號默認是開啓中斷的。也就是ISER中的值設置爲1了。

四、中斷函數

A.  中斷函數名的書寫有要求,否則會找不到中斷入口。

stm32f10x_it.c是專門用來存放中斷服務函數的。

3.5 庫函數之前,在stm32f10x_it.c中就預先寫好了個外部中斷的函數名稱,我們只要將對應的執行過程填充進去就可以。

3.5庫函數中,文件中默認只有幾個福安與系統異常的中斷服務函數,而且都是空函數,在需要的時候自行編寫。但是中斷服務函數名是不可以自己定義,中斷服務函數的名字必須要與啓動文件startup_stm32f10x_hd.s中的中斷向量表中定義一致。

B. 在進入中斷後我們需要做的動作有 2 部,一次執行中斷過程,2 是清除中斷掛起標識,因爲執行完畢了。如果不清除中斷掛起標識,則無法再次進入中斷。

例程:

void EXTI0_IRQHandler(void)

{

 delayMs(10);

  if(((GPIOA->IDR)&0x01)==0)

 {

      while(((GPIOA->IDR)&0x01)==1);            

      GPIOA->ODR  = ~(GPIOA->ODR&0X02);

         EXTI->PR=1;    

   }     

}

這裏 EXTI->PR=1,即想中斷掛起寄存器中寫1,清除中斷

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章