上位机控制步进电机

Posted 皮皮黄-机电工程师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了上位机控制步进电机相关的知识,希望对你有一定的参考价值。

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

程序界面:

硬件清单:
1、单片机最小系统(本案例使用Atmega16芯片)
2、步进电机(二相四线)
3、稳压电源(24V)
4、步进电机驱动器(TB6600)
5、USB转TTL数据线

实物连接图:

原理图:

软件:
ICCV7 FOR AVR-写程序
Progisp-烧程序
VB6.0-写上位机程序

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

单片机程序:

//头文件
#include<iom16v.h>
#include<macros.h>//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<n;i++) 
delay_1ms(); 


//4位数码管驱动函数
#define SCLK0 (PORTB &=~BIT(0))//定义接线口,需要添加#include<macros.h>才能使用
#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<<UDRE)));
UDR=i;


void VBsend(unsigned char i)//发送数据到VB上位机

while(!(UCSRA&(1<<UDRE)));
UDR=i;


unsigned char uart0_receive(void)//接受数据

while(!(UCSRA&(1<<RXC)));
return UDR;

/*unsigned int VBreceive(uchar VBdata[5])//接受VB上位机数据

 uchar i;
 uint VCdata;
 uchar temp;
 while(temp!='e')
 
 temp=uart0_receive();
 if(temp>='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

微信/QQ:pph846375164

以上是关于上位机控制步进电机的主要内容,如果未能解决你的问题,请参考以下文章

上位机控制步进电机

PID控制能否控制步进电机转速?如果想实现力控制可否用PID控制?

单片机pwm控制电机转速

在线仿真Arduino UNO PWM 控制直流电机转速

使用驱动器控制直流无刷伺服电机

用C#语言开发上位机(来控制下位机比如了解下位机测量的温度湿度压力并控制下位机)要用到啥知识?