STM32學習筆記(6)中斷優先級及EXTI外部中斷

中斷優先級分組(NVIC)

CM3 內核支持 256 箇中斷,其中包含了 16 個內核中斷和 240 個外部中斷,並且具有 256級的可編程中斷設置。但STM32 只有 其中84 箇中斷,包括 16 個內核中斷和 68 個可屏蔽中斷,具有 16 級可編程的中斷優先級。在 STM32F103 系列上面,又只有 60 個(在 107 系列有 68 個)。本文將對STM32F103 系列這 60 個可屏蔽中斷進行介紹。

相關寄存器介紹

ISER[8]:( Interrupt Set-Enable Registers),中斷使能寄存器組。由 8 個 32 位寄存器來控制,每個位控制一箇中斷。對於STM32F103,有用的就是兩個(ISER[0]ISER[1]), ISER[0]的 bit0~bit31 分別對應中斷 0~31。 ISER[1]的 bit0~27 對應中斷 32~59;要使能某個中斷,必須設置相應的 ISER 位爲 1。具體每一位對應哪個中斷,請參考 stm32f10x.h 裏面的第 140 行處(針對編譯器 MDK5 來說)。

ICER[8]:( Interrupt Clear-Enable Registers),中斷除能寄存器組。與 ISER 的作用相反,用來清除某個中斷的使能的。其對應位的功能,也和 ICER 一樣。這裏要專門設置一個 ICER 來清除中斷位(即寫1),而不是向 ISER 寫 0 來清除。

CM3 中可以有 240 對使能位/除能位,每個中斷擁有一對。這 240 個對子分佈在 8 對 32 位寄存器中(最後一對沒有用完)。欲使能一箇中斷,你需要寫 1 到對應 SETENA 的位中;欲除能一箇中斷,你需要寫 1 到對應的 CLRENA 位中;如果往它們中寫 0,不會有任何效果。通過這種方式,使能/除能中斷時只需把“當事位”寫成1,其它的位可以全部爲零。
防止有些位被寫入 0 而破壞其對應的中斷設置(寫 0 沒有效果),從而實現每個中斷都可以自顧地設置,而互不侵犯

ISPR[8]:( Interrupt Set-Pending Registers),中斷掛起控制寄存器組。每個位對應的中斷和 ISER 是一樣的。通過置 1,可以將正在進行的中斷掛起,而執行同級或更高級別的中斷。 (不常用)

ICPR[8]:( Interrupt Clear-Pending Registers),中斷解掛控制寄存器組。其作用與 ISPR 相反,對應位也和 ISER 是一樣的。通過設置 1,可以將掛起的中斷接掛。(不常用)

IABR[8]:( Interrupt Active Bit Registers),中斷激活標誌位寄存器組。對應位所代表的中斷和 ISER 一樣,如果爲 1,則表示該位所對應的中斷正在被執行。這是一個只讀寄存器,通過它可以知道當前在執行的中斷是哪一個。在中斷執行完了由硬件自動清零。 (不常用)

IP[240]:( Interrupt Priority Registers),中斷優先級控制寄存器組。 240 個 8bit 的寄存器組成,每個可屏蔽中斷佔用 8bit,總共表示 240 個可屏蔽中斷。 而 STM32 只用到了其中的前 60 個。 IP[59]~IP[0]分別對應中斷 59~0。 而每個可屏蔽中斷佔用的 8bit 並沒有全部使用,而是 只用了高 4 位。這 4 位,又分爲搶佔優先級和子優先級。搶佔優先級在前,子優先級在後。而這兩個優先級各佔幾個位又要根據 SCB>AIRCR 中的中斷分組設置來決定。

搶佔優先級和子優先級的解釋:
搶佔優先級:高優先級可打斷正在進行的低優先級。
子優先級:中斷同時發生,高優先級先執行。
若兩個中斷的兩種優先級相同,則先發生先執行。(值越低,優先級越高)

STM32 的中斷分組: STM32 將中斷分爲 5 個組,組 0~4。該分組的設置是由 SCB->AIRCR 寄存器的 bit10~8 來定義的。具體的分配關係 :
在這裏插入圖片描述

例如選擇2組,則每種優先級通過兩位來設置,則各有2^2,即0~3共4種等級差別。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_X); //X=0~4,該函數在系統中只能被調用一次來確定組別

優先級設定

設定相關的結構體:

typedef struct
{
uint8_t NVIC_IRQChannel;//定義初始化的是哪個中斷 
uint8_t NVIC_IRQChannelPreemptionPriority;//定義該中斷的搶佔優先級別。 
uint8_t NVIC_IRQChannelSubPriority;//定義該中斷的子優先級別。 
FunctionalState NVIC_IRQChannelCmd; //該中斷是否使能。 
} NVIC_InitTypeDef; 

