GPIO-AFIO-EXTI-NVIC
AFIO中断引脚选择
GPIO初始化
定义任务与任务句柄
NVIC相当于中断管家,NVIC跟CPU一样在内核,不需要额外对NVIC进行开启时钟的操作。
内部有开关部分:负责中断屏蔽,将用不到的中断源开关断开,进行屏蔽
中断优先级:由4个bit位进行存储
中断仲裁:将存储的中断优先级拿出来进行比较,看看谁优先
中断优先级分组可以根据需要,设置不同的分组方式。(1-1)
X位抢占优先级4-x位子优先级 (子优先级就是响应优先级)
一位对应着4个字节
例如:
第0组中断优先级有0位抢占优先级,4位子优先级。即:所有4位都用来配置响应优先级,16种中断向量都具有不相同的响应优先级。(1-2)
第1组中断优先级具有1位抢占优先级,3位子优先级。即:最高一位用来配置响应优先级,低三位用来配置响应优先级。其中有两种级别的抢占优先级,为0级和1级。响应优先级有8种,响应优先级分别从0-7
数值越小表示优先级越高
中断寄存器
ISER【8】是一个中断使能寄存器,如果要使能某个中断,则将响应的ISER位为1,使该中断被使能,再配合上中断分组、屏蔽、IO口映射等设置才算是一个完整中断设置。具体对应哪一个要参考
stm32f10x.h中140行处
ICER【8】是一个中断除能寄存器组。禁止某个中断。跟ISER相反。
ISPR【8】是一个中断挂起控制寄存器。每个位对应的中断跟ISER是一样的,通过置1,可以将正在进行的中断挂起,进而执行同级或更高级别的中断。写0是无效的。
ICPR【8】是一个中断解挂控制寄存器。通过设置1可以将挂起的中断继续。跟ISPR相反。
IABR【8】是一个中断激活标志位寄存器。如果为1,则代表该位对应的中断正在被执行。是一个只读寄存器,通过它可以知道当前正在执行的中断是哪一个。中断执行完了之后由硬件自动清零F。
IP【240】是一个中断优先级控制的寄存器组。内容就如同上面的1-1跟1-2一样,
关于优先与抢占的应用:
如果两个中断的抢占优先级与响应优先级相同,则看哪个中断先发生就先执行。
高抢占优先级可以打断低抢占优先级的中断,响应优先级就不可以打断。
如果抢占优先级相同,则谁响应优先级级别高(即数低,因为数值为低优先级越高),谁先响应。
NVIC中断管理函数主要在misc.c文件处
代码如何编写:
先设置中断优先级分组,用中断优先级分组函数NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 设置中断优先级分组值为2
再中断初始化
函数为NVIC_Init(NVIC_InitTypeDef)
其中InitTypeDef为结构体,中间有三个成员变量
NVIC_InitStructure.NVIC_IRQChannel:定义初始化的是哪个中断,例如USART1_IRQn
NVIC_InitStructure.NVIC_IRQchannelPreemptionPriority = 1; 定义抢断优先级
NVIC_InitStructure.NVIC_IRQchannelsubPriority = 1; 定义子优先级(响应优先级)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; IRQ通道使能
NVIC_Init (&NVIC_InitStructure); 根据上面的参数初始化NVIC寄存器
介绍完NVIC内部中断,与之对应的是EXTI外部中断
NVIC是内部时钟时间一到就产生中断,执行中断任务。
EXTI外部中断检测外部输入信号的变化边沿,若外部输入信号发现变化,产生中断。
EXTI寄存器:
上升沿选择寄存器
下降沿选择寄存器
软件触发寄存器
中断屏蔽寄存器
挂起寄存器
事件屏蔽寄存器
STM32F103中有19个外部中断,其中0-15口对应外部IO口的输入中断
16:连接到PVD输出 17:RTC闹钟 18:USB唤醒
PA0.PB0.……PG0对应EXTI0 PA1.PB1.……PG1对应EXTI1,不能同时触发中断
EXTI代码:
1、初始化GPIO管脚
GPIO_InitTypeDef GPIO_InitStruct;
GPIO时钟使能
2、配置外部中断源并进行中断源和GPIO口的连接
3、编写相应中断源的中断处理程序
编程实战:
将红外接在GPIOB的Pine14引脚上,设置为下降沿触发中断,在中断处理函数中,每触发一次,改变一次GPIOC的Pin13引脚的电平,
已知在该引脚上接有一个LED灯,实现的效果即为每触发一次中断,就改变一次LED灯的状态。
思路:
打开GPIO,AFIO时钟-GPIO初始化-将指定的GPIO引脚映射到外部中断线(EXTI-Line),从而允许该GPIO引脚触发相应的中断-EXTI初始化-NVIC初始化-中断处理函数编写
开始时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
定义GPIO初始化结构体
GPIO_InitTypeDef GPIO_InitStrucutre;
配置管脚
GPIO_InitStrucutre.GPIO_Mode_IPU; 上拉
GPIO_InitStrucutre.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStrucutre.GPIO_Speed = GPIO_Speed_50MHZ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStrucutre.GPIO_Mode_Out_PP; 上拉
GPIO_InitStrucutre.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStrucutre.GPIO_Speed = GPIO_Speed_50MHZ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
管脚映射
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
EXTI.InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line 14; 选择外部中断线14,对应GPIOB的14引脚。
EXTI_InitStructure.EXTI_LineCmd = ENABLE; 使能EXTI Line 14
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 设置为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; 下降沿触发
EXTI_Init(&EXTI_InitStructure); 初始化
配置NVIC中断优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; 指定中断通道为EXTI15-10,
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQchannelPreemptionPriority = 1; 定义抢断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 定义子优先级
NVIC_Init (&NVIC_InitStructure); 根据上面的参数初始化NVIC寄存器
编写中断服务函数
Void EXTI15_10_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line14) == SET)
{
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14 = 0)
{
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
else GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
}
EXTI_ClearITpendingBit(EXTI_Line14); 清空标志位
}
若中断当中有两个,那么在中断服务函数之中使用两个if,不是使用if elseif,因为可能两个都为1,都需要执行。
执行完中断服务函数之后记得把标志位清零,至于是在函数一开始清零还是函数最末尾清零都可以,不要遗忘就行。