串口通讯与步进电机驱动

这个实验的内容是:电脑通过虚拟的COM端口与单片机进行相互通讯(电脑发给单片机,然后单片机又把接收到的信息发给电脑),发送的信息分别为正转、反转、加速、减速、停止,来控制电机做出相应的反应,并在Proteus上仿真。

模拟串口通讯需要用到2个软件,这里是网盘下载链接:
串口助手
提取码:rzqe
虚拟串口驱动
提取码:1172

这个实验有一个重要的问题,就是一定要选对虚拟串口和波特率,要不然就会不能进行通讯或是通讯时出现乱码。COM端口使用要配对,COM1-COM2,COM3-COM4,优先推荐使用COM3-COM4,波特率最好设置低一点,因为我传输时没有校验位,波特率太高的话容易出现乱码,所以我选择的波特率是4800。再就是程序中设置波特率初值,如果你设置了波特率加倍的话,最终波特率要在波特率的初值上乘以2,注意程序设置的波特率与串口助手要一致。

Proteus图:
串口通讯与步进电机驱动_第1张图片

具体实现方式请看下面的程序:

#include"main.h"

// 五条信息的Unicode 码如下 
//正转:d5 fd d7 aa
//反转:b7 b4 d7 aa
//加速:bc d3 cb d9
//减速:bc f5 cb d9
//停止:cd a3 d6 b9

void main(){
	UsartInit();  //串口初始化
	timer0_init();  //定时器初始化
	while(1){
		setmotor();   //控制电机状态的函数
	}
}
#ifndef __MAIN_H__
#define __MAIN_H__

	#include"setmotor.h"
 	#include"usart.h"

#endif
#include"setmotor.h"

static unsigned char state=0; //赋0、1、2分别表示电机的三个状态
static unsigned char k=4;  //k值决定电机速度的大小,k值越小电机的速度就越大,k值代表延时的长度
static int i;
unsigned char code zz[]={0x11,0x31,0x21,0x61,0x41,0xc1,0x81,0x91};//正转四相八拍步进电机
unsigned char code fz[]={0x91,0x81,0xc1,0x41,0x61,0x21,0x31,0x11};//反转

//电机正转
void motor_zz(){
	unsigned int j;
	for(j=0;j<8;j++){
		P1=zz[j];
		//每一拍延时一下
		for(i=0;i<k;i++){
			unsigned int t;
			for(t=0;t<3;t++){
				timer0_init();
				while(~TF0);  //当定时器溢出时,TF0为1,退出循环
				TF0=0;	//置0后方便下一次溢出提醒			
		  }
		}
			
	}
}

//电机反转
void motor_fz(){
	unsigned int j;
	for(j=0;j<8;j++){
		P1=fz[j];
		for(i=0;i<k;i++){
			unsigned int t;
			for(t=0;t<3;t++){
				timer0_init();
				while(~TF0);
				TF0=0;				
		  }
		}
	}
}

