带有Start/Reset/Stop/Rotate/Main motor runs命令的二自由度自动进样器(Version1.0)

#include <STC89C5xRC.h>
char tcount = 0;
char step = 0;//记录主电机走过的步数(走过的步数=step/2)
char buf[30];//存放命令
int en = 0;//en = 1 -> 系统工作, en = 0 -> 系统停止
int k = 0;
int len = 0;
int re = 0;//复位信号, 1 -> 复位, 0 -> 不复位
int direction = 0;//0 -> 顺时针, 1 -> 逆时针
int step_B = 0;//命令要求主电机转的步数
int motorRun = 0;// 1 -> 按命令转相应步数, 0 -> 无动作

void delay()
{
    int i,j;
	for(i = 0; i < 40; i++)
	    for(j = 0; j < 40 ; j++)
        {
		    ;//为针臂步进电机提供时延
		}
}
void delay2()//针臂在底部停留时延
{
    int i,j;
	for(i=0;i<800;i++)
	    for(j=0;j<800;j++)
		{
		    ;
		}
}
void motor_Control(int steps)//控制主转盘电机转动指定步数
{
    int i;
	for(i = 0; i < steps; i++)
	{
	    P20 = 0;
		delay();
		P20 = 1;
		delay();
	}
}
void timer0() interrupt 1
{
	int i = 0;
	if(step == 0)
	{
		if(direction == 0)
		{
			P21 = 0;//顺时针
		}
		else if(direction == 1)
		{
			P21 = 1;//逆时针
		}
	}
    TR0 = 0;//关闭定时器0
    TH0 = 0x3c;
	TL0 = 0xB0;//50ms
	if(re == 1)//复位信号起作用
	{
		re = 0;
		//针臂移至上限位, 转盘转回0号瓶
		P03 = 0;//往上转
		while(P01 == 1)//若未到上限位置,P0.1接单片机P01
		{
		    P22 = 0;
			delay();
			P22 = 1;	
			delay();
		}
		while(P00 == 1)//若未到0号瓶位置
		{
			P20 = 0;
			delay();
			P20 = 1;
			delay();
		}
		//霍尔传感器有误差, 还差2.5格左右, 再发20个脉冲
		if(P21 == 1)//转盘逆时针转过来
		{
			while(i++ < 20)
			{
				P20 = 0;
				delay();
				P20 = 1;
				delay();
			}
		}
		else if(P21 == 0)//转盘顺时针转过来
		{
			while(i++ < 22)
			{
				P20 = 0;
				delay();
				P20 = 1;
				delay();
			}	
		}
		tcount = 0;
		en = 0;
		step = 0;
		goto END;
	}
	if(motorRun == 1)//电机按要求转命令起作用
	{
		motorRun = 0;
		step = 0;
		tcount = 0;
		en  = 0;
		motor_Control(step_B);
		step_B = 0;
		goto END;
	}
	tcount++;
	if(tcount == 2)//100ms = 0.1s
	{
	    P20 = ~P20;//P20翻转,相当于发送脉冲
		tcount = 0;
		step ++;
		if(step / 2 == 8)//电机走了8步(经历了8次高低电平的转换)
		{
		    step = 0;//将步数归零
            //P1.3=1代表向下,P1.3=0代表向上
	        P03 = 1;//往下转,P13接单片机P03
			while(P02 == 1)//若未到下限位置,P0.2接单片机P02
			{
			    P22 = 0;
   			    delay();
				P22 = 1;
				delay();
			}
            delay2();//针臂在底部停留片刻
			P03 = 0;//往上转
			while(P01 == 1)//若未到上限位置,P0.1接单片机P01
			{
			    P22 = 0;
				delay();
				P22 = 1;
				delay();
			}
		}
	}//1000ms = 1s 发送一个完整的脉冲
END: ;
	TR0 = 1;//开启定时器0
}

