2662|5

27

帖子

1

TA的资源

一粒金砂(中级)

楼主
 

TimerA0 + P1中断 = 跑飞?? [复制链接]

最近在用MSP430G2553作红外线发射
我先以LaunchPad版上P1.3的按键触发中断来发射
实验结果一切正常,但是发射16次后第17次就会跑飞,并从main的头重跑一次

后来我最简化了整个程序,只留下Timer与P1中断函数
它变成按第26次会跑飞
能请板上对这有经验帮我看看有可能是哪边出的问题吗?
  1. #include"MSP430G2553.h"

  2. char sendCount;

  3. void main(void){
  4.         WDTCTL= WDTPW + WDTHOLD;        //关狗
  5.         DCOCTL=CALDCO_16MHZ;
  6.         BCSCTL1=CALBC1_16MHZ;                                 /* Set DCO to16MHz */
  7.         BCSCTL2 = SELM_0 + DIVM_0 + DIVS_1;        //SMCLK频率为MCLK/2=8Mhz

  8.         P1REN|= BIT3;                                //启用P1.3内部上下拉电阻
  9.         P1OUT = BIT3;                                //将电阻设为上拉
  10.         P1DIR&=~BIT3;                                // P1.3输入
  11.         P1IES = BIT3;                                // P1.3下降沿中断
  12.         P1IE  = BIT3;                                // 允许P1.3中断
  13.         P1IFG=0;                                        //清P1中断标志
  14.         P1DIR|= BIT0 + BIT6;                //P1.0、P1.6设为输出LED

  15.         TA0CCR0=30000;
  16.         CCTL0= CCIE;

  17.         _BIS_SR(GIE);                                     //开启总中断致能
  18.         _bis_SR_register(LPM3_bits);
  19. }

  20. //------------------------发射------------------------
  21. #pragma vector=PORT1_VECTOR
  22. __interrupt void port1(void){
  23.         P1IFG=0;                                                //清除P1中断旗标
  24.         P1IE &=~BIT3;                                        //停用发射键P1.3中断,避免按键弹跳导致重覆中断
  25.         __delay_cycles(160000);                        //10ms
  26.         P1IE |= BIT3;                                        //启用P1.3中断
  27.         if((P1IN&0x08)!=0)                                //如果变为按键放开
  28.                 return;
  29.         if(P1IN & BIT3 != 0)                        //确定触发中断的是P1.3
  30.                 return;
  31.         P1IE=0;                                                        //关P1中断
  32.         CCTL0= CCIE;                                        //设置定时器CCRO中断致能
  33.         sendCount=0;                                        //重置目前收发数据计数
  34.         CCR0+=9000;                                                //设置中断间隔
  35.         TA0CTL= TASSEL_2 + MC_2 + ID_3;        //设置Timer_A0的时钟源为SMCLK,工作模式MC_0~3,除频8,clk=1Mhz
  36.         P1OUT|=1;                                                //开始发射,LED亮
  37.         _BIS_SR(GIE);
  38.         _bis_SR_register(LPM0_bits);
  39. }

  40. void SendIr(void){
  41.         if(sendCount==80){
  42.                 TACTL=MC_0;                                        //停用计时器
  43.                 P1IE=BIT3;                                        //* 启用发射键中断
  44.                 P2IE=BIT3;                                        //*
  45.                 sendCount=0;
  46.                 P1OUT&=~1;                                        //LED暗
  47.                 while((P1IN&0x08)==0);                //确定P1.3已放开
  48.                 _BIS_SR(GIE);
  49.                 _bis_SR_register(LPM0_bits);
  50.                 return;
  51.         }
  52.         CCR0+=1200;
  53.         sendCount++;
  54. }

  55. #pragma vector=TIMER0_A0_VECTOR
  56. __interrupt void Timer_A(void){
  57.         SendIr();
  58. }
复制代码

目前我想到的解决方法是每按15次就WDTCTL=0手动Reset
然后我发现用来计数按下次数的变量,它的数据也会乱跳... 像是固定从6跳到27

最新回复

_bis_SR_register(LPM0_bits); 这句话要包含到while死循环里面  详情 回复 发表于 2015-4-4 08:50
 
点赞 关注

回复
举报

1976

帖子

1

TA的资源

五彩晶圆(初级)

沙发
 
看了一下你的程序,发现你在按键中断和定时器中断中没有退出中断而是直接进入低功耗模式,这样会不会发生中断嵌套的情况而导致程序堆栈溢出所以单片机从头开始?我的建议是你在主函数中的最后进入低功耗3模式的那句加入到一个while(1)死循环中来,一旦发生中断,在处理完相应事件后就直接退出中断函数就可以了
 
 

回复

6366

帖子

4917

TA的资源

版主

板凳
 
