单片机实现RS232串口指令对二相四线步进电机的控制设计

前言

此设计的目的是使用STC12C5A60S2单片机实现电脑端通过RS232发送串口指令控制二相步进电机
(此处为本实验所用单片机,其实STC80C51系列单片机也可以达到同样的目的)

一、设计思路分析

RS232串口指令控制二相四线步进电机设计框图
实现RS232发送串口指令控制二相步进电机,需要实现以下几大功能模块的设计开发:控制系统、驱动系统、步进电机、RS232通讯模块。
(1)这里的控制系统选择了单片机STC12C5A60S2,借助单片机的最小系统控制IO口输出步进电机所需要的引脚控制信号,从而达成控制的效果,此实验为减少焊接和电路设计步骤,直接采用了单片机最小系统模块来进行设计,此处要注意选择单片机芯片和晶振;
(2)驱动模块此处选择了TB6600驱动器,这是一款常用的步进电机驱动器,可实现7档细分控制、8档电流控制,基本市场上常见的步进电机都可用其来实现驱动。
(3)步进电机,此处使用的步进电机为二相四线步进电机,也是很常用的一款电机,通过单片机控制后可实现控制正反转、控制转动速度 、控制旋转距离。
(4)RS232通讯模块目的是实现单片机与PC端的通讯,借助这个模块可以实现PC端向单片机发送RS232串口指令,通过单片机的处理后便可实现对步进电机的控制。此处可以直接采用USB转TTL的CH340模块进行实验,替换掉单片机的RS232电路模块的设计。
下面主要就是围绕着以上几大功能模块来实现设计开发,从而达成RS232发送串口指令控制二相步进电机的目的。


一、单片机控制系统与电路图

在这里插入图片描述
如上所述,控制系统采用了单片机STC12C5A60S2,立足于此单片机,搭建单片机最小系统,并以此为基础,搭建通讯和步进电机控制电路,为了偷懒,此处直接使用了单片机最小系统模块和USb转TTl电平的CH340模块,简化从零开始焊接最小系统和RS232通讯电路的设计(有兴趣和时间的,可以自行从零开始设计完整的电路)。

二、步进电机驱动器(TB6600)

1.基本原理

在这里插入图片描述
我们都知道单片机作为控制器,其IO口的电流和电压是非常小的,不足以驱动步进电机,因而我们在使用单片机控制步进电机时,需要借助驱动器来实现(驱动器可以是放大电路、也可以是一些常用的驱动模块,这里使用的便是一个驱动模块TB6600驱动器),借助TB6600驱动器实现对二相四项驱动电机的控制,主要留意以下几个参数
(1)驱动器电源(DC9-40V),这边使用过12V和24V的电源适配器都可以达到驱动电机的目的,根据本实验所需驱动的步进电机,这边选择了使用12V的电源适配器来给其供电。
(2)细分(6400细分),细分驱动器可通过改变A,B相电流的大小,以改变合成磁场的夹角,从而可将一个步距角细分为多步,TB6600驱动器含有7档细分控制(1、2/A、2/B、4、8、16、32),此处实验使用的是4细分,因而设置S1、S2、S3的开关状态为:ON、OFF、OFF,根据公式:步距角=电机固有步距角/细分数可计算得出电机步距角实际值,即每输送一个脉冲,电机转动的角度大小值。
(3)电流(输出电流),8档电流控制(0.5A、1A、1.5A、2A、2.5A、2.8A、3.0A、3.5A),步进电机因为型号的不同,所支持的驱动电压电流的数值也不同,TB6600驱动器提供的8档电流控制便很好的适配了绝大部分电机的驱动需求,后面所使用的两款电机所支持的电流便存在着明显的差异。一般先设置为0.5A,而后根据实际情况进行调节,即设置S4、S5、S6的开关状态为:ON、ON、ON
(4)电机接口,如上图所示,TB6600驱动器提供了电相B-、电相B+、电相A-、电相A+四个电机接口,这四个电机接口分别接入步进电机的电相B-、电相B+、电相A-、电相A+,一般购买步进电机时,店家都会提供步进电机四根线的对应的线序代表的电相,我们按规格接好便可,如果不确定,可以使用万用表的二极管档位测试,红笔接步进电机的电相B-/A-和黑笔接步进电机的电相B+/A+,相同的相位,万用表会发出蜂鸣声,通过这种方法可以确定出两组相位,在接线的时候,确保两组相位接入无误便可以(A相和B相无明显区别,A相与B相接反只会导致电机转向不一样,不影响电机转动)
(5)控制信号接口,如上图所示,TB6600驱动器的控制信号一共有6个接口:ENA-、ENA+、DIR-、DIR+、PUL-、PUL+,这六个接口连接到我们的单片机最小系统,通过单片机的IO引脚实现对TB6600驱动器的控制,从而实现对步进电机的控制使用。这里的接法有共阳极和共阴极两种接法,此处采用的是共阳极的接法。ENA+、DIR+、、PUL+三个接口接到单片机提供的+5V电源上;ENA-(P1.2)、DIR-(P1.0)、PUL-(P1.1)分别接到对应的单片机引脚,ENA- 引脚为使能引脚,低电平时有效(即单片机控制引脚输入高电平时,电机停止转动,为低电平时可转动);DIR-引脚为正反转控制引脚,低电平和高电平分别控制正转和反转(由于电机转动跟电机的接线也有关系,这边最好根据实际调试确定正转和反转的电平);PUL-(P1.1)为脉冲控制引脚,通过给这个引脚发送一定频率的电平脉冲从而实现对电机的速度和转动角度的控制。如上所说,每当输送一个脉冲信号时,电机便会移动一个步距角(电机固有步距角/细分数),通过控制脉冲的数值便可实现对电机转动角度的控制,比如此次实现采用的细分数为4细分,使用的步进电机的固有步距角为18°,所以发送一个脉冲,电机转动的角度为18°/4=4.5°,电机转动一圈需要脉冲数=360°/4.5°=80;脉冲发送的频率(1s能发送多少个脉冲)则可以实现对电机速度的控制。

