給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]

helesheng發表於2021-12-25

本人和教研室幾位老師編著的《基於STM32的嵌入式系統原理及應用》(ISBN:9787030697974)剛剛在科學出版社出版。這本書花費了半年以上的時間,凝聚了筆者作為高校教師和嵌入式工程師的一些經驗,希望對大學生、嵌入式初學者和有一定經驗的工程師都有參考和借鑑作用。在寫作中尤其注意了不做晶片手冊的“搬運工”和“翻譯者”,試圖從開發者和工程師的角度理清知識點之間的邏輯關係,給讀者一條清晰的學習路徑。寫作中儘量做到用生活中的例項來闡述抽象的概念;用工程例項來幫助大家提高嵌入式開發的實踐能力。另外為幫助讀者理解某些難點,我們在Bilibili上陸續釋出免費的講解的視訊,歡迎大家關注我的B站賬號:“何樂生0”(本文講解點這裡)。高校教師朋友們還可在微信中搜尋公眾號“科學EDU”公眾號,申請免費樣書和課程PPT。

下面將該書中關於STM32的Cortex-M3中斷控制器NVIC的一小節發出來供大家拍磚,歡迎大家批評指正。以下內容歡迎轉載,但請註明出處: https://www.cnblogs.com/helesheng

一、中斷機制概述

中斷是計算機系統的一種處理非同步事件的重要方法。它的作用是在計算機的CPU執行軟體的同時,監測系統內外有沒有發生需要CPU處理的“緊急事件”:當需要處理的事件發生時,中斷控制器會打斷CPU正在處理的常規事務,轉而插入一段處理該緊急事件的程式碼;而該事務處理完成之後,CPU又能正確地返回剛才被打斷的地方,以繼續執行原來的程式碼。中斷可以分為“中斷響應”、“中斷處理”和“中斷返回”三個階段。

中斷處理事件的非同步性是指,緊急事件在什麼時候發生與CPU正在執行的程式完全沒有關係,是無法預測的。既然無法預測,只能隨時檢視這些“緊急事件”是否發生,而中斷機制最重要的作用,是將CPU從不斷監測緊急事件是否發生這類繁重工作中解放出來,將這項“相對簡單”的繁重工作交給“中斷控制器”這個硬體來完成。中斷機制的第二個重要作用是判斷哪個或哪些中斷請求更緊急,應該優先被響應和處理,並且尋找不同中斷請求所對應的中斷處理程式碼所在的位置。中斷機制的第三個作用是幫助CPU在執行完處理緊急事務的程式碼後,正確地返回之前執行被打斷的地方。根據上述中斷處理的過程及其作用,讀者會發現中斷機制既提高了CPU正常執行常規程式的效率,又提高了響應中斷的速度,是幾乎所有現代計算機都配備的一種重要機制。

嵌入式系統是嵌入宿主物件中,幫助宿主物件完成特定任務的計算機系統,其主要工作就是和真實世界打交道。能夠快速、高效地處理來自真實世界的非同步事件成為嵌入式系統的重要標誌,因此中斷對於嵌入式系統而言顯得尤其重要,是學習嵌入式系統的難點和重點。

1.1 中斷的基本概念

這裡通過一個生活例項來解釋中斷機制中涉及的各種概念:某人在家中讀書學習,假設可能有兩件打斷他學習的事情分別是:有人敲門來訪和接聽電話。安靜地讀書學習相當於嵌入式處理器的常規程式,而“有人敲門來訪”和“接聽電話”兩件事就是可能引發中斷的“中斷源”,中斷之前他讀書所達到的頁碼稱為“斷點”。如圖1所示,中斷源提出要求響應中斷稱為“中斷請求”;而CPU打斷原來的程式執行,轉而處理開門或接電話等事情稱為“中斷響應”;為響應事件而執行的程式稱為“中斷服務程式”;處理完非同步事件,返回的過程稱為“中斷返回”。中斷響應過程又可以分為自動儲存當前暫存器值的“現場保護”和定位並跳轉到中斷服務程式地址兩個小步驟。中斷返回也相應地分為恢復暫存器值的“恢復現場”和恢復原來主程式執行的位置的“返回斷點”兩個小步驟。當然,也可以選擇不理睬這些打斷讀書的事情,例如,將手機設定為靜音狀態,此時就稱為“中斷遮蔽”。

圖1 中斷示意圖

 如圖2所示,當電話鈴聲和敲門聲同時響起時,只能根據事情的重要性,先響應一件事,而決定孰先孰後的分級機制稱為“中斷優先順序”。顯然圖2中開門迎客的優先順序高於接聽電話。

