1.中断组简介
STM32 将中断分为 5 个组,组 0 ~ 4。该分组的设置是由 SCB->AIRCR 寄存器的 bit10 ~ 8 来定义的。
通过这个表,我们就可以清楚的看到组 0~4 对应的配置关系,例如组设置为 3,那么此时所有的 60 个中断,每个中断的中断优先寄存器的高四位中的最高 3 位是抢占优先级,低 1 位是响应优先级。每个中断,你可以设置抢占优先级为 0 ~ 7,响应优先级为 1 或 0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。
第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
举例:假定设置中断优先级组为 2,然后设置中断 3(RTC 中断)的抢占优先级为 2,响应优先级为 1。中断 6(外部中断 0)的抢占优先级为 3,响应优先级为 0。中断 7(外部中断 1)的抢占优先级为 2,响应优先级为 0。那么这 3 个中断的优先级顺序为:中断 7>中断 3>中断 6。
上面例子中的中断 3 和中断 7 都可以打断中断 6 的中断。而中断 7 和中断 3 却不可以相互
打断!
2.NVIC控制器结构体成员
NVIC_InitTypeDef 结构体中间有四个成员变量,这四个成员变量的作用是:
NVIC_IRQChannel:
定义初始化的是哪个中断,这个我们可以在 stm32f10x.h 中找到每个中断对应的名字。例如 USART1_IRQn。
NVIC_IRQChannelPreemptionPriority:
定义这个中断的抢占优先级别。
NVIC_IRQChannelSubPriority:
定义这个中断的子优先级别。
NVIC_IRQChannelCmd:
该中断是否使能。
3外部中断控制器结构体成员
typedef struct
{
uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled.
This parameter can be any combination of @ref EXTI_Lines */
EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines.
This parameter can be a value of @ref EXTIMode_TypeDef */
EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines.
This parameter can be a value of @ref EXTIMode_TypeDef */
FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines.
This parameter can be set either to ENABLE or DISABLE */
}EXTI_InitTypeDef;
4.外部中断简介
STM32 的每个 IO 都可以作为外部中断的中断输入口。STM32F103 的中断控制器支持 19 个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F103 的19 个外部中断为:
线 0~15:对应外部 IO 口的输入中断。
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB 唤醒事件。
STM32 供 IO 口使用的中断线只有 16 个,但是 STM32 的 IO 口却远远不止 16 个,那么 STM32 是怎么把 16 个中断线和 IO 口一一对应起来的呢?
GPIO 的管脚 GPIOx.0 ~ GPIOx.15(x=A,B,C,D,E,F,G)分别对应中断线 0~15。这样每个中
断线对应了最多 7 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。
5.外部中断相关函数
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); //确定端口与中断线映射关系
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); //初始化中断线,触发方式
typedef struct
{
uint32_t EXTI_Line; //指定要配置的中断线
EXTIMode_TypeDef EXTI_Mode; //模式:事件or中断
EXTITrigger_TypeDef EXTI_Trigger; //触发方式:上升沿/下降沿/双沿
FunctionalState EXTI_LineCmd; //是否使能
}EXTI_InitTypeDef;
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line); //判断中断线中断状态是否发生
void EXTI_ClearITPendingBit(uint32_t EXTI_Line); //清楚中断线上的中断标志位
6.实现步骤
1.先打开gpio时钟和AFIO复用时钟
2.打开gpio和中断组映射
3.串口中断组的选择
4.gpio结构体配置与初始化
4.用外部中断的如gpio要配置exti外部中断与初始化
5.外部中断控制器结构体配置与初始化
中断线控制器结构体配置与初始化
6.编写中断服务函数
说明:中断服务函数中多次EXTI_GetITStatus判断是否发生中断,if和清除中断标志位配合写,避免在执行完中断前发生下一次中断
附上代码
.c文件
#include "stm32f10x.h"
#include "exti.h"
void exti_init(void)//中断io和前面配置的shake复用
{
GPIO_InitTypeDef shake_init;//gpio结构体变量名
EXTI_InitTypeDef exti_init;//外部中断结构体变量名
NVIC_InitTypeDef nvic_init;//中断控制器结构体变量名
//1.打开gpioA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//2.打开gpio中断线映射关系
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
//3.配置中断组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//4.配置gpioA结构体
shake_init.GPIO_Pin = GPIO_Pin_1;
shake_init.GPIO_Speed= GPIO_Speed_10MHz;
shake_init.GPIO_Mode = GPIO_Mode_IPD;
//gpioA初始化
GPIO_Init(GPIOA, &shake_init);
//5.配置exti外部中断结构体与初始化
exti_init.EXTI_Line =EXTI_Line1;
exti_init.EXTI_Mode =EXTI_Mode_Interrupt;
exti_init.EXTI_Trigger=EXTI_Trigger_Falling;
exti_init.EXTI_LineCmd=ENABLE;
EXTI_Init(&exti_init);
//6.配置NICV中断控制器与初始化
nvic_init.NVIC_IRQChannel =EXTI1_IRQn;//中断通道
nvic_init.NVIC_IRQChannelPreemptionPriority =1;//抢占优先级
nvic_init.NVIC_IRQChannelSubPriority =1;//子优先级
nvic_init.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&nvic_init);//初始化
}
main函数的中断服务函数
void XTI1_IRQHandler(void)//中断函数配置
{
if(EXTI_GetITStatus(EXTI_Line1)!= RESET)//判断是否法发生中断
{
GPIO_ResetBits(GPIOA,GPIO_Pin_3);//拉低函数,将3电平拉低,初始化继电器为关闭状态
delay(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_3);//拉高函数,将A3电平拉高
}
EXTI_ClearFlag(EXTI_Line1);//清除中断标志位
}