<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> 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.      實現了模塊化的編程,就像函數的模式,有兩個輸入參數,沒有輸出參數.
                 還可以想一想如果用<=的方式能不能,構建一個完美的程序,這個問題有時間再想.先想到這里吧.這個問題有想過,會有一點小小的不完美.具體細節以后再說.

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