2018-11-02 11:33:59 weixin_42670445 阅读数 14806
  • 直流电机和步进电机-第1季第12部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第12个课程,主要讲解了直流电机和步进电机,其中步进电机是关键,通过学习让大家初步掌握步进电机相关的概念和时序,能够将时序转化为驱动程序以驱动步进电机。

    2658 人正在学习 去看看 朱有鹏

    之前尝试用单片机控制42步进电机正反转,电机连接导轨实现滑台前进后退,在这里分享一下测试程序及接线图,程序部分参考网上找到的,已经实际测试过,可以实现控制功能。

    所用硬件:步进电机及驱动器、STC89C52单片机、直流电源

1、硬件连接图

              

  • 注意:上图为共阳极接法,实际连接参考总体线路连接。
  • 驱动器信号端定义:

PUL+:脉冲信号输入正。( CP+ )

PUL-:脉冲信号输入负。( CP- )

DIR+:电机正、反转控制正。

DIR-:电机正、反转控制负。

EN+:电机脱机控制正。

EN-:电机脱机控制负。

  • 电机绕组连接

A+:连接电机绕组A+相。

A-:连接电机绕组A-相。

B+:连接电机绕组B+相。

B-:连接电机绕组B-相。

  • 电源连接

VCC:电源正端“+”

GND:电源负端“-”

注意:DC直流范围:9-32V。不可以超过此范围,否则会无法正常工作甚至损坏驱动器.

  • 总体线路连接

输入信号共有三路,它们是:①步进脉冲信号PUL+,PUL-;②方向电平信 号DIR+,DIR-③脱机信号EN+,EN-。输入信号接口有两种接法,可根据 需要采用共阳极接法或共阴极接法。

在这里我采用的是共阴极接法:分别将 PUL-,DIR-,EN-连接到控制系统的地端(接入单片机地端); 脉冲输入信号通过PUL+接入单片机(代码中给的P2^6脚),方向信号通过DIR+接入单片机(代码中给的P2^4脚),使能信号通过EN+接 入(不接也可,代码中未接,置空)。按键连接见代码,分别用5个按键控制电机启动、反转、加速、减速、正反转。

注意:接线时请断开电源,电机接线需注意不要错相,相内相间短路, 以免损坏驱动器。

2、代码

#include<reg51.h> 
#define MotorTabNum 5
unsigned char T0_NUM;
sbit K1 = P3^5;        // 启动
sbit K2 = P3^4;        // 反转
sbit K3 = P3^3;        // 加速
sbit K4 = P3^2;        // 减速
sbit K5 = P3^1;        //正反转

sbit FX      = P2^4;     // 方向
//sbit MotorEn = P2^5;     // 使能
sbit CLK     = P2^6;     // 脉冲

int table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};           

unsigned char g_MotorSt = 0;     // 
unsigned char g_MotorDir = 0;    // 
unsigned char MotorTab[7] = {12, 10, 8, 6, 4, 2,1};

signed char g_MotorNum = 0;

void delayms(xms);
void mDelay(unsigned int DelayTime);                
void T0_Init();

void KeyScan(void);



void main(void)
{
        T0_Init();            
 //       MotorEn = 0;     // 
        FX = 0;
        while(1)
        {
                KeyScan();              // 
        }


}

void T0_Init()
{
        TMOD = 0x01;
        TH0 = (65535-100)/256;  // 1ms
        TL0 = (65535-100)%256;
        EA = 1;
        ET0 = 1;
//        TR0 = 1; 

}

void T0_time() interrupt 1
{
//        TR0 = 0;
        TH0 = (65535-100)/256;   
        TL0 = (65535-100)%256;
        T0_NUM++;
        if(T0_NUM >= MotorTab[g_MotorNum])        // 
        {
                T0_NUM = 0;
                CLK=CLK^0x01;               //   
        }
//        TR0 = 1;
}         


