总线协议.docx
《总线协议.docx》由会员分享,可在线阅读,更多相关《总线协议.docx(25页珍藏版)》请在冰豆网上搜索。
![总线协议.docx](https://file1.bdocx.com/fileroot1/2022-11/21/5e32e212-46a0-42ef-be89-e22e0d8ff245/5e32e212-46a0-42ef-be89-e22e0d8ff2451.gif)
总线协议
Profile
总线一般是可以接2个以上用户相互通讯的硬件通讯系统。
协议一般是传输信号的事先约定的信号结构,比如速率、电平、数据字节、数据包结构。
当各种同类动物之间沟通的时候,空气组成了总线,动物间的声音(语言)就是协议。
只有同类才听得懂。
BACnet与Lonwork协议已经被大家所熟知,那么行业所涉及的其他协议又有哪些呢?
这里为大家编辑整理了一些协议,供大家学习与参考。
下面向大家介绍一下其他协议:
(1)OPC
OPC(用于过程控制的OLE)是一个工业标准。
它由一些世界上占领先地位的自动化系统和硬件、软件公司与微软(Microsoft)紧密合作而建立的。
这个标准定义了应用Microsoft操作系统在基于PC的客户机之间交换自动化实时数据的方法。
它是在MicrosoftCOM、DCOM和ActiveX技术的功能规程基础上开发一个开放的和互操作的接口标准,这个标准的目标是促使自动化/控制应用、现场系统/设备和商业/办公室应用之间具有更强大的互操作能力。
(2)ODBC
开放数据库互连(ODBC)是Microsoft引进的一种早期数据库接口技术。
它实际上是ADO的前身。
Microsoft引进这种技术的一个主要原因是,以非语言专用的方式,提供给程序员一种访问数据库内容的简单方法。
换句话说,访问DBF文件或AccessBasic以得到MDB文件中的数据时,无需懂得Xbase程序设计语言。
事实上,VisualC++就是这样一个程序设计平台,即Microsoft最初是以ODBC为目标的。
ODBC的确能履行承诺,提供对数据库内容的访问,并且没有太多的问题。
它没有提供数据库管理器和C之间尽可能最好的数据转换,这种情况是有的,但它多半能像广告所说的那样去工作。
唯一影响ODBC前程的是,它的速度极低,至少较早版本的产品是这样。
ODBC最初面世时,一些开发者曾说,因为速度问题,ODBC永远也不会在数据库领域产生太大的影响。
然而,以Microsoft的市场影响力,ODBC毫无疑问是成功了。
今天,只要有两种ODBC驱动程序的一种,那么几乎每一个数据库管理器的表现都会很卓越。
(3)Socket
一个完整的socket有一个本地唯一的socket号,由操作系统分配。
最重要的是,socket是面向客户/服务器模型而设计的,针对客户和服务器程序提供不同的socket系统调用。
客户随机申请一个socket(相当于一个想打电话的人可以在任何一台入网电话上拨号呼叫),系统为之分配一个socket号;服务器拥有全局公认的socket,任何客户都可以向它发出连接请求和信息请求(相当于一个被呼叫的电话拥有一个呼叫方知道的电话号码)。
Socket利用客户/服务器模式巧妙地解决了进程之间建立通信连接的问题。
服务器socket半相关为全局所公认非常重要。
读者不妨考虑一下,两个完全随机的用户进程之间如何建立通信?
假如通信双方没有任何一方的socket固定,就好比打电话的双方彼此不知道对方的电话号码,要通话是不可能的。
在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。
每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
Socket正如其英文原意那样,象一个多孔插座。
一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目。
客户软件将插头插到不同编号的插座,就可以得到不同的服务。
(4)RS232
计算机与计算机或计算机与终端之间的数据传送可以采用串行通讯和并行通讯二种方式。
由于串行通讯方式具有使用线路少、成本低,特别是在远程传输时,避免了多条线路特性的不一致而被广泛采用。
在串行通讯时,要求通讯双方都采用一个标准接口,使不同的设备可以方便地连接起来进行通讯。
RS-232-C接口(又称EIARS-232-C)是目前最常用的一种串行通讯接口。
它是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。
它的全名是“数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准”该标准规定采用一个25个脚的DB25连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。
(5)RS-485
RS-485是双向、半双工通信协议,允许多个驱动器和接收器挂接在总线上,其中每个驱动器都能够脱离总线。
该规范满足所有RS-422的要求,而且比RS-422稳定性更强。
具有更高的接收器输入阻抗和更宽的共模范围(-7V至+12V)。
接收器输入灵敏度为±200mV,这就意味着若要识别符号或间隔状态,接收端电压必须高于+200mV或低于-200mV。
最小接收器输入阻抗为12k,驱动器输出电压为±1.5V(最小值)、±5V(最大值)。
驱动器能够驱动32个单位负载,即允许总线上并联32个12k的接收器。
对于输入阻抗更高的接收器,一条总线上允许连接的单位负载数也较高。
RS-485接收器可随意组合,连接至同一总线,但要保证这些电路的实际并联阻抗不高于32个单位负载(375)。
(6)EtherNet/IP协议
EtherNet/IP是ODVA发起的基于以太网传输的协议标准,全称为“以太网工业协议”。
现在这个协议受到三大组织的支持:
ControlNetInternational(CI),theIndustrialEthernetAssociation(IEA),theOpenDeviceNetVenderAssociation(ODVA)。
这个协议旨在应用层建立一个开放的网络协议,以构建开放式的工业控制网络。
我个人理解,以太网也就是IEEE802.3只是定义了网络下两层的规范,对于网络层,是由IP协议规范的,运输层由TCP和UDP,会话层向上由包含TFTP、SMTP、FTP、DNS、NFS等协议的应用程序来构成。
这就象现场总线CAN协议规范底层传输,DeviceNet基于CAN定义应用层一样。
现在EtherNet/IP和DeviceNet一样,都是在传输层以上寻找结合二者特点的规范,也就是建立一种基于以太网上的,具有DeviceNet协议扩展特性的协议,那就是EtherNet/IP。
这个协议对于原有DeviceNet产品的供应商来说,具有以较少投资换来以太网接入方案的实惠,根据前面的分析,是混合型网络结构方案的一种。
(7)Modbus协议
Modbus协议最初由Modicon公司开发出来,在1979年末该公司成为施耐德自动化(SchneiderAutomation)部门的一部分,现在Modbus已经是工业领域全球最流行的协议。
此协议支持传统的RS-232、RS-422、RS-485和以太网设备。
许多工业设备,包括PLC,DCS,智能仪表等都在使用Modbus协议作为他们之间的通讯标准。
有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。
当在网络上通信时,Modbus协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。
如果需要回应,控制器将生成应答并使用Modbus协议发送给询问方。
Modbus协议包括ASCII、RTU、TCP等,并没有规定物理层。
此协议定义了控制器能够认识和使用的消息结构,而不管它们是经过何种网络进行通信的。
标准的Modicon控制器使用RS232C实现串行的Modbus。
Modbus的ASCII、RTU协议规定了消息、数据的结构、命令和就答的方式,数据通讯采用Maser/Slave方式,Master端发出数据请求消息,Slave端接收到正确消息后就可以发送数据到Master端以响应请求;Master端也可以直接发消息修改Slave端的数据,实现双向读写。
Modbus协议需要对数据进行校验,串行协议中除有奇偶校验外,ASCII模式采用LRC校验,RTU模式采用16位CRC校验,但TCP模式没有额外规定校验,因为TCP协议是一个面向连接的可靠协议。
另外,Modbus采用主从方式定时收发数据,在实际使用中如果某Slave站点断开后(如故障或关机),Master端可以诊断出来,而当故障修复后,网络又可自动接通。
因此,Modbus协议的可靠性较好。
I2C(Inter-IntegratedCircuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
I2C总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信。
例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。
可随时监控内存、硬盘、网络、系统温度等多个参数,增加了系统的安全性,方便了管理。
一、I2C总线特点
I2C总线最主要的优点是其简单性和有效性。
由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。
总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。
I2C总线的另一个优点是,它支持多主控(multimastering),其中任何能够进行发送和接收的设备都可以成为主总线。
一个主控能够控制信号的传输和时钟频率。
当然,在任何时间点上只能有一个主控。
二、I2C总线工作原理
2.1、总线的构成及信号类型
I2C总线是一种串行数据总线,只有二根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。
各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既是主控器(或被控器),又是发送器(或接收器),这取决于它所要完成的功能。
CPU发出的控制信号分为地址码和控制量两部分,地址码用来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对比度、亮度等)及需要调整的量。
这样,各控制电路虽然挂在同一条总线上,却彼此独立,互不相关。
2.2、位的传输
SDA线上的数据必须在时钟的高电平周期保持稳定数据线的高或低电平状态只有在SCL线的时钟信号是低电平时才能改变。
2.3、开始信号
SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
2.4、结束信号
SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
2.5、应答信号
接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。
CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。
若未收到应答信号,由判断为受控单元出现故障。
2.6、总线基本操作
I2C规程运用主/从双向通讯。
器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。
主器件和从器件(本文为AT24C01)都可以工作于接收和发送状态。
总线必须由主器件(通常为微控制器CPU)控制,主器件产生串行时钟(SCL)控制总线的传输方向,并产生起始和停止条件。
SDA线上的数据状态仅在SCL为低电平的期间才能改变,SCL为高电平的期间,SDA状态的改变被用来表示起始和停止条件。
三、单片机模拟I2C总线C语言代码
/*************************************
单片机模拟I2C总线C语言代码
*************************************/
#include
#include
#include
#defineDELAY_TIME60/*只有不小于50!
才不会造成时序混乱*/
#defineTRUE1
#defineFALSE0
sbitSCL=P1^7;/*串行时钟*/
sbitSDA=P1^6;/*串行数据*/
/**********FunctionDefinition函数定义************/
voidDELAY(unsignedintt)/*延时函数*/
{
while(t!
=0)
t--;
}
/*启动I2C总线的函数,当SCL为高电平时使SDA产生一个负跳变*/
voidI2C_Start(void)
{
SDA=1;
SCL=1;
DELAY(DELAY_TIME);
SDA=0;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
/*终止I2C总线,当SCL为高电平时使SDA产生一个正跳变*/
voidI2C_Stop(void)
{
SDA=0;
SCL=1;
DELAY(DELAY_TIME);
SDA=1;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
/*发送0,在SCL为高电平时使SDA信号为低*/
voidSEND_0(void)/*SENDACK*/
{
SDA=0;
SCL=1;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
/*发送1,在SCL为高电平时使SDA信号为高*/
voidSEND_1(void)
{
SDA=1;
SCL=1;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
/*发送完一个字节后检验设备的应答信号*/
bitCheck_Acknowledge(void)
{
SDA=1;
SCL=1;
DELAY(DELAY_TIME/2);
F0=SDA;
DELAY(DELAY_TIME/2);
SCL=0;
DELAY(DELAY_TIME);
if(F0==1)
returnFALSE;
returnTRUE;
}
/*向I2C总线写一个字节*/
voidWriteI2CByte(charb)reentrant
{
chari;
for(i=0;i<8;i++)
if((b<
SEND_1();
else
SEND_0();
}
/*从I2C总线读一个字节*/
charReadI2CByte(void)reentrant
{
charb=0,i;
for(i=0;i<8;i++)
{
SDA=1;/*释放总线*/
SCL=1;/*接受数据*/
DELAY(10);
F0=SDA;
DELAY(10);
SCL=0;
if(F0==1)
{
b=b<<1;
b=b|0x01;
}
else
b=b<<1;
}
returnb;
}
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitSO=P0^3;/*25045输出*/
sbitSI=P0^2;/*25045输入*/
sbitSCK=P0^1;/*25045时钟*/
sbitCS=P0^0;/*25045片选*/
ucharcodeWREN_INST=0X06;
/*Writeenablelatchinstruction(WREN)*/
ucharcodeWRDI_INST=0X04;
/*Writedisablelatchinstruction(WRDI)*/
ucharcodeWRSR_INST=0X01;
/*Writestatusregisterinstruction(WRSR)*/
ucharcodeRDSR_INST=0X05;
/*Readstatusregisterinstruction(RDSR)*/
ucharcodeWRITE_INST=0X02;
/*Writememoryinstruction(WRITE)*/
/*写入25045的先导字,应当为0000A010,其中的A为写入25045的高位地址
将此WRITE_INST和写入高位地址相或后即为正确的写先导字*/
ucharcodeREAD_INST=0X03;
/*Readmemoryinstruction(READ)*/
/*读出25045的先导字,应当为0000A011,其中的A为读出25045的高位地址
将此READ_INST和读出高位地址相或后即为正确的读先导字*/
uintcodeBYTE_ADDR=0X55;
/*Memoryaddressforbytemodeoperations*/
ucharcodeBYTE_DATA=0X11;
/*Databyteforbytewriteoperation*/
uintcodePAGE_ADDR=0X1F;
/*Memoryaddressforpagemodeoperations*/
/*页面写入的其始地址*/
ucharcodePAGE_DATA1=0X22;
/*1stdatabyteforpagewriteoperation*/
ucharcodePAGE_DATA2=0X33;
/*2nddatabyteforpagewriteoperation*/
ucharcodePAGE_DATA3=0X44;
/*3rddatabyteforpagewriteoperation*/
ucharcodeSTATUS_REG=0X20;
/*Statusregister,设置DOG时间设置为200毫秒,无写保护*/
/*这是状态寄存器的值,他的意义在于第5,第4位为WDI1,WDI0代表DOG的时间,00为1.4秒,01为600毫秒,10为200毫秒,00为disabled
第3位和第2位为BL1,BL0,是写保护设置位,00为无保护,01为保护180-1FF,10为保护100-1FF,11为保护000-1FF.第1位为WEL,
当他为1时代表已经"写使能"设置了,现在可以写了,只读位.第0位为WIP,当他为1时代表正在进行写操作,是只读*/
ucharcodeMAX_POLL=0x99;
/*Maximumnumberofpolls*/
/*最大写过程时间,确定25045的最大的写入过程的时间*/
ucharcodeINIT_STATE=0x09;
/*Initializationvalueforcontrolports*/
uintcodeSLIC=0x30;
/*AddresslocationofSLIC*/
voidwren_cmd(void);/*写使能子程序*/
voidwrdi_cmd(void);/*写使能复位*/
voidwrsr_cmd(void);/*复位时间位和数据保护位写入状态寄存器*/
ucharrdsr_cmd(void);/*读状态寄存器*/
voidbyte_write(ucharaa,uintdd);/*字节写入,aa为写入的数据,dd为写入的地址*/
ucharbyte_read(uintdd);/*字节读出,dd为读出的地址,返回读出的数据*/
voidpage_write(ucharaa1,ucharaa2,ucharaa3,ucharaa4,uintdd);/*页写入*/
voidsequ_read(void);/*连续读出*/
voidrst_wdog(void);/*DOG复位*/
voidoutbyt(ucharaa);/*输出一个字节到25045中,不包括先导字等*/
ucharinputbyt();/*由25045输入一个字节,不包括先导字等额外的东西*/
voidwip_poll(void);/*检查写入过程是否结束*/
/*25045操作子程序集*/
/*;*******************************************************************************************
*
;*Name:
WREN_CMD
;*Description:
Setwriteenablelatch
;*Function:
ThisroutinesendsthecommandtoenablewritestotheEEPROMmemoryarrayor
;*statusregister
;*Calls:
outbyt
;*Input:
None
;*Outputs:
None
;*RegisterUsage:
A
;*******************************************************************************************
*/
/*写使能子程序*/
voidwren_cmd(void)
{
ucharaa;
SCK=0;/*BringSCKlow*/
CS=0;/*Bring/CSlow*/
aa=WREN_INST;
outbyt(aa);/*SendWRENinstruction*/
SCK=0;/*BringSCKlow*/
CS=1;/*Bring/CShigh*/
}
/*;*******************************************************************************************
*
;*Name:
WRDI_CMD
;*Description:
Resetwriteenablelatch
;*Function:
ThisroutinesendsthecommandtodisablewritestotheEEPROMmemoryarrayor
;*statusregister
;*Calls:
outbyt
;*Input:
None
;*Outputs:
None
;*RegisterUsage:
A
;*******************************************************************************************
*/
/*写使能复位子程序*/
voidwrdi_cmd(void)
{
ucharaa;
SCK=0;/*BringSCKl