分别试了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复位重启。
请问这种异常现象的可能原因?
Charles Wu:
看起来和外围线路无关,而和MSP430内部的程序有关系。中断处理函数正确嘛?把断点放在P1或者P2的中断处理函数看看是否能正常进入?430若允许了某中断向量发生中断,但却没有指定正确的中断处理函数,程序就会发生复位的情况。
Yun Zhang:
回复 Charles Wu:
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。
Yun Zhang:
回复 Yun Zhang:
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
}
Yun Zhang:
回复 Yun Zhang:
初步想到一个办法:
进入P1.5的外部中断后,清除中断位、立即禁用P1.5的外部中断,置标志变量,在主程序内处理完任务后,再启用P1.5的外部中断。
尚未实测验证……
Charles Wu:
回复 Yun Zhang:
问题应该就处在TA20ms函数里,在一个IO口中断处理函数里,调用一个延时,且延时是通过定时器中断来实现的,而且还打开了GIE,这就是一个中断嵌套。太多的问题会导致楼主这种错误发生了,列举几种可能:
1.TimerA的中断处理函数是否没有做推出低功耗的处理?
2.是否能保证在在IO口中断发生后,一定只发生Timer的中断,而没有别的中断发生,比如IO口中断?
3.看门狗是否溢出?
Charles Wu:
回复 Charles Wu:
其实若要处理楼主的这种情况,我个人还是喜欢用Timer的捕获功能。
1.在主程序打开Timer的捕获功能,triger模式用下降沿。
2.RI下降沿发生后,进入Timer中断处理函数,记录当前CCRx的数值,然后将tigger模式改为上升沿。
3.当RI上升沿发生后,再次进入Timer中断,记录当前CCRx,将两次得到的CCRx数值相减,记得得到这个下降沿的宽度,再判断是哪种信号即可。
当然,楼主应该还需要加入一些冗余代码处理一些意外情况,比如RI信号的毛刺的处理,RI信号过长,导致超过Timer一个周期等等的情况。
Charles Wu:
回复 Charles Wu:
最后再啰嗦几句。
不能说430不支持中断嵌套,在中断处理函数里再次打开GIE即可实现中断嵌套。但是这样使用后,一定要注意整个中断的时序,一定一定不能发生中断函数递归的情况。猜测楼主这种情况最大的可能性就是发生了中断函数的递归,不断得重复进入中断函数,导致堆栈溢出,或者看门狗复位。
Young Hu:
回复 Charles Wu:
Yun Zhang,
按照Charles说的做肯定没错的。
Charles,
每次看您的回复都能学到很多东西啊!膜拜中。。。