玩转MSP-ESP430G2(基础篇)
(十三)中断系统
中断是暂停CPU正在运行的程序,转去执行相应的中断服务程序,完毕后返回被中断的程序继续运行的现象和技术。
中断源(中断分类)
中断首先要有中断源发出中断请求,并征得系统允许(屏蔽、优先权)后才会发生。转去执行中断服务程序前需要保护中断现场,执行完终端服务程序后恢复中断现场。
中断分为软件中断(内中断)和硬件中断(外中断)
而硬件中断又分为 非屏蔽中断和可屏蔽中断
中断种类
按中断源的响应是否受控
- 系统复位 POR、PUC、BOR、SVS
- 非屏蔽中断 NMI、晶振失败、FLASH失败、DMA
- 可屏蔽中断 TA、BT、COMP、UART
非屏蔽中断的控制机制
**可屏蔽中断的控制机制(分控位、总控位)
按中断源来自MCU外部引脚还是内部
- 由外部引脚(RST/NMI)产生的中断,为外中断
- 由MCU内部模块产生的中断,为内中断
中断源、标志和矢量
**状态寄存器SR(Status Register)
15-9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|
保留 | V | SCG1 | SCG0 | OSCOFF | CPUOFF | GIE | N | Z | C |
GIE:可屏蔽中断屏蔽位(General Interrupt Enable Bit)
置位1:允许所有可屏蔽中断
置位2:禁止所有可屏蔽中断
开/关总中断控制位指令
(Disable/enable general interrupt bit)
指令格式 | 执行操作 | V | Z | N | C |
---|---|---|---|---|---|
_DINT(); | 0→GIE | * | * | * | * |
_EINT(); | 1→GIE |
实现中断嵌套需要注意以下几点
- 430默认的是关闭中断嵌套的,一定要中断嵌套的话,就必须在中断服务程序中打开总中断msp430的指令中,_DINT()和_EINT()分别指关和开总中断。
- 当进入中断服务程序时,只要不在中断服务程序中再次开中断,则总中断是关闭的,此时来中断不管是比当前中断的优先级高还是低都不执行;
- 若在中断服务程序A中开了总中断,则可以响应后来的中断B(不管B的优先级比A高还是低),B执行完再继续执行A。
注意:进入中断服务程序B后总中断同样也会关闭,如 果B中断程序执行时需响应中断C,则此时也要开总中断,若不需响应中断,则不用开中断,B执行完后跳出中断程序进入A程序时,总中断会自动打开; - 若在中断服务程序中开了总中断,后来的中断同时有多个,则会按优先级来执行,即中断优先级只有在多个中断同时到来时才起做用!中断服务不执行抢先原则。
- 对于单源中断,只要响应中断,系统硬件自动清中断标志位,对于TA/TB定时器的比较/捕获中断,只要访问TAIV/TBIV标志位倍被自动清除;
- 对于多源中断要手动清标志位,比如P1/P2口中断,要手工清除相应的标志,如果在这种中断用"EINT();"开中断,而在打开中断前没有清标志,就会有相同的中断不断嵌入,而导致堆栈溢出引起复位,所以在这类中断中必须先清标志再打开中断开关.
// Interrupt Vectors (offset from 0xFFE0)
#define PORT1_VECTOR (2*2u)/*0xFFE4 Port 1 */
#define PORT2_VECTOR (3*2u) /*0xFFE6 Port 2 */
#define ADC10 VECTOR (5*2u) /*0xFFEA ADC10 */
#define USCIAB0TX VECTOR (6*2u) /*0xFFEC USCI A0/B0 Transmit
*/
#define USCIABORX VECTOR (7*2u) /*0xFFEE USCI A0/B0 Receive
*/
#define TIMERO A1_VECTOR (8*2u) /*0xFFF0 Timer0)A CC1, TA0 */
#define TIMERO A0 VECTOR (9*2u) /*0xFFF2 Timer0 A CCO */
#define WDT VECTOR (10 *2u) /*0xFFF4 Watchdog Timer */
#define COMPARATORA_VECTOR (11 *2u)/* 0xFFF6 Comparator A */
#define TIMER1_A1_VECTOR (12*2u) /*0xFFF8 Timer1_A CC1-4, TA1
*/
#define TIMER1 A0 VECTOR (13 *2u) /*0xFFFA Timer1_A CCO */
#define NMI_VECTOR (14*2u) /*0xFFFC Non-maskable */
#define RESET VECTOR (15*2u)/*0xFFFE Reset [Highest Priority]
*/
作为中断申请的端口P1和P2引脚,应设置下列相应寄存器:
- 设置功能选择寄存器PxSEL.y对应位为0(基本1/0功能)
- 设置方向选择寄存器PxDIR.y对应位为0(输入)
- 设置PxlES.y选择中断源有效信号类型是上升还是下降沿
- 设置PxIE.y打开分中断允许位
- 设置GIE=1打开总中断允许位
中断程序中:
- 由于端口的8个引脚共用一个中断向量,当有多个引脚做中断源时,需利用PxIFG判断产生中断的中断源引脚
- 在中断子程中应清除PxIFG相应的中断标志位
中断编程步骤:
编程前应了解可屏蔽硬中断的响应过程,了解有关的寄存器和引脚与中断响应过程的关系
a. 主程序做好相关设置:中断源发出中断申请时CPU能够响应的准备工作
b. 中断程序:处理与中断源有关的关键任务
c. 设置中断向量:根据中断源在中断向量表的相应位置,设置中断向量
C语言中的中断程序结构
_interrupt void intName(void)
{
}
- 定义了一个函数名为intName的中断程序
- 结构上与普通函数的区别
使用了关键字_interrupt
使得反汇编中断程序时返回的语句时RETI而不是RET
C语言程序设置中断的方法
在中断程序前使用#pragma vector=偏址语句
将中断程序的入口地址放入到FFE0+偏址中断向量表中
#pragam vector=N*2 //使用中断类型号计算偏址
_interrupt void intName(void)
{
}
#pragma vector=PORT1_VECTOR//使用符号表示的中断偏址
_interrupt void intName(void)
{
}
C语言:开关总中断控制位函数
(disable/enable general interrupt bit)
函数名称 | 功能 | 包含在 |
---|---|---|
_disable_interrupt() | 0→GIE | intrinsics.h |
_enable_interrupt() | 1→GIE | intrinsics.h |
用C语言编写中断程序的方法1
- 包含intrinsics.h文件中
- 使用_disable_interrupt()和_enable_interrupt()
#include"in430.h"
#include "intrinsics.h"
int main( void )
{
//Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
_disable_interrupt(); //关总中断控制(非必要)
… //主程序初始化准备工作
…
_enable_interrupt(); //开总中断控制
while(1){ }; //主程序循环
}
#pragma vector=数字或符号表示的偏址//中断向量设置
_interrupt void port_int(void) //中断子程
{
....
}
....
#include "instrinsics.h"
....
/*Deprecated,please use "_disable_interrupt"instead.*/
#define _DINT() _disable_interrupt()
/*Deprecated,please use "_disable_interrupt"instead.*/
#define _EINT() _disable_interrupt()
/*Deprecated,please use "_disable_interrupt"instead.*/
#define _NOP() _disable_interrupt()
....
用C语言编写中断程序方法2
包含in430.h文件
使用DINT()和EINT()
#include"in430.h"
int main( void )
{
//Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
_DINT( ); //关总中断控制(非必要)
//主程序初始化准备工作
….…
_EINT( ); //开总中断控制
while(1){ }; //主程序循环
}
#pragma vector=数字或符号表示的偏址//中断向量设置
interrupt void port_int(void) //中断子程
{
....
}