搜索
bottom↓
回复: 7

飞思卡尔单片机MC9S12D64定时器中断和频率捕捉中断问题

[复制链接]

出0入0汤圆

发表于 2011-2-25 14:34:13 | 显示全部楼层 |阅读模式
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;
    }
    MCFLG_MCZF=1;  
}
interrupt void PT3_isr()
{
    DisableInterrupts;  //总中断关闭
    ptflag3=0;          //清除无输入或者10Hz以下频率标志
    ptcount3=0;         //清除无输入或者10Hz以下频率计数器
    TIE_C0I = 1;   //开放ECT0局部中断   
    TFLG1_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局部中断   
    TFLG1_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局部中断   
    TFLG1_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局部中断   
    TFLG1_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:设置为输出比较
    TFLG1=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;
    }
    MCFLG_MCZF=1;  
}
interrupt void PT3_isr()
{
    DisableInterrupts;  //总中断关闭
    ptflag3=0;          //清除无输入或者10Hz以下频率标志
    ptcount3=0;         //清除无输入或者10Hz以下频率计数器
    //TIE_C0I = 1;   //开放ECT0局部中断   
    TFLG1_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;
    }
    MCFLG_MCZF=1;  
}
interrupt void PT3_isr()
{
    DisableInterrupts;  //总中断关闭
    ptflag3=0;          //清除无输入或者10Hz以下频率标志
    ptcount3=0;         //清除无输入或者10Hz以下频率计数器
    //TIE_C0I = 1;   //开放ECT0局部中断   
    //TFLG1_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:设置为输出比较
    TFLG1=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;如果不加定时器中断的话,输入和输出都是正确的,加上定时器的话,程序一直在中断函数中执行,不能进入主循环。请问哪位大侠能支招解决这个问题!谢谢!

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2011-3-7 14:51:14 | 显示全部楼层
发了那么久了,没有一个人回,难道都没有用过这个功能?

出0入0汤圆

 楼主| 发表于 2011-3-14 11:50:28 | 显示全部楼层
还是只能自己解决了!

出0入0汤圆

发表于 2011-5-31 09:50:43 | 显示全部楼层
你好!我初接触MC9S12D64单片机,需要写一个定时器中断的程序,但是我参照网上别人的程序,尝试过主定时器溢出中断、模数减法计数器中断,但都不好用。网上大家用的多是dg128b的片子,我想这两个单片机里面的寄存器也都是一样的啊,但是即使别人宣称已调试通过的程序在我这都不好用。我这片子上主定时器好用,能够查询到溢出标志,但就是进不去中断程序。现在就是想找个在D64单片机上调试通过的程序。

我看你的这个程序用MDC写的,能不能麻烦你将其中的定时中断程序提出来,在你的片子上跑一下,调试通过之后贴出来?或者发到我的邮箱里,guihua603@sohu.com
恳请帮助,不胜感激!!!

出0入0汤圆

发表于 2012-12-11 22:59:06 | 显示全部楼层
你好 我问一下 我写的PT0的中断函数为什么一直进不去 2-7的输入捕捉中断都能进去 就是PT0 和PT1进不去 这是我的代码
/**************************************************************************************
* Function Name  : ECT中断
* Description    :
***************************************************************************************/
void ECT_Init(void)
{
    TIOS=0X00;    //设置全部为输入捕捉
          TCTL3 = 0x55; //上升沿捕捉
          TCTL4 = 0x55; //上升沿捕捉
    TIE=0xff;     //通道使能
    TSCR1=0x80;   //1000 0000 定时器工作 等待模式工作 冻结模式工作 快速清楚标志位选0
}
//中断函数
#pragma CODE_SEG DEFAULT
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt 8 IC0_ISR(void)       //注意把地址写上 左轮 PA0口判断方向
{   
    EnableInterrupts;
    TFLG1 = TFLG1_C0F_MASK;
}
谢谢了

出0入0汤圆

发表于 2012-12-17 23:16:20 | 显示全部楼层
请把初始化的地方贴出来,

出0入0汤圆

发表于 2012-12-17 23:17:04 | 显示全部楼层
注意中断矢量地址,还有中断嵌套。你都没贴,中断怎么能正常进行?

出0入0汤圆

发表于 2012-12-17 23:19:45 | 显示全部楼层
中断优先级你怎么设置的?主定时器的初始化的地方呢?prm文件贴出来看看呢?贴这些东西有用吗?
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-14 20:53

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表