中断屏蔽寄存器源的是否允许中断屏蔽寄存器是由()寄存器决定的,中断屏蔽寄存器源的优先级别是由()寄存器决定的

早在2016年11月,经过3GPP RAN1 87次会议讨论,华为主推……
各行业芯片自主问题备受关注。然而,谁知被冠以“中国特……
日的谷歌I/O大会已经召开完毕,颇具戏剧性的是……
多年前,日本电产新建总公司大楼,日本电产的永守重信董……
物联网、智能硬件、汽车电子、工业4.0等的发展,给传感器……
演讲人:卢柱强时间: 10:00:00
演讲人:曾伟权时间: 10:00:00
演讲人:黄科涛时间: 10:00:00
预算:¥20000预算:¥15000
广东省上海市
MCS-51单片机多个中断源中的外中断分析方案
[导读]MCS-51单片机有多个中断源,以8051为例,有5个中断源,两个外中断、两个定时中断和一个串行中断,这一节我们讨论lcd液晶屏图外中断软件编程。外中断是由外部原因引起的中断,有两个中断源。即外中断0(INT0)和外中断1
MCS-51单片机有多个中断源,以8051为例,有5个中断源,两个外中断、两个定时中断和一个串行中断,这一节我们讨论lcd液晶屏图外中断软件编程。本文引用地址:
外中断是由外部原因引起的中断,有两个中断源。即外中断0(INT0)和外中断1(INT1),中断请求信号由引脚P3.2(INT0)和P3.3(INT1)输入。
外中断请求信号有两种方式,一是电平方式,二是脉冲方式。可通过有关控制位的定义进行规定。
电平方式为低电平有效,只需在单片机的(INT0)和(INT1)中断请求输入端采样到有效的低电平时,就会激活外部中断。
脉冲方式则在脉冲的后负跳沿有效,即在相邻两个机器周期对中断请求引入端进行采样中,如前一次为高,后一次为低即为有效中断请求。这就要求在这种中断方式,中断请求信号的脉冲宽度必须大于一个机器周期,以保证电平变化能被单片机采样到。
定时器控制寄存器 (TCON)
外中断请求方式的控制位在lcd液晶屏图定时控制寄存器TCON(地址为88H)中的位88(IT0)和位8A(IT1)两个位,当IT0(IT1)=0为电平方式,IT0(IT1)=1为脉冲方式。同时在此寄存器中的位89(IE0)和位8B(IE1)为外中断请求标志位,当CPU采样到INT0(INT1)端出现有效中断请求时,此位由硬件置1。在中断响应完成后转向中断服务时,再由硬件自动清0。
中断允许控制寄存器 (IE)
下面我们对有关控制位作说明:
&EA&&中断允许总控制位,EA=0,中断总禁止,禁止所有中断。EA=1,中断总允许,总允许位打开后,各中断的允许或禁止由各中断允许控制位设置决定。
&EX0(EX1)&&外部中断允许控制位,EX0(EX1)=0,禁止外部中断。EX0(EX1)=1,允许外部中断。
&ET0(ET1)&&定时/计数中断允许控制位,ET0(ET1)=0,禁止定时/计数中断。ET0(ET1)=1,允许定时/计数中断。
&ES&&串行中断允许控制位,ES=0,禁止串行中断。ES=1,允许串行中断。
中断的允许和禁止就是中断的开放和关闭,lcd液晶屏图中断允许就是开放中断,中断的禁止就是关闭中断。从以上说明我们可看出,MCS-51的中断允许是通过两级控制的,以EA位作为总中断控制位,以各中断控制位为分控制位。当总中断位为禁止状态时,不管分控制位是允许或禁止整个中断都是禁止的。只有当EA=1(允许)时,才能由各分控制位设置各自的中断允许与禁止。MCS-51单片机复位后,IE=00H,因此中断处于禁止状态。
值得一提的是:单片机中断响应后不会自动关闭中断,因此在转入中断服务程序后,应由软件指令禁止中断。
中断优先级控制寄存器 (IP)
MCS-51的中断优先级控制比较简单,只设置了高、低两个级别的有限级,各中断源的优先级别由优先寄存器(IP)进行控制。
&PX0&&外中断0(INT0)优先级控制位。
&PT0&&定时中断0(T0)优先级控制位。
&PX1&&外中断1(INT1)优先级控制位。
&PT1&&定时中断1(T1)优先级控制位。
&PS &&串行中断(ES)优先级控制位。
控制位=0,优先级为低。控制位=1,优先级为高。
中断优先级是为了中断嵌套服务的,控制原则为:
(1) 低优先级中断不能打断高优先级的中断服务,而高优先级的中断服务可以打断低优先级的中断服务。
(2) 同级的中断已经响应,其他中断将被禁止。
(3) 如果同级的多个中断源同时出现,CPU将按查询次序确定哪个中断被响应,次序为:外中断0&定时中断0&外中断1&定时中断1&串行中断。
中断控制寄存器的状态设置
在应用中,我们可以通过相应的控制寄存器来使用中断系统,因此从使用的角度上看,这些控制寄存器是面向用户的。这些控制寄存器既可以进行字节寻址,也可以进行lcd液晶屏图位寻址,也就是对位状态的寻址既可以使用字节操作指令也可以使用位操作指令,例如:
MOV IE,#81H
如使用位操作指令,也可写为:
对于一般的外中断程序,我们可以这样安排:
ORG 0000H ;主程序入口
START: AJMP MAIN
ORG 0003H ;外中断程序入口
AJMP INT00
MAIN: MOV IE,#81H ;允许lcd液晶屏图总中断和外中断
&& ;主程序
INT00: && ;外中断服务程序
RETI ;中断返回
对于搞单片机的特别用8051系列工程师来说,谈到单片机的RTOS,很多时候会问一句:“为什么要用RTOS?单片机就这一点资源,使用RTOS能保证效率吗?”......关键字:
现在想起来,当时的情形还历历在目。当时工作非常艰辛,累得我是满地找牙。记得进厂的第一天,就加班通霄,以后天天晚上加班至12点,早上7点起床。......关键字:
我 要 评 论
热门关键词INTERRUPT CONTROLLER - DoubleLi - 博客园
&1,中断的基本概念
&&&& CPU与外设之间传输数据的控制方式通常有3种:查询方式,中断方式和DMA方式。查询方式的优点是硬件开销小不需要额外的硬件支持只是通过软件不断的轮询,使用起来也就比较简单,但在此方式下,CPU要不断地查询外设的状态,当外设未准备好时,CPU就只能循环的等待,不能执行其他程序,这样就浪费了CPU的大量时间,降低了CPU的利用率,为了解决这个矛盾,通常采用中断传送方式,即当CPU进行主程序的操作时,外设的数据已经存入输入端口的数据寄存器或者输出端口的数据输出寄存器已为空,则由外设通过接口电路向CPU发出中断请求信号,CPU在满足一定条件下,会暂停执行当前正在执行的主程序,然后转入执行相应能够进行输入/输出操作的中断子程序,待输入/输出操作执行完毕之后,CPU再返回并继续执行原来被中断的主程序。这样CPU就避免了把大量时间耗费在等待查询状态信号的操作上,使其工作效率得以大大提高。能够向CPU发出中断请求的设备或事件称为中断源,系统引入中断机制后,CPU与外设(甚至多个外设)处于&并行&工作状态,便于实现信息的实时处理和系统的故障处理。
&&&& (1)中断响应
&&&&& 中断源向CPU发出中断请求,若优先级别是最高的,则CPU在满足一定的条件时,可中断当前程序的运行,保护好被中断的主程序的断点及现场信息,然后根据中断源提供的信息,找到特定中断服务子程序的入口地址,转去执行新的程序段。
&&&&&&CPU响应中断是有条件的,如内部要允许中断,中断未被屏蔽,关键一点CPU当前指令要执行完才回去响应中断(只有在CPU执行完一条指令后才会停下当前的程序去响应中断)等
&&&&& (2)中断服务子程序
&&&&& CPU响应中断以后,就会中止当前的程序,转去执行一个中断服务子程序,以完成为相应的设备服务,中断服务子程序的一般结构为:
&&&&& 保护现场:由一系列压栈指令完成,目的是为了保护那些与主程序中有冲突的寄存器也就是在中断子程序中也需要用到的寄存器(如r0,r1,r2等),若中断服务子程序中所使用的寄存器与主程序中所使用的寄存器没有冲突,则这一步可省略。
&&&&& 中断处理:中断处理程序在检查到相应的中断源后,调用对应的中断处理程序来执行。
&&&&& 恢复现场并返回:由一系列的出栈指令完成,与现场保护对应的,但要注意数据恢复的次序。
&&&&& 由于中断服务子程序需要打断主程序的执行,所以其处理应该及时完成,较长时间的延时会导致系统性能下降。
&&&&& 在进入正题之前,我想先把ARM920T的异常向量表(Exception Vectors)做一个简短的介绍。ARM920T的异常向量表有两种存放方式,一种是低端存放(从0x处开始存放),另一种是高端存放(从0xfff000000处开始存放)。关于为什么要分两种方式进行存放这点我将在介绍MMU的文章中进行说明,本文采用低端模式。ARM920T能处理有8个异常,他们分别是:Reset,Undefined instruction,Software Interrupt,Abort (prefetch),Abort (data),Reserved,IRQ,FIQ下面是某个采用低端模式的系统源码片段:
_start:b Handle_Resetb HandleUndefb HandleSWIb HandlePrefetchAbortb HandleDataAbortb HandleNotUsedb HandleIRQb HandleFIQ&..&..other codes&
&&& 上面这部分片段一般出现在一个名叫&head.s&的汇编文件里,&b Handle_Reset&这条语句就是系统上电之后运行的第一条语句。也就是说这部分代码的二进制码必须位于内存的最开始部分(这正是低端存放模式),因为上电后CPU会从SDRAM的0x处取第一条指令并执行。
Address&&&& Instruct0x:&b Handle_Reset0x:&b HandleUndef0x:&b HandleSWI0x0000000C:&b HandlePrefetchAbort0x:&b HandleDataAbort0x:&b HandleNotUsed0x:&b HandleIRQ0x0000001C:&b HandleFIQ
&&& 上面是该程序段在系统上电后加载到内存后的分布情况,我们可以看到每条指令占用了4个字节。&&& 上电后,PC指针会跳转到Handle_Reset处开始运行。以后系统每当有异常出现,则CPU会根据异常号,从内存的0x处开始查表做相应的处理,比如系统触发了一个IRQ异常,IRQ为第6号异常,则CPU将把PC指向0x地址(4*6=24=0x)处运行,该地址的指令是跳转到&中断异常服务例程&(HandleIRQ)处运行。以上就是我对异常向量表的一个简单介绍。现在可以进入我们文章的主题 &中断异常处理&,s3c2410的中断分快中断(FIQ)和普通中断(IRQ),我们讨论的重点是普通中断(IRQ)。s3c2410的中断异常处理模块总共由以下寄存器构成& SRCPND(SOURCE PENDING REGISTER)& INTMOD(INTERRUPT MODE REGISTER)& INTMSK(INTERRUPT MASK REGISTER)& PRIORITY( PRIORITY REGISTER)& INTPND(INTERRUPT PENDING REGISTER)& INTOFFSET(INTERRUPT OFFSET REGISTER)& SUBSRCPND&(INTERRUPT SUB SOURCE PENDING)& INTSUBMSK&&(INTERRUPT SUB MASK REGISTER)下面我将讲解每个寄存器在一个中断处理流程中所扮演的角色:&&& SRCPND/ SUBSRCPND这两个寄存器在功能上是相同的,它们是中断源引脚寄存器,在一个中断异常处理流程中,中断信号传进中断异常处理模块后首先遇到的就是SRCPND/ SUBSRCPND,这两个寄存器的作用是用于标示出哪个中断请求被触发。SRCPND的有效位为32,SUBSRCPND&的有效位为11,它们中的每一位分别代表一个中断源。SRCPND为主中断源引脚寄存器,SUBSRCPND为副中断源引脚寄存器。这里列举出SRCPND的各个位信息:
&& 每个位的初始值皆为0。假设现在系统触发了TIMER0中断,则第10bit将被置1,代表TIMER0中断被触发,该中断请求即将被处理(若该中断没有被屏蔽的话)。SUBSRCPND情况与SRCPND相同,这里就不多讲了。&&& INTMOD寄存器有效位为32位,每一位与SRCPND中各位相对应,它的作用是指定该位相应的中断源处理模式(IRQ还是FIQ)。若某位为0,则该位相对应的中断按IRQ模式处理,为1则以FIQ模式进行处理,该寄存器初始化值为0x,即所有中断皆以IRQ模式进行处理。(详细请参考s3c2410操作手册)。INTMSK/ INTSUBMSK&寄存器为中断屏蔽寄存器 ,INTMSK为主中断屏蔽寄存器,INTSUBMSK为副中断屏蔽寄存器。INTMSK有效位为32,INTSUBMSK有效位为11,这两个寄存器各个位与SRCPND和SUBSRCPND分别对应。它们的作用是决定该位相应的中断请求是否被处理。若某位被设置为1,则该位相对应的中断产生后将被忽略(CPU不处理该中断请求),设置为0则对其进行处理。这两个寄存器初始化后的值是0xFFFFFFFF和0x7FF,既默认情况下所有的中断都是被屏蔽的。到目前为止我们总共讲解了SRCPND,INTMOD,INTMSK,SUBSRCPND,INTSUBMSK五个寄存器,在继续讲解PRIORITY寄存器之前我们先来看一张图。
&& 先弄清楚一点,现在要讨论的是一个中断优先级的判断问题。为什么会有中断有先级的问题呢?我们知道CPU某个时刻只能对一个中断源进行中断处理,如果现在有3个中断同时发生了,那CPU要按什么顺序处理这个3个中断呢?这正是引入优先级判断的原因所在,通过优先级判断,CPU可以按某种顺序逐个处理中断请求。3sc2410的优先级判断分为两级。&&& 如上图所示,SRCPND寄存器对应的32个中断源总共被分为6个组,每个组由一个ARBITER(0~5)寄存器对其进行管理。中断必须先由所属组的ARBITER(0~5)进行第一次优先级判断(第一级判断)后再发往ARBITER6进行最终的判断(第二级判断)。ARBITER(0~5)这六个组的优先级已经固定,我们无法改变,也就是说由ARBITER0控制的该组中断优先级最高(该组产生的中断进行第一级判断后永远会以REQ0向ARBITER6传递过去)其次是ARBITER1, ARBITER2, ARBITER4, ARBITER4, ARBITER5.我们能够控制的是某个组里面各个中断的优先级顺序。怎么控制?通过PRIORITY寄存器进行控制:]以下是PRIORITY寄存器各个位的参数表
&&&从表上我们可以知道PRIORITY寄存器内部各个位被分为两种类型,一种是ARB_MODE,另一种为ARB_SEL, ARB_MODE类型有7组对应ARBITER(0~6),ARB_SEL类型有7组对应ARBITER(0~6)。现在我将以ARBITER2为例,讲解中断组与PRIORITY寄存器中ARB_SEL, ARB_MODE之间的相互关系。&首先我们看到ARBITER2寄存器管理的该组中断里包括了6个中断,分别是INT_TIMER0,INT_TIMER1,INT_TIMER2,INT_TIMER3,INT_TIMER4,INT_UART2,她们的默认中断请求号分别为REQ0,REQ1,REQ2,REQ3,REQ4,REQ5。我们先看PRIORITY寄存器中的ARB_SEL2,该参数由两个位组成,初始值为00。从该表可以看出00定义了一个顺序&0-1-2-3-4-5&,这个顺序就是这组中断组的优先级排列,这个顺序指明了以中断请求号为0(REQ0)的INT_TIMER0具有最高的中断优先级,其次是INT_TIMER1,INT_TIMER2&。假设现在ARB_SEL2的值被我们设置为01。则一个新的优先级次序将被使用,01对应的优先级次序为0-2-3-4-1-5,从中可以看出优先级最高和最低的中断请求和之前没有变化,但本来处于第2优先级的INT_TIMER1中断现在变成了第5优先级。从ARB_SEL2被设置为00,01,10,11各个值所出现的情况我们可以看出,除最高和最低的优先级不变以外,其他各个中断的优先级其实是在做一个旋转排列(rotate)。为了达到对各个中断平等对待这一目标,我们可以让优先级次序在每个中断请求被处理完之后自动进行一次旋转,如何自动让它旋转呢?我们可以通过ARB_MODE2达到这个目的,该参数只有1个 bit,置1代表开启对应中断组的优先级次序旋转,0则为关闭。事实上当该位置为1之后,每处里完某个组的一个中断后,该组的ARB_SEL便递增在1(达到11后恢复为00)。&&& 现在我们另ARB_MODE2=1,ARB_SEL2=00,则当前ARBITER2的优先级顺序为0-1-2-3-4-5,假设现在该组的1号中断请求INT_TIMER1和2号中断请求INT_TIMER2被同时触发,CPU根据优先级判断后决定先把INT_TIMER1中断向ARBITER6进行发送(在ARBITER6做第最终优先级判断),接着再向ARBITER6发送INT_TIMER2中断。请注意,在INT_TIMER1被处理完毕后,该组中段的优先级次序被自动做了一次旋转,旋转后ARBITER2的优先级顺序变为0-2-3-4-1-5。假设之后某个时刻该组的INT_TIMER1和INT_TIMER2又被同时触发,则此时CPU优先处理的会是INT_TIMER2。若我们另ARB_MODE2=0,则改组的中断优先级次序在任何情况下都不做任何改变,除非我们人为地重新设置了ARB_SEL2的值。INTPND&寄存器可能是整个中断处理过程中我们要特别注意的一个寄存器了,他的操作比较特别,先看一下该寄存器各位详细功能列表
&&& 正如你所见的,INTPND寄存器与SRCPND长得一模一样,但他们在中断异常处理中却扮演着不同的角色,如果说SRCPND是中断信号进入中断处理模块后所经过的第一个场所的话,那么INTPND则是中断信号在中断处理模块里经历的最后一个寄存器。它的每个位对应一个中断请求,若该位被置1,则表示相应的中断请求被触发,描述到这里你可能会发现它不仅和SRCPND长得一模一样,就连功能都一样,其实不然,他们在功能上有着重大的区别。SRCPND是中断源引脚寄存器,某个位被置1表示相应的中断被触发,但我们知道在同一时刻内系统可以触发若干个中断,只要中断被触发了,SRCPND的相应位便被置1,也就是说SRCPND在同一时刻可以有若干位同时被置1,然而INTPND则不同,他在某一时刻只能有1个位被置1,INTPND 某个位被置1(该位对应的中断在所有已触发的中断里具有最高优先级且该中断没有被屏蔽),则表示CPU即将或已经在对该位相应的中断进行处理。于是我们可以有一个总结:SRCPND说明了有什么中断被触发了,INTPND说明了CPU即将或已经在对某一个中断进行处理。特别注意:每当某一个中断被处理完之后,我们必须手动地把SRCPND/SUBSRCPND , INTPND三个寄存器中与该中断相应的位由1设置为0,刚才我说INTPND的操作很特别,它的特别之处就在于对当我们要把该寄存器中某个值为1的位设置为0时,我们不是往该位置0,而是往该位置1。假设SRCPND=0x,INTPND=0x,该值说明当前0号中断和1号中断被触发,但当前正在被处理的是0号中断,处理完毕后我们应该这样设置INTPND和SRCPND:& SRCPND=0x& && && && & &//位0被置为0& INTPND =0x& && && && & //位0被置为0(方法是往该位写入1)INTOFFSET寄存器的功能则很简单,它的作用只是用于表明哪个中断正在被处理。下面是该寄存器各位详细功能列表
&&& 若当前INT_TIMER0被触发了,则该寄存器的值为10,以此类推。&&& 现在我把整个中断流程用一个图加以说明
以上这个图清楚地说明了一个中断异常处理流程。&&& 下面我用INT_TIMER0, INT_TIMER2和INT_UART0三个中断完整地介绍一次中断异常处理。首先我们得做几个假设:
假设1:这三个中断的屏蔽被取消。假设2:PRIORITY寄存器中ARB_MODE2,ARB_MODE5皆为0,既不进行优先级的自动旋转排序,任何时候&&&&&&ARBITER2,ARBITER5控制的中断组优先级次序分别为0-1-2-3-4-5和1-2-3-4。假设3:这三个中断皆为IRQ类型。假设4:这三个中断同时被触发。INT_TIMER0,INT_TIMER2和INT_UART0三个中断被同时触发,此时三个中断信号流向SRCPND寄存器,使该寄存器中的第10位,12位,28位被置为1,中断信号继续向前流经INTMASK寄存器,这三个中断都没有被屏蔽,于是信号进一步流经INTMODE寄存器,这三个中断皆为IRQ类型,故中断信号继续向前流向PRIORITY寄存器,经过优先级判断,INT_TIMER0中断信号使INTPND寄存器的第10位置1(INT_TIMER0优先级最高),此时INTOFFSET寄存器的值为10,CPU转向相应的中断服务例程进行处理。处理完毕后,我们的程序将INTPND和SRCPND的第10置为0,至此INT_TIMER0中断处理完毕。此时SRCPND的第12位,28位仍为1(这两个中断请求未被处理),故他们会继续被CPU已刚才描述的方式进行处理。
&&& S3C2410X处理器的中断处理与其他CPU的处理模式基本上是一致的,只是由于它引入了几种不同的处理器模式,使中断处理变得更加的容易,步骤如下:
&&&&&& (1) 保存现场,当系统出现中断时,处理器会首先保存现场,这一过程包括将主程序当前的PC值存入到LR中,保存当前的程序运行状态也就是CPSR的值到SPSR中。
&&&&&&&(2)&模式切换,当处理器完成现场保护后,就要进入到中断模式,并将PC值设置为一个固定的值,也就是我们之前提到的通过从0x开始查表查到,中断处理是0x,这也就是IRQ模式的中断入口地址,在中断模式下,有两个独立的寄存器r13,r14,
可以便于中断程序使用自己特有的堆栈,但这样就会产生一个问题,也就是中断处理时堆栈溢出保护的问题,这需要认真的估计堆栈的大小,通常在中断处理时也要尽量减少函数的调用层次,否则会有一些不可预知的错误。&&&&&& (3)& 获取中断源,所有的IRQ中断都是从0x开始执行,通常在该地址处放一条跳转指令,进一步跳到中断程序中,一般是如:&b HandleIRQ,或 LDR pc,=0x,也就是完成中断三级跳的第一跳,从NAND FLASH跳到SDRAM的中断入口。我们可以看到中断入口的一部分汇编代码:
&&&&&0x:&&&&&& LDR& pc, =0x
&&&& ......
&&&&&0x:&&&&&& b& HandlerIRQ
&&&& HandlerIRQ:
&&&& sub&&& sp,sp,#4& //将堆栈指针向上移动4个字节用来为中断分发例程入口地址预留栈空间
&&&& stmfd& sp!,{r0}& //将r0保存到堆栈中sp自加4个字节
&&&& ldr&&& r0, =HandleIRQ //将中断分发例程入口地址的指针保存到r0中
&&&&&ldr&&& r0,[r0] //将中断分发例程入口地址保存到r0中
&&&&&str&&& r0,[sp,#4] //将中断分发入口地址保存到预留的堆栈空间中
&&&& ldmfd& sp!,{r0,pc} //这个涉及到赋值的一个顺序,堆栈中现在已经保存了两个寄存器的值,最开始r0的初始值以及中断分发例程入口地址值,这句代码的意思也就是,从堆栈中取出中断分发例程入口地址赋值给PC,sp自加4个字节指向第一次存放r0的位置,然后将该值取出来赋值给r0,所以sp的值最终不变,ldmfd的赋值顺序是从右到左。sp完成自加运算。这条指令也实现了一个跳转,因为将中断分发入口地址赋值给了PC,所以会转去执行中断分发例程。这也就实现了中断三级跳的第二跳。
&&&&&&&& 在此有个前提条件,即必须在HandleIRQ地址处保存正确的分发例程入口地址,如使用下面代码后,IsrIRQ就是中断分发例程。
&&&&&&&&& ldr& r0, =HandleIRQ
&&&&&&&&& ldr& r1, =IsrIRQ
&&&&&&&&& str& r1, [r0]
IsrIRQ通常采用汇编语言编写,通过读取INIOFFSET寄存器获取产生中断的中断源的偏移,然后根据该偏移值获取该中断对应向量表中的偏移,最后从中断向量表中获取到中断服务函数入口地址,并跳转到该地址处执行。
&&&&&&&& IsrIRQ:
&&&&&&&&&&&&& sub&&& sp,sp,#4&&& //为保存PC预留栈区域
&&&&&&&&&&&&& stmfd sp!,{r8-r9}& //将r8,r9保存到堆栈中,sp对应自加8
&&&&&&&&&&&&&&ldr&&&& r9, =INTOFFSET& //在某一时刻INTOFFSET寄存器中只存放在INTPND中的那个中断的偏移值,将INTOFFSET地址保存到r9
&&&&&&&&&&&&&&ldr&&&& r9,[r9]&&& //将该寄存器中存放的对应中断的偏移地址取出来存放到r9中
&&&&&&&&&&&&& ldr&&&& r8, =HandleEINT0& //HandleEINT0是中断向量表的入口地址,每四个字节保存一个终端服务函数的入口地址。
&&&&&&&&&&&&& add&& r8,r8,r9,lsl #2 //将r9获取到的值左移2位也就是乘以4,然后加上中断向量表的入口地址,结果保存到r8,此时r8也就是该中断对应中断函数入口地址的指针
&&&&&&&&&&&&& ldr&&&& r8,[r8]&& //将该中断函数入口地址保存到r8中
&&&&&&&&&&&&& str&&&& r8,[sp,#8]& //将r8保存到堆栈中
&&&&&&&&&&&&& ldmfd sp!,{r8-r9,pc}& //主要是将r8取出来赋值给pc,然后去执行对应的中断服务函数。
IsrIR跳转到相应的ISR执行后,必须由ISR在执行完毕后推出IRQ模式,因此必须需将该函数定义为中断服务函数,若采用GNU编译器,使用如下关键字:__attribute__((interrupt("IRQ")))
&&&&&&&&&&& (4)处理中断,在中断程序中需要进一步获取中断源,即谁引发了中断,然后通过查表获取到相应的中断的处理程序入口,并调用对应的函数。这一步在上面已经讲叙过了。
&&&&&&&&&&&& (5) 中断返回,恢复现场, 在返回时需要恢复处理器的模式,包括恢复中断处理用到的所有寄存器,恢复被中断的程序运行状态CPSR,并跳转到被中断的主程序。[汇总]STM32的中断(优先级,开关总中断)不懂的大家看下转载的【stm32吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:29,998贴子:
[汇总]STM32的中断(优先级,开关总中断)不懂的大家看下转载的收藏
一:综述STM32 目前支持的中断共为 84 个(16 个内核+68 个外部), 16 级可编程中断优先级的设置(仅使用中断优先级设置 8bit 中的高 4 位)和16个抢占优先级(因为抢占优先级最多可以有四位数)。二:优先级判断
(一)中断优先级概念
STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两种优先级。
(二)中断响应次序
(1)具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。
(2)当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。
(3)如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。抢占优先级高啊,抢占优先级高的中断可以打断抢占优先级低的中断,这时是不用管响应优先级的;响应优先级只是在两个或者多个抢占优先级相同的中断同时到来时进入响应优先级高的中断,而如果进入这个中断之后再来一个抢占优先级相同但是响应优先级更高的中断,则不会打断已有的中断。 总之就是抢占优先级不同的时候看抢占优先级级数,先响应抢占优先级高的中断,而且抢占优先级高的中断可以打断抢占优先级低的中断;当抢占优先级相同的时候看响应优先级级数,先响应响应优先级高的中断,但是响应优先级高的中断不可以打断响应优先级低的中断; 如果把 NVIC_PriorityGroup_4 =& 选择第4组,所有的4位用于响应抢占优先级了。三:优先级分组
既然每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位在NVIC应用中断与复位控制寄丛器(AIRCR)的中断优先级分组域中,可以有8种分配方式,如下:
所有8位用于指定响应优先级最高1位用于指定抢占式优先级,最低7位用于指定响应优先级最高2位用于指定抢占式优先级,最低6位用于指定响应优先级最高3位用于指定抢占式优先级,最低5位用于指定响应优先级最高4位用于指定抢占式优先级,最低4位用于指定响应优先级最高5位用于指定抢占式优先级,最低3位用于指定响应优先级最高6位用于指定抢占式优先级,最低2位用于指定响应优先级最高7位用于指定抢占式优先级,最低1位用于指定响应优先级这就是优先级分组的概念。--------------------------------------------------------------------------------Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位(AIRCR高四位),这4个寄存器位的分组方式如下:第0组:所有4位用于指定响应优先级第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级第4组:所有4位用于指定抢占式优先级可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:NVIC_PriorityGroup_0 =& 选择第0组NVIC_PriorityGroup_1 =& 选择第1组NVIC_PriorityGroup_2 =& 选择第2组NVIC_PriorityGroup_3 =& 选择第3组NVIC_PriorityGroup_4 =& 选择第4组中断优先级分组是为了给抢占式优先级和响应优先级在中断优先级寄丛器的高四位分配各个优先级数字所占的位数。在一个程序中只能设定一次四:中断源的优先级接下来就是指定中断源的优先级,中断源优先级是在中断优先级寄存器中设置的,只能设置及高四位,必须根据中断优先级分组中设置好的位数来在该寄存器中设置相应的数值。假如你选择中断优先级分组的第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级,那么抢占式优先级就有000-111共八种数据选择,也就是有八个中断嵌套,而响应优先级中有0和1两种,总共有8*2=16种优先级。中断源优先级具体的设置了该中断源的优先级别在一个程序中可以设定多个(最多16个)优先级,每个中断源只能设定的一个。每写一个关于中断优先级的程序必须包含下列两个函数:(1)void NVIC_PriorityGroupConfig(u32 NVIC_PriorityGroup)中断分组设置(2)void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)中断优先级设置具体设置:
可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:NVIC_PriorityGroup_0 =& 选择第0组NVIC_PriorityGroup_1 =& 选择第1组NVIC_PriorityGroup_2 =& 选择第2组NVIC_PriorityGroup_3 =& 选择第3组NVIC_PriorityGroup_4 =& 选择第4组 五:举例接下来就是指定中断源的优先级,下面以一个简单的例子说明如何指定中断源的抢占式优先级和响应优先级:// 选择使用优先级分组第1组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);// 使能EXTI0中断NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQCNVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定抢占式优先级别1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// 使能EXTI9_5中断NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQCNVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);六:注意事项1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;2)抢占式优先级别相同的中断源之间没有嵌套关系;3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。七:开关总中断在STM32/Cortex-M3中是通过改变CPU的当前优先级来允许或禁止中断。PRIMASK位:只允许NMI和hard fault异常,其他中断/异常都被屏蔽(当前CPU优先级=0)。FAULTMASK位:只允许NMI,其他所有中断/异常都被屏蔽(当前CPU优先级=-1)。在STM32固件库中(stm32f10x_nvic.c和stm32f10x_nvic.h) 定义了四个函数操作PRIMASK位和FAULTMASK位,改变CPU的当前优先级,从而达到控制所有中断的目的。下面两个函数等效于关闭总中断:void NVIC_SETPRIMASK(void);void NVIC_SETFAULTMASK(void);下面两个函数等效于开放总中断:void NVIC_RESETPRIMASK(void);void NVIC_RESETFAULTMASK(void);上面两组函数要成对使用,不能交叉使用。例如:第一种方法:NVIC_SETPRIMASK();
//关闭总中断NVIC_RESETPRIMASK();//开放总中断第二种方法:NVIC_SETFAULTMASK();
//关闭总中断NVIC_RESETFAULTMASK();//开放总中断常常使用NVIC_SETPRIMASK();
// Disable InterruptsNVIC_RESETPRIMASK();
// Enable Interrupts 补充 可以用 #define CLI()
__set_PRIMASK(1)
#define SEI()
__set_PRIMASK(0)stm32优先级
1.优先级等级:
STM32用户能分配的优先级有16级,也就是用优先级寄存器NVIC-&IP[x]的高四位来表示莫个中断的优先级。
2.优先级组:
在STM32中将一个中断的优先级分为:抢占优先级和子优先级。
在进行优先级判断的时候先是比较抢占优先级然后比较子优先级。
在固件库中用变量分别表示抢占优先级和子优先级:
NVIC_InitTypeDef.NVIC_IRQChannelPreemptionP(抢占优先级)
NVIC_InitTypeDef.NVIC_IRQChannelSubP(子优先级)
优先级组就是对抢占优先级和子优先级进行的分界:
例如设置优先级组为0x05,那么表示的是莫个中断的优先级从第5位开始为界限,高两位[6:7]是抢占优先
级.第两位是[5:4]表示的是子优先级。
//调用优先级组设置函数,设置优先级是0x05.
NVIC_SetPriorityGrouping(5);
//这里说明了一个优先级寄存器的(NVIC-&IP[x])的7,6位表示的是抢占优先级。5,4表示的是优先级。
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//这里进行优先级的设置:通过上面的设置可以知道抢占优先级和子优先级的范围都是3~0;
//那么这样就设置好了一个中断的优先级//====================================================//STM32 中断与嵌套NVIC 快速入门。//
//====================================================我也是靠看这本书才弄懂的:Cortex-M3 权威指南Joseph Yiu 著宋岩 译其实很简单。 //CM3 有 最多240个中断(通常外部中断写作IRQs),就是 软件上说的 IRQ_CHANAELx(中断通道号x) 每个中断有自己的可编程的中断优先级【 有唯一对应的 中断优先级寄存器 】.由于CM3支持 硬件中断嵌套,所以可以有 256 级的可编程优先级和 256级中断嵌套【 书上称:抢占(preempt) 优先级】所以大家可以设: IRQ CHANAEL 0 通道 = 2
中断优先级WWDG 窗口定时器中断IRQ CHANAEL 1 通道 = 0
中断优先级PVD联到EXTI的电源电压检测(PVD)中断 IRQ CHANAEL 3 通道 = 255
中断优先级RTC 实时时钟(RTC)全局中断IRQ CHANAEL 6 通道 = 10
中断优先级EXTI0 EXTI线0中断..... IRQ CHANAEL 239 通道 =
中断优先级.. 这个实在是太恐怖了! 是的,其实CM3 并没有这样做。 实在的芯片例如STM32等就只有设计来可用才64级可编程优先级和8级中断嵌套。对 64级中断就是说:( INT0 到 INT63)这个大家比较好理解,其它的64···239就不用了。IRQ CHANAEL 0 。。。 IRQ CHANAEL
63 而8级中断嵌套这又是何解呢? 是这样的,上面说 一个 【中断】对应一个【中断优先级寄存器】,而这个寄存器是 8 位的。 当然就是 256级了。而现在就用了 它其中的 BIT7,IT6,BIT5三位来表示,而且是MSB对齐的。 用了3 个位来表达优先级(MSB 对齐的我们能够使用的8 个优先级为:0x00(最高),0x20,0x40,0x60,0x80,0xA0,0xC0 以及0xE0。)这样我们在【中断优先级寄存器】就不能按理论的填 0到255之间的数了,而只能填0x00(最高),0x20,0x40,0x60,0x80,0xA0,0xC0 以及0xE0。)所以大家可以设: IRQ CHANAEL 0 通道 = 0x20
中断优先级 WWDG 窗口定时器中断 IRQ CHANAEL 1 通道 = 0x40
中断优先级PVD联到EXTI的电源电压检测(PVD)中断 IRQ CHANAEL 3 通道 = 0x20
中断优先级RTC 实时时钟(RTC)全局中断IRQ CHANAEL 6 通道 = 0xA0
中断优先级EXTI0 EXTI线0中断..... IRQ CHANAEL 63 通道 =
【0x00(最高),0x20,0x40,0x60,0x80,0xA0,0xC0以及0xE0。)】 大家注意到了,上面通道0和通道3 的优先级都是0X20, 这怎么办?// 如果优先级完全相同的多个异常同时悬起,则先响应异常编号最小的那一个。如IRQ#0会比IRQ #3 先得到响应,而且文中还讲了 【优先级分组】,这又是什么回事? 其实我回头看来,这个【优先级分组】和【抢占优先级】【亚优先级】都毫无意义的。
如果当时用 256级即是把【中断优先级寄存器】的8位都全用上,就没这个必要了。还什么优先级分组呢!就是因为厂家现在【偷工减料】,才搞出这个明堂来的。 是这样的,在应用程序中断及复位控制寄存器(AIRCR) 中的 10:8位【3位】是表示【优先级分组】它作用主要是用于对【中断优先级寄存器】『我们现在中用了BIT7,BIT6,BIT5三位』的功能的说明。 有一个表,在《Cortex-M3 权威指南》的110页, 例如我们把AIRCR的10:8位设为【5】 ,查表可得【抢占优先级】=【7:6】,【亚优先级】=【5:0】,对于【中断优先级寄存器】只用了BIT7,6,5, 因此我们可以看作是【7:6】,【5】。那4-0 可以不管。 现在我们的 IRQ0=0X20, IRQ3=0X20, 也就是
】『bit7=0,bit6=0,bit5=1,bit4=0』 因为大家(IRQ0/IRQ3)的 【抢占优先级】=【7:6】都是0,说明它们的中断相应级别是一样的。再继续判断它们哪个更优先的责任就要看【5】,结果连【5】都是一样的!那就按默认:// 如果优先级完全相同的多个异常同时悬起,则先响应异常编号最小的那一个。如IRQ#0会比IRQ #3 先得到响应,由于CM3没有 进中断【关全局中断相应】这事,只要是中断通道打开了,就会存在通道间的 嵌套,即是会发生【抢占】的情况了。 上面就简短的说明,如果要详细理解,可以看《Cortex-M3 权威指南》。有任何理解不当,请各位多多指教! 补充注意: “2)抢占式优先级别相同的中断源之间没有嵌套关系;”
所以大家可以设: IRQ CHANAEL 0 通道 = 0x20
中断优先级
WWDG 窗口定时器中断IRQ CHANAEL 1 通道 = 0x40
中断优先级
PVD联到EXTI的电源电压检测(PVD)中断 IRQ CHANAEL 3 通道 = 0x20
中断优先级
RTC 实时时钟(RTC)全局中断IRQ CHANAEL 6 通道 = 0xA0
中断优先级
EXTI0 EXTI线0中断 这样 0 通道和3 通道就不会有嵌套情况,而是0 通道按默认比3 通道优先高些。而0 通道与1 通道就会有嵌套情况。
芯片复位后,默认的优先级分组 是 0, 就是 【7:1】表示抢占式优先级,【0】表示亚优先级, 这样对于MSB对齐的 8 个优先级为:0x00(最高),0x20,0x40,0x60,0x80,0xA0,0xC0 以及0xE0。)使用就很方便了,建议大家就用默认的默认的优先级分组 是0,也就是复位后的值,哈哈! 例如下面的两个按键,都使用外中断方式, 使用了PD.3,和PD.4两个引脚。这两个中断的优先级都是0X20,按默认的优先级分组,它们之间不会发生中断嵌套。/* Enable the EXTI3 Interrupt on PD.3 */ STM32_Nvic_Regs-&Priority[9].all=0x20;
// 中断的优先级是 0X20STM32_Nvic_Regs-&Enable[0].bit.INT9=1;
// 开INT9 中断
IRQ9 /* Enable the EXTI4 Interrupt on PD.4 */ STM32_Nvic_Regs-&Priority[10].all=0x20;
// 中断的优先级是 0X20 STM32_Nvic_Regs-&Enable[0].bit.INT10=1; // 开INT10 中断
本文是复制转载的
热销好货「天猫618」大牌尖货,限量特惠折上折,购物满就返红包,多买多得,不可错过!「天猫618」理想生活狂欢季,&嗨&购大品牌!
好长,看晕了
大神,向您请教个问题。如果我用了usart2和tim2的中断,usart2中断分组设置的是“NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);”而TIM2中断分组设置的是“NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);”这样可以吗?如果不可以,会造成什么样的后果呢?谢谢
谢谢楼主写的很好
恍然大悟,一直以为响应高的也可嵌套在响应低的
多谢楼主,受教了
应该如何设置NVIC_PriorityGroupConfig,比如我要使用一个TIM2_CH2做输入捕获,一个DMA中断,还有一个TIM3定时器中断,有多少个嵌套关系就使用第几组吗
标记,回去看
NVIC-&IP[]=
;方括号里面是直接写中断号么?优先级怎么设置呢
登录百度帐号}

我要回帖

更多关于 中断允许寄存器 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信