51单片机实现步进电机(39BYG316/28BYJ48)的启停,圈数设定,正反转,速率调整,LCD1602显示等调节

51单片机实现步进电机(39BYG316/28BYJ48)的启停,圈数设定,正反转,速率调整,LCD1602显示等调节

一、方案设计
方案1:采用89C51+ULN2003+28BYJ48,28BYJ48是一种常见的四相五线步进减速电机,其减速比为1/64,步进角1.8°,即如果采用四相四拍运行,若使步进电机转一周则需要64*(360/1.8)个脉冲;如果采用四相八拍运行,若使步进电机转一周则需要64*(360/0.9)个脉冲;
方案2:采用89C51+ULN2003+39BYG316,39BYG316是一种常见的四相五线步进电机,步进角1.8°,即如果采用四相四拍运行,若使步进电机转一周则需要6360/1.8个脉冲;如果采用四相八拍运行,若使步进电机转一周则需要360/0.9个脉冲;

二、硬件设计
硬件设计分为MCU模块、LCD和按键模块、电源模块、驱动模块共四大模块。
MCU模块采用较为常见的STC89C52RC,一般的淘宝店都能买到,设计时要特别注意P0口需要配置上拉电阻,晶振选取11.0592M的。
LCD和按键模块,四个按键的功能分别是K1启停,K2设定圈数,K3方向转换,K4速率调整,LCD选取LCD1602。
电源模块的设计比较简单,测试用的输入为7.2V电源,因此仅采用一稳压芯片AMS1117-5.0即可得到所需要的单片机供电电压,并添加了一个自锁开关方便及时断电,电源指示灯用于指示电源状态。
驱动模块采用最最常用的达林顿管驱动器ULN2003,并在输出端口设置四路LED显示当前驱动状态。
另外,步进电机的接线较为麻烦易错,28BYJ48在淘宝上有现成的解决办法,结合ULN2003驱动很容易接线;39BYG316电机也是在淘宝上买的,4.5元一个,接线仿照28BYJ48也很容易解决。

二、软件设计
首先,为了步进电机更好的运行,采用八拍的运行方式,给出四相八拍正反转表,如下:

//为了简便的宏定义
#define uchar unsigned char
#define uint  unsigned int
//四相八拍反转表
uchar code FFW[8]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09};
//四相八拍正转表
uchar code REV[8]={0x09,0x01,0x03,0x02,0x06,0x04,0x0c,0x08};

然后,按照硬件设计编写软件连接

sbit K1 = P3^2;   // 启停
sbit K2 = P3^3;   // 设定圈数
sbit K3 = P3^4;   // 方向调整
sbit K4 = P3^5;   // 速率调整

sbit LCD_RS = P2^6;   // LCD连接
sbit LCD_RW = P2^5;   // LCD连接
sbit LCD_EN = P2^7;   // LCD连接

设置必须用的延时函数,为后面按键消抖,LCD1602通信等所使用

//空指令延时函数
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};

/********************************************************/
/*延时 t ms函数
/********************************************************/
void delay(uint t)
{
 uchar k;
 while(t--)
 {
  for(k=0; k<125; k++)
  {}
 }
}

再然后设置LCD1602的通信

/********************************************************/
/* 检查LCD状态
/* lcd_busy=1 忙,等待
/* lcd_busy=0 闲,可写指令与数据
/********************************************************/
bit lcd_busy()
{
  bit result;
  LCD_RS = 0;
  LCD_RW = 1;
  LCD_EN = 1;
  delayNOP();
  result = (bit)(P0&0x80);
  LCD_EN = 0;
  return(result);
}

/********************************************************/
/* 写指令到LCD
/* RS=L , RW=L, E=高脉冲, D0-D7= 指令码
/*
/********************************************************/
void lcd_wcmd(uchar cmd)
{
  while(lcd_busy());
	LCD_RS = 0;
  LCD_RW = 0;
  LCD_EN = 0;
	
  P0 = cmd;
  delay(1);
	
  LCD_EN = 1;
  delay(5);
  LCD_EN = 0;
}