2.接线方式

在这里插入图片描述
根据以上电路图和实物图连接好TB6600驱动器与单片机,便可进行下一步操作

代码如下:通过单片机的P1端口驱动TB6600驱动器,实现控制步进电机

#include"reg52.h"
#include <intrins.h>
sbit dir=P1^0;	//DIR-引脚为正反转控制引脚
sbit pul=P1^1;	//PUL-(P1.1)为脉冲控制引脚
sbit ena=P1^2;	//ENA- 引脚为使能引脚,低电平时有效

三、步进电机

在这里插入图片描述
此次实验,使用了以上步进电机模块,当电机转动时,会转发为前进后退的运动。

1、基本参数

(1) 电机类型:二相四线制
(2)驱动电压:4-9V/100-500mA(电压越高力越大,发热也越大)
(3)丝杆长度:90mm
(4)滑块行程:80mm
(5)电机直径:15mm
(6)丝杆直径:3mm
(7)丝杆螺距:0.5mm
(8)步距角:18°
(9)相电阻:15.5欧
(10)整体尺寸158105mm
(11)蓝A+、黑A-、红B+、黄B-
要驱动此步进电机,我们需要了解跟电机有关的一些参数,而最基本便是驱动电压和电流,如上参数显示,驱动电压为4-9V,电流为100-500mA,我们这里采用的是TB6600驱动器,驱动器电压给个12V/24V,然后设置电流档位为0.5A便可达到驱动此步进电机的目的了;丝杆长度为丝杆的总长度;滑块行程即可控制步进电机行进的距离;丝杆螺距则为转动一圈所行进的距离;步距角为步进电机接收到一个脉冲所转动的角度;以上几个参数是操作此步进电机时所需要用到的参数。比如说,这里实现让步进电机向前移动50mm的距离则计算设计方法如下(TB6600为4细分,0.5A):
(1)转动一圈需要的脉冲:360°/(步距角/细分数)= 360°/(18°/4)= 80
(2)前进50mm需要转动多少圈:50mm/0.5=100
(3)实现前进50mm,则需要发送80*100 = 8000个脉冲

2.步进电机的使用与代码分析

如上所述,使用TB6600驱动器连接上步进电机后,便可通过单片机发送脉冲信号,实现对步进电机的控制了。

代码如下:此函数为步进电机的驱动函数,调用这个函数可实现对电机移动距离和速度的控制

