中断与事件
事件建立在OS的基础上的。
在intel微处理手册中,把同步中断和异步中断分别称为异常和中断。
中断是由间隔定时器和I/O设备产生的。
异常是由程序的错误产生的。
同步:在计算机中,同步指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回,那么这个进程将会一直等待下去直到返回信息才能继续执行下去。
异步:异步是指进程需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有消息返回时系统会通知进程处理,这样可以提高效率。
在中断异常向量表中:复位(reset)的优先级时最高的:-3然后是NMI(Non Maskable Interrupt)不可屏蔽中断。(在LINUX中为异常信号)。优先级位:-2;
因此可以这样认为:异常时优先级很高的中断。高到必须立即执行。
外部中断/事件控制器(EXTI)
对于一般的STM32,互联型有20个产生事件/中断请求的检测边沿检测器构成,其他的有19个。
这些控制器的映射关系:
每个I/O口有16个引脚分别对应EXTI(0~15).
EXTI线16连接到PVD输出
EXTI线17连接到RTC闹钟事件EXTI线18连接到USB唤醒事件EXTI线19连接到以太网唤醒事件(只适用于互联型产品)中断与事件的区别
每条中断/事件边沿检测器检测到信号是并不区别信号是中断信号还是事件信号,只有到信号到中断屏蔽寄存器(同时信号到达事件屏蔽寄存器)如果是一个中断,将信号送到NVIC中断控制器,否则将是一个事件信号,送到脉冲发生器。
中断/事件的产生
要产生中断,必须先配置好并使能中断线。根据需要的边沿检测设置2个触发寄存器,同时在中断屏蔽寄存器的相应位写’1’允许中断请求。当外部中断线上发生了期待的边沿时,将产生一个中断请求,对应的挂起位也随之被置’1’。在挂起寄存器的对应位写’1’,将清除该中断请求。如果需要产生事件,必须先配置好并使能事件线。根据需要的边沿检测通过设置2个触发寄存器,同时在事件屏蔽寄存器的相应位写’1’允许事件请求。当事件线上发生了需要的边沿时,将产生一个事件请求脉冲,对应的挂起位不被置’1’。通过在软件中断/事件寄存器写’1’,也可以通过软件产生中断/事件请求。
硬件中断配置
通过如下过程来配置20个线路做为中断源:
配置20个中断线的屏蔽位(EXTI_IMR)
配置所选中断线的触发选择位(EXTI_RTSR和EXTI_FTSR);
配置对应到外部中断控制器(EXTI)的NVIC中断通道的使能和屏蔽位,使得20个中断线中的请求可以被正确地响应。
硬件事件配置
配置20个事件线的屏蔽位(EXTI_EMR)
配置事件线的触发选择位(EXTI_RTSR和EXTI_FTSR)
软件的中断/事件配置
20个线路可以被配置成软件中断/事件线。产生软件中断的过程:
配置20个中断/事件线屏蔽位(EXTI_IMR, EXTI_EMR)
设置软件中断寄存器的请求位(EXTI_SWIER)
STM32的外部中断初始化
初始化IO口为输入时:可以设置为上拉/下拉输入,也可以设置为浮空输入,但浮空的时候外部一定要带上拉,或者下拉电阻。否则可能导致中断不停的触发。在干扰较大的地方,就算使用了上拉/下拉,也建议使用外部上拉/下拉电阻,这样可以一定程度防止外部干扰带来的影响 。
需要开启IO口复用时钟,设置IO口与中断的映射关系:
STM32 的 IO 口与中断线的对应关系需要配置外部中断配置寄存器 EXTICR,需要先开启复用时钟,然后配置 IO 口与中断线的对应关系。才能把外部中断与中断线连接起来
配置中断分组(NVIC),使能中断。
编写中断服务函数。
编写中断的代码解析;
中断服务函数是在相应中断到的时候对中断到来时做出的响应,这个函数可以编写任意你需要的函数,但对于一个中断函数在函数结束时必须清除中断标志,不然中断将一直存在。需要注意的是:服务函数命名的格式为Name_IRQHandler(void),(Name为你设置的中断类型。如:TIMx,EXTIx等表示你使用的中断类型,因为在给定的代码对相应的进行了定义可以参考(stm32f10x.h));
中断的初始化函数定义如下:
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)
这里有四个参数,下面说明含义
中断分组函数(NVIC_Group):它是一个给一个中断优先级的函数,函数如下:
void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
{ u32 temp,temp1;
temp1=(~NVIC_Group)&0x07;
temp1<<=8;
temp=SCB->AIRCR;
temp&=0X0000F8FF;
temp|=0X05FA0000; //写入钥匙
temp|=temp1;
SCB->AIRCR=temp; // 写入优先级
}
这个函数有一个SCB->AIRCR 可以理解为一个寄存器也看可以理解为一个变量,在这个寄存器中bit[10:8]位标志着一个函数的抢占优先级和响应优先级(抢占优先级>响应优先级,同抢占优先级看响应优先级,数值越小,优先级越高)。
这个表给出了相应设置下的优先级分配。
本函数为一个系统函数不用做修改。
还有两个参数,分别是抢占优先级(NVIC_PreemptionPriority)和响应优先级(NVIC_SubPriority),对于这连个参数的是设置中断IP[240]寄存器的(Interrupt Priority Registers),IP 寄存器组由 240 个 8bit 的寄 存器组成,每个可屏蔽中断占用 8bit,这样总共可以表示 240 个可屏蔽中断。8bit用了高4位来表示优先级。如上表给出的结果。
需要注意的是:对于这个函数需要设置中断屏蔽位,把相应的中断置1,这里还有一个参数也就NVIC_Channel,这个参数就是一个中断编号,它的格式Name_IRQn(Name为你设置的中断类型。如:TIMx,EXTIx等表示你使用的中断类型)
对于一般的使用来说,我们只要掌握对函数:
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group) 的使用就行
各个参数的含义:
//NVIC_PreemptionPriority:抢断优先级
//NVIC_SubPriority :相应优先级
//NVIC_Channel :中断编号(中断服务函数)
//NVIC_Group :中断分组。