//-----????---------------------
void KeyScan(void)
{
        if(K1 == 0)
        {
                delayms(10);   
                if(K1 == 0)
                {
                        g_MotorSt = g_MotorSt ^ 0x01;
                      //  MotorEn ^= 1;
                        TR0 = 1; 
						FX ^= 0;   //反转
                }
        }

        if(K2 == 0)
        {
                delayms(10);   //正转
                if(K2 == 0)
                {    
                        g_MotorDir = g_MotorDir ^ 0x01;
                        FX ^= 1;    //加速
                }
        }

        if(K3 == 0)  // 
        {
                delayms(5);   //加速
                if(K3 == 0)
                {   
                        g_MotorNum++;
                        if(g_MotorNum > MotorTabNum)
                                g_MotorNum = MotorTabNum;
                }
        }

        if(K4 == 0)  // 
        {
                delayms(5);   // 减速
                if(K4 == 0)
                {       
                    g_MotorNum--;
                    if(g_MotorNum < 0)
                    g_MotorNum = 0;
                }
        }

		if(K5 == 0)  // 
		{
				delayms(10);   // 正反转
				if(K5 == 0)
				{      
				    g_MotorSt = g_MotorSt ^ 0x01;
					g_MotorDir = g_MotorDir ^ 0x01;
                    MotorEn ^= 1;
                    TR0 = 1;
			        while(1)
					{
                       FX ^= 1;    //													        
                       delayms(90000);
					   FX ^= 0;    //
					   delayms(90000);
					}
				}
		}
}

void delayms(xms)//延时
{
         unsigned int x,y;
         for(x=xms;x>0;x--)
                 for(y=110;y>0;y--);
}

3、常见问题解答

  • 控制信号高于5v一定要串联电阻,否则可能会烧坏驱动器控制接口电路。
  • 接通电源后如果驱动器灯亮,但是无法控制电机旋转,考虑控制部分驱动能力不足或者驱动器所设置的驱动电流不够(我就遇到过这种情况,后来通过调高驱动器限制电流解决的此问题)。如果调高驱动电流步进电机仍无法转动,查看电路板上的按键有没有接对,程序中按键引脚可根据电路板设计的按键引脚连接自行改动。
  • 判断步进电机四条线的定义:将任意两条线接在一起,用手旋转电机,如果有阻力,则两条线是同一相。用相同方法测试另外两条线是否是同一相。确定同相的两条线任意接入两相接口,如果旋转方向相反只需换相即可。
  • 如需调试或增加功能可联系QQ:1932900294。
  • 增加启停及加减速功能代码:https://download.csdn.net/download/weixin_42670445/11978165
2018-11-13 21:07:38 EverestRs 阅读数 4548
  • 直流电机和步进电机-第1季第12部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第12个课程,主要讲解了直流电机和步进电机,其中步进电机是关键,通过学习让大家初步掌握步进电机相关的概念和时序,能够将时序转化为驱动程序以驱动步进电机。

    2658 人正在学习 去看看 朱有鹏

加速:

#include<reg52.h>
#define uchar unsigned char
#define uint  unsigned int
#define MotorData P1                    
uchar phasecw[4] ={0x08,0x04,0x02,0x01};//正转 电机导通相序 D-C-B-A
uchar phaseccw[4]={0x01,0x02,0x04,0x08};//反转 电机导通相序 A-B-C-D
uchar speed;
//延时
void Delay_xms(uint x)
{
 uint i,j;
 for(i=0;i<x;i++)
  for(j=0;j<112;j++);
}
//电机顺时针转动
void MotorCW(void)
{
 uchar i;
 for(i=0;i<4;i++)
  {
   MotorData=phasecw[i];
   Delay_xms(speed);
  }
}
//停转
void MotorStop(void)
{
 MotorData=0x00;
}

void main(void)
{
 uint i;
 Delay_xms(50);//等待系统稳定
 speed=25;
 while(1)
 {
 for(i=0;i<10;i++)
  {
   MotorCW();  
  }  
  speed--;     //加速
  if(speed<4)  
  {
   speed=25;    
   MotorStop();
   Delay_xms(500);
  }  
 }
}

减速:

#include<reg52.h>
#define uchar unsigned char
#define uint  unsigned int
#define MotorData P1                    
uchar phasecw[4] ={0x08,0x04,0x02,0x01};
uchar phaseccw[4]={0x01,0x02,0x04,0x08};
uchar speed;

