打印

MC9S12D64同时使用定时器中断和频率捕捉中断问题

[复制链接]
3915|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
luciatian|  楼主 | 2011-2-25 13:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 luciatian 于 2011-2-25 15:31 编辑

MC9S12D64定时器中断和频率捕捉中断冲突问题
    一、首先大致功能:
    1:四路频率捕捉中断,要求可同时输入四路,也可任意输入一路、两路或者三路(10~2.5KHz)。
    2、将捕捉到的频率通过四路PWM依次输出,要求实时、稳定、输入多少输出就为多少(误差:千分之二)。
    3:定时器中断,1毫秒中断一次。利用定时器屏蔽10Hz(100ms)以下的频率或者无频率输入时,置为0,屏蔽输出。
    二、调试过程
    1、开始使用定时器中断和频率捕捉中断,频率捕捉中断开通方法:初始化四路全部开通, 进入第一路捕捉中断,开通第二路捕捉中断,关闭第一路捕捉中断
          进入第二路捕捉中断,开通第三路捕捉中断,关闭第二路捕捉中断
          进入第三路捕捉中断,开通第四路捕捉中断,关闭第三路捕捉中断
          进入第四路捕捉中断,开通第一路捕捉中断,关闭第二路捕捉中断形成一个环状,只有当频率全部有输入时才能采集正常,有任意一路没有输入时都将停止中断的执行。
    存在问题,当四路频率全部输入时,捕捉正常,但当只有一路或者两路或者三路输入时,能进入中断的那几路也只能响应一次中断。程序如下:
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt void    MDC_ISR()     //定时器1ms中断一次
{
    CpuCounter++;       //工作指示灯计数器,500ms翻转一次
    if(ptflag0==1)    //10Hz以下或者无输入时计数,进入捕捉中断标志和计数清零,中断结束时打开标志
    {      
        ptcount0++;
    }
    if(ptflag1==1)
    {     
        ptcount1++;
    }
    if(ptflag2==1)
    {     
        ptcount2++;
    }
    if(ptflag3==1)
    {     
        ptcount3++;
    }
    if(ptcount0>100)  //10Hz以下或者无输入时不允许输出
    {
        ptcount0=0;     //计数清零
        flagECT0=0;     //标志清零
        fin1=0;         //频率置为0
        PTH_PTH7=0;     //指示灯熄灭
        PWME=PWME&0xfc; //不允许输出
    }
    if(ptcount1>100)
    {
        ptcount1=0;
        flagECT1=0;
        fin2=0;
        PTH_PTH6=0;
        PWME=PWME&0xf3;
    }
    if(ptcount2>100)
    {
        ptcount2=0;
        flagECT2=0;
        fin3=0;
        PTH_PTH5=0;
        PWME=PWME&0xcf;
    }
    if(ptcount3>100)
    {
        ptcount3=0;
        flagECT3=0;
        fin4=0;
        PTH_PTH4=0;
        PWME=PWME&0x3f;
    }
        
    if(CpuCounter>=500)  //处理器工作指示灯
    {      
        cpuflag=1;
        CpuCounter=0;
    }
    MC**_MCZF=1;  
}
interrupt void PT3_isr()
{
    DisableInterrupts;  //总中断关闭
    ptflag3=0;          //清除无输入或者10Hz以下频率标志
    ptcount3=0;         //清除无输入或者10Hz以下频率计数器
    TIE_C0I = 1;   //开放ECT0局部中断   
    T**1_C3F=1;      //中断标志寄存器对C3F清零
    //newcount3=TC3; //读一次TCx
    if(TC3>TC3H)
    {
        count3=TC3-TC3H;
    }
    else
    {              
        count3=65535-TC3H+TC3;
    }
    if((count3>148)&&(count3<37450))  //10~2.5KHz有效,其余无效   
    {
        flagECT3=1;   //输出标志置一
        PWME=PWME|0xc0;   //允许输出
    }
    else    //无效不允许输出
    {
        flagECT3=0;    //输出标志清零
        fin4=0;
        PTH_PTH4=0;
        PWME=PWME&0x3f;   //不允许输出
    }
    ptflag3=1;      //打开无输入或者10Hz以下频率标志
    ptcount3=0;     //清除无输入或者10Hz以下频率计数器
    EnableInterrupts;  //总中断开启
    TIE_C3I = 0;    //关闭ECT3局部中断   
}
interrupt void PT2_isr()
{
    DisableInterrupts;
    ptflag2=0;
    ptcount2=0;
    TIE_C3I = 1;    //开放ECT3局部中断   
    T**1_C2F=1;    //中断标志寄存器对C2F清零
    //newcount2=TC2;
    if(TC2>TC2H)
    {
        count2=TC2-TC2H;
    }
    else
    {
        count2=65535-TC2H+TC2;
    }  
    if((count2>148)&&(count2<37450))  //570  ->7hz   
    {
        flagECT2=1;
        PWME=PWME|0x30;
    }
    else
    {
        flagECT2=0;
        fin3=0;
        PTH_PTH5=0;
        PWME=PWME&0xcf;
    }
    ptflag2=1;   
    ptcount2=0;
    EnableInterrupts;  
    TIE_C2I = 0;  //关闭ECT2局部中断
}
interrupt void PT1_isr()
{
    DisableInterrupts;
    ptflag1=0;
    ptcount1=0;
    TIE_C2I = 1;  //开放ECT2局部中断   
    T**1_C1F=1;     //中断标志寄存器对C1F清零
    //newcount1=TC1;
    if(TC1>TC1H)
    {
        count1=TC1-TC1H;
    }
    else
    {
        count1=65535-TC1H+TC1;
    }
    if((count1>148)&&(count1<37450))  //570  ->7hz   
    {
        flagECT1=1;
        PWME=PWME|0x0c;
    }
    else
    {
        flagECT1=0;
        fin2=0;
        PTH_PTH6=0;
        PWME=PWME&0xf3;
    }
    ptflag1=1;   
    ptcount1=0;
    EnableInterrupts;  
    TIE_C1I = 0;  //关闭ECT1局部中断
}
interrupt void PT0_isr()
{
    DisableInterrupts;
    ptflag0=0;
    ptcount0=0;
    TIE_C1I = 1;  //开放ECT1局部中断   
    T**1_C0F=1;     //中断标志寄存器对C0F清零
    //newcount0=TC0;
    if(TC0>TC0H)
    {
        count0=TC0-TC0H;
    }
    else
    {
        count0=65535-TC0H+TC0;//溢出
    }
    if((count0>148)&&(count0<37450))  //570  ->7hz   
    {
        flagECT0=1;
        PWME=PWME|0x03;
    }
    else
    {
        flagECT0=0;
        fin1=0;
        PTH_PTH7=0;
        PWME=PWME&0xfc;
    }
    ptflag0=1;  //
    ptcount0=0;
    EnableInterrupts;  
    TIE_C0I = 0;  //关闭ECT0局部中断
}
#pragma CODE_SEG DEFAULT
void main(void)
{
    InitPort();
    InitECT();
    InitPWM();
    InitMDC();   
    EnableInterrupts;     
    for(;;)
    {        
        if(cpuflag==1)
        {
            PORTK_BIT1=~PORTK_BIT1;
            cpuflag=0;
        }   
        siout(); //PWM输出
show(); //显示函数      
    }
}
//   
void  InitMDC(void)
{
    MCCTL=0xEF;
    MCCNT=750;      //定时1ms=750*16/(24/2)
}
//初始化ECT
void InitECT()
{
    TIOS=0;               //0:设置为输入捕捉  1:设置为输出比较
    T**1=0xff;           //定时器中断寄存器1  ,写1清零。
    TSCR1=0x80;           //10000000定时器允许位,允许定时器工工作
    TSCR2=0x05;           //0.375m定时器控制寄存器2,32分频
    TCTL4=0x55;           //设置为单上升沿捕捉
    ICOVW=0x00;  //输入控制修改寄存器,=0,当新值被所存时,
                           //自动用新值覆盖对应寄存器~~
    ICSYS=0x02;           //启动输入捕捉和脉冲累加器保持器寄存器
    TIE=0x0f;             //0.1.2.3允许中断
}
//初始化PWM
void InitPWM()
{
    PWMCAE=0xaa;         //pwm居中对齐允许寄存器,10101010,1为居中对齐,0为左对齐
    PWMCTL=0xf0;         //pwm控制寄存器;01,23,45,67联合为四个16为pwm通道,PFRZ=1,冻结模式时pwm计数停止,=0冻结模式时
依然计数
    PWMPOL=0x00;         //pwm极性寄存器  8个通道:1首先输出高电频,占空比计数器完毕后变低电频
    PWMCLK=0x00;         //pwm时钟选择寄存器
    PWMPRCLK=0x44;       //pwm预分频时钟选择寄存器, 01000100:clka和clkb都是总线的16分频
    PWME=0xaa;           //pwm允许寄存器,允许或禁止各个通道输出
}
    2、着手解决只有三路或者三路一下的问题,利用定时器1毫秒中断一次,第一毫秒开通第一通道中断捕捉,第二毫秒开通第二通道中断捕捉,第三毫秒开通第三通道中断捕捉,第四毫秒开通第四通道中断捕捉,依次循环……,在捕捉中断中屏蔽掉ECT局部中断的开和关。
    存在问题:捕捉到的频率正确,但在低频率150Hz以下某些频率段(125,112.5,100,50,25等,还挺有规律)输出不允许,造成输出跳跃,原因:在这某些频率段执行了10Hz以下或者无输入时不允许输出的限制程序,不加限制的话ptcount0~ptcount3计数能够计到九千多,差不多是10秒的时间,所以输出跳变也正常。但是不知为何在这某些频率段会计数计到那么大。程序如下:
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt void    MDC_ISR()     //定时器1ms中断一次
{
    CpuCounter++;       //工作指示灯计数器,500ms翻转一次
    ptcounter++;      //1ms中断一次
    if(ptcounter==1)    //第一毫秒开通第一路
    {
        TIE_C0I = 1;  //开放ECT1局部中断
        TIE_C1I = 0;  //关闭ECT1局部中断
        TIE_C2I = 0;  //关闭ECT1局部中断
        TIE_C3I = 0;  //关闭ECT1局部中断   
    }
    if(ptcounter==2)    //第二毫秒开通第二路
    {
        TIE_C0I = 0;  //关闭ECT1局部中断
        TIE_C1I = 1;  //开放ECT1局部中断
        TIE_C2I = 0;  //关闭ECT1局部中断
        TIE_C3I = 0;  //关闭ECT1局部中断  
    }   
    if(ptcounter==3)    //第三毫秒开通第三路
    {
        TIE_C0I = 0;  //关闭ECT1局部中断
        TIE_C1I = 0;  //关闭ECT1局部中断
        TIE_C2I = 1;  //开放ECT2局部中断
        TIE_C3I = 0;  //关闭ECT1局部中断   
    }   
    if(ptcounter==4)    //第四毫秒开通第四路,依次循环开通
    {
        TIE_C0I = 0;  //关闭ECT1局部中断
        TIE_C1I = 0;  //关闭ECT1局部中断
        TIE_C2I = 0;  //关闭ECT1局部中断
        TIE_C3I = 1;  //开放ECT3局部中断
        ptcounter=0;   
    }
   
    if(ptflag0==1)    //10Hz以下或者无输入时计数,进入捕捉中断标志和计数清零,中断结束打开标志
    {      
        ptcount0++;
    }
    if(ptflag1==1)
    {     
        ptcount1++;
    }
    if(ptflag2==1)
    {     
        ptcount2++;
    }
    if(ptflag3==1)
    {     
        ptcount3++;
    }
    if(ptcount0>100)  //10Hz以下或者无输入时不允许输出,在某些频率段执行了此程序,造成输出跳变
    {
        ptcount0=0;     //计数清零
        flagECT0=0;     //标志清零
        fin1=0;         //频率置为0
        PTH_PTH7=0;     //指示灯熄灭
        PWME=PWME&0xfc; //不允许输出
    }
    if(ptcount1>100)
    {
        ptcount1=0;
        flagECT1=0;
        fin2=0;
        PTH_PTH6=0;
        PWME=PWME&0xf3;
    }
    if(ptcount2>100)
    {
        ptcount2=0;
        flagECT2=0;
        fin3=0;
        PTH_PTH5=0;
        PWME=PWME&0xcf;
    }
    if(ptcount3>100)
    {
        ptcount3=0;
        flagECT3=0;
        fin4=0;
        PTH_PTH4=0;
        PWME=PWME&0x3f;
    }
        
    if(CpuCounter>=500)  //处理器工作指示灯
    {      
        cpuflag=1;
        CpuCounter=0;
    }
    MC**_MCZF=1;  
}
interrupt void PT3_isr()
{
    DisableInterrupts;  //总中断关闭
    ptflag3=0;          //清除无输入或者10Hz以下频率标志
    ptcount3=0;         //清除无输入或者10Hz以下频率计数器
    //TIE_C0I = 1;   //开放ECT0局部中断   
    T**1_C3F=1;      //中断标志寄存器对C3F清零
    //newcount3=TC3;
    if(TC3>TC3H)
    {
        count3=TC3-TC3H;
    }
    else
    {              
        count3=65535-TC3H+TC3;
    }
    if((count3>148)&&(count3<37450))  //10~2.5KHz有效,其余无效   
    {
        flagECT3=1;   //输出标志置一
        PWME=PWME|0xc0;   //允许输出
    }
    else    //无效不允许输出
    {
        flagECT3=0;    //输出标志清零
        fin4=0;
        PTH_PTH4=0;
        PWME=PWME&0x3f;   //不允许输出
    }
    ptflag3=1;      //打开无输入或者10Hz以下频率标志
    ptcount3=0;     //清除无输入或者10Hz以下频率计数器
    EnableInterrupts;  //总中断开启
    //TIE_C3I = 0;    //关闭ECT3局部中断   
}
#pragma CODE_SEG DEFAULT
    3、想另外的方法实现只有三路或者三路一下的问题,在网上找资料好不容易搜到这样一篇帖子《请教MC9S12DG128B的中断优先问题》,跟我先前遇到的问题一样。我按照张教主的方法改了程序,但是这个方法光是输入捕捉倒是没有问题,但是如果要用到定时器中断的时候,程序一直执行的是定时器中断程序和捕捉中断,进不了主程序,工作指示灯是定时器定时的,但却是在主程序循环里面控制指示灯的闪烁的,这个问题怎么解决?程序如下:
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt void    MDC_ISR()     //定时器1ms中断一次
{
    CpuCounter++;       //工作指示灯计数器,500ms翻转一次
    if(ptflag0==1)    //10Hz以下或者无输入时计数,进入捕捉中断标志和计数清零,中断结束打开标志
    {      
        ptcount0++;
    }
    if(ptflag1==1)
    {     
        ptcount1++;
    }
    if(ptflag2==1)
    {     
        ptcount2++;
    }
    if(ptflag3==1)
    {     
        ptcount3++;
    }
    if(ptcount0>100)  //10Hz以下或者无输入时不允许输出
    {
        ptcount0=0;     //计数清零
        flagECT0=0;     //标志清零
        fin1=0;         //频率置为0
        PTH_PTH7=0;     //指示灯熄灭
        PWME=PWME&0xfc; //不允许输出
    }
    if(ptcount1>100)
    {
        ptcount1=0;
        flagECT1=0;
        fin2=0;
        PTH_PTH6=0;
        PWME=PWME&0xf3;
    }
    if(ptcount2>100)
    {
        ptcount2=0;
        flagECT2=0;
        fin3=0;
        PTH_PTH5=0;
        PWME=PWME&0xcf;
    }
    if(ptcount3>100)
    {
        ptcount3=0;
        flagECT3=0;
        fin4=0;
        PTH_PTH4=0;
        PWME=PWME&0x3f;
    }        
    if(CpuCounter>=500)  //处理器工作指示灯
    {      
        cpuflag=1;
        CpuCounter=0;
    }
    MC**_MCZF=1;  
}
interrupt void PT3_isr()
{
    DisableInterrupts;  //总中断关闭
    ptflag3=0;          //清除无输入或者10Hz以下频率标志
    ptcount3=0;         //清除无输入或者10Hz以下频率计数器
    //TIE_C0I = 1;   //开放ECT0局部中断   
    //T**1_C3F=1;      //中断标志寄存器对C3F清零
    newcount3=TC3;    //读一次TCx
    if(TC3>TC3H)
    {
        count3=TC3-TC3H;
    }
    else
    {              
        count3=65535-TC3H+TC3;
    }
    if((count3>148)&&(count3<37450))  //10~2.5KHz有效,其余无效   
    {
        flagECT3=1;   //输出标志置一
        PWME=PWME|0xc0;   //允许输出
    }
    else    //无效不允许输出
    {
        flagECT3=0;    //输出标志清零
        fin4=0;
        PTH_PTH4=0;
        PWME=PWME&0x3f;   //不允许输出
    }
    ptflag3=1;      //打开无输入或者10Hz以下频率标志
    ptcount3=0;     //清除无输入或者10Hz以下频率计数器
    EnableInterrupts;  //总中断开启
    //TIE_C3I = 0;    //关闭ECT3局部中断   
}
#pragma CODE_SEG DEFAULT
//初始化ECT
void InitECT()
{
    TIOS=0;               //0:设置为输入捕捉  1:设置为输出比较
    T**1=0xff;           //定时器中断寄存器1  ,写1清零。
    TSCR1=0x90;           //10000000定时器允许位,允许定时器工工作
    TSCR2=0x05;           //0.375m定时器控制寄存器2,32分频
    TCTL4=0x55;           //设置为单上升沿捕捉
    ICOVW=0x00;           //输入控制修改寄存器,=0,当新值被所存时,自动用新值覆盖对应寄存器~~
    ICSYS=0x02;           //启动输入捕捉和脉冲累加器保持器寄存器
    TIE=0x0f;             //0.1.2.3允许中断
}
    这三种方法都存在问题,第一种方法肯定不行,只能四路同时输入。
    第二种方法低频时有些频率段输出要跳变,不知计数器为何跑那么快,以致进入10Hz以下或者无输入时不允许输出的限制程序,导致跳变。
    第三种方法程序一直都在定时器中断和捕捉中断函数中执行,没有进入主循环,导致工作指示灯及跟定时器相关的函数段不能执行。
    综上所述,我偏向于第三种方法,只要解决了不老是进入定时器中断程序就可以正常运行。原因是改了TSCR1=0x80;改成了TSCR1=0x90;如果不加定时器中断的话,输入和输出都是正确的,加上定时器的话,程序一直在中断函数中执行,不能进入主循环。请问哪位大侠能支招解决这个问题!谢谢!

相关帖子

沙发
luciatian|  楼主 | 2011-2-27 11:04 | 只看该作者
帖子都发了几天,怎么都没有人回答啊?张教主好像好久都没有上来看看了哦!

使用特权

评论回复
板凳
luciatian|  楼主 | 2011-2-27 11:09 | 只看该作者
是不是写得太长了,大家都没有心情往下看?其实上面大多是程序代码,弄成附件就只有十几行了!

使用特权

评论回复
地板
luciatian2006| | 2011-3-3 14:33 | 只看该作者
在定时器中断中恢复快速清除标志,在捕捉中断中恢复快速清除标志!试试看!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

17

帖子

0

粉丝