void distance_160(uint distance,uint velocity)
{
    
    
	uint x,y;
	//distance参数为步进电机转动多少圈的参数,通过圈数可以控制步进距离
	//velocity为脉冲的延时时间,改变这里的时间,可以改变电机移动的速度
	for( x = 0; x < distance; x++){
    
    
		for( y = 0; y < 80; y++) {
    
    	//这里的80指的是,80个脉冲转一圈(18/4=4.5 360/4.5=80,一圈为0.5mm);电机长度80mm,80/0.5=160(电机可移动距离)
		//下面为一个脉冲
			pul=1; 
			delay_1s(velocity);                //修改微秒值可以调速
			pul=0;
			delay_1s(velocity);             
		}
	}
}

3.扩展

在这里插入图片描述

如图上所示市面上还有一款常见的二相四线步进电机(42步进电机),虽说类型不同,但其驱动原理是一样的,我们都可以通过改变TB6600驱动器的电流和细分值来实现对其的控制。

四、RS232通讯

在这里插入图片描述

1.USB转TTL的CH340模块

此次实验,为了偷懒,直接采用了USB转TTL的CH340模块来实现这一部分的内容,用此模块可直接通过模块上的RXD和TXD引脚直接连接到单片机的TXD和RXD引脚,且此模块还能输出单片机所需的5V电压,极大的简化了实验。

RS232串口通讯代码分析如下:

//RS232串口功能初始化函数
void init()
{
    
    
	TMOD=0x20;	//定时器1,工作方式2,8位自动重装
	TH1=0xfd;	//初值
	TL1=0xfd;	//初值
	TR1=1;	//开定时器
	REN=1;	//允许串口接收
	SM0=0;	//设定串口工作方式
	SM1=1;	//设定串口工作方式
	EA=1;	//开总中断
	ES=1;	//开串口中断
}
//主函数
void main()
{
    
    
	uchar i;
	//初始化函数
	init();
	while(1)
	{
    
    
		if(flag==1)
		{
    
    
			ES=0;	//关串口中断
			//根据串口接受到的数值进行判断进行不同的步进操作
			switch(a)
			{
    
    
				case '1':	break;
				case '2':	break;	
				...
				...
				default:	break;		
			}
			ES=1;	//开串口中断
			flag=0;	//标志位清零
		}
	}
				
void ser() interrupt 4
{
    
    
	//目前已经实现把数据存储到数组再判断,但必须要一次性发送固定的字符串,不然会错乱
		if(RI)										//如果是串口接收到一帧数据,就会产生中断,RI标志变为1
		{
    
    
			RI = 0;									//手动将标志置0,方便下次判断
			a=SBUF;			//出去接收到的数据	
		}
		flag=1;		//标志位用于,只有当4位数据接收完,主函数才进行数据比较
}

五、实际应用和代码分析

以下代码功能为:可通过串口发送0-9的数字,实现对步进电机不同方向和不同移动距离的控制
视频

完整代码如下:

#include"reg52.h"
#include <intrins.h>
sbit dir=P1^0;
sbit pul=P1^1;
sbit ena=P1^2;
#define uint  unsigned int
#define uchar unsigned char
uchar flag,a;
uchar code table1[]="A01B01";
uchar code table2[]="A05B05";
uchar code table3[]="A10B10";
uchar code table4[]="A30B30";
uchar code table5[]="A50B50";
uchar code table6[]="No OK";
void distance_160(uint distance,uint velocity);

//RS232串口功能初始化函数
void init()
{
    
    
	TMOD=0x20;	//定时器1,工作方式2,8位自动重装
	TH1=0xfd;	//初值
	TL1=0xfd;	//初值
	TR1=1;	//开定时器
	REN=1;	//允许串口接收
	SM0=0;	//设定串口工作方式
	SM1=1;	//设定串口工作方式
	EA=1;	//开总中断
	ES=1;	//开串口中断
}

//延时函数,但是实际并不准确
void delay_1s(uint xms)
{
    
    
	uint i,j;
	for(i=xms;i>0;i--)
		for(j=110;j>0;j--);
}

void distance_160(uint distance,uint velocity)
{
    
    
	uint x,y;
	//distance参数为步进电机转动多少圈的参数,通过圈数可以控制步进距离
	//velocity为脉冲的延时时间,改变这里的时间,可以改变电机移动的速度
	for( x = 0; x < distance; x++){
    
    
		for( y = 0; y < 80; y++) {
    
    	//这里的80指的是,80个脉冲转一圈(18/4=4.5 360/4.5=80,一圈为0.5mm);电机长度80mm,80/0.5=160(电机可移动距离)
		//下面为一个脉冲
			pul=1; 
			delay_1s(velocity);                //修改微秒值可以调速
			pul=0;
			delay_1s(velocity);             
		}
	}
}

void main()
{
    
    
	uchar i;
	//初始化
	init();
	while(1)
	{
    
    
		if(flag==1)
		{
    
    
			ES=0;	//关串口中断
			//根据串口接受到的a的数值进行判断进行不同的步进操作	
			switch(a)
			{
    
    
				//RS232发送指令为1时,正向前进1mm,返回A01
				case '1':
					dir=0;       //dir为1时正转,dir为0时反转
					ena=1;      //使能电机
					distance_160(2,4);
					for(i=0;i<3;i++)
					{
    
    
						SBUF=table1[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令为2时,反向前进1mm,返回B01
				case '2':
					dir=1;
					ena=1;				
					distance_160(2,4);
					for(i=3;i<6;i++)
					{
    
    
						SBUF=table1[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令为3时,正向前进2.5mm,返回A05
				case '3':
					dir=0;
					ena=1;				
					distance_160(5,1);	
					for(i=0;i<3;i++)
					{
    
    
						SBUF=table2[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令为4时,反向前进2.5mm,返回B05
				case '4':
					dir=1;
					ena=1;				
					distance_160(5,1);
					for(i=3;i<6;i++)
					{
    
    
						SBUF=table2[i];
						while(!TI);
						TI=0;
					}
					break;		
				//RS232发送指令为5时,正向前进5mm,返回A10	
				case '5':
					dir=0;
					ena=1;				
					distance_160(10,1);	
					for(i=0;i<3;i++)
					{
    
    
						SBUF=table3[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令为6时,反向前进5mm,返回B10
				case '6':
					dir=1;
					ena=1;				
					distance_160(10,1);	
					for(i=3;i<6;i++)
					{
    
    
						SBUF=table3[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令为7时,正向前进15mm,返回A30
				case '7':
					dir=0;
					ena=1;				
					distance_160(30,1);	
					for(i=0;i<3;i++)
					{
    
    
						SBUF=table4[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令为8时,反向前进15mm,返回B30
				case '8':
					dir=1;
					ena=1;				
					distance_160(30,1);	
					for(i=3;i<6;i++)
					{
    
    
						SBUF=table4[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令为9时,正向前进25mm,返回A50
				case '9':
					dir=0;
					ena=1;				
					distance_160(50,1);	
					for(i=0;i<3;i++)
					{
    
    
						SBUF=table5[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令为0时,反向前进25mm,返回B50
				case '0':
					dir=1;
					ena=1;				
					distance_160(50,1);	
					for(i=3;i<6;i++)
					{
    
    
						SBUF=table5[i];
						while(!TI);
						TI=0;
					}
					break;
				//RS232发送指令不为0-9的数值时,返回No OK
				default:
					for(i=0;i<5;i++)
					{
    
    
						SBUF=table6[i];
						while(!TI);
						TI=0;
					}
					break;
			}
			ES=1;
			flag=0;
		}
	}	
}

void ser() interrupt 4
{
    
    
	//目前已经实现把数据存储到数组再判断,但必须要一次性发送固定的字符串,不然会错乱
		if(RI)										//如果是串口接收到一帧数据,就会产生中断,RI标志变为1
		{
    
    
			RI = 0;									//手动将标志置0,方便下次判断
			a=SBUF;			//出去接收到的数据	
		}
		flag=1;		//标志位用于,只有当4位数据接收完,主函数才进行数据比较
}

总结

步进电机效果视频


至此,本实验的内容讲完了,以上是本实验的实际效果。本文简单介绍了使用串口指令控制步进电机的基本方法,把本实验做完便可掌握基本的步进电机控制方法了。

猜你喜欢

转载自blog.csdn.net/qq_46166916/article/details/126513669
今日推荐