多机串口通讯

★使用器件

使用了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则表明校验出错,重新发送
     }

}

多机串口通讯,布布扣,bubuko.com

时间: 2024-10-23 09:23:50

多机串口通讯的相关文章

STM32与PC机串口通讯

有时要将板子的信息输出到电脑上来调试之类的,或者把传感器收集到的数据显示到电脑. 当然了,这只是最基本的串口通信,简单的说,是有一根USB线连着的. mbed上并没有能显示printf的功能.需要自己配置一下.我用的是win8,只讲一下win8了. 1.在官网下载板子的驱动程序. 2.win8没有超级终端,自己下一个.这里推荐Tera Term.下载地址 http://osdn.jp/projects/ttssh2/downloads/64118/teraterm-4.89.exe/ 这两步都是

串口通讯1---单片机

摘要:最近在做Qt串口通讯部分.  在验证串口通讯部分是否可行,是否可行时,通过虚拟端口. 单片机来测试. 本文主要写单片机的串口通讯,下篇将写通过单片机发送一个字符串,Qt编写的通讯界面接收时,这个过程是如何进行的. ----------------------------------------------------------------------------------------------------------- 主要思路如下图所示: 开始理解第一部分,单片机的串口通讯.

串口通讯方式1编程

在上位机上用串口调试助手发送一个字符X,单片机收到字符后返回给上位机"I get X",串口波特率设为9600bps. #include<reg52.h> #define uchar unsigned char unsigned char flag,a,i; uchar code table[]="I get"; void init() { TMOD=0x20;  //设定T1定时器的工作模式2 TH1=0xfd; //T1定时器装初值 TL1=0xfd

C#串口通讯

本文提供一个用C#实现串口通讯实例,亲自编写,亲测可用! 开发环境:VS2008+.net FrameWork3.5(实际上2.0应该也可以) 第一步 创建一个WinForm窗体,拉入一些界面元素 重点就是,图中用红框标出的,工具箱——组件——SerialPort,做.net串口通讯,这是必备控件 第二步 设置SerialPort控件属性 用C#向串口发送数据没什么特别的,就是调用SerialPort的Write方法往串口写数据就行 但是从串口那里接收数据的方式就比较特别了 首先,需要在代码里声

串口屏(触摸屏)组态软件+多台51单片机MODBUS RTU多机串口通信程序源码

串口屏(触摸屏)组态软件+多台51单片机MODBUS RTU多机串口通信程序源码实现触摸屏(串口屏)与单片机的通讯,主要是解决通讯协议的问题.本文使用开放的Modbus通讯协议,以广州易显的HMImaker触摸屏作主机(Master),单片机作从机(Slaver).HMImaker触摸屏本身支持Modbus通讯协议,只要单片机按照Modbus协议进行收发数据,就可以进行通信了.触摸屏与单片机之间采用RS-485标准接口直接连接,与多台51单片机MODBUS RTU多机串口通信一.包括如下实例:二

[delphi技术]Delphi MSComm 实时串口通讯

Delphi  MSComm 实时串口通讯 MSComm控件具有丰富的与串口通信密切相关的属性,提供了对串口进行的多种操作,进而使串行通信变得十分简便.MSComm的控件属性较多,常用的属性如下:1).CommPort:设置或返回串行端口号,缺省为1.2).Setting:设置或返回串口通信参数,格式为“波特率,奇偶校验位,数据位,停止位”.例如:MSComm1.Setting:=9600,n,8,13).PortOpen:打开或关闭串行端口,格式为:MSComm1.PortOpen:={Tru

Java程序与RSR232串口通讯小练手(转载)

一直以来都是在学习J2EE方面的应用系统开发,从未想过用JAVA来编写硬件交互程序,不过自己就是喜欢尝试一些未曾接触的新东西.在网上搜索了些资源,了解到JAVA写串口通讯的还是蛮多的,那么便着手准备开发调试环境.软件程序开发环境搭建不成问题,可这硬件环境就有点犯难啦.更何况自己用的是笔记本哪来的串口呀,再说要是真拿这串口硬件来自己也不会弄,随即想到了虚拟机,觉得这东西应该也有虚拟的吧,果真跟自己的猜测一样还真有这东西,顺便也下载了个串口小助手做为调试之用.下面就先看看软件环境的搭建: 1.下载c

Android通过JNI实现与C语言的串口通讯操作蓝牙硬件模块

一直想写一份技术文档,但因为自感能力有限而无从下笔,近期做了个关于Android平台下实现与C语言的通讯来操作蓝牙模块的项目,中间碰到了很多问题,也在网上查了很多资料,在完毕主要功能后.也有一些人在网上问我一些问题.这里写下这篇文档算是一个阶段性的总结. 假设反响好.兴许将会发上Android Stub与新版Android HAL的学习文档. 因为蓝牙模块是串口通讯机制.使用C语言来訪问,而Android的应用层採用Java.无法直接操作硬件.故使用JNI的技术实现主要功能.Android的JN

pcommlite串口通讯库使用

MFC下串口编程使用最多的两种方法是读取注册表和使用mscomm组件,都有着或多或少的缺陷,调用系统SDK比较麻烦,而MSCOMm组件最多支持16个串口,串口号大于16的时候无法打开,遇到这种情况,可以使用一个名为pcommlite的串口通讯库,下载安装之后,解压出来的文件包括 根据编译的平台选择相应的lib文件加入工程,并加入pcomm.h文件 寻找系统串口,sio_open()打开串口 sio_close()关闭串口 BYTE i = 0; CString str; // TODO: 在此添