中断源和中断向量:
缺省情况下,AVR的程序存储区的最低端,即从Flash地址的0x0000开始用于放置中断向量,称做中断向量区。中断向量区大小 = 中断源个数 \* 每个中断向量占据字数。对于Flash比较小的AVR处理器,每个中断向量占据一个字的空间,用于放置一条相对转移指令 rjmp(跳转范围-2K~+2K),而Flash较大的AVR,每个中断向量占据两个字空间,用于放置一条绝对转移指令 jmp,用于跳转到相应中断的中断服务程序的起始地址。
在这21个中断中,包含1个非屏蔽中断(RESET)3个外部中断(INT0、INT1、INT2)和17个内部中断。
RESET $000 | INT0 $002 | INT1 $004 | INT2 $024 |
INT0、INT1和INT2是3个外部中断源,它们是分别由芯片外部引脚PD2、PD3、PB2上的电平变化或状态触发的。通过对控制寄存器MCUCR和控制与状态寄存器MCUCSR的配置,外部中断可以定义为由PD2、PD3、PB2引脚上的电平的下降沿、上升沿、逻辑电平变化,或者低电平触发(INT2仅支持电平变化的边沿触发),这为外部硬件电路和设备向AVR申请中断服务提供了很大的方便。
\*\*关于计数器的中断寄存器:TIMER2 COMP、TIMER2 OVF、TIMER1 CAPT、TIMER1 COMPA、TIMER1 COMPB、TIMER1 OVF、TIMER0 OVF、TIMER0 COMP这8个中断是来自于ATmega16内部的3个定时计数器触发的内部中断。定时器处在不同的工作模式下时,这些中断的发生条件和具体意义是不同的。
ATmega16的中断控制:
1)、中断优先级的确定
AVR单片机中,一个中断在中断向量区中的位置决定了它的优先级,位于低地址的中断优先级高于位于高地址的中断。所以 RESET 具有最高优先级。
AVR单片机采用固定的硬件优先级方式,不支持通过软件对中断优先级的重新设定。当有多个中断源向MCU申请中断的情况中,MCU根据中断优先级的不同,把低优先级的中断挂起,首先响应中断优先级最高的那个中断。待优先级最高的中断服务程序执行完成返回后,再顺序响应低优先级的中断。
2)、中断标志
AVR有两种机制不同的中断:带有中断标志的中断(可挂起)和不带中断标志的中断(不能挂起)。在 AVR 中,大多数的中断都属于带中断标志的中断。所谓的中断标志,是每个中断源在其 I/O 空间寄存器中具有自己的一个中断标志位。AVR 的硬件系统在每个时钟周期内都会检测(接受)外部(内部)中断源的中断条件。一旦中断条件满足,AVR 的硬件就会将置位相应的中断标志位(置为“1”),表示向 MCU 提起中断请求。
3)、中断屏蔽与管理
AVR 对中断采用两级控制方式。两级控制是指 AVR 有一个中断允许的总控制位 I(既 AVR 标志寄存器 SREG 中的 I 标志位“SREG.7”),通常称为全局中断允许控制位。同时 AVR 为每一个中断源都设置了独立的中断允许位,这些中断允许位分散位于各中断源所属模块的控制寄存器中。
▋AVR响应一个可屏蔽中断源(假定为A中断)的中断的条件是: 响应A中断 = 全局中断允许标志 AND 中断A允许标志位 AND 中断A标志 当某个中断条件成立后,硬件会自动将该中断的标志位置"1",表示中断产生,同时也作为申请中断服务的请求信号。如果该中断的允许位为"1",同时AVR的全局中断允许位 I 也是"1"时,那么MCU在执行完当前一条指令之后就会响应该中断。 ▋AVR复位后,各个中断允许位以及全局中断允许位均被清零,这保证了程序在开始执行时(一般程序开头是对芯片内部以及外围系统的初始化设置)不会受到中断的干扰。 ▋AVR复位后的用户初始化程序中,需要先对需要使用的中断源进行必要的配置,待系统初始化过程结束后在置位 I ,使系统进入正常的工作状态,开始响应中断请求。 |
4)、中断嵌套
AVR在响应一个中断的过程中通过硬件将 I 标志位自动清零,这样就阻止了MCU响应其它中断。通常情况下,AVR是不能自动实现中断嵌套的。如果系统中必须要实现中断嵌套的应用,用户可以在中断服务程序中使用指令将全局中断允许位开放,通过间接的方式实现中断的嵌套处理。
滥用中断嵌套会造成程序流程的不确定性。因此建议只有当某中断确实需要得到实时响应时才考虑使用中断嵌套处理,一般情况下尽量不要采用中断嵌套,因为 AVR 本身是高速单片机,它运行速度是能足够快速的将中断服务程序执行完的。当然,用户编写中断服务程序时,应遵循尽量短小的原则。
AVR的中断响应过程:
1)、中断响应的过程
AVR在响应中断请求时,MCU会使用4个时钟周期自动顺序的完成以下任务:
▶ 清零状态寄存器SREG中的全局中断允许标志位 I ,禁止响应其他中断。
▶ 将被响应中断的标志位清零(这个只是部分中断有此操作)。
▶ 将中断断点的地址(即当前程序计数器PC的值)压入堆栈,并将SP寄存器中的堆栈指针减二。
▶ 自动将相应的中断向量地址压入程序计数器PC,即强行转入执行中断入口地址处的指令。
中断响应过程全部由硬件自己实现,不需要用户干预。
2)、中断返回的过程
AVR一旦执行中断返回RETI指令,MCU便开始了中断返回的过程。AVR在中断返回过程中,使用4个时钟周期自动按顺序完成以下任务:
▶ 从栈顶弹出2个字节的数据,将这两个数据压入程序计数器PC中,并将SP寄存器中的堆栈指针加2。
▶ 置位状态寄存器SREG中的全局中断允许标志位I,允许响应其他中断。
中断返回后,会检测中断标志,如果存在其他被挂起的中断,则AVR在中断返回后还需执行一条指令,被挂起的中断才会得到响应。
3)、中断现场的保护
AVR的中断响应和返回过程主要都是由硬件自动完成的,而在整个过程中用户程序的作用在于:
▶ 中断入口处的指令。用于指引MCU转移到中断服务程序。
▶ 中断服务程序。完成中断服务的功能。
▶ 中断返回指令。指引MCU从中断服务程序中返回。
为了提高中断响应的实时性,AVR在中断响应和返回过程中,硬件上的处理仅仅保护和恢复了中断的断点(PC值)。而对中断现场没有采取任何处理。 因此,中断现场的保护工作需要用户在自己编写的中断服务程序中通过软件完成,以保证主程序在被打断时所使用的标志位和临时寄存器等不会被中断服务程序改变,例如,对状态寄存器SREG的保护等! |
中断服务程序编写:(三个框架)中断向量区部分、主程序部分和中断服务程序部分。
1)、中断向量区部分
缺省情况下,AVR的中断向量区在Flash程序存储器的最低端。最开始的0x0000是不可屏蔽的复位上电的中断向量,此处有一条转移到主程序开始处的跳转指令。
2)、主程序部分
单片机主程序的开始阶段通常要对整个系统已经芯片本身进行初始化设置,然后才能进入正常的工作流程中。分为:堆栈指针的初始化、中断源设置、开放全局中断、各中断源相应的中断允许设置。
开放中断源本身的中断允许位之前,最好先使用指令将该中断的中断标志位清除,然后马上将中断允许位置“1”。 在开放中断前清楚可能存在的中断标志,保证了中断开放后不会形成一次“多余”的中断,这个“多余”的中断有时会造成致命的错误。因为在对中断源进行设置过程中,或中断源对应的硬件模块在工作中都有可能改变中断标志位。 |
3)、中断服务程序
由于在中断向量处通常放置一条转移指令,用于再次跳转到中断服务程序的开始处,所以中断服务程序可以放置在FLASH空间的任何地方。
中断服务程序中要考虑被中断现场的保护和恢复问题。中断的产生和响应是随机的,而且在中断服务程序中经常要使用一些寄存器,或对RAM中的变量进行操作,也会有判断和跳转的操作,这些指令可能会改变SREG中的标志位,所以必须确保当从中断服务程序返回时,被中断服务程序改变的现场全部正确的恢复,这样当中断返回后,主程序才能正确继续运行下去。 |
除了一些必须在中断中完成的工作外,对于那些不需要马上处理的工作,如键盘处理、扫描显示等应该放在主程序中完成,也就是说,中断服务程序应尽可能的短。中断服务程序短,不是程序指令少,而是执行一次中断服务程序所需要的时间短。尽量减少中断服务程序的执行时间有以下优点:
▋可以不必采用中断嵌套技术。AVR的硬件不支持自动的中断嵌套处理,因此中断执行时间短的话能够尽快的响应其他被挂起的中断,提供系统总体的实时响应速度。
▋能够防止丢失周期性中断或其它短时中断。列如,当系统有一个1ms产生一次的周期型中断源,你的中断服务程序就必须在1ms完成,否则将会造成下一个中断的“丢失”。
有很多情况下,中断仅仅表示外围设备或内部功能部件的工作过程已经达到某种状态,但不需要马上去处理,或者允许在一个比较充裕的限定时间内处理,这就可以将它们的处理工作放到主程序中完成。在这种情况下,最好的方式就是定义和使用信号量或标志变量,在中断服务程序中只是简单的对这些信号量或标志量进行必要的设置,不做其他处理就马上返回主程序,由主程序中根据这些信号量或表质量的值进行和完成处理工作。 这样做的另一个好处是,可以大大减少中断服务程序中的对中断现场保护和恢复的工作,从而又减少了中断程序的执行时间,同时也节省了堆栈空间和FLASH空间(代码少了)。 |