STM32 中斷總結(1)
前言
由於個人部落格被攻擊,現逐漸將部落格內容搬運至CSDN,本文原寫於2020年4月。
中斷是微控制器的核心之一,stm32具有強大的中斷,幾乎每個外設都可設中斷。
補充知識
- 中斷和異常向量表(見st官方stmF10x英文資料手冊),共60個可設定中斷
- NVIC:巢狀向量中斷控制器,控制著整個晶片中斷相關的功能,它跟核心緊密耦合,是核心裡面的一個外設。但是各個晶片廠商在設計晶片的時候會對 Cortex-M3 核心裡面的 NVIC 進行裁剪,把不需要的部分去掉,所以說 STM32 的 NVIC 是 Cortex-M3 的 NVIC 的一個子集。
- 《STM32F10xxx Cortex-M3程式設計手冊》
NVIC
結構體定義:
優先順序
概況
在NVIC中 中斷優先順序暫存器 NVIC_IPRx用來配置優先順序,該暫存器寬度為8bit,但是在F103中只使用了高4bit,這4bit又分組為搶佔優先順序和子優先順序。如果多個終端同時響應,依次比較搶佔優先順序、子優先順序和硬體中斷編號(越小越先)。
分組
優先順序的分組由核心外設 SCB 的應用程式中斷及復位控制暫存器 AIRCR 的PRIGROUP[10:8]位決定, F103 分為了 5 組,具體如下圖:主優先順序=搶佔優先順序
對應位於misc.h和misc.c中函式 NVIC_PriorityGroupConfig() 實現
步驟
配置步驟
- 使能外設某個中斷,具體由每個外設的相關中斷使能位控制;
- 初始化NVIC_InitTypeDef結構體,設定搶佔優先順序和子優先順序,使能中斷請求。
- 編寫中斷服務函式
解釋:
對於步驟二:程式碼如下
typedef struct
{
uint8_t NVIC_IRQChannel; // 中斷源
uint8_t NVIC_IRQChannelPreemptionPriority; //搶先優先順序
uint8_t NVIC_IRQChannelSubPriority; //子優先順序
FunctionalState NVIC_IRQChannelCmd; //中斷使能或者失能
} NVIC_InitTypeDef;
對於中斷源的配置特此說明:不同的中斷中斷源不一樣,寫錯不報錯。成員過多,此處不再展示,具體參考stm32f103.h裡的IRQn_Type結構體定義。
對於步驟三:在 在啟動檔案
startup_stm32f10x_hd.s 中預先為每個中斷都寫了一箇中斷服務函式,只是這些中斷函式都是為空,為的只是初始化中斷向量表。實際的中斷服務函式都需要重新編寫, 為了方便管理中斷服務函式統一寫在 stm32f10x_it.c 這個庫檔案中 .
EXTI
這部分不打算寫很詳細,講起來太多了,寫個大致 。主要涉及程式碼編寫流程。主要方便自個程式設計作為參考
簡單說,EXTI全稱外部中斷/事件控制器。管理了20箇中斷線,具有邊沿檢測器,可實現輸入訊號上升沿or下降沿的檢測。可實現對每個中斷線進行單獨配置。
硬體流程圖
中斷線/實踐線
每個GPIO都可以被設定為輸入線,見表:
EXTI結構體
EXTI初始化結構體(stm32f10x_exti.c,stm32f10x_exti.h)
typedef struct
{
uint32_t EXTI_Line; //中斷/事件線
EXTIMode_TypeDef EXTI_Mode; //模式
EXTITrigger_TypeDef EXTI_Trigger; //觸發型別
FunctionalState EXTI_LineCmd;//使能
}EXTI_InitTypeDef;
說明:
-
EXTI_Line見上表
-
XTIMode_TypeDef EXTI_Mode可選擇產生中斷還是事件
-
EXTITrigger_TypeDef EXTI_Trigger選擇上升沿or下降沿
程式設計
步驟
- 初始化GPIO
- 初始化EXTI
- 初始化NVIC
- 編寫中斷服務函式
NVIC配置
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置NVIC為優先順序組1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置中斷源:按鍵1 */
NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
/* 配置搶佔優先順序 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 配置子優先順序 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中斷通道 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 配置中斷源:按鍵2,其他使用上面相關配置 */
NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
NVIC_Init(&NVIC_InitStructure);
}
GPIO設定和EXTI終端配置
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/*開啟按鍵GPIO口的時鐘*/
RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);
/* 配置 NVIC 中斷*/
NVIC_Configuration();
/*--------------------------KEY1配置-----------------------------*/
/* 選擇按鍵用到的GPIO */
GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
/* 配置為浮空輸入 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
/* 選擇EXTI的訊號源 */
GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE);
EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
/* EXTI為中斷模式 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 上升沿中斷 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
/* 使能中斷 */
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/*--------------------------KEY2配置-----------------------------*/
/* 選擇按鍵用到的GPIO */
GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;
/* 配置為浮空輸入 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);
/* 選擇EXTI的訊號源 */
GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE);
EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
/* EXTI為中斷模式 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 下降沿中斷 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
/* 使能中斷 */
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
[/highlight]
EXTI中斷服務函式
[highlight lanaguage="C"]
void KEY1_IRQHandler(void)
{
//確保是否產生了EXTI Line中斷
if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)
{
// LED1 取反
LED1_TOGGLE;
//清除中斷標誌位
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
}
}
void KEY2_IRQHandler(void)
{
//確保是否產生了EXTI Line中斷
if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET)
{
// LED2 取反
LED2_TOGGLE;
//清除中斷標誌位
EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
}
}