专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

一个程序顺序引发的血案(关于软件PWM编程)

作者:huqin   来源:本站原创   点击数:  更新时间:2014年04月15日   【字体:

四段不同顺序的程序会有如此巨大的差别!

程序段一:

__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.      实现了模块化的编程,就像函数的模式,有两个输入参数,没有输出参数.
         还可以想一想如果用<=的方式能不能,构建一个完美的程序,这个问题有时间再想.先想到这里吧.这个问题有想过,会有一点小小的不完美.具体细节以后再说.

关闭窗口

相关文章