|
本帖最后由 ceiwei 于 2015-5-23 19:12 編輯
做了一個用PWM控制步進電機輸出的實驗,我設定了一個溢出步數int step_number_over;//溢出步數和實時累加計算的步數 int step_number,如果溢出步數設定為全局變量輸出一開始沒有問題,但如果溢出步數設定為局部變量,也就是調用子程序的參數就會導致輸出波形在運行一段時間后改變,而且全部變量那個方法的輸出也會在經過十多分鐘后改變。具體對比可以看兩張圖,失真的那張圖的波形上升和下降沿都跳到格子中間了。
以下是程序可能導致波形失真的地方我已經用黑字描述出來。
原始程序
# include<reg51.h> //頭文件
sbit pulse=P1^0;//脈沖輸出口
sbit pulse2=P1^1;
sbit pwm_manual_button=P2^0;//手動輸出一步
sbit pwm_auto_button=P2^1; //自動連續輸出
sbit pwm_increase_button=P2^2;
sbit pwm_decrease_button=P2^3;
int pwm_hz=1000;//預設脈沖頻率為1000 //默認步進電機頻率為1000,即1ms
int pwm1=(65536-1000)/256; // 不可以直接把pwm_hz放進去,這是全局變量定義,除非是系統自設的變量,如P1等,否則就不能放進去計算,只能用數字計算
int pwm2=(65536-1000)%256; //
int pwm3=(65536-500)/256;
int pwm4=(65536-500)%256;
char out1_4[4]={0x03,0x06,0x0c,0x09};//雙四拍輸出
char out1_8[8]={0x02,0x06,0x04,0x0c,0x08,0x09,0x01,0x03}; //等待輸入八拍數據 ,為何模擬的時候會后退半步? 把0x01,0x03這兩個拍從最開始兩位放到最后兩位,然后輸出,否則一開始是0x01會導致后退一步,0x03會原地不動一步
char out_loop=0;
int step_number_over;//溢出步數
int step_number; //總步數
bit shep_one_yes; //是否走了一步
void t0sss() interrupt 1 //定時器中斷0為確定輸出頻率
{
TH0=pwm1;//重新賦值,就代表高低電平的半周期,TH和TL中的是計數器初值,中斷則是計數器從初值到溢出之后發生的,輸出一個信號,如果要產生脈寬,則設置第二個定時器中斷,輸出相反信號
TL0=pwm2;
P1=out1_8[out_loop];
if(out_loop<=6) //判斷是否到數組3號元素,到了以后就回零,重復循環
{
out_loop++;
}
else
{
out_loop=0;
} //啟動定時器中斷1,類似于嵌套結構
step_number++;
}
void t1sss() interrupt 3 //定時器中斷1,輸出特定脈寬 采用了2個定時器后,原本定時器0設定的周期要再度減半。所以原本如果定時器0設定為500還想保持1kHz,就要增加
{
TH1=pwm3;//重新賦值,
TL1=pwm4;
pulse=~pulse;
TR1=0; //必須要加上這一句,防止重復中斷
}
void pwm_auto() //自動輸出模式
{
TMOD=0x11;//使用模式1
TH0=pwm1;//重新賦值,這里是
TL0=pwm2;
ET0=1; //允許定時器1中斷
TR0=1; //允許定時器1工作
while(1)
{
//進行增減速計算,如果不按下就直接以默認頻率運行
if(pwm_increase_button==0) //按下增速按鈕
{
pwm_hz=pwm_hz-10; //通過減小數值來增大每秒脈沖。來增加速度的目的
}
if(pwm_decrease_button==0) //按下減速按鈕
{
pwm_hz=pwm_hz+10; //通過增大數值來增大脈沖的周期,達到減速的目的
}
pwm1=(65536-pwm_hz)/256; // 實驗已經證明如果需要更改脈沖頻率可以從這里改變
pwm2=(65536-pwm_hz)%256; //
if(pwm_auto_button==1)break; //如果自動PWM按鈕復位,跳出
if(step_number>=step_number_over)break;//總步數的大于上限,跳出
} //如果這里有有{}則不要加;
}
void pwm_manual() //手動輸出,單步模式
{
int step_number_plus=step_number+1; //預設下一步的步數
ET0=0; //允許定時器1中斷
TR0=0; //允許定時器1工作
TH0=pwm1;//重新賦值,這里是
TL0=pwm2;
ET0=1; //允許定時器1中斷
TR0=1; //允許定時器1工作
P1=out1_8[out_loop]; //輸出P1口狀態給步進電機放大芯片
if(out_loop<=6) //判斷是否到數組3號元素,到了以后就回零,重復循環
{
out_loop++;
}
else
{
out_loop=0;
} //啟動定時器中斷1,類似于嵌套結構
step_number++; //總步數加1
shep_one_yes=(step_number_plus==step_number); //確認是否走了一步后
while(shep_one_yes)break; //走了一步后跳出
}
main()
{
char out_loop_plus=out_loop+1;
//這里可以更改總步數上限
EA=1; //允許總中斷
while(1)
{
TR0=0;//預先關閉定時器中斷
//自動模式的啟動和復位
if((pwm_auto_button==0)&&(pwm_manual_button==1)&&(step_number<step_number_over)) //自動輸出打開而手動輸出關閉同時總步數小于上限的時候啟動自動輸出
{
pwm_auto();
}
if(step_number>=step_number_over) //總步數大于上限,關閉中斷,等待復位
{
TR0=0;
if(pwm_auto_button==1) //自動輸出按鍵彈起來的時候,總步數復位,也可以是其他情況
{
step_number=0;
}
}
//手動模式的啟動和復位
if((pwm_auto_button==1)&&(pwm_manual_button==0)&&(~shep_one_yes)) //手動輸出打開而自動輸出關閉同時還沒有走步的時候啟動手動輸出
{
pwm_manual();
}
if((pwm_manual_button==1)&&(shep_one_yes)) //手動輸出關閉同時走了一步
{
shep_one_yes=0;
}
}
}
程序第二次改變
# include<reg51.h> //頭文件
sbit pulse=P1^0;//脈沖輸出口
sbit pulse2=P1^1;
sbit pwm_manual_button=P2^0;//手動輸出一步
sbit pwm_auto_button=P2^1; //自動連續輸出
sbit pwm_increase_button=P2^2;
sbit pwm_decrease_button=P2^3;
int pwm_hz=1000;//預設脈沖頻率為1000 //默認步進電機頻率為1000,即1ms
int pwm1=(65536-1000)/256; // 不可以直接把pwm_hz放進去,這是全局變量定義,除非是系統自設的變量,如P1等,否則就不能放進去計算,只能用數字計算
int pwm2=(65536-1000)%256; //
int pwm3=(65536-500)/256;
int pwm4=(65536-500)%256;
char out1_4[4]={0x03,0x06,0x0c,0x09};//雙四拍輸出
char out1_8[8]={0x02,0x06,0x04,0x0c,0x08,0x09,0x01,0x03}; //等待輸入八拍數據 ,為何模擬的時候會后退半步? 把0x01,0x03這兩個拍從最開始兩位放到最后兩位,然后輸出,否則一開始是0x01會導致后退一步,0x03會原地不動一步
char out_loop=0;
int step_number; //總步數
int step_number_over_max=10000;//總步數上限 ,設為10000,用作主程序判斷與 int step_number_over不是一個變量
bit shep_one_yes; //是否走了一步
void t0sss() interrupt 1 //定時器中斷0為確定輸出頻率
{
TH0=pwm1;//重新賦值,就代表高低電平的半周期,TH和TL中的是計數器初值,中斷則是計數器從初值到溢出之后發生的,輸出一個信號,如果要產生脈寬,則設置第二個定時器中斷,輸出相反信號
TL0=pwm2;
P1=out1_8[out_loop];
if(out_loop<=6) //判斷是否到數組3號元素,到了以后就回零,重復循環
{
out_loop++;
}
else
{
out_loop=0;
} //啟動定時器中斷1,類似于嵌套結構
step_number++;
}
void t1sss() interrupt 3 //定時器中斷1,輸出特定脈寬 采用了2個定時器后,原本定時器0設定的周期要再度減半。所以原本如果定時器0設定為500還想保持1kHz,就要增加
{
TH1=pwm3;//重新賦值,
TL1=pwm4;
pulse=~pulse;
TR1=0; //必須要加上這一句,防止重復中斷
}
void pwm_auto(int step_number_over) //自動輸出模式 ,本次自動輸出步數上限,step_number_over從開始到這里了
{
TMOD=0x11;//使用模式1
TH0=pwm1;//重新賦值,這里是
TL0=pwm2;
ET0=1; //允許定時器1中斷
TR0=1; //允許定時器1工作
while(1)
{
//進行增減速計算,如果不按下就直接以默認頻率運行
if(pwm_increase_button==0) //按下增速按鈕
{
pwm_hz=pwm_hz-10; //通過減小數值來增大每秒脈沖。來增加速度的目的
}
if(pwm_decrease_button==0) //按下減速按鈕
{
pwm_hz=pwm_hz+10; //通過增大數值來增大脈沖的周期,達到減速的目的
}
pwm1=(65536-pwm_hz)/256; // 實驗已經證明如果需要更改脈沖頻率可以從這里改變
pwm2=(65536-pwm_hz)%256; //
if(pwm_auto_button==1)break; //如果自動PWM按鈕復位,跳出
if(step_number>=step_number_over)break;//總步數的大于上限,跳出
} //如果這里有有{}則不要加;
}
void pwm_manual() //手動輸出,單步模式
{
int step_number_plus=step_number+1; //預設下一步的步數
ET0=0; //允許定時器1中斷
TR0=0; //允許定時器1工作
TH0=pwm1;//重新賦值,這里是
TL0=pwm2;
ET0=1; //允許定時器1中斷
TR0=1; //允許定時器1工作
P1=out1_8[out_loop]; //輸出P1口狀態給步進電機放大芯片
if(out_loop<=6) //判斷是否到數組3號元素,到了以后就回零,重復循環
{
out_loop++;
}
else
{
out_loop=0;
} //啟動定時器中斷1,類似于嵌套結構
step_number++; //總步數加1
shep_one_yes=(step_number_plus==step_number); //確認是否走了一步后
while(shep_one_yes)break; //走了一步后跳出
}
main()
{
char out_loop_plus=out_loop+1;
//這里可以更改總步數上限
EA=1; //允許總中斷
while(1)
{
TR0=0;//預先關閉定時器中斷
//自動模式的啟動和復位
if((pwm_auto_button==0)&&(pwm_manual_button==1)&&(step_number<step_number_over_max)) //自動輸出打開而手動輸出關閉同時總步數小于上限的時候啟動自動輸出
{
pwm_auto(100);
}
if(step_number>=step_number_over_max) //總步數大于上限,關閉中斷,等待復位
{
TR0=0;
if(pwm_auto_button==1) //自動輸出按鍵彈起來的時候,總步數復位,也可以是其他情況
{
step_number=0;
}
}
//手動模式的啟動和復位
if((pwm_auto_button==1)&&(pwm_manual_button==0)&&(~shep_one_yes)) //手動輸出打開而自動輸出關閉同時還沒有走步的時候啟動手動輸出
{
pwm_manual();
}
if((pwm_manual_button==1)&&(shep_one_yes)) //手動輸出關閉同時走了一步
{
shep_one_yes=0;
}
}
}
為何把總步數上限從全局變量改成局部變量后就會發生失真,并且CPU使用量大增?
|
|