void Delay_xms(uint x)
{
 uint i,j;
 for(i=0;i<x;i++)
  for(j=0;j<112;j++);
}

void MotorCW(void)
{
 uchar i;
 for(i=0;i<4;i++)
  {
   MotorData=phasecw[i];
   Delay_xms(speed);
  }
}

void MotorStop(void)
{
 MotorData=0x00;
}

void main(void)
{
 uint i;
 Delay_xms(50);
 speed=4;
 while(1)
 {
 for(i=0;i<10;i++)
  {
   MotorCW();  
  }  
  speed++;     //减速
  if(speed>25)  
  {
   speed=4;    
   MotorStop();
   Delay_xms(500);
  }  
 }
}

正反转:

#include<reg52.h>
#define uchar unsigned char
#define uint  unsigned int
#define MotorData P1                
uchar phasecw[4] ={0x08,0x04,0x02,0x01};
uchar phaseccw[4]={0x01,0x02,0x04,0x08};

void Delay_xms(uint x)
{
 uint i,j;
 for(i=0;i<x;i++)
  for(j=0;j<112;j++);
}

void MotorCW(void)
{
 uchar i;
 for(i=0;i<4;i++)
  {
   MotorData=phasecw[i];
   Delay_xms(4);
  }
}

void MotorCCW(void)
{
 uchar i;
 for(i=0;i<4;i++)
  {
   MotorData=phaseccw[i];
   Delay_xms(4);
  }
}

void MotorStop(void)
{
 MotorData=0x00;
}

void main(void)
{
 uint i;
 Delay_xms(50);
 while(1)
 {
  for(i=0;i<500;i++)
  {
   MotorCW();   //顺时针转动
  } 
  MotorStop();  //停转
  Delay_xms(500);
  for(i=0;i<500;i++)
  {
   MotorCCW();  //逆时针转动
  } 
  MotorStop();  //停转
  Delay_xms(500);  
 }
}
2019-06-18 19:06:01 weixin_44041987 阅读数 635
  • 直流电机和步进电机-第1季第12部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第12个课程,主要讲解了直流电机和步进电机,其中步进电机是关键,通过学习让大家初步掌握步进电机相关的概念和时序,能够将时序转化为驱动程序以驱动步进电机。

    2658 人正在学习 去看看 朱有鹏

51单片机是许多单片机初学者的入门开发板,今天给大家做一个基于51内核的stc89c52板子来控制步进电机,可以实现步进电机的正反转、加减速。另外,使用板子自带的Ds18b20模块进行环境测温,并将测得的数据用lcd液晶屏进行显示。并在温度达到设定值时蜂鸣器报警。

第一步,硬件
1 stc89c52开发板,这个板子就不多讲了,网上有很多
在这里插入图片描述
2 步进电机,用的是网上非常便宜的4相5线步进电机 28BYJ-48,电压为5v
在这里插入图片描述
第二,程序
1 步进电机程序,定义步进电机的IO口以及方向以便调速和转向
在这里插入图片描述
2 LCD程序,主要是三个函数,一个初始化函数,一个写函数,一个显示函数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3 温度传感器Ds18b20,主要是这个读函数,读出的温度值
在这里插入图片描述
4 主函数,LCD初始化,用Lcddispaly来显示Ds18b20ReadTemp()函数读到的温度值,在液晶显示屏上显示,设定温度界线,到达一定界线蜂鸣器报警。用按键来控制转向和转速,通过改变设定的speed的值可以改变转速的大小

在这里插入图片描述
在这里插入图片描述
三 实验结果
在这里插入图片描述
在这里插入图片描述
这是51单片机里面比较基础的几个实验,初学者可以试试做一下这个实验,会了这些,51你就基本会啦。

2018-11-13 20:18:40 EverestRs 阅读数 3230
  • 直流电机和步进电机-第1季第12部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第12个课程,主要讲解了直流电机和步进电机,其中步进电机是关键,通过学习让大家初步掌握步进电机相关的概念和时序,能够将时序转化为驱动程序以驱动步进电机。

    2658 人正在学习 去看看 朱有鹏
#include <reg52.h>
#define uchar unsigned char 

