⑴ 单片机多机通讯时,多是主机向从机发送命令后,从机给出应答信号,能不能从机主动给主机发送数据呢,谢谢
主机和从机通讯时,不可以从机主动发数据给主机。一般要主机主动去发布命令,从机去应答,如果从机也主动和主机联系,那么会造成主机接收数据错误,或者发送数据错误!
下面分析下原因。
1、首先说明下单片机多机通讯的原理:简单点就是多个单片机TXD和RXD连接到一个,主机的TXD连接从机的RXD,从机之前是并联状态;复杂的呢就是通过RS485芯片,连接方式和上面一样的,RS485相对来说传输数据抗干扰。
2、主机给从机发送数据,从机怎么来接收这一帧数据。一般我们是给每个从机都设置一个独一无二的地址。从机接收到数据首先判断是不是发送给自己的,就像是收快递一样的。不是发给自己的,后面的数据就不处理,或者不接收数据。
3、说明下主机和从机的概念。其实主机、从机都是一样的设备,作歼如为主机来说,这个设备要主动去和从机的设备去沟通,就好像车间的班长和流水线上的操作工,班长去下发任务,操作工根据任务命令去做事。
主机就是去告诉从机,什么时间去做什么事。从机就是等待命令,然后去检测外部信号,执行命令。
4、主机和从机通讯的时候罩御,能不能从机主动。明白了主机和从机的概念,深入的想一下,为什么要主机发送命令,从机做出应答呢
。一般是主机会和很多从机进行通信。主机和从机通信一般是有个时间的间隔。比如200ms发送一次,然后切换到下一个从机。
如果主机在发送数据的时候,从机突然主动和主机联系了,那么
就会出现数据错误了,因为主机在发送数据,发送的过程中肯定会造成来不及处理接收数据,因为单片机同时只能处理一件事情。
所以
主机就是要主动联系,从机就是要等待主机联系之后再回应主机。不然就会出现沟通混乱的问氏闷启题,在编写程序的时候一定要注意这一点。
⑵ 怎么设计一个多机通信系统(单片机)
简单说明用一个主机串口实现上述要求的思路:
从机地址分别为01和02
从机的串口相同引脚相互并联作为一个串口连接于主机串口,注意接线正确。
主机命令:地址号 + 命令字符串
从机命令:地址号 + 命令字符串
然后在各自收发代码中利用地址号来区别命令执行
其它请参阅如下网址本人的答复:
http://..com/question/12535506.html
http://..com/question/12522809.html
http://..com/question/11725744.html
http://..com/question/11040704.html
http://..com/question/10941227.html
补充:
串行通讯的基本知识
每台计算机都提供了一个或多个串行端口。它们被依次命名为:COM1、COM2 等等。在标准的 PC 中,鼠标通常被连接到 COM1 端口。调制解调器可能连接到 COM2,扫描仪被连接到 COM3,等等。串行端口提供了计算机与这些外部串行设备之间的数据传输通道。
串行端口的本质功能是作为 CPU 和串行设备间的编码转换器。当数据从 CPU 经过串行端口发送出去时,字节数据被转换为串行的位。在接收数据时,串行的位将被转换为字节数据。
我的理解:串行口数据通信的实质是ASCII(美国标准信息交换码)的传输。你可理解是传输ASCII码,而实际传输的是ASCII码(其二进制形式,8位组成一字节)。它又可看成是8位二进制数,例字符A 其二进制表示为 01000001,MSCOMM发送时完全按照此二进制信号发送,由低位至高位传输。又能理解为10进制的64。在计算机内通常以16进制表示为41。由2个8位二进制数据组成16位二进制数,通常用于数据的二进制通信。你的程序代码采用以文本方式取回数据,这是在MSCOMM控件内部进行解决,而无须VB编程员来处理。
见MSCOMM控件的:
InputMode 常数
常数 值 描述
comInputModeText 0 (缺省)通过 Input 属性以文本方式取回数据。
comInputModeBinary 1 通过 Input 属性以二进制方式检取回数据。
以下是由MICROSOFT提供的关于串行通讯和MSCOMM控件的一些说明,可能对你答辩有用,供参考。
串行通讯的基本知识
每台计算机都提供了一个或多个串行端口。它们被依次命名为:COM1、COM2 等等。在标准的 PC 中,鼠标通常被连接到 COM1 端口。调制解调器可能连接到 COM2,扫描仪被连接到 COM3,等等。串行端口提供了计算机与这些外部串行设备之间的数据传输通道。
串行端口的本质功能是作为 CPU 和串行设备间的编码转换器。当数据从 CPU 经过串行端口发送出去时,字节数据被转换为串行的位。在接收数据时,串行的位将被转换为字节数据。
要完成数据的传输,还需要进一步一个解释层。在操作系统一边,Windows 使用了通讯驱动程序 Comm.drv,以便使用标准的 Windows API 函数发送和接收数据。驱动程序通常由串行设备制造商提供,以便将其硬件与 Windows 连接。在使用 Communications 控件时,实际上使用了 API 函数,API 函数将被 Comm.drv 解释并传输给设备驱动程序。
作为程序员,只需关心如何与 Windows 打交道。作为 Visual Basic 程序员,只需要关心 Communications 控件提供的对 Windows 通讯驱动程序的 API 函数的接口。换句话说,只需要设置和监视 Communications 控件的属性和事件。
建立串行端口连接
使用 Communications 控件的第一步是建立与串行端口的连接。下表列出了用于建立串行端口连接的属性:
属性 描述
CommPort 设置或返回通讯端口号。
Settings 以字符串形式设置或返回波特率、奇偶校验、数据位和停止位。
PortOpen 设置或返回通讯端口的状态。以及打开和关闭端口。
打开串行端口
要打开串行端口,可以使用 CommPort、PortOpen 和 Settings 属性。例如:
'打开串行端口
MSComm1.CommPort = 2
MSComm1.Settings = "9600,N,8,1"
MSComm1.PortOpen = True
CommPort 属性确定打开哪个串行端口。假如 COM2 上连接有一个调制解调器,则在上面的例子中需要将值设置为 2 (COM2) 才能连接到该调制解调器。CommPort 属性值可以设置为 1 到 16 之间的任何值(缺省值为 1),然而,如果将该值设置为系统中并不存在的 COM 端口,将会产生错误。
Settings 属性可以用来指定波特率、奇偶校验、数据位数和停止位数。按照缺省规定,波特率被设置为 9600。奇偶校验设置为了进行数据校验。这通常是不用的,并设置为"N"。数据位数指定了代表一个数据块的比特数。停止位指出了何时接收到一个完整数据块。
在指定了要打开的端口,以及如何进行数据通讯之后,就可以使用 PortOpen 属性建立连接了。它是一个布尔值,即取值范围为 True 或 False。然而,如果端口无效,或者 CommPort 属性设置有误,或者该设备不支持指定的设置,就会产生错误;即使没有产生错误,外部设备也不能正常工作。将 PortOpen 属性设置为 False 即可关闭该端口。
缓冲区内存分配
InBufferSize 和 OutBufferSize 属性指定了为接收和发送缓冲区分配的内存数量。按照缺省规定,它们被分别设置为上图所示的值。这两个值设置得越大,应用程序中可用的内存就越少。然而,如果缓冲区太小,就要冒缓冲区溢出的风险,除非采用握手信号。
注意 鉴于现在大多数微机可用的内存量,由于有更多的可用资源,缓冲区内存分配已不那么至关紧要了。换言之,可以把缓冲区的值设得高一些而不影响应用程序的性能。
RThreshold 和 SThreshold 属性
RThreshold 和 SThreshold 属性,表示在 OnComm 事件发生之前,接收缓冲区或发送缓冲区中可以接收的字符数。OnComm 事件被用来监视和响应通讯状态的变化。如果将每个属性的值都设置为零 (0),就可以避免发生 OnComm 事件。如果将该值设置为非零的值(比如 1),那么每当缓冲区中接收到一个字符时,就会产生 OnComm 事件。
Output 属性被用来向发送缓冲区发出命令和数据。
与 Input 属性类似,数据可以以文本或二进制格式发送。Output 属性必须用字符串变体型发送文本,用 Byte 数组变体型发送二进制数据。
可用 Output 属性发送命令、文字字符串或 Byte 数组数据。
MSComm 控件
MSComm 控件通过串行端口传输和接收数据,为应用程序提供串行通讯功能。
语法
MSComm
说明
MSComm 控件提供下列两种处理通讯的方式:
事件驱动通讯是处理串行端口交互作用的一种非常有效的方法。在许多情况下,在事件发生时需要得到通知,例如,在 Carrier Detect (CD) 或 Request To Send (RTS) 线上一个字符到达或一个变化发生时。在这些情况下,可以利用 MSComm 控件的 OnComm 事件捕获并处理这些通讯事件。OnComm 事件还可以检查和处理通讯错误。所有通讯事件和通讯错误的列表,参阅 CommEvent 属性。
在程序的每个关键功能之后,可以通过检查 CommEvent 属性的值来查询事件和错误。如果应用程序较小,并且是自保持的,这种方法可能是更可取的。例如,如果写一个简单的电话拨号程序,则没有必要对每接收一个字符都产生事件,因为唯一等待接收的字符是调制解调器的"确定"响应。
每个使用的 MSComm 控件对应着一个串行端口。如果应用程序需要访问多个串行端口,必须使用多个 MSComm 控件。可以在 Windows"控制面板"中改变端口地址和中断地址。
尽管 MSComm 控件有很多重要的属性,但首先必须熟悉几个属性。
属性 描述
CommPort 设置并返回通讯端口号。
Settings 以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位。
PortOpen 设置并返回通讯端口的状态。也可以打开和关闭端口。
Input 从接收缓冲区返回和删除字符。
Output 向传输缓冲区写一个字符串。
OnComm 事件
无论何时当 CommEvent 属性的值变化时,就产生 OnComm 事件,标志发生了一个通讯事件或一个错误。
语法
Private Sub object_OnComm ()
OnComm 事件语法包括下列部分:
部分 描述
object 对象表达式,其值是"应用于"列表中的对象。
说明
CommEvent 属性包含实际错误或产生 OnComm 事件的数码。注意,设置 Rthreshold 或 Sthreshold 属性为 0,分别使捕获 comEvReceive 和 comEvSend 事件无效。
MSComm 控件常数
Handshake 常数
常数 值 描述
comNone 0 无握手。
comXonXoff 1 XOn/Xoff 握手。
comRTS 2 Request-to-send/clear-to-send 握手。
comRTSXOnXOff 3 Request-to-send 和 clear-to-send 握手皆可。
OnComm 常数
常数 值 描述
comEvSend 1 发送事件。
comEvReceive 2 接收事件。
comEvCTS 3 clear-to-send 线变化。
comEvDSR 4 data-set ready 线变化。
comEvCD 5 carrier detect 线变化。
comEvRing 6 振铃检测。
comEvEOF 7 文件结束。
Error 常数
常数 值 描述
comEventBreak 1001 接收到中断信号
comEventCTSTO 1002 Clear-to-send 超时
comEventDSRTO 1003 Data-set ready 超时
comEventFrame 1004 帧错误
comEventOverrun 1006 端口超速
comEventCDTO 1007 Carrier detect 超时
comEventRxOver 1008 接收缓冲区溢出
comEventRxParity 1009 Parity 错误
comEventTxFull 1010 传输缓冲区满
comEventDCB 1011 检索端口 设备控制块 (DCB) 时的意外错误
InputMode 常数
常数 值 描述
comInputModeText 0 (缺省)通过 Input 属性以文本方式取回数据。
comInputModeBinary 1 通过 Input 属性以二进制方式检取回数据。
Output 属性
往传输缓冲区写数据流。该属性在设计时无效,在运行时为只读。
语法
object.Output [ = value ]
Output 属性语法包括下列部分:
部分 描述
object 对象表达式,其值是"应用于"列表中的对象。
value 要写到传输缓冲区中的一个字符串。
说明
Output 属性可以传输文本数据或二进制数据。用 Output 属性传输文本数据,必须定义一个包含一个字符串的 Variant。发送二进制数据,必须传递一个包含字节数组的 Variant 到 Output 属性。
正常情况下,如果发送一个 ANSI 字符串到应用程序,可以以文本数据的形式发送。如果发送包含嵌入控制字符、Null 字符等等的数据,要以二进制形式发送。
数据类型
Variant
⑶ 单片机多机通信程序
单片机多机通信,一个主机多个从机+一个通信协议就可以了,正常的串口设置就可以,协议可以以数据包形式,如:引导符、从机号、数据长度、指令类型、数据1---数据n、校验码、结束符,以主机发送指令从机应答,从机间需由主机协助。
⑷ 单片机多机通讯的最佳连接方式
硬件连接。
1、首先单片机构成的多机系统,常采用总线型主从式结构启唯前,硬件连接。
2、其次所谓主从式,即在数个单片机中,有一个是山轿主机,其余的是从机;从机要服从主机的调动、支配。串行口方悄清式2、方式3适合于这种主从式通信结构。
3、最后采用不同的通信标准时,还需进行相应的电平转换,有时还要对信号进行光电隔离;在实际的多机应用系统中,常采用RS-485串行标准总线进行数据传输。
⑸ C51单片机多机通信C语言
单片机a,b,c.a为主机,bc为从机。a上有一个外部中断0输入,按第一次a的两个LED亮500ms,再按一下,b机的两个LED灯亮500ms,第三次按下c机的两个LED灯亮500ms,然后周而复始。两个数码管分别显示0/1/2,和abc(bc由从机反馈)
/*
主从通信基本步骤:
1.主机从机初始化为方式2或者3,从机都置SM2=1,允许中断
2.主机置TB8=1,发送从机地址
3.所有从机均接收主机发送要寻址的从机地址
4.被寻址的从机确认地址后,置本机SM2=0,向主机返回地址,供主机核对
5.核对无误后,主机向被寻址的从机发送命令,通知从机接受或者发送数据。
6.本次通信结束后,主从机重置SM2=1,主机可再对其他从机寻址
*/
******************************************************************
主机a:
******************************************************************
#include<reg51.h>
#defineucharunsignedchar
#defineuintunsignedint
ucharleddata[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x40,0x00};
ucharMode;
sbitP10=P1^0;
sbitP13=P1^3;
sbitP17=P1^7;
sbitP20=P2^0;
sbitP21=P2^1;
voidUART_init()
{
TMOD=0x20;
TH1=0xfd;
TL1=0xfd;
TR1=1;
SCON=0xd0;
ES=1;
EX0=1;
IT0=1;//INT0下跳触发
EA=1;
TI=0;
}
voidDelayMs(intms)
{
uchari;
while(ms--)
for(i=0;i<120;i++);
}
voidputc_to_SerialPort(ucharc)
{
SBUF=c;
while(TI==0);
TI=0;
}
voidMasterControl(unsignedcharAddr,unsignedcharComd)
{
TB8=1;
putc_to_SerialPort(Addr);
DelayMs(50);
TB8=0;
putc_to_SerialPort(Comd);
DelayMs(50);
}
Ex0_int(void)interrupt0
{
P0=leddata[Mode];
P20=0;
if(Mode==0)
{
P2=leddata[10];
P10=0;
P13=0;
DelayMs(500);
P10=1;
P13=1;
//MasterControl('b','C');
//MasterControl('c','C');
}
elseif(Mode==1)
{
P10=1;
P13=1;
MasterControl('b','O');
//MasterControl('c','C');
}
elseif(Mode==2)
{
P10=1;
P13=1;
//MasterControl('b','C');
MasterControl('c','O');
}
Mode=(Mode+1)%3;
}
com_int(void)interrupt4
{
if(RI)
{
RI=0;
if(SBUF=='b')
{
P2=leddata[11];
}
if(SBUF=='c')
{
P2=leddata[12];
}
}
}
voidmain(void)
{
P0=0x00;
P1=0xff;
P2=0x00;
UART_init();
Mode=0;
while(1);
}
******************************************************************
从机b:
******************************************************************
#include<reg51.h>
#defineucharunsignedchar
ucharRecData;
sbitP10=P1^0;
sbitP13=P1^3;
voidUART_init()
{
TMOD=0x21;
TH1=0xfd;
TL1=0xfd;
TR1=1;
SCON=0xf0;
ES=1;
PS=1;
EA=1;
}
voidDelayMs(intms)
{
uchari;
while(ms--)
for(i=0;i<120;i++);
}
voidputc_to_SerialPort(ucharc)
{
SBUF=c;
while(TI==0);
TI=0;
}
com_int(void)interrupt4
{
if(RI)
{
RecData=SBUF;
RI=0;
if(RB8==1)//地址
{
if(RecData=='b')//是自己的地址,置SM2=0,准备接受数据
{
SM2=0;
putc_to_SerialPort('b');
}
else//不是自己的地址
{
SM2=1;
}
}
if(RB8==0)//数据
{
if(RecData=='O')
{
P10=0;
P13=0;
DelayMs(500);
P10=1;
P13=1;
}
if(RecData=='C')
{
P10=1;
P13=1;
}
SM2=1;
}
}
}
voidmain(void)
{
P0=0xff;
P1=0xff;
UART_init();
while(1);
}
******************************************************************
从机c:
******************************************************************
#include<reg51.h>
#defineucharunsignedchar
ucharRecData;
sbitP10=P1^0;
sbitP13=P1^3;
voidUART_init()
{
TMOD=0x21;
TH1=0xfd;
TL1=0xfd;
TR1=1;
SCON=0xf0;
ES=1;
PS=1;
EA=1;
}
voidDelayMs(intms)
{
uchari;
while(ms--)
for(i=0;i<120;i++);
}
voidputc_to_SerialPort(ucharc)
{
SBUF=c;
while(TI==0);
TI=0;
}
com_int(void)interrupt4
{
if(RI)
{
RecData=SBUF;
RI=0;
if(RB8==1)//地址
{
if(RecData=='c')//是自己的地址,置SM2=0,准备接受数据
{
SM2=0;
putc_to_SerialPort('c');
}
else//不是自己的地址
{
SM2=1;
}
}
if(RB8==0)//数据
{
if(RecData=='O')
{
P10=0;
P13=0;
DelayMs(500);
P10=1;
P13=1;
SM2=1;
}
if(RecData=='C')
{
P10=1;
P13=1;
SM2=1;
}
}
}
}
voidmain(void)
{
P0=0xff;
P1=0xff;
UART_init();
while(1);
}