在STM32中執(zhí)行中斷主要分三部分:
1.配置NVIC_Config()函數(shù)
2.配置EXTI_Config()函數(shù)
3.編寫中斷服務(wù)函數(shù)
(注:本文章所用代碼為中斷按鍵代碼,實(shí)現(xiàn)了按鍵進(jìn)入中斷從而控制LED亮滅)
配置NVIC_Config()函數(shù)
NVIC 是嵌套向量中斷控制器,控制著整個芯片中斷相關(guān)的功能,它跟內(nèi)核緊密耦合,是內(nèi)核里面的一個外設(shè)。
NVIC_Config()函數(shù)代碼如下:
static void NVIC_Config(void) /* 主要是配置中斷源的優(yōu)先級與打開使能中斷通道 */
{
NVIC_InitTypeDef NVIC_InitStruct ;
/* 配置中斷優(yōu)先級分組(設(shè)置搶占優(yōu)先級和子優(yōu)先級的分配),在函數(shù)在misc.c */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1) ;
/* 配置初始化結(jié)構(gòu)體 在misc.h中 */
/* 配置中斷源 在stm32f10x.h中 */
NVIC_InitStruct.NVIC_IRQChannel = KEY1_EXTI_IRQN ;
/* 配置搶占優(yōu)先級 */
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ;
/* 配置子優(yōu)先級 */
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0 ;
/* 使能中斷通道 */
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
/* 調(diào)用初始化函數(shù) */
NVIC_Init(&NVIC_InitStruct) ;
/* 對key2執(zhí)行相同操作 */
NVIC_InitStruct.NVIC_IRQChannel = KEY2_EXTI_IRQN ;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1 ;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
NVIC_Init(&NVIC_InitStruct) ;
}
配置NVIC_Config()的目的是選擇中斷源的優(yōu)先級以及打開中斷通道,主要功能通過配置NVIC初始化結(jié)構(gòu)體NVIC_InitStruct來完成。通俗的講,STM32中有很多中斷,而當(dāng)有多個中斷同時發(fā)生時就涉及到中斷執(zhí)行的先后問題了,所以引入了中斷優(yōu)先級的概念,中斷優(yōu)先級越高中斷就越先執(zhí)行。在這里我們只討論外部中斷的優(yōu)先級,在 NVIC 有一個專門的寄存器:中斷優(yōu)先級寄存器 NVIC_IPRx,用來配置外部中斷的優(yōu)先級。優(yōu)先級高低的比較包括搶占優(yōu)先級和子優(yōu)先級,先比較搶占優(yōu)先級,如果搶占優(yōu)先級相同就比較子優(yōu)先級,從而得出中斷之間的優(yōu)先級高低。NVIC的主要任務(wù)就是給對應(yīng)的中斷源分配中斷優(yōu)先級。 中斷優(yōu)先級分配的原理繁雜,但固件庫編程的好處就是化繁為簡,我們只需要按照NVIC_InitStruct()中的內(nèi)容進(jìn)行配置就行。
接下來簡單講解一下NVIC_Config()函數(shù)的內(nèi)容:
1.首先設(shè)置中斷優(yōu)先級分組
中斷優(yōu)先級分組其實(shí)是確立一個大綱,中斷優(yōu)先級寄存器 NVIC_IPRx中有4個位用來確定優(yōu)先級,中斷優(yōu)先級的分組就是把這4個位分配在搶占優(yōu)先級和子優(yōu)先級中。比如設(shè)定一個位配置搶占優(yōu)先級,其余三個位配置子優(yōu)先級。通過函數(shù)NVIC_PriorityGroupConfig() ; 實(shí)現(xiàn)分組,詳細(xì)代碼如下:
1 /**
2 * 配置中斷優(yōu)先級分組:搶占優(yōu)先級和子優(yōu)先級
3 * 形參如下:
4 * @arg NVIC_PriorityGroup_0: 0bit for 搶占優(yōu)先級
5 * 4 bits for 子優(yōu)先級
6 * @arg NVIC_PriorityGroup_1: 1 bit for 搶占優(yōu)先級
7 * 3 bits for 子優(yōu)先級
8 * @arg NVIC_PriorityGroup_2: 2 bit for
9 * 2 bits for 子優(yōu)先級
10 * @arg NVIC_PriorityGroup_3: 3 bit for 搶占優(yōu)先級
11 * 1 bits for 子優(yōu)先級
12 * @arg NVIC_PriorityGroup_4: 4 bit for 搶占優(yōu)先級
13 * 0 bits for 子優(yōu)先級
14 * @注意 如果優(yōu)先級分組為 0,則搶占優(yōu)先級就不存在,優(yōu)先級就全部由子優(yōu)先級控制
15 */
16 void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
17 {
18 // 設(shè)置優(yōu)先級分組
19 SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
20 }
2.優(yōu)先級分組完畢后,是配置NVIC初始化結(jié)構(gòu)體
typedef struct {
2 uint8_t NVIC_IRQChannel; // 中斷源
3 uint8_t NVIC_IRQChannelPreemptionPriority; // 搶占優(yōu)先級
4 uint8_t NVIC_IRQChannelSubPriority; // 子優(yōu)先級
5 FunctionalState NVIC_IRQChannelCmd; // 中斷使能或者失能
6 } NVIC_InitTypeDef;
初始化結(jié)構(gòu)體的作用是,收集中斷源的信息(包括配置的是哪一個中斷源、中斷源的搶占優(yōu)先級是多少、中斷源的子優(yōu)先級是多少、中斷源的使能是否開啟)。
NVIC_IROChannel:用來設(shè)置中斷源,不同的中斷中斷源不一樣,且不可寫錯,即使寫錯了程序也不會報(bào)錯,只會導(dǎo)致不響應(yīng)中斷。 stm32f10x.h 頭文件里面的 IRQn_Type 結(jié)構(gòu)體定義,這個結(jié)構(gòu)體包含了所有的中斷源。
NVIC_IRQChannelPreemptionPriority和NVIC_IRQChannelSubPriority 分別設(shè)置搶占優(yōu)先級和子優(yōu)先級,具體的值要根據(jù)中斷優(yōu)先級分組來確定。
NVIC_IRQChannelCmd:設(shè)置中斷使能(ENABLE)或者失能(DISABLE),相當(dāng)于一個電源總開關(guān)。
3.最后借助NVIC初始化函數(shù)將NVIC初始化結(jié)構(gòu)體中的信息寫入相應(yīng)的寄存器中 (體現(xiàn)了固件庫編程的優(yōu)點(diǎn),不需要我們深入到寄存器層次去,只需要掌握相應(yīng)函數(shù)的配置即可)
配置EXTI_Config()函數(shù)
EXTI(External interrupt/event controller):外部中斷/事件控制器,管理了控制器的 20個中斷/事件線。每個中斷/事件線都對應(yīng)有一個邊沿檢測器,可以實(shí)現(xiàn)輸入信號的上升沿檢測和下降沿的檢測。 EXTI 可以實(shí)現(xiàn)對每個中斷/事件線進(jìn)行單獨(dú)配置,可以單獨(dú)配置為中斷或者事件,以及觸發(fā)事件的屬性。
按我的理解,EXTI是一個有著多達(dá)20個接口的控制器,它可以為每一個接入接口的信號源配置中斷(或事件)線、設(shè)置信號的檢測方式、設(shè)置觸發(fā)事件的性質(zhì),也就是說,傳入EXTI的僅僅是一個信號,EXTI的功能就是根據(jù)信號傳入的“線”對信號做出相應(yīng)的處理,然后將處理后的信號轉(zhuǎn)向NVIC。 就像一個分揀機(jī)器,傳入的東西經(jīng)過篩選處理被送往不同的地方,只是EXTI分揀的是信號罷了。 如果說NVIC是配置中斷源,那么EXTI就是向NVIC傳送中斷信號。
EXTI功能框圖:
EXTI 可分為兩大部分功能,一個是產(chǎn)生中斷,另一個是產(chǎn)生事件,線路1-2-4-5是產(chǎn)生中斷的流程,20/代表著有20條相同的線路。
接下來講解一下EXTI_Config()函數(shù)代碼:
void EXTI_Config() /* 主要是連接EXTI與GPIO */
{
GPIO_InitTypeDef GPIO_InitStruct ;
EXTI_InitTypeDef EXTI_InitStruct ;
NVIC_Config();
/* 初始化要與EXTI連接的GPIO */
/* 開啟GPIOA與GPIOC的時鐘 */
RCC_APB2PeriphClockCmd(KEY1_EXTI_GPIO_CLK | KEY2_EXTI_GPIO_CLK, ENABLE) ;
GPIO_InitStruct.GPIO_Pin = KEY1_EXTI_GPIO_PIN ;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_Init(KEY1_EXTI_GPIO_PORT , &GPIO_InitStruct) ;
GPIO_InitStruct.GPIO_Pin = KEY2_EXTI_GPIO_PIN ;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_Init(KEY2_EXTI_GPIO_PORT , &GPIO_InitStruct) ;
/* 初始化EXTI外設(shè) */
/* EXTI的時鐘要設(shè)置AFIO寄存器 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE) ;
/* 選擇作為EXTI線的GPIO引腳 */
GPIO_EXTILineConfig( KEY1_GPIO_PORTSOURCE , KEY1_GPIO_PINSOURCE) ;
/* 配置中斷or事件線 */
EXTI_InitStruct.EXTI_Line = KEY1_EXTI_LINE ;
/* 使能EXTI線 */
EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
/* 配置模式:中斷or事件 */
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
/* 配置邊沿觸發(fā) 上升or下降 */
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising ;
EXTI_Init(&EXTI_InitStruct) ;
GPIO_EXTILineConfig( KEY2_GPIO_PORTSOURCE , KEY2_GPIO_PINSOURCE) ;
EXTI_InitStruct.EXTI_Line = KEY2_EXTI_LINE ;
EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
EXTI_Init(&EXTI_InitStruct);
}
代碼可大體分為三部分:
配置GPIO相應(yīng)引腳、配置EXTI并連接GPIO引腳、傳入NVIC_Config()
1.配置GPIO相應(yīng)引腳
該代碼是通過按鍵產(chǎn)生一個電平信號,然后經(jīng)EXTI處理傳入NVIC產(chǎn)生中斷的,所以要配置連接按鍵的GPIO引腳,主要是設(shè)置相應(yīng)的引腳模式為浮空輸入 。老規(guī)矩,先開啟相應(yīng)GPIO的時鐘,然后配置引腳初始化結(jié)構(gòu)體,再利用初始化函數(shù)將初始化結(jié)構(gòu)體寫入寄存器中。
2.配置EXTI并連接GPIO引腳
要操作外設(shè),首先要打開相關(guān)的時鐘,EXTI掛載在APB2總線上,并且開啟時鐘時要操作AFIO寄存器 ,準(zhǔn)備工作就緒后連接GPIO相應(yīng)的引腳到EXTI中,前面說了EXTI有20個接口,所以特定的引腳有特定的接口,所以要根據(jù)GPIO_EXTILineConfig();函數(shù)選擇用作EXTI線的GPIO引腳,函數(shù)說明如下
/**
* @brief Selects the GPIO pin used as EXTI Line.
* @param GPIO_PortSource: selects the GPIO port to be used as source for EXTI lines.
* This parameter can be GPIO_PortSourceGPIOx where x can be (A..G).
* @param GPIO_PinSource: specifies the EXTI line to be configured.
* This parameter can be GPIO_PinSourcex where x can be (0..15).
* @retval None
*/
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
{
uint32_t tmp = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));
assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));
AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;
AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));
}
其實(shí)對應(yīng)的EXTI線就對應(yīng)GPIO引腳號,這樣看起來還比較直觀。
連接好GPIO引腳與EXTI后就該配置EXTI的初始化結(jié)構(gòu)體了,結(jié)構(gòu)體如下:
typedef struct
{
uint32_t EXTI_Line; // 中斷/事件線
EXTIMode_TypeDef EXTI_Mode; // EXTI 模式
EXTITrigger_TypeDef EXTI_Trigger; // 觸發(fā)類型
FunctionalState EXTI_LineCmd; // EXTI 使能
} EXTI_InitTypeDef;
配置此結(jié)構(gòu)體主要是:選擇相應(yīng)的EXTI線 、選擇觸發(fā)模式、選擇產(chǎn)生的結(jié)果(中斷還是事件)、是否使能EXTI線。
EXTI_Line:中斷線選擇,可選 EXTI_0 至 EXTI_19(一共20個)。既然剛才配置好了與GPIO引腳對應(yīng)的EXTI線,所以初始化結(jié)構(gòu)體中的EXTI線就是與GPIO連接的那個線。
EXTI_Mode: EXTI 模式選擇,可選為產(chǎn)生中斷或者產(chǎn)生事件。就是決定信號的發(fā)展方向,是產(chǎn)生中斷呢?還是產(chǎn)生事件呢?此處是中斷。
EXTI_Trigger: EXTI 邊沿觸發(fā)模式,可選上升沿觸發(fā)、下降 沿 觸 發(fā) 或 者 上 升 沿 和 下 降 沿 都 觸 發(fā)。觸發(fā)信號。
EXTI_LineCmd:控制是否使能 EXTI 線,可選使能 EXTI 線或禁用。
初始化結(jié)構(gòu)體配置完畢后交由初始化函數(shù)寫入相應(yīng)的寄存器中。
3.傳入NVIC_Config()
之后就自動傳入NVIC中了。。。
編寫中斷服務(wù)函數(shù)
到這里就萬事俱備只欠東風(fēng)了,中斷的觸發(fā)與處理及優(yōu)先級定義都已經(jīng)安排上了,最后一步就是編寫中斷函數(shù)的內(nèi)容了,只要進(jìn)入中斷就會執(zhí)行中斷函數(shù)中的代碼,所以這是收尾工作。STM32的中斷服務(wù)函數(shù)不同于51單片機(jī)中的中斷服務(wù)函數(shù),STM32的所有中斷函數(shù)都被偷偷安排了,每個中斷都有其固定的名字,只有找到這個名字,在這個固定的函數(shù)名下編寫中斷服務(wù)函數(shù)才是有效的,所有中斷函數(shù)的編寫都要在stm32f10x_it.c 中,如示:
從所給的信息可得知外設(shè)的中斷服務(wù)函數(shù)的名字都存放在startup_stm32f10x_xx.s 中,而且是由匯編語言編寫,如示:
可知EXTI線0到EXTI線4線都是單獨(dú)的中斷函數(shù)名、EXTI線5到EXTI線9共用一個中斷函數(shù)名、EXTI線10線到EXTI線15線共用一個中斷函數(shù)名。
我們要做的就是以相應(yīng)的EXTI線的中斷函數(shù)名字在stm32f10x_it.c中編寫中斷函數(shù) 如下:
void EXTI0_IRQHandler(void)
{
if( EXTI_GetITStatus(KEY1_EXTI_LINE)!=RESET)
{
LED1_TOGGLE; //LED1的亮滅狀態(tài)反轉(zhuǎn)
}
EXTI_ClearITPendingBit(KEY1_EXTI_LINE);
}
void EXTI15_10_IRQHandler(void)
{
if( EXTI_GetITStatus(KEY2_EXTI_LINE)!=RESET)
{
LED2_TOGGLE; //LED2的亮滅狀態(tài)反轉(zhuǎn)
}
EXTI_ClearITPendingBit(KEY2_EXTI_LINE);
}
每次進(jìn)入中斷函數(shù)后,靠ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)讀取中斷是否執(zhí)行 ,執(zhí)行完之后要利用void EXTI_ClearITPendingBit(uint32_t EXTI_Line)清除清除中斷標(biāo)志位,以免不斷進(jìn)入中斷
大功告成
到此完整的中斷系統(tǒng)就已經(jīng)完成,主函數(shù)只需調(diào)用即可?。?!
(附上主函數(shù)及倆個頭文件)
希望可以一起交流學(xué)習(xí)
qq:2723808286
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"
int main(void)
{
LED_GPIO_Config();
EXTI_Config();
while(1)
{
}
}
#ifndef __BSP_KEY_H
#define __BSP_KEY_H
#include "stm32f10x.h"
#define KEY1_EXTI_GPIO_CLK RCC_APB2Periph_GPIOA
#define KEY1_EXTI_GPIO_PORT GPIOA
#define KEY1_EXTI_GPIO_PIN GPIO_Pin_0
#define KEY1_EXTI_IRQN EXTI0_IRQn /* 對應(yīng)著引腳號 */
#define KEY1_EXTI_LINE EXTI_Line0 /* 中斷、事件線對應(yīng)引腳號 */
#define KEY1_GPIO_PORTSOURCE GPIO_PortSourceGPIOA
#define KEY1_GPIO_PINSOURCE GPIO_PinSource0
#define KEY1_EXTI_IRQHANDLER EXTI0_IRQHandler
#define KEY2_EXTI_GPIO_CLK RCC_APB2Periph_GPIOC
#define KEY2_EXTI_GPIO_PORT GPIOC
#define KEY2_EXTI_GPIO_PIN GPIO_Pin_13
#define KEY2_EXTI_IRQN EXTI15_10_IRQn
#define KEY2_EXTI_LINE EXTI_Line13
#define KEY2_GPIO_PORTSOURCE GPIO_PortSourceGPIOC
#define KEY2_GPIO_PINSOURCE GPIO_PinSource13
#define KEY2_EXTI_IRQHANDLER EXTI15_10_IRQHandler
void EXTI_Config(void);
#endif
#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "stm32f10x.h"
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOC /*時鐘*/
#define LED1_GPIO_PORT GPIOC /*端口*/
#define LED1_GPIO_PIN GPIO_Pin_2 /*引腳*/
#define LED2_GPIO_PIN GPIO_Pin_3
#define LED2_GPIO_CLK RCC_APB2Periph_GPIOC
#define LED2_GPIO_PORT GPIOC
#define digitalTOGGLE(p,i) {p->ODR ^=i;}
#define LED1_TOGGLE digitalTOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN)
上一篇:STM32—重定向printf和getchar函數(shù)到串口
下一篇:STM32—串口通訊詳解
推薦閱讀最新更新時間:2025-06-11 09:04