圖2 中斷優先順序示意圖

 優先順序高可以有兩種體現,一種如圖2所示,兩個中斷同時到來時先響應優先順序較高的那個中斷請求,再響應優先順序低的那個。優先順序高還可以體現為,即使優先順序低的中斷服務程式在執行中,優先順序高的中斷也可以打斷優先順序低的中斷服務程式,而優先順序低的中斷服務程式只有等到優先順序高的中斷服務程式執行完成後才能繼續執行。如圖3所示,開門任務能夠打斷接聽電話任務,形成類似“菊花”的巢狀結構,就稱為“中斷巢狀”。STM32中將能夠被打斷,實現中斷巢狀的優先順序稱為“搶佔優先順序”,而不能夠被打斷,只能優先響應的中斷優先順序稱為“子優先順序”。

圖3 中斷巢狀示意圖

 中斷機制中還有一個重要概念稱為“中斷向量表”,中斷向量表是一張由中斷服務程式的入口地址構成的表格,一般佔據程式碼空間的起始地址。處理器設計者會將所有可能響應的中斷源所對應的中斷服務程式入口地址按照固定的順序排列在該表格中。當某個中斷源被響應時,處理器會自動跳轉到該中斷源的中斷服務程式入口所在的表格地址,並由該表格位置進一步跳轉到中斷服務程式。

1.2 ARM Cortex-M3的中斷控制器——NVIC

ARM V7架構將處理器分為應用處理器A型、實時處理器R型和微控制器M型。M型中最重要的ARM Cortex-M3充分考慮了嵌入式應用中對非同步事件處理的實時性要求。因而與之前的ARM架構不同,直接在Cortex-M3核心中整合了功能強勁的中斷控制器,並命名為NVIC。在核心中整合中斷控制器不但防止了不同晶片生產廠商間的不相容,還大大提高了中斷控制器和Cortex-M3核心的結合緊密度,降低了中斷響應時間,提高了實時性。

NVIC直譯為巢狀向量中斷控制器,顧名思義,指ARM Cortex-M3的中斷控制器支援中斷巢狀和中斷向量表的自動跳轉功能。典型的NVIC可支援256箇中斷,其中包括16個由核心產生的異常中斷和240個外設中斷。其中,核心異常中斷指由Cortex-M3核心產生的復位、硬體錯誤、SysTick定時器中斷等中斷,而外設中斷則是由管腳電平變化、UART或DMA等外設變化引起的中斷。NVIC還能實現Cortex-M3核心響應中斷請求後的自動現場保護(自動儲存處理器狀態暫存器)和中斷返回時的自動現場恢復(自動恢復處理器狀態暫存器)。另外還有一種稱為“中斷尾鏈(末尾連鎖)”的技術,能夠在從高優先順序的中斷服務程式返回時避免多餘的自動現場恢復,即自動進入低優先順序的中斷服務程式,從而避免了一輪多餘的自動現場恢復和自動現場保護操作。

二、 STM32的NVIC

STM32的NVIC也只是標準NVIC的一部分,但主要功能都已經包含在其中:STM32的NVIC可支援16個核心異常中斷和68個外設中斷(其中STM32F103系列60個,STM32F107系列68個)。同時,每個中斷源可配置4位優先順序控制字PRI_n(ARM Cortex-M3核心定義了8位,STM32微控制器只使用了其中的4位),具有16級可程式設計中斷優先順序。

表1是STM32F103系列的中斷向量表,供讀者查詢。其中灰色部分是核心異常中斷。

表1 STM32F103系列的中斷向量表

 

 

 NVIC通過中斷優先順序控制字PRI_n既支援巢狀中斷又支援非巢狀中斷,方法如表2所示,將每個中斷的優先順序控制字PRI_n(4位)分為兩截:前半截用於定義本中斷的搶佔優先順序,後半截用於定義子優先順序。而分割的具體辦法由優先順序組別暫存器定義:若優先順序組別定義為4,則前半截的搶佔優先順序佔據全部4位(共可定義24=16中搶佔優先順序),而後半截的子優先順序佔據0位(無法定義子優先順序);若優先順序組別定義為3,則前半截的搶佔優先順序佔據全部3位(共可定義23=8種搶佔優先順序),而後半截的子優先順序佔據1位(共可定義21=2種子優先順序);其他優先順序組別定義以此類推,表2所示是NVIC的中斷優先順序配置。

表2 NVIC的中斷優先順序配置

優先順序組別

搶佔優先順序

子優先順序

4

4位/16級

0位/0級

3

