Modbus是一种单主站的主/从通信模式
Modbus网络上只能有一个主站存在,主站在 Modbus网络上没有地址,从站的地址范围为 0 - 247,其中 0 为广播地址,从站的实际地址范围为 1 - 247。 Modbus通信标准协议可以通过各种传输方式传播,如 RS232C、RS485、光纤、无线电等。 Modbus具有两种串行传输模式,ASCII 和 RTU以及以太网tcp变种。它们定义了数据如何打包、解码的不同方式。支持 Modbus 协议的设备一般都支持 RTU 格式。通信双方必须同时支持上述模式中的一种。Modbus rtu和Modbus tcp两个协议的本质都是MODBUS协议,都是靠MODBUS寄存器地址来交换数据;但所用的硬件接口不一样,Modbus RTU一般采用串口RS232C或RS485/422,而Modbus TCP一般采用以太网口。现在市场上有很多协议转换器,可以轻松的将这些不同的协议相互转换 如:Intesisbox可以把modbus rtu转换成Modbus tcp。
标准的Modicon控制器使用RS232C实现串行的Modbus。Modbus的ASCII、RTU协议规定了消息、数据的结构、命令和就答的方式,数据通讯采用Maser/Slave方式。
Modbus协议需要对数据进行校验,串行协议中除有奇偶校验外,ASCII模式采用LRC校验,RTU模式采用16位CRC校验。ModbusTCP模式没有额外规定校验,因为TCP协议是一个面向连接的可靠协议。TCP和RTU协议非常类似,只要把RTU协议的两个字节的校验码去掉,然后在RTU协议的开始加上几位数并通过TCP/IP网络协议发送出去即可。
使用tcp:
request:transactionid+protocolid +lengthcode+slaveid+functioncode+address+quantity+data
查询的response:
transactionid+protocolid +lengthcode+slaveid+functioncode+information
使用tcp的rtu:
Request:
slaveid+functioncode+address+quantity+data+crc
从机地址 功能号 数据地址 数据 CRC校验
查询的response:
slaveid+functioncode+address+quantity+length+crc
从机地址 功能号 数据地址 读取数据个数 CRC校验
modbus协议也只是通讯协议的一种,通讯协议包括两个方面: 一、通讯格式,即: 波特率,检验方式,数据位,停止位 波特率:一秒钟传送的位数,也就是通讯速率;比如波特率为9600,即,一秒种可以传送9600个位数,位的概念看下面的数据位介绍 校验方式:奇校验或偶校验或无校验,目的是判断传输过程中是否有错误!它只是用于判断一个字符(比如八个位或是七个位组成一个字符)传输是否有错误。但是它并不能完全能够判断传输是否有错。比如偶校验,在检验送八个“11111111”时,如果到达接收方,由于干扰而变成了“10111101”,“1”的个数仍然是偶数,接收方就判断不出来传送的字符已经错误! 数据位:传输一个字符由几个位组成,计算机的基本单位就是“位”,其值非“0”即“1”,又如传送A,定义通讯格式时,是定义的八位,其传送的数据可能就是:00001010; 停止位:传输一个字符有几个停止位,用天判断某个字符是否传输结束,以便开始接收下一个字符。 通讯格式的作用是规范发送方与接收方的传输格式,如果双方通讯格式不一样,接收方就不可能正确判断发送方发来的东西是什么。 比如,接收方设置的波特率是10(一秒只接收十个位)位,而发送方的波特率是20(一秒发送二十个位),那么发送方一秒种发送的20个字符,接收方就不可能都收到,只能接收到10个,造成通讯出错。 校验方式:双方校验方式不一样,就没有一个统一的标准认定传输是否有错误。 数据位,接收方设定的七位,即它接收到七个位就认为是一个字符,而实际发送方设定的是八位,那么接收方认定的字符与发送方发送的字符就不一样了。 参预通讯的双方设定的通讯格式必须一样的! 通讯格式只是保证接收方正确地接收到发送方传输过来的每一个字符(实际如上所述,检验方式并不能保证完全正确,还要靠通讯规范中的校验和计算来验证整体正确性,下面会继续说明),那么接收到的整串字符做什么用呢,就要靠通讯规范了 MODBUS的通讯规范很简单!
ModBus协议是应用层报文传输协议(OSI模型第7层),它定义了一个与通信层无关的协议数据单元(PDU),即PDU=功能码+数据域。
ModBus协议能够应用在不同类型的总线或网络。对应不同的总线或网络,Modbus协议引入一些附加域映射成应用数据单元(ADU),即ADU=附加域+PDU。目前,Modbus有下列三种通信方式:
- 以太网,对应的通信模式是MODBUS TCP。
- 异步串行传输(各种介质如有线RS-232-/422/485/;光纤、无线等),对应的通信模式是MODBUS RTU或MODBUS ASCII。
- 高速令牌传递网络,对应的通信模式是Modbus PLUS。
RTU方式: RTU方式发送时的规范定义如下:
至少3.5个字符传输时间的停顿间隔时间标定消息的开始 设备地址 + 功能代码+ 数据 + 校验 + 至少3.5个字符传输时间的停顿间隔时间标定了消息的结束 其他见下方与ASCII方式一样的作用,至少3.5个字符传输时间的停顿保证发送字符串的连续性,中间停顿时间超过4毫秒,接收方就认为您已经发送完了这组消息,开始处理了。这就是至少3.5个字符传输时间的停顿间隔时间标定了消息的结束的含义
如果您发送的太连续,下一组消息与上一组消息之间的间隔时间没超过4毫秒,接收方就认为这些字符是一组消息,按一组消息去处理。所以,您发送结束一组命令后,必须间隔4毫秒才能发送下一组命令. 这就是至少3.5个字符传输时间的停顿间隔时间标定消息的开始的含义。
Modbus通信标准协议可以通过各种传输方式传播,如 RS232C、RS485、光纤、无线电等。
“232”或是“485”只是一种线路传输方式,与协议是无关的。232传输抗干扰性差,485传输抗干扰相对强。
MODBUS做为一种标准的协议,应用于各种PLC,控制器,仪表。这些仪表或是控制器应用中,元件的通讯地址肯定是不一样了;各个命令码的各部分组成的意义也许也会不同;
但是,它一定会遵守MODBUS的协议规范。即,每个命令码的组成一定符合MODBUS的规范。
ASCII方式: ASCII方式发送时的规范定义如下: 起始符 + 设备地址 + 功能代码 + 数据 + 校验 + 结束符 起始符: 接收到一串字符,总要知道这串字符从哪个地方开始吧,这就是起始符的作用,接收方不管以前收到多少个字符。当接收到起始符时,以前的字符就不再理它了,从起始符开始分析以后的字符。 MODBUS的ASCII方式起始符是一个冒号 “:”
设备地址: 前面说过,MODBUS是单主站的主/从通信模式,一个主站下面可以接十多个从站。大家都挂在一条线,如果没有一个设备地址,就不知道是发给哪个从站的,大家都回应的话,这条线上的信号就乱七八糟了,主站也不知道接收到的是什么了。所以,设这么一个设备地址,告诉是给那个从站的。只要这个从站回答,其他不应答。
广播地址(0)是命令式的,不要求从站回答的。
设备地址是要求两个字符,比如发给2号站,则是“02”
现在的组合是“:02”
功能代码:
告诉从站应该做什么,比如读数据的命令是“3”,从站接收到这个命令,再根据下面数据要求的具体地址,把具体地址的数据返回给主站。
功能代码也是要求两个字符,比如读命令3,则是“03”
现在的组合是“:0203“
”
数据:
1、告诉从站具体的元件通讯地址,写入到哪里,从哪里读。如读变频器的设定频率的通讯地址是00A0
元件的通讯地址要求是四个字符,如果控制器的元件地址不足四个字符,则在前面补0,比如元件通讯地址是A0,则在前面补足两个0:“00A0”
2、数据又有可能包括您要读取的字节数( 有的控制器是字数),比如连续读取PLC的两个十六位寄存器,其字节数为四个,则是“0004”。您看出来了吧,读取个数也是要求四个字符,不足四个,前面补零
现在的组合是“:020300A00004“
3、而当您要实现写入功能时,数据又可能包括写入的数据,比如写入一个十六位寄存器的值,则要包括是写入的数值,如“0D98”
现在的组合是“:020600A00D98“ 06是单个寄存器的写入命令
4、当连续写入多个寄存器时,这个数据包括的内容又不一样,它可能是:
寄存器通讯地址(四个字符) +字数(四个字符)+字节数(两个字符)+ 要写入的数值
您看乱了吗?没关系的,等您拿到具体控制器时,此控制器的通讯说明上会告诉您此数据都包括什么内容,以什么样的格式排列!您一定为我上面四点中的可能字样而生气,您认为讲解就应该讲解的具体,而不是可能什么又可能什么!
这又要重复说明一下MODBUS的通讯规范,
起始符 + 设备地址 + 功能代码 + 数据 + 校验 + 结束符
MODBUS是一种标准通讯协议,这种标准定义了上面红色字符的通讯规范,除了数据项,其他的都是固定字符个数。
数据呢,因为功能代码的不同,其包含的内容也不同!所以我只好说可能包含这个,可能包含那个。您无须担心此数据变来变去,造成接收方不知道如何分析。接收方在接收到功能代码时,就已经知道此数据包含多少个字符了!
检验和:
前面说过,通讯格式里的校验方式并不能保证每个字符都正确,所以这里就把所有字符的值加在一起,其和(检验值)传给接收方,接收再把接收到的字符的值加在一起,与发送方传送过来的检验值比较,如果相等,就算接收正确了。
“这种方式极大地提高了传输的可靠性,保证了传输的顺利进行,为传输事业做出了巨大贡献”
检验只是提高了校验的可靠性。并不能完全判断传输是否正确。想要最大限度的提高传输的可靠性,唯有最大限度地降低干扰!于是产生了232,485,422传输方式,他们的区别就在于传输的可靠性!
1+2+3=6 3+2+1=6 这两个字符串的作用肯定是不一样的!但是其校验和是一样的,如果在传输过程中,由于干扰,1变3,3变1,根据校验和的计算,接收方并不知道由于干扰而造成传输错误,此时,或是出现通讯错误,或是出现通讯混乱。
如,命令码03,由于干扰而变成了30,此时校验和是一样的,而MODBUS并没有30这个命令码,接收不认识,于是出现通讯错误。
再如,读变频器的设定频率通讯地址是0001,由于干扰而变成了0010,此时校验和是一样的,但是通讯地址却变了,变频器就可能返回的是其他数据,造成通讯混乱!
校验字符是要求两个字符,如果计算结果超过两个字符,则取后两位!
参加校验计算的字符是起始符与校验符之间的字符串(不含起始符与校验符)
现在的组合是“:02030A000004FB“ (假设校验和为FB)
02030A000004参加校验和计算
结束符:
接收到一串字符,总要知道在那个地方结束吧,这就是结束符的作用,接收方不管以后还会收到多少个字符。当接收到结束符时,以后再接收的字符就算是下一轮的东西了,从起始符到结束符之间的字符就是它要分析的字符! MODBUS的ASCII方式结束符是— Chr(13)+Chr(13)+Chr(10)
现在的组合是“:02030A000004FB“+ Chr(13)+Chr(13)+Chr(10)
至此,ASCII方式的发送就完成了,控制器接收到此串字符后,根据MODBUS协议定义的通讯规范分析此串字符的作用,然后返回相应的字符!
注意:发送的字符都是以十六进制数表示!
下面针对某种支持MODBUS协议的控制器,说一下具体的读/写例子
1读某控制器的十五个寄存器值,发送的字符串是:(ASCII方式)
“: 01031000000FDD”+ Chr(13)+Chr(13)+Chr(10)
起始符“:” + 站号(01) + 读命令(03)+ 起始寄存器通讯地址(1000)+ 字数(15;转换成十六进制000F)+ 校验和(DD)+ 结束符
控制器返回的字符数是71个
起始符“:” + 站号(01) + 读命令(03)+ 字数(0F)+ 60个数据字符(一个寄存器是4个,一共十五个) + 校验和(DD)+ 结束符(两个)
2 分别向某控制器两个寄存器写入数值,发送的字符串是:(ASCII方式)
“: 01101000000204”+ 写入的数值(8个字符)+ 校验和 + Chr(13)+Chr(13)+Chr(10)
起始符“:” + 站号(01) + 写命令(10)+ 起始寄存器通讯地址(1000)+ 字数(2;转换成十六进制0002)+ 字节数(04) + 校验和(因为写入数值是变化的,需要得经过计算得出校验和)+ 结束符
控制器返回的字符数是17个
起始符“:” + 站号(01) + 写命令(10)+ 起始寄存器通讯地址(1000)+ 字数(02)+ 错误码(2个) + 校验和(DD)+ 结束符(两个)
错误码,当通讯正确时是什么,通讯错误时是什么,具体控制器会有说明
读其他仪表的某值时,参照上述读的规范,也就是更改一下起始寄存器通讯地址、字数、校验和(校验和是编制程序块自动计算的。)
要读多个仪表的同一个检测值更简单,更改站号就可以了。
Golang Modbus包:https://github.com/leaniot/modbus
对接场地电梯、卷帘门等设备,需重写tcp接口 Encode、Decode、Verify、Send
WriteSingleCoil(address, value uint16):value 只有ON/OFF状态,输入值为 0xFF00 或 0x0000
WriteMultipleCoils()/WriteSingleRegister()/WriteMultipleRegisters()
参数:address 寄存器起始位置,quantity 寄存器数量,value 数据