上位机控制步进电机

实现功能:
利用PC控制步进电机转动。控制电机转动方向、转动速度、电机ENA以及读取转动角度

程序界面:
上位机控制步进电机_第1张图片

硬件清单:
1、单片机最小系统(本案例使用Atmega16芯片)
2、步进电机(二相四线)
3、稳压电源(24V)
4、步进电机驱动器(TB6600)
5、USB转TTL数据线
上位机控制步进电机_第2张图片上位机控制步进电机_第3张图片上位机控制步进电机_第4张图片上位机控制步进电机_第5张图片上位机控制步进电机_第6张图片
实物连接图:
上位机控制步进电机_第7张图片

原理图:
上位机控制步进电机_第8张图片
软件:
ICCV7 FOR AVR-写程序
Progisp-烧程序
VB6.0-写上位机程序

程序下载地址:
https://download.csdn.net/download/ludantongxue/11133814

单片机程序:

//头文件
#include
#include//SEI()函数_NOP()BIT();
#define uint unsigned int
#define uchar unsigned char

//步进电机控制变量
uchar bjfangxiang=0;//步进电机方向
uint bjzhuansuxishu[10]={0x00,0XDE3F,0XEF1F,0XF4BF,0XF78F,0XF93F,0XFA5F,0XFB2D,0XFBC7,0XFC3F};//步进电机转速数组/64分频状态下0.75RPM x1-9
uint bjzhuansu;//步进电机转速变量
uint n0=500;//电机转动步数
uchar n0flag;//判断将N0值发给PC
uchar n0pc[3];//步进电机角度发送给PC

//串口接收变量
uchar buzhoutemp;//接收中断第一级步骤
uchar buzhoutemp1;//接收中断第二级步骤



//步进电机接口定义
#define ENA0 (PORTA &=~BIT(0))
#define ENA1 (PORTA |=BIT(0))
#define DIR0 (PORTA &=~BIT(1))
#define DIR1 (PORTA |=BIT(1))
#define PUL0 (PORTA &=~BIT(2))
#define PUL1 (PORTA |=BIT(2))
//PORTD ^=BIT(2);取反操作

//********IO口初始化START**************************************************
void port_init(void)
{
 PORTA = 0xFF; 
 DDRA  = 0xFF; 
 PORTB = 0xFF; 
 DDRB  = 0xFF; 
 PORTC = 0xFF; 
 DDRC  = 0xFF; 
 PORTD = 0xFF; 
 DDRD  = 0x02; //串口通讯
}
//***************口初始化END**************************************************