3位/8級

1位/2級

2

2位/4級

2位/4級

1

1位/2級

3位/8級

0

0位/0級

4位/16級

值得注意的是,每個中斷源都擁有自己的優先順序控制字PRI_n(n為中斷源編號),但優先順序組別暫存器只有一個。即一旦對NVIC定義了優先順序控制字的分割方式,則對所有中斷源的所有PRI_n,分割方式都是相同的,並且意法半導體官方不建議在程式中頻繁修改優先順序組別暫存器的內容。

與本節關於通用中斷巢狀規則的描述相同,STM32的NVIC的優先順序巢狀規則如下:

(1)搶佔優先順序高的中斷可以打斷搶佔優先順序低的中斷服務,構成中斷巢狀。

(2)當兩個或多個同級別搶佔優先順序的中斷出現時,它們不能構成中斷巢狀,但STM32先響應子優先順序高的中斷請求。

(3)當兩個或者多個同級別搶佔優先順序和同級別子優先順序的中斷同時出現時,STM32先響應在中斷向量表中靠前的那個中斷。

通過實際生活的例子類比上述NVIC響應順序原則:在火車站購票時,先比較搶佔優先順序,搶佔優先順序高(軍人)的中斷優先響應;當搶佔優先順序相同時,比較子優先順序,子優先順序高(軍銜)的中斷優先響應;當上述兩者都相同時,比較它們在中斷向量表中的位置(年齡),位置低(年齡大)的中斷優先響應。

再通過一箇中斷配置例項,說明STM32的NVIC配置和響應順序:假定設定優先順序組為2,然後進行以下設定。

(1)中斷3(RTC中斷)的搶佔優先順序為2,子優先順序為1。

(2)中斷6(外部中斷0)的搶佔優先順序為3,子優先順序為0。

(3)中斷7(外部中斷1)的搶佔優先順序為2,子優先順序為0。

則中斷優先順序順序為:中斷7 >中斷3 >中斷6。其中,中斷3和中斷7的搶佔優先順序相同,所以中斷3不能被中斷7打斷,但中斷6可以被中斷3或中斷7打斷。

三、NVIC的配置和使用

STM32的巢狀向量中斷控制器需要和中斷源配合使用,本書將在後續章節中採用標準外設庫提供的庫函式,並結合具體中斷源外設來詳細講解。這裡為了幫助讀者理解NVIC的工作方式,僅給出基於標準外設庫的NVIC通用配置流程。

(1)配置中斷優先順序分組,例如:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//將中斷優先順序組別配置為2

上面程式碼呼叫的函式“void NVIC_PriorityGroupConfig(uint32_t NVIC_Priority Group);”是意法半導體官方提供的標準外設庫函式,其功能是對中斷優先順序組別進行配置。而其引數NVIC_PriorityGroup_2是由標準外設庫事先定義的巨集,代表將組別設為2,也就是2位搶佔優先順序,2位子優先順序。

(2)針對具體需要的中斷源,設定對應的搶佔優先順序和子優先順序,初始化NVIC,例如: 

NVIC_Init(&NVIC_InitStructure);   //用結構體NVIC_InitStructure中定義的引數初始化NVIC                                  //暫存器

函式“void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);”也是標準外設庫中提供的函式。&NVIC_InitStructure是指向初始化結構體NVIC_InitStructure的指標。結構體NVIC_InitStructure的定義如下,其成員包含了NVIC的主要引數。

typedef struct
{
  uint8_t NVIC_IRQChannel;                  //設定中斷源是哪一個
  uint8_t NVIC_IRQChannelPreemptionPriority;   //搶佔優先順序
  uint8_t NVIC_IRQChannelSubPriority;          //子優先順序
  FunctionalState NVIC_IRQChannelCmd;        //使能/禁能本中斷源
} NVIC_InitTypeDef;

(3)編寫對應的中斷服務程式。官方提供的標準外設庫已經在檔案stm32f10 x_it.c中為STM32所包含的每一個外設編寫了中斷服務程式的框架。其命名規則為“void PPP_IRQHandler(void);”,其中PPP代表了具體中斷源的縮寫,如:

void WWDG_IRQHandler(void);   //視窗看門狗中斷服務
void RTC_IRQHandler (void);     //實時時鐘中斷服務
void EXTI0_IRQHandler (void);   //外部中斷0中斷服務
void EXTI1_IRQHandler (void);   //外部中斷1中斷服務
void USART1_IRQHandler(void);  //串列埠1中斷服務
void SPI1_IRQHandle(void);      //SPI1中斷服務

 

 

相關文章