一、相关概念
(1)中断:单片机执行主程序时,由于某个事件的原因,暂停主程序的执行,调用相应的中断处理程序处理该事件,处理完毕后再自动继续执行主程序的过程
(2)中断源:可以引起中断的事件
(3)中断优先级:不同事件的重要程度。当有多个中断源同时申请中断,CPU会根据中断源的轻重缓急进行裁决,优先响应更加重要的中断源
(4)中断嵌套:当正在执行一个中断程序时,又被一个更高优先级的事件打断,暂停执行当前中断程序,转去处理新的中断程序,处理完成后再继续处理本中断的过程
中断嵌套的两条基本规则:
①低优先级的中断服务可被高优先级中断源中断,反之则不能
②任何一种中断一旦得到响应,不会被它的同级中断源的请求所中断
(5)中断向量:对应中断服务程序的入口地址
(6)中断处理过程包含中断请求、中断响应、中断服务及中断返回四个步骤
中断请求:中断源向CPU发出中断请求
中断响应:CPU允许中断,主程序或中断服务程序暂停,进入中断服务程序
中断服务:执行中断服务程序的过程
中断返回:中断服务程序执行完毕后回到主程序或者次级别中断服务程序的过程
二、中断系统结构
2.1 中断源及中断向量
STM32F103中断系统提供10个系统异常和60个可屏蔽中断源,具有16个中断优先级
可屏蔽中断源包括外部中断、定时器中断、串口中断、直接内存访问中断、模/数转换中断、集成电路总线中断、串行外设接口中断等
其中,外部中断由嵌套向量中断控制器NVIC和外部中断/事件控制器EXTI共同控制
中断向量表:定义一块固定的内存,以4字节对齐,存放各个中断服务函数程序的首地址
中断向量表定义在启动文件,当发生中断,CPU会自动执行对应的中断服务函数
2.2 嵌套向量中断控制器NVIC
NVIC是一个在Cortex-M3内核的中断控制器,支持68个可屏蔽中断,提供16个可编程的优先级。中断发生时,自动获取中断服务程序的入口地址并直接调用
STM32的中断向量有两个属性,即抢占属性和响应属性,属性编号越小,优先级越高
中断优先级有寄存器组IPR(Interrupt Priority Registers)控制,包含15个32位的寄存器,一个可屏蔽中断占8bit,在这占用的8bit中只使用了高四位,可分为5组,即0、1、2、3、4组
抢占是指打断其他中断的属性,即中断嵌套。
判断两个中断的优先级时先看抢占优先级的高低,如果相同再看响应优先级的高低,如果都相同则看向量表中的优先级
上电复位后,中断配置为4组,并且60个外部中断抢占优先级为0级,无响应优先级
2.3 外部中断/事件控制器EXTI(Extern Interrupt)
EXTI由19个产生事件/中断请求的边沿触发器组成,每根线都可以独立的配置输入类型(脉冲或挂起)和对应事件触发方式(上升沿、下降沿、双边沿),每根输入线都可以被独立屏蔽,由挂起寄存器保持状态线的中断请求
外部信号首先经过边沿检测单路,该边沿检测单路受两个平行的寄存器控制。为了使外部中断线上的事件能够产生中断,首先将设置两个边沿触发寄存器,并且将中断屏蔽寄存器置1以使能外部中断请求。当发出中断请求,该中断线对应的挂起标志位被置1,通过挂起寄存器写1操作可以清除中断请求。
上图的电路符号:16选1数据选择器
支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断,比如A0、B0、C0
通道数:16个GPIO_Pin,外加PVD输出(16)、RTC闹钟(17)、USB唤醒(18)、以太网唤醒(19)(互联型)
Cortex_M3内核可以通过内部或外部事件来唤醒内核,利用以上19根中断/事件请求线,可以配置任何I/O口、RTC闹钟和USB唤醒事件来唤醒CPU
触发响应方式:中断响应/事件响应(事件响应:外部中断信号不流向NVIC,而是通向其他外设,用来触发其他外设操作,比如,触发ADC转换)
2.4 AFIO
AFIO主要用于引脚复用功能的选择和重定义
在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择
三、EXTI寄存器
必须以字(32位)的方式操作这些寄存器,对于寄存器操作,常常适用&=、|=进行操作
3.1 中断屏蔽寄存器(EXTI_IMR)
3.2 事件屏蔽寄存器(EXTI_EMR)
3.3 上升沿触发选择寄存器(EXTI_RTSR)
3.4 下降沿触发选择寄存器(EXTI_FTSR)
3.5 软件中断事件寄存器(EXTI_SWIER)
3.6 挂起寄存器(EXTI_PR)
四、中断相关的库函数
4.1 NVIC分组函数:NVIC_PriorityGroupConfig()
4.2 NVIC初始化函数:NVIC_Init()
4.3 EXTI初始化EXTI_Init()
4.4 AFIO:将引脚映射到中断线上
五、相关配置流程
5.1 中断配置
(1)打开GPIO、AFIO(使用外部中断,用于选择中断引脚)的时钟
(2)配置GPIO口,完成初始化
(3)配置AFIO,将引脚映射到中断线上
(4)配置EXTI,完成初始化
(5)设置优先级分组(整个工程设置依次即可,若多次设置,以最后依次为准)
(6)配置NVIC,完成初始化
5.2 中断服务程序配置(外部中断为例)
(1)检测中断请求,EXTI_GetITStatus()
(2)中断服务内容
(3)清除中断请求,EXTI_ClesrITStatus()
六、应用实例
对射式红外传感器的DO接在B14引脚,实现每次遮挡,计数器加1
main.c
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Infrared_Sensor.h"
uint8_t count = 0;
int main()
{
Infrared_Init();
OLED_Init();
OLED_ShowString(1,1,"Count:");
while(1)
{
OLED_ShowNum(1,7,count,5);
}
}
Infrared_Sensor.c
#include "stm32f10x.h" // Device header
/**
* @brief 对射式红外传感器初始化
* @param 无
* @retval 无
*/
void Infrared_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //打开GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //打开AFIO的时钟,外部中断必须开始AFIO时钟
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14); //将B14映射到外部中断14号线上
EXTI_InitTypeDef EXTI_InitStruct; //配置EXTI外设
EXTI_InitStruct.EXTI_Line = EXTI_Line14;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //配置NVIC为分组1
//即抢占优先级范围:0,响应优先级范围:0~7
//此分组配置在整个工程中仅需调用一次
//若有多个中断,可以把此代码放在main函数内,while循环之前
//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
NVIC_InitTypeDef NVIC_InitStruct; //配置NVIC外设
NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);
}
stm32f10x_exti.c
extern uint8_t count;
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line14) == SET)
{
count++;
EXTI_ClearITPendingBit(EXTI_Line14);
}
}