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