本文介绍如何使用STM32标准外设库设置并使用中断,单片机中断系统的目的是为了让MCU对内部或外部的突发事件及时地作出响应,并执行相应的程序,最简单直观的为外部中断,可以用作检测按键的按下和弹起,本例程设置GPIOA的Pin0作为外部中断。
本文适合对单片机及C语言有一定基础的开发人员阅读,MCU使用STM32F103VE系列。
初始化分为三步,包括设置优先级分组、结构体初始化和初始化库函数调用。
共5组,一般选择NVIC_PriorityGroup_2,即2位抢占优先级、2位子优先级。
调用库函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
typedef struct { uint8_t NVIC_IRQChannel; uint8_t NVIC_IRQChannelPreemptionPriority; uint8_t NVIC_IRQChannelSubPriority; FunctionalState NVIC_IRQChannelCmd; } NVIC_InitTypeDef;
/* 配置中断源:外部中断0 */
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
直接设置为ENABLE即可。
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
调用库函数:
NVIC_Init(&NVIC_InitStructure);
可以把中断服务函数统一写在 stm32f10x_it.c 这个库文件中,也可以写在其他文件中,中断服务函数的函数名必须跟启动文件(startup_stm32f10x_hd.s)里面预先设置的一样,比如外部中断0的中断服务函数名称为EXTI0_IRQHandler ()。
void EXTI0_IRQHandler(void)
中断服务函数进入之后首先判定中断标志位是否置位,如果未置位则直接退出,如果已置位则执行相应的处理,退出中断之前需要清除中断标志位。有些操作如读串口数据会自动清除中断读数据寄存器非空标志位,因此无需手动清除。
分三部分:GPIO、通用中断、EXTI(External interrupt/event controller)
结构体:
typedef struct { uint32_t EXTI_Line; EXTIMode_TypeDef EXTI_Mode; EXTITrigger_TypeDef EXTI_Trigger; FunctionalState EXTI_LineCmd; }EXTI_InitTypeDef;
/*开启AFIO时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
直接调用库函数GPIO_EXTILineConfig()即可
/* 配置信号源 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
/* EXTI中断线选择Line0 */ EXTI_InitStructure.EXTI_Line = EXTI_Line0;
/* EXTI为中断模式 */ EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 上升沿中断 */ EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
外部中断0的中断服务函数名称为EXTI0_IRQHandler ()。
void EXTI0_IRQHandler(void);
2.2. 中断处理
中断服务函数中调用EXTI_GetITStatus()函数判定中断标志位状态以确定中断是否发生,调用EXTI_ClearITPendingBit()函数清除中断标志位。
if(EXTI_GetITStatus(EXTI_Line0) != RESET) { EXTI_ClearITPendingBit(EXTI_Line0); }
1 void GPIO_Config(void) 2 { 3 /*定义一个GPIO_InitTypeDef类型的结构体*/ 4 GPIO_InitTypeDef GPIO_InitStructure; 5 6 /*开启指定端口的GPIO外设时钟*/ 7 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 8 9 /*选择要控制的GPIO引脚*/ 10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 11 12 /*设置引脚模式为浮空输入*/ 13 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 14 15 /*调用库函数,初始化GPIO*/ 16 GPIO_Init(GPIOA, &GPIO_InitStructure); 17 } 18 19 void NVIC_Config(void) 20 { 21 NVIC_InitTypeDef NVIC_InitStructure; 22 23 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 24 25 /* 配置中断源:外部中断0 */ 26 NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; 27 /* 配置抢占优先级 */ 28 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 29 /* 配置子优先级 */ 30 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 31 /* 使能中断通道 */ 32 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 33 34 NVIC_Init(&NVIC_InitStructure); 35 } 36 37 void EXTI0_Config(void) 38 { 39 EXTI_InitTypeDef EXTI_InitStructure; 40 41 /*开启AFIO时钟*/ 42 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 43 44 /*配置信号源*/ 45 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); 46 47 /* EXTI中断线选择Line0 */ 48 EXTI_InitStructure.EXTI_Line = EXTI_Line0; 49 /* EXTI为中断模式 */ 50 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 51 /* 上升沿中断 */ 52 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; 53 /* 使能中断 */ 54 EXTI_InitStructure.EXTI_LineCmd = ENABLE; 55 56 EXTI_Init(&EXTI_InitStructure); 57 } 58 59 void EXTI0_init(void) 60 { 61 GPIO_Config(); 62 NVIC_Config(); 63 EXTI0_Config(); 64 } 65 66 //中断服务函数,待完善 67 void EXTI0_IRQHandler(void) 68 { 69 if(EXTI_GetITStatus(EXTI_Line0) != RESET) 70 { 71 EXTI_ClearITPendingBit(EXTI_Line0); 72 } 73 } 74 75 76 int main(void) 77 { 78 // 外部中断0中断初始化 79 EXTI0_init(); 80 81 while (1) 82 { 83 } 84 }
程序编译成功后,点击
开始仿真,打开菜单栏Peripherals→General Purpose I/O→GPIOA,如果中断触发类型为上升沿,那么触发条件为指定端口先低电平,再设置为高电平;反之如果触发类型为下降沿,那么触发条件为指定端口先高电平,再设置为低电平。
可在中断服务函数内发生中断后设置断点,程序开始运行,当满足中断触发条件后,程序在断点处暂停,表明中断成功。

https://files.cnblogs.com/files/greatpumpkin/EXTI_int.zip
原文:https://www.cnblogs.com/greatpumpkin/p/13234977.html