本帖最后由 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;如果不加定时器中断的话,输入和输出都是正确的,加上定时器的话,程序一直在中断函数中执行,不能进入主循环。请问哪位大侠能支招解决这个问题!谢谢! |