以初始化串口 1 的中斷,同時設置搶佔優先級爲 1,子優先級位 2 爲例:

NVIC_InitTypeDef NVIC_InitStructure;//初始化相應結構體
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口 1 中斷對應名
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 搶佔優先級爲 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子優先級位 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道(中斷請求通道)使能
NVIC_Init(&NVIC_InitStructure); //根據上面指定的參數初始化 NVIC 寄存器 

EXIT外部中斷相關

概述

STM32每個IO口都可以作爲外部中斷輸入,其中斷控制器支持19個外部中斷/事件請求,分別爲:
線 0~15:對應外部 IO 口的輸入中斷。
線 16:連接到 PVD 輸出。
線 17:連接到 RTC 鬧鐘事件。
線 18:連接到 USB 喚醒事件。

對STM32的IO口,可分爲GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G)分別對應中斷線 0~15。這樣每個中斷線對應了最多 7 個 IO 口。如圖:(同一時刻,一組GPIO只能有一個IO口映射到中斷線)
在這裏插入圖片描述
中斷線對應中斷服務函數

EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler 

中斷控制器框圖

在這裏插入圖片描述

相關寄存器簡介

1.EXTI_IMR:中斷屏蔽寄存器,控制是否屏蔽來自線上的中斷請求;
2.EXTI_EMR:事件屏蔽寄存器,控制是否屏蔽來自線上的事件請求;

事件:是表示檢測到某一動作(電平邊沿)觸發事件發生了。
中斷:有某個事件發生併產生中斷,並跳轉到對應的中斷處理程序中。
事件只是一個觸發信號(脈衝),而中斷則是一個固定的電平信號 。

3.EXTI_RTSR:上升沿觸發選擇寄存器,控制是否允許輸入線x上的上升沿觸發(中斷和事件);
4. EXTI_FTSR:下降沿觸發選擇寄存器,控制是否允許輸入線x上的下降沿觸發(中斷和事件);
5.EXTI_SWIER:軟件中斷事件寄存器,當該位爲’0’時,寫’1’將設置EXTI_PR中相應的掛起位。如果在EXTI_IMR和EXTI_EMR中允許
產生該中斷,則此時將產生一箇中斷。
6.EXTI_PR:掛起寄存器,控制是否發生觸發請求;
寄存器相關位配置參考相關資料(中文參考手冊第九章)

EXIT_Init函數

相應結構體:

typedef struct
{
  uint32_t EXTI_Line;//指定配置的中斷線        
  EXTIMode_TypeDef EXTI_Mode;//中斷模式      
  EXTITrigger_TypeDef EXTI_Trigger; //觸發方式
  FunctionalState EXTI_LineCmd;//使能/失能    
}EXTI_InitTypeDef;

使用步驟

( 1)初始化 IO 口爲輸入。
(2)開啓 AFIO 時鐘
(3) 設置 IO 口與中斷線的映射關係。

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

(4)初始化線上中斷,設置觸發條件(上升沿觸發,下降沿觸發,邊沿觸發等)等。

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

(5)配置中斷分組(NVIC),並使能中斷。
(6)編寫中斷服務函數。

例:

void EXTIX_Init(void)//自定義相關初始化函數
{
 EXTI_InitTypeDef EXTI_InitStrue;//初始化相關結構體
 NVIC_InitTypeDef NVIC_InitStrue; 
 
 KEY_Init();//按鍵初始化,爲中斷服務函數準備
 
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//開啓AFIO時鐘 
  
 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);//設置 IO 口與中斷線的映射關係
 
 EXTI_InitStrue.EXTI_Line=EXTI_Line4;
 EXTI_InitStrue.EXTI_Mode=EXTI_Mode_Interrupt;
 EXTI_InitStrue.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿觸發
 EXTI_InitStrue.EXTI_LineCmd=ENABLE;
  EXTI_Init(&EXTI_InitStrue);//初始化線上中斷
 
 NVIC_InitStrue.NVIC_IRQChannel=EXTI4_IRQn;
 NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=2;
 NVIC_InitStrue.NVIC_IRQChannelSubPriority=2;
 NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;
 NVIC_Init(&NVIC_InitStrue);//初始化優先級設置
}
 
void EXTI4_IRQHandler(void)//相關中斷服務函數
{
 delay_ms(10);//防抖
 if(KEY0==0)//低電平被觸發
 {
 LED0=!LED0;
 LED1=!LED1;
  }
 EXTI_ClearITPendingBit(EXTI_Line4);//清除標誌位
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章