sbit dula=P2^6;
sbit wela=P2^7;
sbit dianji=P1^7;
sbit jia_key=P3^6;
sbit jian_key=P3^7;

uchar num=0,show_num=1,gao_num=1,di_num=3;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                        0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(uchar i)
{
  uchar j,k;
  for(j=i;j>0;j--)
  for(k=125;k>0;k--);
}
void display()
{
   dula=0;
   P0=table[show_num];
   dula=1;
   dula=0;
   
   wela=0;
   P0=0xfe;
   wela=1;
   wela=0;
   delay(5);
   
   P0=table[0];
   dula=1;
   dula=0;
   
   P0=0xfd;
   wela=1;
   wela=0;
   delay(5);

   P0=table[0];
   dula=1;
   dula=0;
   
   P0=0xfb;
   wela=1;
   wela=0;
   delay(5);

   P0=table[0];
   dula=1;
   dula=0;
   
   P0=0xf7;
   wela=1;
   wela=0;
   delay(5);
}
void key ()
{
   if(jia_key==0)
   {
     delay(5);
	 if(jia_key==0)
	 {
	   num++;
	   if(num==4)
	     num=3;	
	 	 while(jia_key==0);
	 }
   }

   if(jian_key==0)
   {
     delay(5);
	 if(jian_key==0)
	 {
        if(num!=0)	  
         num--;
		 else 
		 num=0;
		 while(jian_key==0);
	 }
   }
}

void dispose()
{
  switch(num)
  {
    case 0:
     show_num=1;
	 gao_num=1;
	 di_num=3;
	 break;
	case 1:
	 show_num=2;
	 gao_num=2;
	 di_num=2;
	 break;
	case 2:
	 show_num=3;
	 gao_num=3;
	 di_num=1;
	 break;
	case 3:
	 show_num=4;
	 gao_num=4;
	 di_num=0;
	 break;
  }
}
void qudong()
{
  uchar i;
  if(di_num!=0)
  {
    for(i=0;i<di_num;i++)
	{
	  dianji=0;
	  display();
	}
  }

  for(i=0;i<gao_num;i++)
  {
    dianji=1;
	display();
  }
}

void main()
{
     while(1)
       {
         dianji=0;
		 key();
		 dispose();
		 qudong();
        }

 }
2019-09-12 15:29:54 xuezhaoye 阅读数 166
  • 直流电机和步进电机-第1季第12部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第12个课程,主要讲解了直流电机和步进电机,其中步进电机是关键,通过学习让大家初步掌握步进电机相关的概念和时序,能够将时序转化为驱动程序以驱动步进电机。

    2658 人正在学习 去看看 朱有鹏

    对于经常接触单片机控制步进电机 伺服电机的工程师来说, 步进电机加减速可以有各种实现方法, 本来有可以用的驱动, 可是我总感觉有什么不完善的地方, 抽时间写了个感觉功能足够完善的, 共享一下, 也希望有大神指点指点, 给点意见,有问题 QQ 328971422。

  实现的功能有  查表法加减速控制, 可以运动过程中限制最大速度, 运功过程中重新设置目标位置, 如果设置的目标位置在另一方向 或者 在减速范围之内, 会自动减速停止后反向运行到目标位置。 Offset可以对应当前速度, 两个Pos是以脉冲数定义的电机绝对位置, 方向使用了 -1,0 +1, Pos直接 + 方向 来累积位置。

调用方法: 直接设置目标位置, 根据是否停止 决定是否在此设置方向, 其实不设置也没问题, 如果方向不对,中断函数内 也会走错误的方向一步后自动调转方向,  感觉不严谨, so do it here。。。

{

        motTurn.aimPos   =    xxxxxxxx;
        if(0 == motTurn.Offset)    // 检查停止, 停止可以设置方向, 否则直接en tim
        {
            if(motTurn.aimPos > motTurn.curPos)
                TurnDir(Right);
            else TurnDir(Left);
        }  delay_us(5);
        Turn_Enable(ENABLE);

}

 

typedef enum     // 方向 枚举
{
    Left = (char)-1, Stop = (char)0, Right = (char)1
}Dir;