void UART_INT() interrupt 4//串行通信中断处理程序
{
    int len = 0;
    int j = 0;
    if(RI == 1)//如果收到数据
    {
        if(k == 30)
        {
            k = 0;//防止越界访问
        }
        RI = 0;
        buf[k++] = SBUF;//将数据接收下来
        if(buf[k - 1] == 'E')//到达结尾
        {
            len = k - 1;//记录数据长度
            k = 0;
            if(len == 6)
            {
                if(buf[0] == 'S' && buf[1] == 't' && buf[2] == 'a' && buf[3] == 'r' && buf[4] == 't' && buf[5] == '.')
                {
                    //Start命令(开机)
                    en = 1;
                    P27 = 0;//D8亮
                    P26 = 1;
                    P25 = 1;
                    P24 = 1;
                    //再将en的值传回去
                    SBUF = en + 48;
                }
                else if(buf[0] == 'R' && buf[1] == 'e' && buf[2] == 's' && buf[3] == 'e' && buf[4] == 't' && buf[5] == '.')//主转盘回到原始位置,针臂抬到最高位置
                {
                    //Reset命令(复位命令)
                    en = 1;
                    P27 = 1;
                    P26 = 0;//D7亮
                    P25 = 1;
                    P24 = 1;
                    SBUF = en + 48;
					re = 1;//复位信号
                }
            }
            else if(len == 5)//停机命令
            {
                if(buf[0] == 'S' && buf[1] == 't' && buf[2] == 'o' && buf[3] == 'p' && buf[4] == '.')
                {
                    //Stop命令(停机命令)
                    en = 0;
                    P27 = 1;
                    P26 = 1;
                    P25 = 0;//D6亮
                    P24 = 1;
                    SBUF = en + 48;
                }
            }
            else if(len == 19)//要求主转盘转动相应格数(>=10)
            {
                if(buf[0] == 'M' && buf[1] == 'a' && buf[2] == 'i' && buf[3] == 'n' && buf[4] == ' ' && buf[5] == 'm' && buf[6] == 'o' && buf[7] == 't' && buf[8] == 'o' && buf[9] == 'r' && buf[10] == ' ' && buf[11] == 'r' && buf[12] == 'u' && buf[13] == 'n' && buf[14] == 's' && buf[15] == ' ' && buf[18] == '.')
                {
                    //Main motor runs命令,比如Main motor runs 22.
                    if(buf[16] >= '1' && buf[16] <= '9' && buf[17] >= '1' && buf[17] <= '9')//确定发来的步数是数字
                    {
                        en = 1;
                        P27 = 1;
                        P26 = 1;
                        P25 = 1;
                        P24 = 0;//D5亮
                        SBUF = en + 48;
						step_B = 8 * (((buf[16] - 48) * 10 + (buf[17] - 48)));
						motorRun = 1;
                    }
                }
            }
			else if(len == 18)//要求主转盘转动相应格数(<=9)
			{
				if(buf[0] == 'M' && buf[1] == 'a' && buf[2] == 'i' && buf[3] == 'n' && buf[4] == ' ' && buf[5] == 'm' && buf[6] == 'o' && buf[7] == 't' && buf[8] == 'o' && buf[9] == 'r' && buf[10] == ' ' && buf[11] == 'r' && buf[12] == 'u' && buf[13] == 'n' && buf[14] == 's' && buf[15] == ' ' && buf[17] == '.')
                {
                    //Main motor runs命令,比如Main motor runs 22.
                    if(buf[16] >= '1' && buf[16] <= '9')//确定发来的步数是数字
                    {
                        en = 1;
                        P27 = 1;
                        P26 = 1;
                        P25 = 1;
                        P24 = 0;//D5亮
                        SBUF = en + 48;
						step_B = 8 * (buf[16] - 48);
						motorRun = 1;
                    }
                }		
			}
			else if(len == 9)//要求主转盘转动的方向
			{
				//Rotate 0/Rotate 1命令
				if(buf[0] == 'R' && buf[1] == 'o' && buf[2] == 't' && buf[3] == 'a' && buf[4] == 't' && buf[5] == 'e' && buf[6] == ' ' && buf[8] == '.')
				{
					if(buf[7] == '0')
					{
						direction = 0;//顺时针
					}
					else if(buf[7] == '1')
					{
						direction = 1;//逆时针
					}
				}
			}
        }
    }
    else if(TI == 1)//如果发送数据完毕
    {
        TI = 0;
    }
}

