中断是MSP430微处理器的一大特色,有效地利用中断可以简化程序和提高执行效率。MSP430的几乎每个外围模块都能够产生中断,为MSP430针对事件(即外围模块产生的中断)进行的编程打下基础。MSP430在没有事件发生时进入低功耗模式,事件发生时,通过中断唤醒CPU,事件处理完毕后,CPU再次进入低功耗状态。由于CPU的运算速度和退出低功耗的速度很快,所以在应用中,CPU大部分时间都处于低功耗状态。
一、MSP430的中断种类
MSP430的中断分为3种:
1、系统复位
系统复位的中断向量为0xFFFE。
2、不可屏蔽中断
不可屏蔽中断的中断向量为0xFFFC。响应不可屏蔽中断时,硬件自动将OFIE、NMIE、ACCVIE复位。软件首先判断中断源并复位中断标志,接着执行用户代码。退出中断之前需要置位OFIE、NMIE、ACCVIE,以便能够再次响应中断。
需要特别注意点:置位OFIE、NMIE、ACCVIE后,必须立即退出中断相应程序,否则会再次触发中断,导致中断嵌套,从而导致堆栈溢出,致使程序执行结果的无法预料。
3、可屏蔽中断
可屏蔽中断的中断来源于具有中断能力的外围模块,包括看门狗定时器工作在定时器模式时溢出产生的中断。每一个中断都可以被自己的中断控制位屏蔽,也可以由全局中断控制位屏蔽。
多个中断请求发生时,响应最高优先级中断。响应中断时,MSP430会将不可屏蔽中断控制位SR.GIE复位。因此,一旦响应了中断,即使有优先级更高的可屏蔽中断出现,也不会中断当前正在响应的中断,去响应另外的中断。但SR.GIE复位不影响不可屏蔽中断,所以仍可以接受不可屏蔽中断的中断请求。
二、中断的响应及返回过程
1、中断响应的过程
1)如果CPU处于活动状态,则完成当前指令;
2)若CPU处于低功耗状态,则退出低功耗状态;
3)将下一条指令的PC值压入堆栈;
4)将状态寄存器SR压入堆栈;
5)若有多个中断请求,响应最高优先级中断;
6)单中断源的中断请求标志位自动复位,多中断源的标志位不变,等待软件复位;
7)总中断允许位SR.GIE复位。SR状态寄存器中的CPUOFF、OSCOFF、SCG1、V、N、Z、C位复位;
8)相应的中断向量值装入PC寄存器,程序从此地址开始执行。
2、中断返回的过程
1)从堆栈中恢复PC值,若响应中断前CPU处于低功耗模式,则可屏蔽中断仍然恢复低功耗模式;
2)从堆栈中恢复PC值,若响应中断前CPU不处于低功耗模式,则从此地址继续执行程序。
三、MSP430单片机中断的注意事项
不要使用中断嵌套。同时,为了使用C语言来编写MSP430的高质量代码需要注意,微处理器一般用于特定环境和特定用途,出于成本、功耗和体积的考虑,一般都要求尽量节省使用资源,并且,由于微处理器硬件一般都不支持有符号数、浮点数的运算,且运算位有限,因此,分配变量时必须仔细。另外要说明的是,速度和存储器的消耗经常是2个不可兼顾的目标,在多数情况下,编程者必须根据实际情况作出权衡和取舍。需要注意的事项如下:
1、通常在满足运算需求的前提下,尽量选择为变量定义字节少的数据类型。比如最常用的int和char,int是16位的,char是8位的,如果没有必要,不要使用int,而且使用char也最好使用unsignedchar。运行时,可以在变量窗口看到,使用类型为unsignedchar的变量是16进制的格式,而使用int的是十进制格式,如果char没有定义为unsigned,会出现负号,如果没有必要的话,在430中是不需要负数的。
2、尽量不用过长的数据类型,如long、longlong和double。
3、MSP430的C编译器不支持位寻址,所以运算中尽量减少位操作,对于只有“是”和“否”的变量,如果RAM容量允许,则可分配为unsignedchar类型,可提高运算速度。如果分配为某字节的某个位,可以减少存储器的消耗,但是会降低运算速度。
4、避免使用浮点数,尽量使用定点数进行小数运算。如果必须使用浮点数,则尽量用32位的float,而不是64位的double。
5、尽量将变量分配为无符号数据类型。
6、对于指针变量,如果声明后其值不再改变,则声明为const类型,这样编译器编译时能更好的优化生成的代码。
7、尽可能的使用局部变量而非全局变量或者静态变量(static)。这样有利于编译器编译时更好的优化生成的代码。
8、避免对局部变量使用&取地址符。因为这样会使编译器无法把此变量放在CPU的寄存器中,而是放在RAM中,从而失去了优化的机会。
9、仅在模块内使用的变量声明为static,有利于优化代码。
10、如果堆栈空间有限,尽量减少函数调用的层次和递归调用。
11、如果传送参数过多,可将参数组成一个数组或者结构体,然后用指针传递。
12、某些变量在中断程序和普通级别程序中都会被用到,所以必须加以保护。将变量声明为volatile类型,编译器优化时就不会移动它,对它的访问不会被延迟。为保证对volatile的变量不被打断,为此,可以在访问它的部分(即访问它的函数)前面加上__moniter的声明。