typedef struct    // 电机主要数据结构体
{
    s32 aimPos;
    s32 curPos;         //根据 发送的 pluse 确定的位置, 右转为正, 左转为负, 校准时置零
    u16 Offset;          //  查表偏移

    Dir dir;      //  -1 Left, 1 Right,  0, Stop
    u8  err;
};

MOT_DAT motTurn;


void TIM2_IRQHandler(void)   //TIM2中断, 全部的 电机驱动都在这个中断中
{    
    static s32 lastAimPos,  newPwmNum;   //保存的上次目标 位置,   新的需要移动脉冲量
    static u32 pwm_num=0;   //剩余需要发送 脉冲数
    static u8  last_dir=0, stopCal = 0;    //
    
    if(TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)    //检查TIM2 ccr2比较中断 发生与否
    {                      
        .curPos += motTurn.dir;        //  不管还有没有脉冲数,  进此中断, 一个脉冲就发完了, 需要位置 计数                                                                
        
        if(lastAimPos != motTurn.aimPos)    //    允许 运动过程中 调整目标位置
        {
            lastAimPos = motTurn.aimPos;
            newPwmNum  = motTurn.aimPos - motTurn.curPos;
            
//    u32 calPlusNum(u8* stopCalFlag)   // use motTurn    这里这个函数未提取出去,

                 //为了可以随意设置目标位置,而不需 检查停止
//{
            if(0 == pwm_num)
            {
                if(newPwmNum > 0)
                {
                    TurnDir(Right);
                    pwm_num = newPwmNum;
                }
                else
                {
                    TurnDir(Left);
                    pwm_num = -newPwmNum;                    
                }
            }else
            {
                if(newPwmNum > 0)
                {
                    if(motTurn.dir == Right)
                    {
                        if(pwm_num > newPwmNum)
                        {
                            if(newPwmNum >= SP_OFF_MAX)
                                pwm_num = newPwmNum;
                            else
                                stopCal = 1;        // 需要停止后  计算, 反向移动
                        }else
                            pwm_num = newPwmNum;
                    }else
                        stopCal = 1;
                }else
                {
                    newPwmNum = -newPwmNum;
                    if(motTurn.dir == Left)
                    {
                        if(pwm_num > newPwmNum)
                        {
                            if(newPwmNum >= SP_OFF_MAX)
                                pwm_num = newPwmNum;
                            else
                                stopCal = 1;        // 需要停止后 反向移动
                        }else
                            pwm_num = newPwmNum;
                    }else
                        stopCal = 1;
                }
            }
        }
//}
        if(pwm_num > motTurn.Offset)                         //    确定处于加速还是减速过程
        {
            if(motTurn.Offset < SP_OFF_MAX)                            //need 加速  每个电机的加速表最大值
                motTurn.Offset++;
            else if(motTurn.Offset > SP_OFF_MAX)                    //need 减速
                motTurn.Offset--;
        }
        else if(motTurn.Offset)                                                 //need 减速
            motTurn.Offset--;

        if(pwm_num)                                                        //未走完, 计位置,重装值
        {
            pwm_num--;
            TIM_SetAutoreload(TIM2, pwm_value2[motTurn.Offset]);    
            TIM_SetCompare2(  TIM2, pwm_value2[motTurn.Offset]/4);
        }else            //                          //走完了 停止 或者 需要反向 走
        {
        }else            //if(pwm_nu == 0)        //走完了, 或限位了, 停止...
        {
            if(stopCal)  //需要停止后  再计算反向步数, 反向运行      --为了可以随意设置目标位置,而不需 先停止
            {
                newPwmNum = motTurn.aimPos - motTurn.curPos;
                if(newPwmNum > 0)
                {
                    TurnDir(Right);
                    pwm_num = newPwmNum;
                }
                else
                {
                    TurnDir(Left);
                    pwm_num = -newPwmNum;
                }
                stopCal = 0;
            }else    // 目标到达, 停止
            {
                Turn_Enable(DISABLE);//关闭pwm    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
                motTurn.Offset=0;    //            return;
            }
        }
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);  //清除TIMx更新中断标志  
    }
}

没有更多推荐了,返回首页