上位机控制步进电机

实现功能:
利用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

  • 17
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值