//延时函数
void delay_1ms(void) 
{  
unsigned int i;  
for(i=1;i<(unsigned int)(11.059*143-2);i++);//定义晶振频率
}  
void delay(unsigned int n)//延时微妙级 
{  
unsigned int i; 
for(i=0;i才能使用
#define SCLK1 (PORTB |=BIT(0))
#define RCLK0 (PORTB &=~BIT(1))
#define RCLK1 (PORTB |=BIT(1))
#define DAT0 (PORTB &=~BIT(2))
#define DAT1 (PORTB |=BIT(2))
unsigned char  number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//0~9
unsigned char  location[]={0x00,0x01,0x02,0x04,0x08};//0~4
void shumaguan(unsigned char weizhi,unsigned char shuzi)
{  unsigned char i,num; //定义一个无字符串变量
		num=number[shuzi];
		for(i=0;i<8;i++)   //for 循环,循环8次,把一个数变成二进制发送出去
        {	
		 SCLK0;	
		 		if((num&0x80)==0)
				 DAT0;
				else
				 DAT1;
				num=num<<1;	
         SCLK1; // 把595频率置高
        }
		num=location[weizhi];
   		for(i=0;i<8;i++)   //for 循环,循环8次,把一个数变成二进制发送出去
        {
         SCLK0;// 把595 SCLK频率置低电平	
				if((num&0x80)==0)
				 DAT0;
				else
				 DAT1;
				num=num<<1;
		 SCLK1;
		 }

		RCLK0;
        _NOP();_NOP();_NOP();_NOP();_NOP(); //延时函数,系统自带
		RCLK1;
}

//***********串口初始化START**************************************************
void uart0_init(void)//初始化
{
 UCSRB = 0x00;//接受中断关闭
 UCSRA = 0x02;//异步倍速
 UCSRC = 0x06;//异步,8位数据位
 UBRRL = 0x8F;//波特率9600,晶振频率11.0592
 UBRRH = 0x00; 
 UCSRB = 0x98;//0x18接收使能+发送使能,0x98开接收中断
}
void uart0_send(unsigned char i)//发送数据
{
while(!(UCSRA&(1<='0'&&temp<='9')
		{
			VBdata[i]=temp;
			i++;
		}
 else if(temp=='e')
 	    {
		 	VCdata=chartoint(VBdata);
			//UDR='\0';
			return(VCdata);
		}
}
}*/
unsigned int chartoint(uchar i,uchar a[5])
{	
	unsigned int num;
	unsigned char num1=a[0]-'0';
	unsigned char num2=a[1]-'0';
	unsigned char num3=a[2]-'0';
	unsigned char num4=a[3]-'0';
	unsigned char num5=a[4]-'0';
	if(i==5)
	num=num1*10000+num2*1000+num3*100+num4*10+num5;
	else if(i==4)
	num=num1*1000+num2*100+num3*10+num4;
	else if(i==3)
	num=num1*100+num2*10+num3;
	else if(i==2)
	num=num1*10+num2;
	else if(i==1)
	num=num1;
	else
	{};
	return(num);
}
void time1_int(void)
{
TCCR1B=0X03;//定时器1产生256分频(0X01不分频(定时小于5.9毫秒),0X02-8分频(定时小于47毫秒),0X03-64分频(定时小于379毫秒),0X04-256分频(定时小于1510毫秒),0X05-1024分频(定时小于6000毫秒))
TCNT1=bjzhuansu;//0.75RPM//定时器1放初值。初值=65535-晶振频率/分频X定时时间
TIMSK|=0x00;//关定时器1 TIMSK|=BIT(2);//开定时器1
DIR1;//电机正方向
ENA0;//电机自由状态 ENA0;//电机锁紧
bjzhuansu=bjzhuansuxishu[1];//电机速度初始化
}

//主程序
void main(void)
{
CLI();//关中断
 port_init();//IO口初始化
 uart0_init();//串口初始化
 time1_int();//定时器1初始化
SEI();//开中断

 while(1)
 {
  shumaguan(1,n0%10);
  delay(1);
  shumaguan(2,n0%100/10);
  delay(1);
  shumaguan(3,n0/100);
  delay(1);
  if(n0flag==1)
  {
   n0flag=0;
   n0pc[0]=n0/100;
   uart0_send(n0pc[0]+'0');
   n0pc[1]=n0%100/10;
   uart0_send(n0pc[1]+'0');
   n0pc[2]=n0%10;
   uart0_send(n0pc[2]+'0');
  }
 }
}

#pragma interrupt_handler time1:9
void time1(void)
{
  TCNT1=bjzhuansu;//步进电机转速调整
  PORTA ^=BIT(2);
  if((PINA & BIT(2))==0)//电机步数加减
   {
    n0flag=1; 
    if(bjfangxiang==1)n0++;
	else if(bjfangxiang==0)n0--;//
   }
}

#pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC//接收中断
void uart0_rx_isr(void)//串口中断程序
{
 uchar temp;
 temp=UDR;
 CLI();//关总中断
 switch(buzhoutemp) //PC控制单片机
 {
 case 0:if(temp=='#'){buzhoutemp=1;}
 	  	else {buzhoutemp=0;}break;
 case 1:buzhoutemp1=temp;buzhoutemp=2;break;//步进电机功能控制项
 case 2:if(buzhoutemp1=='1')//电机转向选择
        {
		 if(temp=='0'){DIR0;bjfangxiang=0;buzhoutemp=3;}
		 else if(temp=='1'){DIR1;bjfangxiang=1;buzhoutemp=3;}
		 else {buzhoutemp=0;}break;
		}
 	    else if(buzhoutemp1=='2')//电机转速选择
		{
		 bjzhuansu=bjzhuansuxishu[temp-'0'];
		 buzhoutemp=3;
		}
		else if(buzhoutemp1=='3')//控制电机锁紧状态
		{
		 if(temp=='0'){ENA1;buzhoutemp=3;}
		 else if(temp=='1'){ENA0;buzhoutemp=3;}
		 else {buzhoutemp=0;}break;
		}
		else if(buzhoutemp1=='4')//控制电机启停
		{
		 if(temp=='0'){TIMSK=0x00;buzhoutemp=3;}
		 else if(temp=='1'){TIMSK|=BIT(2);buzhoutemp=3;}
		 else {buzhoutemp=0;}break;
		}
		else if(buzhoutemp1=='5')//清零步进电机步数
		{
		 n0=500;//步数清零
		 buzhoutemp=3;
		}
		else {buzhoutemp=0;}break;
 case 3:if(temp=='*'){buzhoutemp=0;}break;
 default:buzhoutemp=0;break;
 }
 SEI();//开总中断
}
//***************串口中断END**************************************************


/*
  a0=uart0_receive()-'0';
  uart0_send(a0+'0');
*/

 /*switch(buzhoutemp) //PC传数据到单片机
 {
 case 0:if(temp=='#'){buzhoutemp=1;}
 	  	else {jieshouflag=0;buzhoutemp=0;}break;
 case 1:if(temp!='*'){jieshou[0]=temp;buzhoutemp=2;}
 	    else {jieshouflag=1;}break;
 case 2:if(temp!='*'){jieshou[1]=temp;buzhoutemp=3;}
 	    else {jieshouflag=1;}break;
 case 3:if(temp!='*'){jieshou[2]=temp;buzhoutemp=4;}
 	    else {jieshouflag=1;}break;
 case 4:if(temp!='*'){jieshou[3]=temp;buzhoutemp=5;}
 	    else {jieshouflag=1;}break;
 case 5:if(temp!='*'){jieshou[4]=temp;buzhoutemp=6;}
 	    else {jieshouflag=1;}break;
 case 6:if(temp=='*'){jieshouflag=1;}break;
 default:buzhoutemp=0;break;
 }*/

上位机程序-VB6.0:

Option Explicit
Dim a As String '电机角度中间变量
Private Sub Combo1_Click()
If Combo1.Text = "正" Then
    MSComm1.Output = "#10*"
ElseIf Combo1.Text = "反" Then
    MSComm1.Output = "#11*"
End If
End Sub


Private Sub Combo2_Click()
  Dim temp As String
  temp = "#2" & Combo2 & "*"
  MSComm1.Output = temp
  Print temp
End Sub

Private Sub Command1_Click()
''''''''''''''''''''自动开串口''''''''''''''''''''''''''''''''
Dim i As Integer
If MSComm1.PortOpen = True Then MSComm1.PortOpen = False
    If Command1.Caption = "打开串口" Then
        For i = 1 To 16
            MSComm1.CommPort = i
            On Error Resume Next
            MSComm1.PortOpen = True
            If MSComm1.PortOpen = False Then GoTo Exit1
            Command1.Caption = "关闭串口" '"COM" & i & "已打开"
            GoTo Exit2
Exit1:
        Next i
    ElseIf Command1.Caption = "关闭串口" Then
            If MSComm1.PortOpen = True Then MSComm1.PortOpen = False
            Command1.Caption = "打开串口"
    End If
Exit2:
''''''''''''''''''''自动开串口''''''''''''''''''''''''''''''''
Frame1.Enabled = True
End Sub

Private Sub Command2_Click()
Text2.Text = 0
MSComm1.Output = "#50*"
End Sub

Private Sub Command4_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Command4.Caption = "转动" Then
       Command4.Caption = "结束"
       MSComm1.Output = "#41*"
    ElseIf Command4.Caption = "结束" Then
           Command4.Caption = "转动"
           MSComm1.Output = "#40*"
    End If
End Sub

Private Sub Command4_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Command4.Caption = "转动" Then
       Command4.Caption = "结束"
       MSComm1.Output = "#41*"
    ElseIf Command4.Caption = "结束" Then
           Command4.Caption = "转动"
           MSComm1.Output = "#40*"
    End If
End Sub


Private Sub Command6_Click()
    If Command6.Caption = "电机释放" Then
           Command6.Caption = "电机锁定"
           MSComm1.Output = "#30*"
    ElseIf Command6.Caption = "电机锁定" Then
           Command6.Caption = "电机释放"
           MSComm1.Output = "#31*"
    End If
End Sub

Private Sub Form_Load()
''''''''''''''''''''串口初始化''''''''''''''''''''''''''''''''''
MSComm1.Settings = "9600,N,8,1" '波特率,无校验,8位数据,1位停止位
MSComm1.InBufferSize = 8 '设置返回接受缓冲区的大小,单位是字符
MSComm1.OutBufferSize = 8
If MSComm1.PortOpen = True Then MSComm1.PortOpen = False '关串口
MSComm1.RThreshold = 3 '设置并返回产生ONCOMM事件的字符数,字符为单位
MSComm1.SThreshold = 3 '接收缓冲区收到每一个字符都会使MSComm产生OMcomm事件
MSComm1.InputLen = 0 '设置从接受缓冲区读取的字数,为0读取整个缓冲区
MSComm1.InputMode = 0 '0以文本方式接收,为1则以二进制取回
'If MSComm1.PortOpen = False Then MSComm1.PortOpen = True '开串口
MSComm1.InBufferCount = 0 '清空接收缓冲区
End Sub


Private Sub MSComm1_OnComm()
a = MSComm1.Input
'If a <> "" Then Text1 = a
'Text2 = (Text1 - 500) * Combo3.Text
If a <> "" Then Text2 = (Val(a) - 500) * Combo3.Text
End Sub

微信ID:saskingku

你可能感兴趣的:(步进电机控制方法)