zoukankan      html  css  js  c++  java
  • 多机串口通讯

    ★使用器件

    使用了3块80c51的单片机,当中U1为主机控制其它两个从机U2,U3。每一个单片机上都有一个数码管用来显示数据。主机上有两个按键KEY_1,KEY_2,分别用来控制不同的从机。

    ★实现目标

    主要实现的目标就是通过写多机通讯来了解他们当中的协议,以及简单协议的写法!本程序主要达到了一下效果,主机能够通过发送命令来控制从机:发送数据给从机、接收从机的数据。然后将从机或者主机显示的数据显示在数码管上。

    ★协议要求

    1、地址:主机的地址设置为0x01,从机1(U3)的地址为0x03,从机2(U2)的地址为0x02

    2、命令:

    0x01表示:主机向从机发送数据

    0x02表示:从机向主机发送数剧

    3、基本步骤:

    ●主机发送地址帧,从机接收到地址帧后就会与本机地址进行比对,假设正确则发送自己的地址应答;假设不对,则丢弃数据,继续监測等待数据;

    ●从机接收地址正确后,返回自己的地址作为应答信号;假设主机接收到的数据与自己发送的地址数据同样,就会发送命令(是让从机接收数据还是发送数据);假设与自己发送的地址数据不同,则发送0xff,当从机接收到数据得到RB8 ==1,则进入继续监測等待数据。

    ●主机发送命令,从机接收到命令后,就会返回接收到的命令作为应答(没有处理异常情况);主机监測到应答数据正确就会发送数据,而且等待从机的应答信号(0x11),接收到应答信号后,再发送第二个数据(这个地方主机没有处理异常情况),指导发送数据结束

    ●发送数据接收后,主机会发送校验和,与从机接收的数据的校验和比較,假设检验和同样说明发送数据正确,然后就退出程序;假设检验和发送不对则又一次发送数据。

    4、详细实现

    串行口有一个非常重要的寄存器:


    SM2为多机通讯控制位。当从机的SM2=1时,能够利用收到的RB8来控制RI。当RB8 = 1接收数据而且使RI = 1,当RB8 = 0时不接受数据;当SM2= 0时,不管RB8是否为1都会接收数据,而且使RI = 1。因此能够依据这个特点来差别地址和数据。从机首先将SM2置1,然后将要发送数据的TB8置1,从机接收到数据后就会比較地址是否与本机地址同样,假设同样就是将SM2置0,然后发送数据(TB = 0),而其它的从机仍然处于SM=1的状态,接收不到数据。

    ★电路图




    ★程序实现

    主机:

    #include <reg52.h>
    
    #define uint unsigned int
    #define uchar unsigned char
    
    sbit key_1 = P1^0;
    sbit key_2 = P1^1;
    sbit Led = P1^7;
    
    #define master_U1 0x01 //主机地址
    #define slave_U2 0x02  //从机地址
    #define slave_U3 0x03  //从机地址
    
    uchar tbuf[16] = {0x3f,0x06,0x5b,0x4f, 
    				  0x66,0x6d,0x7d,0x07, 
    				  0x7f,0x6f,0x77,0x7c, 
    				  0x39,0x5e,0x79,0x71};
    uchar rbuf[16];//待接收数据的数组
    
    void DelayUs2x(unsigned char t)
    {   
    	while(--t);
    }
    
    void DelayMs(unsigned char t)
    {
         
    	while(t--)
    	{
    		 //大致延时1mS
    		 DelayUs2x(245);
    		 DelayUs2x(245);
    	}
    }
    
    void Uart_init(void)
    {
    	SCON |= 0xf8;//工作方式1,T1,R1置零,同意串行口接收数据
    	TMOD |= 0x20;//定时器1,模式2 
    	TH1 = 0xFD;
    	TL1 = 0xFD;
    	TR1 = 1;
    	EA = 1;//打开总中断 
    	ES = 1;//打开串口中断 
    }
    
    void master_send(uchar addr,uchar command)
    {
        uchar status,check,i = 0;
    
    	SBUF = addr;//发送要操作的地址
    	while(!TI);
    	DelayMs(10);
    		TI = 0;//发送从机地址
        while(!RI);
    		RI = 0;//等待从机地址答复
        
    	if(addr!=SBUF)//假设返回的地址与要操作的地址不同
    	{
    	    SBUF=0xff;
    		while(!TI);    
    		TI=0;
    	}	
    	else
    	{
    	    TB8=0;
    		SBUF=command;
    		while(!TI);
    			TI = 0;	//发送命令
    		while(!RI);
    			RI = 0;//等待从机的回复
    
            status = SBUF; //从机发送确认命令
    		if(status == 0x80)
    		{
    		    TB8 = 1;
    		}  
    		else
    		{
    			if(status == 0x01)//主机知道从机已经准备好接收数据,就进入发送状态
    			{
    				while(1)
    				{
    					check = 0;
    					for(i = 0;i < 16;i++)
    					{
    					    SBUF = tbuf[i];
    						while(!TI);
    							TI = 0;
    				    	while(!RI);	//等待从机返回确认信号0x11
    						    RI = 0;
    						check += tbuf[i];//校验和
    						DelayMs(2000);
    					} 
    					SBUF = check;//向从机发送校验和
    					while(!TI);//发送校验和给从地址
    					TI = 0; 
    					
    					while(!RI);
    					RI = 0;//接收从地址返回的数据(0x00或者0xff)
                       
    				    
    					if(SBUF == 0x00)
    					{
    					    break; 
    					}
    					    
    					//接收到0x00表明校验正确,则跳出发送函数,假设接收到0xff则表明校验出错,又一次发送    
    				} 
    				
    			}
    			
    			if(status == 0x02)//主机知道要接收来自从机的数据了
    			{
    			    while(1)
    				{
    				    check = 0;   
    					for(i = 0;i < 16; i++)
    					{
    					    while(!RI);
    							RI = 0;
    						rbuf[i] = SBUF;
    						P2 = rbuf[i];
    
    						SBUF = 0x11;//每收到一个数据,发送0x11
    						while(!TI);	//表示接受到数据后的确认
    							TI = 0;
    					    check += rbuf[i];
    					}    
    				    while(!RI);
    						RI = 0;
    					if(check == SBUF)//假设主机数据的校验和与从机的校验和相等,则返回主机0x00
    					{				 //否则,须要又一次等待接收数据。
    					    SBUF = 0x00;
    						while(!TI);
    						TI = 0;
    						P2 = 0;
    						break;
    					}
    				} 
    			}
    		} 
     	}  
    }
    
    void main()
    {
    	Uart_init();
    	P2 = 0;  
    	Led = 1;
        if(!key_1)
    	{
    	    DelayMs(20);
    		if(!key_1)
    		{
    		    master_send(slave_U2,0x02);
    		}
    	} 
    
    	if(!key_2)
    	{
    		DelayMs(20);
    		if(!key_2)
    		{
    		    master_send(slave_U3,0x01);
    		}
    		Led = 0;
    	}
    
    }

    从机1:

    /**从机1 U3**/
    #include <reg52.h>
    
    #define uint unsigned int
    #define uchar unsigned char
    
    //#define slave_U2 0x02
    #define slave_U3 0x03
    
    sbit key = P1^0;
    static uchar tbuf[] = {0x3f,0x06,0x5b,0x4f, 
    					   0x66,0x6d,0x7d,0x07, 
    					   0x7f,0x6f,0x77,0x7c, 
    					   0x39,0x5e,0x79,0x71};
    
    static uchar rbuf[16];
    void Uart_receive();
    void Send_receive();
    
    void DelayUs2x(unsigned char t)
    {   
    	while(--t);
    }
    
    void DelayMs(unsigned char t)
    {
        while(t--)
    	{
    		 //大致延时1mS
    		 DelayUs2x(245);
    		 DelayUs2x(245);
    	}
    }
    
    void Uart_init()//串口初始化
    {
        PCON = 0;
        SCON |= 0xf8; 
    	TMOD |= 0x20;
    	TH1 = 0xfd;
    	TL1 = 0xfd;
    	TR1 = 1; 
    	EA = 1;
    	ES = 1;
    }
    
    void main()
    {
    	P2 = 0;
    	Uart_init();
    
    	while(1);
    }
    
    void Ser_uart() interrupt 4
    {
        uchar save;
    	RI = 0;
    	ES = 0;
    	if(SBUF != slave_U3)
    	{
    	    ES = 1;
            goto end; //假设发送的从机地址与本从机地址不相符则,运行此语句。
    	}	
        SM2 = 0;//设置为单击模式
    	SBUF = slave_U3;//发送从机地址给主机
    	while(!TI);
        	TI = 0;
    	while(!RI);//接收主机发来的命令
    		RI = 0; 
    
    	
       if(RB8 == 1)//假设返回的地址出错误,则发送0xff,RB8 = 1;
    	{
    		SM2 = 1;
    		ES = 1;
    		goto end;//进入等待地址帧模式
    	}
        
    	save = SBUF;//将接收到的命令存在save中
     	if(save == 0x01)//假设接收的命令是0x01
    	{
    	    SBUF = 0x01;//向主机发送03表示确认,已经做好准备
    		while(!TI);    
     		TI = 0;
    		Uart_receive();//进入接收状态等待
    	}
        else
    	{
    	    if(save == 0x02)
    		{
    		    SBUF = 0x02;//告诉主机,要准备发送数据了
    			while(!TI);
    			TI = 0;
    		    Send_receive();//进入发送数据函数
    		}
    
    		else
    		{
    		   SBUF = 0x80;
    		   while(!TI);
    		   TI = 0;
    
    		   SM2 = 1;
    		   ES = 1;
    		   goto end;
    		}
    	
    	} 
    	end:;
    }
    
    void Uart_receive()
    {
        uchar check,i;
    	while(1)
    	{
    		check = 0;
    		for(i = 0;i < 16;i++)
    		{
    		    while(!RI);
    				RI = 0;
    			rbuf[i] = SBUF;
    			P2 = rbuf[i];//显示接受到的数据
    
    			SBUF = 0x11;//每收到一个数据,发送0x11
    			while(!TI);	//表示接受到数据后的确认
    				TI = 0;
    			check += rbuf[i];
    		}
    	    while(!RI);
    			RI = 0;
    
             if(SBUF == check)//假设主机数据的校验和与从机的校验和相等,则返回主机0x00
    		{
    		    SBUF = 0x00;
    			while(!TI);
    				TI = 0;
    			P2 = 0;
    			break;
    		}  
    		else//假设主机数据的校验和与从机的校验和不相等,则又一次发送数据
    		{
    		    SBUF = 0xff;
    			while(!TI);
    				TI = 0;
    		} 
    	}
    }
    
    void Send_receive()
    {
        uchar check,i;
    	while(1)
    	{
    	    check = 0;
    		for(i = 0;i < 11;i++)
    		{
    		    SBUF = tbuf[i];
    			while(!TI);
    			TI = 0;
    			check += tbuf[i];
    		}
    		SBUF = check;
    		while(!TI);	//发送校验数据
    		TI = 0;
    
       		while(!RI);
    		RI = 0;//等待校验结果,接收主地址返回的数据(0x00或者0xff)
            if(SBUF == 0x00)
    			break;
    		//接收到0x00表明校验正确,则跳出发送函数,假设接收到0xff则表明校验出错,又一次发送 
         }
    	 	while(1)
    		{
    		    for(i = 0;i < 16;i ++)
    			    P2 = rbuf[i];
    				DelayMs(1000);
    		}
    
    
    }

    从机2::

    /**从机2,电路图U2**/
    #include <reg52.h>
    
    #define uint unsigned int
    #define uchar unsigned char
    #define slave_U2 0x02
    //#define slave_U3 0x03
    
    sbit Key = P1^0;
    static uchar tbuf[] = {0x3f,0x06,0x5b,0x4f, 
    					   0x66,0x6d,0x7d,0x07, 
    					   0x7f,0x6f,0x77,0x7c, 
    					   0x39,0x5e,0x79,0x71};
    
    static uchar rbuf[16];
    
    void Uart_receive();
    void Send_receive();
    
    static uchar rbuf[16];
    
    void DelayUs2x(unsigned char t)
    {   
    	while(--t);
    }
    
    void DelayMs(unsigned char t)
    {
         
    	while(t--)
    	{
    		 //大致延时1mS
    		 DelayUs2x(245);
    		 DelayUs2x(245);
    	}
    }
    
    void Uart_init()//串口初始化
    {
        PCON = 0;
        SCON |= 0xf8; 
    	TMOD |= 0x20;
    	TH1 = 0xfd;
    	TL1 = 0xfd;
    	TR1 = 1; 
    	EA = 1;
    	ES = 1;
    }
    
    void main()
    {
        P2 = 0;
    	Uart_init();
    	while(1);
    
    }
    
    void Ser_uart() interrupt 4
    {
        uchar save;
    	RI = 0;
    	ES = 0;
    	
    	if(SBUF != slave_U2)
    	{
    	    ES = 1;
            goto end; //假设发送的从机地址与本从机地址不相符则,运行此语句。
    	}		
    			
        SM2 = 0;//设置为单击模式
    	SBUF = slave_U2;//发送从机地址给主机
    	while(!TI);
        	TI = 0;
    	while(!RI);//接收主机发来的命令
    		RI = 0;
        if(RB8 == 1)//假设返回的地址出错误,则发送0xff,RB8 = 1;
    	{
    		SM2 = 1;
    		ES = 1;
    		goto end;//进入等待地址帧模式
    	}
        
    	save = SBUF;//将接收到的命令存在save中
    
    	if(save == 0x01)//假设接收的命令是0x01
    	{
    	    SBUF = 0x01;//向主机发送01表示确认,已经做好准备
    		while(!TI);    
    		TI = 0;
    		Uart_receive();//进入接收状态等待
    	}
        else
    	{
    	    if(save == 0x02)
    		{
    		    SBUF = 0x02;//告诉主机,要准备发送数据了
    			while(!TI);
    			TI = 0;
    	        Send_receive();//进入发送数据函数
    			//DelayMs(1000);
    		}
    
    		else
    		{
    		   SBUF = 0x80;
    		   while(!TI);
    		   TI = 0;
    
    		   SM2 = 1;
    		   ES = 1;
    		   goto end;
    		} 
    	
    	}  
    	end:;
    }
    
    void Uart_receive()
    {
        uchar check,i;
    	while(1)
    	{
    		check = 0;
    		for(i = 0;i < 11;i++)
    		{
    		    while(!RI);
    			RI = 0;
    			tbuf[i] = SBUF;
    
    			SBUF = 0x11;//每收到一个数据,发送0x11
    			while(!TI);	//表示接受到数据后的确认
    				TI = 0;
    			check += tbuf[i];
    		}
    	    while(!RI);
    			RI = 0;
    
            if(SBUF == check)//假设主机数据的校验和与从机的校验和相等,则返回主机0x00
    		{
    		    SBUF = 0x00;
    			while(!TI);
    				TI = 0;
    			break;
    		}
    		else//假设主机数据的校验和与从机的校验和不相等,则又一次发送数据
    		{
    		    SBUF = 0xff;
    			while(!TI);
    				TI = 0;
    		} 
    	}
    }
    
    void Send_receive()
    {
        uchar check,i;
    	while(1)
    	{
    	    check = 0;   
    		for(i = 0;i < 16;i++)
    		{
    		    SBUF = tbuf[i];
    			while(!TI);
    			TI = 0;
    
    			while(!RI);
    			 RI = 0;
    			check += tbuf[i];
    			DelayMs(2000);
    		}
    		SBUF = check;
    		while(!TI);	//发送校验数据
    		TI = 0;
    
       		while(!RI);
    		RI = 0;//等待校验结果,接收主地址返回的数据(0x00或者0xff)
            if(SBUF == 0x00)
    			break;
    		//接收到0x00表明校验正确,则跳出发送函数,假设接收到0xff则表明校验出错,又一次发送 
         }
    
    
    }



  • 相关阅读:
    APP上线审核注意事项
    xcode环境变量设置(转载)
    iOS 工程中 Other Linker Flags
    iOS 打开应用与系统功能的调用
    在oc中一些常用的宏定义总结
    WebViewJavascriptBridge的简单应用
    UITextField 对键盘一些常用属性 记录一下
    UITextInputMode类的使用
    数组和指针
    自定义ViewGroup实现瀑布流效果
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4033435.html
Copyright © 2011-2022 走看看