int main()
{
    TMOD = 0x21;
	TH0 = 0x3C;
	TL0 = 0xB0;
	IE = 0x92;
	P20 = 0;//给虚拟接口卡P1.0发脉冲,以驱动主转盘步进电机
	P22 = 0;//给虚拟接口卡P1.2发脉冲,以驱动针臂步进电机
	TR0 = 1;//启动定时器0
	//
	SCON = 0x50;
	TH1 = 0xe6;
	TL1 = 0xe6;
	TR1 = 1;//启动定时器1
	RI = 0;
	TI = 0;
	IP = 0x10;//提升串口中断的优先级
	P21 = 0;//主转盘电机方向, 默认为顺时针
	while(1)
	{
	    //如果en = 1开启timer0的中断, 否则将timer0的中断关闭
		if(en == 1)
		{
			IE = 0x92;
		}
		else if(en == 0)
		{
			IE = 0x90;
		}
	}
}
/*
P1.0:转盘电机Pulse信号
P1.1:转盘电机Dir -> P21
P1.2:针臂电机Pulse
P1.3:针臂电机Dir
P0口:输出口,连接虚拟软件中的传感器信号
P0.0:霍尔传感器信号,平时为高电平,有效时为低电平 -> P00
P0.1:针臂上限位信号
P0.2:针臂下限位信号

*/

硬件环境: 8051MCU + Lenovo Y7000(Intel i5 - 8300H @2.30GHz + 16G 2667MB memory) + 虚拟接口卡(学校老师提供).

软件环境: Keil + AutoExampler.exe(学校老师提供) + stc-isp.

-------------------------------------------------------------------------------------------------------------------

虚拟接口卡与8051MCU接口连接情况:

P1.0:转盘电机Pulse信号  -> P20

P1.1:转盘电机Dir  -> P21

 

P1.2:针臂电机Pulse  -> P22

P1.3:针臂电机Dir  -> P03

 

P0.1:针臂上限位信号  -> P01

扫描二维码关注公众号,回复: 6742907 查看本文章

P0.2:针臂下限位信号  -> P02

P0.0:  霍尔传感器信号   ->P00

-------------------------------------------------------------------------------------------------------------------

通信协议处理:

在每条命令后,必须加".E", 这将作为数据包尾处理. 

Start.E -> 系统开始工作.

Stop.E -> 在系统已经开始工作的基础上, 待主转盘走完一整格 ,针臂抬至上限位, 系统停止工作.

Reset.E ->针臂抬至上限位处, 主转盘转至0号瓶位置

Rotate 0/1.E ->只有当完整的一次序列动作后, 才可改变主转盘旋转方向

Main motor runs ××.E命令 -> 主转盘根据要求旋转N格, 之后系统停止工作, 等待下一命令的到来.

-------------------------------------------------------------------------------------------------------------------

一次完整的序列动作:

主转盘旋转8格 -> 针臂从上限位移动至下限位 -> 针臂静止一段时间 -> 针臂从下限位移动至上限位

-------------------------------------------------------------------------------------------------------------------

心得体会:

完成这样一个程序的设计并不是件容易的事情. 在程序实现前, 须分别实现各功能模块的功能-----只有这样, 才能在技术上做到畅通无阻. 表面上看一次完整的序列动作十分简单, 但涉及到两个中断源的处理时, 问题便会变得棘手. 在提高串口中断优先级前, 我遇到了很多目前无法合理解释的问题: 这是因为我没有足够的硬件知识储备, 所以对8051MCU的使用仅仅停留在软件层面. 这是不可取的. 希望各位像我一样的同学们多多加强对硬件知识的学习, 做到"软硬皆通". 另外也十分欢迎各位同仁对我的程序进行多角度的测试 并对我的错误进行指正, 感谢各位.

-------------------------------------------------------------------------------------------------------------------

联系方式: QQ: 377539288 好梦成真 

-------------------------------------------------------------------------------------------------------------------

备注: 定时器中断处理序列动作的问题可参考我的博文"二自由度自动进样器动作序列实现".

         串口接收复杂命令的问题可参考我的博文"8051单片机串口复杂命令接收与解析".

猜你喜欢

转载自blog.csdn.net/weixin_42048463/article/details/93783604