我觉得你的程序结构有问题,,就像1楼说的,你的main主函数有问题,主函数里面怎么可以没有死循环呢?
你最好看看单片机里面主函数的程序结构应该怎样写

点评

谢谢两位的回覆 我试着在main中加入while(1),并在中断函数的最后面都加上return 但是情况依旧.. 然而奇怪的是我把所有LPM去掉后,P1.3按上100次都没跑飞? 再试着谨慎使用LMP0,现在这样是不会跑飞的写法 如  详情 回复 发表于 2015-4-4 08:42
 
 
 

回复

27

帖子

1

TA的资源

一粒金砂(中级)

4
 
本帖最后由 huybn5776 于 2015-4-4 08:46 编辑

谢谢两位的回覆
我试着在main中加入while(1),并在中断函数的最后面都加上return
但是情况依旧..

然而奇怪的是我把所有LPM去掉后,P1.3按上100次都没跑飞?
再试着谨慎使用LMP0,现在这样是不会跑飞的写法

#include"MSP430G2553.h"
char sendCount;

void main(void){
        WDTCTL= WDTPW + WDTHOLD;        //关狗
        DCOCTL=CALDCO_16MHZ;
        BCSCTL1=CALBC1_16MHZ;                                 /* Set DCO to16MHz */
        BCSCTL2 = SELM_0 + DIVM_0 + DIVS_1;        //SMCLK频率为MCLK/2=8Mhz

        P1REN|= BIT3;                                //启用P1.3内部上下拉电阻
        P1OUT = BIT3;                                //将电阻设为上拉
        P1DIR&=~BIT3;                                // P1.3输入
        P1IES = BIT3;                                // P1.3下降沿中断
        P1IE  = BIT3;                                // 允许P1.3中断
        P1IFG=0;                                        //清P1中断标志
        P1DIR|= BIT0 + BIT6;                //P1.0、P1.6设为输出LED

        TA0CCR0=30000;
        CCTL0= CCIE;

        _BIS_SR(GIE);                                     //开启总中断致能
        _bis_SR_register(LPM0_bits);
        while(1);
}

//------------------------发射------------------------
#pragma vector=PORT1_VECTOR
__interrupt void port1(void){
        LPM0_EXIT;
        P1IFG=0;                                                //清除P1中断旗标
        P1IE &=~BIT3;                                        //停用发射键P1.3中断,避免按键弹跳导致重覆中断
        __delay_cycles(160000);                        //10ms
        P1IE |= BIT3;                                        //启用P1.3中断
        if((P1IN&0x08)!=0)                                //如果变为按键放开
                return;
        if(P1IN & BIT3 != 0)                        //确定触发中断的是P1.3
                return;
        P1IE=0;                                                        //关P1中断
        CCTL0= CCIE;                                        //设置定时器CCRO中断致能
        sendCount=0;                                        //重置目前收发數據计数
        CCR0+=9000;                                                //设置中断间隔
        TA0CTL= TASSEL_2 + MC_2 + ID_3;        //设置Timer_A0的时钟源为SMCLK,工作模式MC_0~3,除频8,clk=1Mhz
        P1OUT|=1;                                                //开始发射,LED亮
        _BIS_SR(GIE);
//        _bis_SR_register(LPM0_bits);
}

void SendIr(void){
        if(sendCount==80){
                TACTL=MC_0;                                        //停用计时器
                P1IE=BIT3;                                        //* 启用发射键中断
                P2IE=BIT3;                                        //*
                sendCount=0;
                P1OUT&=~1;                                        //LED暗
                while((P1IN&0x08)==0);                //确定P1.3已放开
                _BIS_SR(GIE);
                _bis_SR_register(LPM0_bits);
                return;
        }
        CCR0+=1200;
        sendCount++;
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A(void){
        SendIr();
}

如果启用把打粗体的那行注释的话
_bis_SR_register(LPM0_bits);
一样按25~32下跑飞




 
 
 

回复

6366

帖子

4917

TA的资源

版主

5
 
_bis_SR_register(LPM0_bits);
这句话要包含到while死循环里面
 
 
 

回复

27

帖子

1

TA的资源

一粒金砂(中级)

6
 
本帖最后由 huybn5776 于 2015-4-4 23:11 编辑

问题已经解决了,谢谢两位的帮忙
结论是只需要在main设置LPM0一次即可

现在明白了MSP430在LPM下中断时的运作方式
每次中断时MSP430会自动把当前状态寄存器SR的内容推入堆栈 (从Registers窗口可以观查到)
完成中断函数后会取回堆栈中的SR并再度进入LPM,不用挂心它没有CPUOFF
看起来好像不着在while(1)中一直让它进入LPM0的样子?
我真应该把教材记清楚点的,省得遇上这个堆栈错误

每次发生中断时会先回到while(1)那边跑一下再跳到中断向量那里
这时可以看到中断前后的SR状态
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表