四段不同顺序的程序会有如此巨大的差别!
程序段一:
__interrupt interrupt_isr(void)
{
if(FTC0IRQ==1) //0.02ms
{
FTC0IRQ = 0;
if(PWM_Flag==0)
{
num++;
sum++;
if(sum >= 100) //2ms
{
num=0;
sum=0;
INPUT1=1;//低电平输出结束,引脚输出高电平
INPUT2=1;
}
if(num >= work)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
}
Tim_1S++;
if(Tim_1S==50000)
{
PWM_Flag=1;
}
}
if(PWM_Flag==1)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
Tim_1S--;
if(Tim_1S==0)
{
PWM_Flag=0;
num=0;
sum=0;
}
}
}
}
显然这个程序的功能是引脚输出一个可调的PWM波形,然后输出一个低电平的波形,PWM的波形和这个低电平的波形持续的时间都是1S钟,程序段一是正确的程序.
下面分析下面的三个程序的问题:
程序段二:
__interrupt interrupt_isr(void)
{
if(FTC0IRQ==1) //0.02ms
{
FTC0IRQ = 0;
if(PWM_Flag==0)
{
if(++sum >= 100) //2ms
{
num=0;
sum=0;
INPUT1=1;//低电平输出结束,引脚输出高电平
INPUT2=1;
}
if(++num >= work)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
}
Tim_1S++;
if(Tim_1S==50000)
{
PWM_Flag=1;
}
}
if(PWM_Flag==1)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
Tim_1S--;
if(Tim_1S==0)
{
PWM_Flag=0;
num=0;
sum=0;
}
}
}
}
程序段二:
现在假设系统初始化,sum和num都是0,现在假设work=20,系统初始化后开始叠加运算,等到num变为20后会有高电平输出结束,引脚输出低电平,占空比为20%,系统正常运行,但等到sum加到100后sum,num会置为0,然后num会加1变为1,此时下一个周期到来了,但是初始化却和第一个周期不一样了,这时num总会比sum大1,也就是最后输出的占空比总是比设定的值会小1,比如设置work值为100,那么从起始状态开始分析,起始状态下num和sum都是0,等sum变为100的时候会先将num置为0,然后num的值会做想应的加1然后下一个周期来了,sum和num有了不同的初始值sum的初始值为0而num的初始值却变为1,这样话,时过境迁,num会首先变为100,这时sum才是99,这时就会了出现一个短暂的低电平,这个低电平的持续时间刚好是一个周期,这样就和我们的初衷相违背了,这时输出的占空比不是100%,而是99%.同样的道理这样的问题不仅会出现有占空比为100%的情况,比如此里的占空比是设置的是20%,那么从初始状态到sum变为20,然后紧接着num又会加1变为1,那么从下一个周期开始两个数据又会出现不同步的情况,从而直接导致下一次等到sum变为99的候,num己经是100了,从而又直接导致下一个周期的起始状态又变成了sum=0,而num=1.周而复始,从而真正得到地占空比变为19%.
程序段三:
__interrupt interrupt_isr(void)
{
if(FTC0IRQ==1) //0.02ms
{
FTC0IRQ = 0;
if(PWM_Flag==0)
{
num++;
sum++;
if(num >= work)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
}
if(sum >= 100) //2ms
{
num=0;
sum=0;
INPUT1=1;//低电平输出结束,引脚输出高电平
INPUT2=1;
}
Tim_1S++;
if(Tim_1S==50000)
{
PWM_Flag=1;
}
}
if(PWM_Flag==1)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
Tim_1S--;
if(Tim_1S==0)
{
PWM_Flag=0;
num=0;
sum=0;
}
}
}
}
关于第三种情况:
第三种情况倒不存在num和sum不同步的问题,但是有一个小问题就是当work是100
的时候num会首先加到100输出一个低电平,而这里的期望占空比是100%,也就是没这里会有一个非常短暂的低电平,用示波器也是发现不了的,因为示波器的分辨能力还是没有单片机执行指令的速度快,所以说这个误差可以忽略不计,不过在逻辑是还是不完美的.
程序段四:
__interrupt interrupt_isr(void)
{
if(FTC0IRQ==1) //0.02ms
{
FTC0IRQ = 0;
if(PWM_Flag==0)
{
if(++num >= work)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
}
if(++sum >= 100) //2ms
{
num=0;
sum=0;
INPUT1=1;//低电平输出结束,引脚输出高电平
INPUT2=1;
}
Tim_1S++;
if(Tim_1S==50000)
{
PWM_Flag=1;
}
}
if(PWM_Flag==1)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
Tim_1S--;
if(Tim_1S==0)
{
PWM_Flag=0;
num=0;
sum=0;
}
}
}
}
关于第四种情况:
第四种情况和第三种情况累似,也不存在num和sum不同步的问题,同样的问题也会出现一个非常短暂的低电平,同样存在逻辑上的不完美.可以发现这两个程序都有一个共同的特点,就是num=0;和sum=0;都在程序的后面,就是这么一个小小的程序顺序上的差别,都能直接导致num和sum的同步和不同步.这个问题虽然不是很严重,也就是说这个问题只会出现在work=100;的时候.也就是在其他的情况下没有这个问题.不过我还是不想让他出现这个问题.
关于这个程序的改进
上面的程序可以进行如下的改进,没有必要使用两个变量来分别对时间来进先计数,可以只用一个变量,这样也可以将计数的不同步问题得到根本的上的解决,同时这个程序的PWM波的周期也不可调节,改进的程序应增加对PWM波形的调节能力,废话不多话直接上程序.
__interrupt interrupt_isr(void)
{
if(FTC0IRQ==1) //0.02ms
{
FTC0IRQ = 0;
if(PWM_Flag==0) //输出PWM波形的状态
{
num++;
if(num >= work)
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
}
if(num>=sum)//周期为sum
{
num=0;//计数器清0,重新开始计数,
INPUT1=1;//高电平输出结束,引脚输出高电平
INPUT2=1;
}
Tim_1S++;
if(Tim_1S==50000)
{
PWM_Flag=1;
}
}
if(PWM_Flag==1) //输出低电平波形的状态
{
INPUT1=0;//高电平输出结束,引脚输出低电平
INPUT2=0;
Tim_1S--;
if(Tim_1S==0)
{
PWM_Flag=0;
num=0;
sum=0;
}
}
}
}
这个改进版的程序输入有两个有效的参数,一个为work,一个为sum,sum用来控制PWM波形的周期,work用来控制PWM波形的占空比,简单粗暴,异常性感.当然可以把这个程序移殖到应广单片机上啊,这个是松瀚单片机的源程序,这个过程是很简单的.
总而言之,这个改进版的程序有以下三个方面的明显提升:
1. 计数的变量由两个变量变为了一个变量.
2. 而且原来的程序的PWM波的周期不可调,现在的程序的周期可调.
3. 实现了模块化的编程,就像函数的模式,有两个输入参数,没有输出参数.
还可以想一想如果用<=的方式能不能,构建一个完美的程序,这个问题有时间再想.先想到这里吧.这个问题有想过,会有一点小小的不完美.具体细节以后再说.