/********************************************************/
/* 写显示数据到LCD
/* RS=H , RW=L, E=高脉冲, D0-D7= 数据
/*
/********************************************************/
void lcd_wdat(uchar dat)
{
 while(lcd_busy());
 LCD_RS = 1;
 LCD_RW = 0;
 LCD_EN = 0;
	
 P0 = dat;
 delay(1);
	
 LCD_EN = 1;
 delay(5);
 LCD_EN = 0;
}

/********************************************************/
/* LCD 初始化
/*
/********************************************************/
void lcd_init()
{
 lcd_wcmd(0x38); 
 lcd_wcmd(0x0c); 
 lcd_wcmd(0x06); 
 lcd_wcmd(0x01); 
 lcd_wcmd(0x80); 
}

/********************************************************/
/* 设定显示位置
/*
/********************************************************/
void lcd_pos(uchar pos)
{
 lcd_wcmd(pos | 0x80); // 数据指针 = 80 + 地址变量
}

然后设置LCD1602的初始化


//LCD1602 显示的状态数据
uchar code cdis1[ ] = {" STEPPING MOTOR "}; 
uchar code cdis2[ ] = {"CONTROL PROCESS"}; 
uchar code cdis3[ ] = {" STOP "}; 
uchar code cdis4[ ] = {"NUM:  RATE:"};  
uchar code cdis5[ ] = {" RUNNING "};

/********************************************************/
/* LCD1602 初始化
/*
/********************************************************/
void LCD_init_DIS()
{
 delay(10);  
 lcd_init(); // 初始化 LCD
	
 lcd_pos(0); // 设置为第一行第一位
 m = 0;
 while(cdis1[m] != '\0')
 { 
  lcd_wdat(cdis1[m]);
  m++;
 }
 
 lcd_pos(0x40); // 设置为第二行第一位
 m = 0;
 while(cdis2[m] != '\0')
 {
  lcd_wdat(cdis2[m]); 
  m++;
 }
 
 delay(3000); // 开机等待,给与提示!
 
 lcd_pos(0); // 设置为第一行第一位
 m = 0;
 while(cdis3[m] != '\0')
 { 
  lcd_wdat(cdis3[m]);
  m++;
 }
 
 lcd_pos(0x40); // 设置为第二行第一位
 m = 0;
 while(cdis4[m] != '\0')
  {
   lcd_wdat(cdis4[m]); 
   m++;
  }
	
	for(m=0;m<2;m++)
  {
   lcd_pos(0x0c+m); // 显示方向符号
   lcd_wdat(0x3e);
  }
}

对于LCD中变化量的显示写了数据替换程序和数据显示程序

/********************************************************/
/*
/* 数据替换程序
/*
/********************************************************/
void data_conv()
{
 data_temP1=data_temp/10; // 高位
	
 if(data_temP1==0)
  {data_temP1=0x20;} // 高位时0不显示
 else
  {data_temP1=data_temP1+0x30;}

 data_temp2=data_temp%10; // 低位
 data_temp2=data_temp2+0x30;
}

/********************************************************/
/*
/* 数据显示程序
/*
/********************************************************/
void data_dis()
{
 data_temp = snum; // Ï显示圈数
 data_conv();
 lcd_pos(0x44);
 lcd_wdat(data_temP1);
 lcd_pos(0x45);
 lcd_wdat(data_temp2);
	
 data_temp = rate; // 显示速率
 data_conv();
 lcd_pos(0x4d);
 lcd_wdat(data_temP1);
 lcd_pos(0x4e);
 lcd_wdat(data_temp2);
}

/********************************************************
/*
/* 显示运行方向符号
/*
/********************************************************/
void motor_DR()
{
 if(direction==1) // 正转
 { 
	 for(m=0;m<2;m++)
    {
		 lcd_pos(0x0c+m); // 显示正转
     lcd_wdat(0x3e);
    }
}
 else // 反转
 { 
	 for(m=0;m<2;m++) 
    {
     lcd_pos(0x0c+m); // 显示反转
     lcd_wdat(0x3c);
    }
 }
}

