四段不同順序的程序會有如此巨大的差別!
程序段一:
__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. 實現了模塊化的編程,就像函數的模式,有兩個輸入參數,沒有輸出參數.
還可以想一想如果用<=的方式能不能,構建一個完美的程序,這個問題有時間再想.先想到這里吧.這個問題有想過,會有一點小小的不完美.具體細節以后再說.