設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- Microchip 升級數(shù)字信號控制器(DSC)產(chǎn)品線 推出PWM 分辨率和 ADC 速度業(yè)界領(lǐng)先的新器件
- 意法半導(dǎo)體STM32MP23x:突破成本限制的工業(yè)AI應(yīng)用核心
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲html,css,js文件,以及網(wǎng)頁和arduino的通訊
- ESP32 freeRTOS使用測試
- 51單片機(jī)-定時器中斷函數(shù)的使用
- 蓄電池內(nèi)阻測試儀在什么情況下使用?
- ST單片 GaN 柵極驅(qū)動器加速工業(yè)和家庭自動化并提高靈活性
- 凌華科技推出市場首款COM-HPC服務(wù)器模塊
- OPPO影像研發(fā)總監(jiān)劉謙易:連續(xù)光學(xué)變焦模組占據(jù)空間不大
- 數(shù)字存儲示波器的根柢構(gòu)成、根柢原理和首要技能目標(biāo)
- 車聯(lián)網(wǎng)仿真測試解決方案
- 基于單片機(jī)的自動化硬幣分揀找零系統(tǒng)設(shè)計(jì)
- 中國半導(dǎo)體反制的思考:需設(shè)立外企負(fù)面清單
- 上汽大眾:汽車網(wǎng)絡(luò)安全漏洞防護(hù)
- 恩智浦推出全新電池控制IC系列 助力新能源解決方案發(fā)展
- 全球首條GWh級新型固態(tài)電池生產(chǎn)線樣件下線
- 總投資455億元!三大動力電池項(xiàng)目齊刷進(jìn)度條
- 現(xiàn)代汽車韓國建氫燃料電池廠,2028年投產(chǎn)
- 6月融資一覽:智能汽車芯片、第三代半導(dǎo)體、機(jī)器人成資本焦點(diǎn)
- 艙駕一體“點(diǎn)燃”新戰(zhàn)事
- 汽車智能化2.0引爆「萬億蛋糕」,誰在改寫游戲規(guī)則?
- 2025研華智能系統(tǒng)產(chǎn)業(yè)伙伴峰會成功舉辦
- 意法半導(dǎo)體公布2025年第二季度財(cái)報(bào)和電話會議時間安排