/********************************************************
/*
/* 显示运行状态
/*
/********************************************************/
void motor_RUN()
{
 if(on_off==1)
 { 
	 TR0=1;
   lcd_pos(0); // 设置为第一行第一位
   m = 0;
   while(cdis5[m] != '\0')
   { 
		 lcd_wdat(cdis5[m]); //RUNNING
     m++; 
   }
   motor_DR(); 
 }
 
 else
 { 
	 TR0=0; 
	 P1 =0x0f;
   lcd_pos(0); // 设置为第一行第一位
   m = 0;
   while(cdis3[m] != '\0')
   { 
		 lcd_wdat(cdis3[m]); //STOP
     m++; 
   }
   motor_DR(); 
   snum=snum1; 
   number1=0; // 清零圈数
 }
}

使用定时器中断进行电机驱动,最快速度下每1ms发一次脉冲,即400ms即可转一圈

/********************************************************/
/*
/* 定时器0中断
/*
/********************************************************/
void motor_onoff() interrupt 1
{
  TL0 = 0x18;
  TH0 = 0xfc; 
  q++;
	
  if(q < rate)
    { return; }
  else
    { 
			q=0;
      number++; // 脉冲计数
      if(number==400) //400 四相八拍,步距角1.8°,每360°/(1.8°/2)=400
                      //脉冲转一圈
      { 
		snum--;
        number=0;
        number1++; 
      } // 电机转动圈数
      if(direction==1) // 方向
      { 
				if(v<8)
          {P1 = FFW[v];v++;} // 正转
        if(v==8)
          { v=0; }
      }
      else
      { if(v<8)
          {P1 = REV[v];v++;} // 反转
        if(v==8)
          { v=0; }
      }
    }
}

在主函数中进行按键扫描,控制电机

/********************************************************
*
* 主函数
*
*********************************************************/
main()
{
 LCD_init_DIS();
 TMOD = 0x01;  // T0 定时 方式1
 TL0 = 0x18;   
 TH0 = 0xfc;   // (65536-64536)*1us=1ms
 EA = 1;
 ET0 = 1;
 P1 = 0x0f;    //电机驱动置1
	
 while(1)
 {
	 
  /********************************************************/
  // 启停
  if(K1==0)
  {
	 delay(100);// 消抖
   while(K1==0); // 待按键释放
   on_off=~on_off;
   motor_RUN();
   } // K1 end
	 
   /********************************************************/
	 // 设定圈数
  if(K2==0)
  {
	  delay(100);// 消抖
		if(K2==0)
		{
			if(snum_dr==1)
      { 
		   snum++;
       snum1=snum;
       if(snum==0x64)// 最大100圈
       { snum_dr=~snum_dr;}
      }
      else
      {
		   snum--;
       snum1=snum;
       if(snum==0x01)
       { snum_dr=~snum_dr; }
      }
		}
  } //K2 end
	
  /********************************************************/
	// 方向转换
  if(K3==0)
  {
	  delay(100);// 按键消抖
		if(K3==0)
		{
			direction=~direction;
      motor_DR();
		}
  }//K3 end
	
  /********************************************************/
	// 速率调整
  if(K4==0)
  {
	  delay(100);// 消抖
		if(K4==0)
		{
			if(rate_dr==1)
      { 
		   rate++;
       if(rate==0x0a)// 最大10档
       { rate_dr=~rate_dr;}
      }
      else
      {
       rate--;
       if(rate==0x01)
       { rate_dr=~rate_dr; }
      }
		}
  } //K4 end
	
/********************************************************/
	if(number1==snum1) // 与设定圈数相等即宕机
  { 
	number1=0;
    on_off=0;
    TR0=0;
    snum=snum1;
    P1=0x0f;
    motor_RUN();
  }
  data_dis();
 } // while(1) end
} //main end

至此,全部控制结束。可用51单片机实现步进电机(39BYG316/28BYJ48)的启停,圈数设定,正反转,速率调整,LCD1602显示等调节。

51单片机实现步进电机(39BYG316/28BYJ48)的启停,圈数设定,正反转,速率调整,LCD1602显示等调节硬件实现(原理图,PCB)+软件实现(keil4代码) 链接如下:
https://download.csdn.net/download/weixin_43058070/10998514

你可能感兴趣的:(嵌入式项目)