找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3645|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

在進(jìn)行PWM控制步進(jìn)電機(jī)時(shí)為何將全局變量改成程序的局部變量會導(dǎo)致波形失真?

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:79077 發(fā)表于 2015-5-18 17:17 | 只看該作者 |只看大圖 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
本帖最后由 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使用量大增?



實(shí)驗(yàn)3失真照片.JPG (263.18 KB, 下載次數(shù): 133)

實(shí)驗(yàn)3失真照片.JPG

正常情況輸出波形.JPG (262.19 KB, 下載次數(shù): 123)

正常情況輸出波形.JPG
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:79077 發(fā)表于 2015-5-19 15:14 | 只看該作者
是我描述的方式不對嗎,沒有人回答
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表