找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3719|回复: 1
打印 上一主题 下一主题
收起左侧

在进行PWM控制步进电机时为何将全局变量改成程序的局部变量会导致波形失真?

[复制链接]
跳转到指定楼层
楼主
本帖最后由 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使用量大增?



实验3失真照片.JPG (263.18 KB, 下载次数: 133)

实验3失真照片.JPG

正常情况输出波形.JPG (262.19 KB, 下载次数: 123)

正常情况输出波形.JPG
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:79077 发表于 2015-5-19 15:14 | 只看该作者
是我描述的方式不对吗,没有人回答
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表