void setmotor(){
	while(state==0){  //状态0有两种模式分别是正转和反转,也是首次能执行的命令
		//正转
		if(com[0]==0xd5&&com[1]==0xfd&&com[2]==0xd7&&com[3]==0xaa){  //正转的Unicode码
			state=1;  //可以进入状态1
			com[1]=0x00;  //如果不改变其中一个com[4]的值,后面就不会执行motor_zz()
			break;  //跳出while循环
		}
		//反转
		if(com[0]==0xb7&&com[1]==0xb4&&com[2]==0xd7&&com[3]==0xaa){
			state=2;  //可以进入状态2
			com[1]=0x00;  //如果不改变其中一个com[4]的值,后面就不会执行motor_fz()
			break;
		}
	}
	//已经正转
	while(state==1){
		//电机停止
		if(com[0]==0xcd&&com[1]==0xa3&&com[2]==0xd6&&com[3]==0xb9){
			state=0;
			com[1]=0x00;
			break;
		}
		//电机正转
		if(com[0]==0xd5&&com[1]==0xfd&&com[2]==0xd7&&com[3]==0xaa){
			state=1;
			com[1]=0x00;
			break;
		}
		//电机反转
		if(com[0]==0xb7&&com[1]==0xb4&&com[2]==0xd7&&com[3]==0xaa){
			state=2;
			com[1]=0x00;
			break;
		}
		//电机加速
		if(com[0]==0xbc&&com[1]==0xd3&&com[2]==0xcb&&com[3]==0xd9){
			k=k-1;  //减小k值
			if(k<1)
				k=1;  //减到1为止
		}
		//电机减速
		if(com[0]==0xbc&&com[1]==0xf5&&com[2]==0xcb&&com[3]==0xd9){
			k=k+1;
			if(k>10)
				k=10;  
		}
		motor_zz();
	}
	//已经反转
	while(state==2){
		//电机停止
		if(com[0]==0xcd&&com[1]==0xa3&&com[2]==0xd6&&com[3]==0xb9){
			state=0;
			com[1]=0x00;
			break;
		}
		//电机正转
		if(com[0]==0xd5&&com[1]==0xfd&&com[2]==0xd7&&com[3]==0xaa){
			state=1;
			com[1]=0x00;
			break;
		}
		//电机反转
		if(com[0]==0xb7&&com[1]==0xb4&&com[2]==0xd7&&com[3]==0xaa){
			state=2;
			com[1]=0x00;
			break;
		}
		//电机加速
		if(com[0]==0xbc&&com[1]==0xd3&&com[2]==0xcb&&com[3]==0xd9){
			k=k-1;
			if(k<1)
				k=1;
		}
		//电机减速
		if(com[0]==0xbc&&com[1]==0xf5&&com[2]==0xcb&&com[3]==0xd9){
			k=k+1;
			if(k>10)
				k=10;
		}
		motor_fz();
	}
}
#ifndef __SETMOTOR_H__
#define __SETMOTOR_H__

	#include"usart.h"
	#include"timer0_init.h"
	extern unsigned char com[4];
	void setmotor();

#endif
#include"usart.h"

unsigned char com[4]={0,0,0,0};  //因为两个汉字对应4个Unicode码
static unsigned int i=0;

void UsartInit(){
	SCON=0x50;  //选择串口工作方式1并允许接收
	TMOD=0x20;  //选择定时器工作方式2,可以初值重装载
	PCON=0x80;  //波特率加倍
	TH1=0xf3;   //波特率初值为2400,加倍后就是4800
	TL1=0xf3;   //TH1的初值不会变,用来赋值给TL1 
	ES=1;  //串口中断允许位
	EA=1;  //打开总中断
	TR1=1;  //开启定时器中断
}

void receivedata() interrupt 4{
	if(RI==0) return;  //单片机没有收到信息,就直接退出函数
	ES=0;  //关掉串口中断,以防多条信息输入时,来不及执行前面的代码
	RI=0;  //接收完一条信息后,RI是为1的,表示接收完成,我们要手动把RI置0
	com[i]=SBUF;  //接收的信息是放在SBUF缓存器中,我们要把它读取出来,方便SBUF接收下一次信息的输入
	SBUF=com[i];  //再把接收的信息发给上位机(电脑),这两个SBUF是不同的,只是命名一样
	i++;  //分四次就接受两个汉字的Unicode码
	while(!TI);  //判断信息是否发送完成,完成了TI就会为1,跳出循环
	TI=0;  //手动置0,用于下一次的判断
	if(i>=4)
		i=0;
	ES=1;  //一条信息完整发送成功,再打开串口中断,接收下一条信息
}
#ifndef __USART_H__
#define __USART_H__

	#include"reg52.h"
	void UsartInit();

#endif
#include"timer0_init.h"

void timer0_init(){
	EA=1;
	ET0=1;
	TR0=1;
	TMOD|=0x01;//定时器工作模式为1,因为还使用了定时器工作方式2,所以TMOD后要有“|”
	TH0=0xd8;//定时器延时10ms
	TL0=0xf0;
}
#ifndef __TIMER0_INIT_H__
#define __TIMER0_INIT_H__

	#include"reg52.h"
	void timer0_init();

#endif

你可能感兴趣的:(单片机,串口通信)