This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

外部中断使MSP430错误地发生复位,请教可能的原因?

Other Parts Discussed in Thread: MSP430F247

分别试了MSP430F247、F5510,UART1连接至GPRS模块SIM900A,根据SIM900A的说明书介绍,当有电话呼入、或者接收到短信时,SIM900A的RI引脚分别会发生50ms、120ms的低电平(平时为高电平)。因此,想利用引脚 RI 产生的中断做为处理短信事件的一个依据。现在的问题是:

两款型号的MSP430都分别试用过P1.5、P2.4,当设置为 High -> Low、即 P1IES |= BIT5 或 P2IES |= BIT4,当电话呼入时会立即造成MSP430F247或F5510复位重启;如果将RI引脚断开、而设置不变,则不会发生复位现象。

当设置为 Low -> High、即 P1IES &=~BIT5 或 P2IES &=~BIT4,当电话呼入时MSP430F247、F5510都不会立即重启,但当挂断电话时立即会造成MSP430F247、F5510复位重启。

请问这种异常现象的可能原因?

  • 看起来和外围线路无关,而和MSP430内部的程序有关系。中断处理函数正确嘛?把断点放在P1或者P2的中断处理函数看看是否能正常进入?430若允许了某中断向量发生中断,但却没有指定正确的中断处理函数,程序就会发生复位的情况。

  • void SMS_ISR(void)

    {

     SIM_RI_PxSEL &=~SIM_RI_PIN;      // 普通IO

     SIM_RI_PxDIR &=~SIM_RI_PIN;      // input

     SIM_RI_PxIES |= SIM_RI_PIN;         // 1.5 Hi->Lo edge

     SIM_RI_PxIFG &=~SIM_RI_PIN;      // P1.5 IFG cleared  

     SIM_RI_PxIE  |= SIM_RI_PIN;          // P1.5 interrupt enabled,RI

    }

    #pragma vector = PORT1_VECTOR

    __interrupt void port1_ISR (void)

    {

     if(P1IFG & SIM_RI_PIN)                    // 处理进来的短信息或电话呼叫

     {

         SMS_call = 0;                                //状态变量,用于识别电话呼入或短信接收

      P1IFG &= SIM_RI_PIN;    

        TA20ms(1);                                    //这里发现问题:当TA20ms(1)执行完后会重新到前面的 SMS_call = 0;

        TA20ms(1);    

        if (!(SIM_RI_PxIN & SIM_RI_PIN)) SMS_call = 1;              // 40ms后仍为低,暂认为是电话呼入

      TA20ms(3);

         if (!(SIM_RI_PxIN & SIM_RI_PIN)) SMS_call = 2;             // 100ms后仍为低,判断为短信息接收

      TA20ms(2);

     }

    }

    单步跟踪发现,当电话呼入时,会进入P1的外部中断,但执行完第一个 TA20ms(1) 语句时就又从中断的入口进入,不停地反复进入P1口的中断。

    本次测试时,使用的是F247、P1.5。

  • void TA20ms(INT8U Times_N)

    {

    //采用定时器方式,TACLK=ACLK/2,LPM3(不考虑低功耗可采用LPM0)进行延时

    //延时时间为 (TB0CCR0 +1)/定时器的时钟频率,同时需要考虑看门狗的喂狗间隔时间

     if (Times_N > 200)

       Times_N = 200;                                              // 最大Times_N限制为200,否则会超出TA0CCR0的范围65535

     TA0CCTL0 |= CCIE;                                         // TACCR0 interrupt enabled

     TA0CCR0 = 327;                                              // 最大允许数为65535

     TA0CCR0 *= Times_N;                                   // 扩大为 Times_N 倍

     TA0CTL = TASSEL_1 + MC_1 + TBCLR;       // TACLK = ACLK, upmode, clear TBR

     __bis_SR_register(LPM0_bits + GIE);              // LPM0, TA0_ISR will force exit

     TA0CCTL0 &= ~CCIE;                                      // Disable timer Interrupt

    }

  • 初步想到一个办法:

    进入P1.5的外部中断后,清除中断位、立即禁用P1.5的外部中断,置标志变量,在主程序内处理完任务后,再启用P1.5的外部中断。

    尚未实测验证......

  • 问题应该就处在TA20ms函数里,在一个IO口中断处理函数里,调用一个延时,且延时是通过定时器中断来实现的,而且还打开了GIE,这就是一个中断嵌套。太多的问题会导致楼主这种错误发生了,列举几种可能:

    1.TimerA的中断处理函数是否没有做推出低功耗的处理?

    2.是否能保证在在IO口中断发生后,一定只发生Timer的中断,而没有别的中断发生,比如IO口中断?

    3.看门狗是否溢出?

  • 其实若要处理楼主的这种情况,我个人还是喜欢用Timer的捕获功能。

    1.在主程序打开Timer的捕获功能,triger模式用下降沿。

    2.RI下降沿发生后,进入Timer中断处理函数,记录当前CCRx的数值,然后将tigger模式改为上升沿。

    3.当RI上升沿发生后,再次进入Timer中断,记录当前CCRx,将两次得到的CCRx数值相减,记得得到这个下降沿的宽度,再判断是哪种信号即可。

    当然,楼主应该还需要加入一些冗余代码处理一些意外情况,比如RI信号的毛刺的处理,RI信号过长,导致超过Timer一个周期等等的情况。

  • 最后再啰嗦几句。

    不能说430不支持中断嵌套,在中断处理函数里再次打开GIE即可实现中断嵌套。但是这样使用后,一定要注意整个中断的时序,一定一定不能发生中断函数递归的情况。猜测楼主这种情况最大的可能性就是发生了中断函数的递归,不断得重复进入中断函数,导致堆栈溢出,或者看门狗复位。

  • Yun Zhang,

    按照Charles说的做肯定没错的。

    Charles,

    每次看您的回复都能学到很多东西啊!膜拜中。。。