MSP430的可屏蔽中断

wstt   2011-1-15 22:07 楼主
    中断很大程度上体现了一款单片机的性能,从这一点将MSP430在中断方面做得很不错,主要是提供了非常丰富的中断源,基本的有IO中断,定时器中断和一些接口中断(SPI,UART,I2C)等等。
    现在我就谈谈关于MSP430中断的一些特性,主要是在项目经历中感觉比较有用的问题,跟大家分享下。
    第一,MSP430中断的优先级。
    MSP430支持中断优先级,但是优先级的高低怎么获知呢?它的用手手册上有个很有意思的说法,我原文引用过来“The nearer a module is to the CPU/NMIRS, the higher the priority”,翻译过来就是说离CPU/NMIRS越近,优先级就越高。那我们怎么知道那个模块离CPU近啊,看datasheet给的框图?总觉得这不可能让一个做电子的人放心,比如框图在中距CPU一样进,那怎么区分呢?所以我们有另外一个更可靠的办法,IAR为每一款型号的430都提供了对应的头问题,只靠看中断向量地址就可以知道了。430的中断向量表从地址值0xFFC0开始至0XFFFF结束,一共有32个表项(每个中断向量对应2byte),0XFFCO对应的中断向量的优先级是最顶的,0XFFFE对应的中断向量的优先级是最高的,也就是从0xFFCO开始至0xFFFF,32个中断优先级由低至高。这样就很容易弄清楚各中断的优先级了。
  第二,MSP430中断的响应过程。
  首先,当然是中断发生对应的标志为置1。这个时候的过程我详述下,其实是翻译的用户手册但是还是了解下好。
  1. CPU会执行完当期的指令。
  2. 指向下一条指令的PC被压栈。
  3. 状态寄存器SR压栈。
  4. 选择最好优先级的中断进行服务。
  5. 单源中断的中断标志位会被自动清零,这个地方需要小心下P1,P2这样的中断标志位不会自动清零,因为P1、P2的IO中断属于多源中断,就是说P1或者P2的8个IO对应到了一个中断向量上,单片机知道是P1或者P2发生了中断,无论是P1的哪一个IO发生的都会指向P1的中断向量,P2也是一样的,所以需要在代码中手动清零。
  6. 状态寄存器SR被清零,将会终止任何低功耗状态,并且全局中断使能被关闭(GIE)。这个地方与51很是有些不同,430响应了中断后会关闭全局中断使能,不会响应任何其他的中断包括优先级高的,就是说默认状态下是没有中断嵌套的,若用到中断嵌套的话需要使用_EINT()打开全局中断。
  7. 中断向量被装载到PC,开始执行中断服务函数。
以上是整个中断的接收过程,比较重要的地方我用彩色字体标出了。
    中断返回就相对简单些,中断服务函数会由RETI这条指令返回,SR被弹出,单片机恢复到中断前的状态,PC也被弹出,继续执行指令。
    第三,开中断和中断服务函数。
    这个是让我在项目中纠结过的地方,也请各位小心。
    MSP430一旦开了外设的中断,比如SPI的接收中断。
    在SPI的接收中断被使能,单片机一旦发现SPI接收标志置位,就会装载中断向量,但是我们如果没有用到SPI的接收中断,会怎样呢?由于没用到,所有就没有写SPI接收中断的服务函数,此时中断向量里指向中断服务函数地址值是啥?是全0。CPU从0-01FFh取指令,只会发生一件事。PUC,上电清零。接着PC会装载0xFFFE中断向量的内容,也就是复位向量,程序会跳转到给IAR我们做的启动代码。程序再往下执行会执行到我们编写的代码的main()的第一句。这样悲剧就诞生了,荡机了!!!!
   所以我在这希望初学430的朋友对于中断,未使用的就不要使能。使能的就一定要写中断服务函数,哪怕是空函数!
   以上是我在430中断使用中的一些经验,希望对各位有用!
    

回复评论 (19)

沙发,不错,有自己的见解
点赞  2011-1-15 23:05
谢谢分享 :)
加油!在电子行业默默贡献自己的力量!:)
点赞  2011-2-10 11:08
学习了!~谢谢分享!~~
点赞  2011-7-4 21:02
既系统又简洁,既准确又通俗,好!
点赞  2011-7-5 10:08
学习了,现在正在整专断这一块儿!
点赞  2011-7-7 00:07

也在学430谢谢了

好帖 ,顶一下。。。。。。
点赞  2011-7-9 21:00
不错。。
点赞  2011-7-17 10:47

回复 楼主 wstt 的帖子

hao tie
点赞  2011-8-12 09:57
好东西
点赞  2011-8-12 15:35
讲得很详细
点赞  2011-9-6 21:54
学些了。
430的中断不支持嵌套。如果真的要嵌套,可以手动方式进行。原理与LZ讲述的差不多,具体实现可能需要些注意事项,否则容易跑飞。
点赞  2011-9-6 22:02
很好
点赞  2012-2-16 15:17
学习了,正需要,谢谢分享
点赞  2012-3-2 21:49
好东西 顶下!!!!
点赞  2012-7-11 14:04
写得好,学习了
点赞  2012-7-23 00:09
不错不错,不写中断函数,却触发了中断,会引起复位,对我有用
点赞  2012-8-12 16:29

回复 17楼 挨紧 的帖子

也是被这样的情况折腾过
点赞  2012-8-12 17:05

430的中断向量表从地址值0xFFC0开始至0XFFFF结束,一共有32个表项

刚刚查阅了msp430的用户手册,在g2553的情况就不是从0XFFC0开始的,而是从0XFFE0开始的。原文:(8) 位于地址0FFDEh至0FFC0h的中断矢量在该器件中未使用,可在需要时用于常规程序代码。
点赞  2012-8-12 20:59
楼至帖子不错,能帮我看一下我的问题吗
void Uart_Init(void)
{
        P3SEL |= 0x30;                            // 选择P3.4和P3.5做UART通信端口
        P3DIR = 0x10;
       UCTL0|= SWRST;                         //开始设置串口   
        ME1 |= URXE0;                             // 使能USART0的发送和接受
        U0CTL |= CHAR;                            // 选择8位字                    
        UTCTL0 |= SSEL0;                          //选择模块时钟源 ; // UCLK = ACLK
        UBR00 = 0xA3;                             // 波特率4800
        UBR10 = 0x635750;                             //
        UMCTL0 = 0x00;                            // Modulation
        UCTL0 &= ~SWRST;                    //设置串口 完毕
        IE1 |= URXIE0;
}
#pragma vector=UART0RX_VECTOR
__interrupt void usart0_rx (void)
{
                  
              
            char ch;
         
             IE1 &= ~URXIE0; //ES = 0;_DINT();
        if((IFG1 & URXIFG0))
       
        {
               ch = RXBUF0;     
                if ((ch == '$') && (gps_flag == 0))  //如果收到字符'$',便开始接收           
                {
                        rev_start = 1;
                        rev_stop  = 0;
                }
        rev_start = 1;
                if (rev_start == 1)  //标志位为1,开始接收            
                {
                        rev_buf[num++] =ch;  //字符存到数组中           
                        if (ch== '\n')     //如果接收到换行           
                        {
                                rev_buf[num] = '\0';
                                rev_start = 0;
                                rev_stop  = 1;
                                gps_flag = 1;
                                num = 0;
                        }
                }
        }
       
        IFG1&=~URXIFG0;
           IE1 |= URXIE0;            //    _EINT();
           
}
就是好像进不去中断,总中断在主函数也开了,不知是啥原因
点赞  2012-8-13 11:07
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复