MODBUS是一个工业上通信常用的通讯协议,一般在PLC上面用的比较多,主要是定义了一种数据传输的规范,比如数据发给谁,数据是干嘛的,数据错没错,接收到数据的从机告诉我数据有没有接受到等.
传输的方式的话比较多的是使用RS232c形式的串口传输,当然485传输也可以,比较高端的可以使用网络的tcp传输,但是是和之前的串口传输有区别的.
在使用232传输的时候,整个系统中只有一个主机,剩下的全部是设备,也就是说,只有作为主机的那个角色才能初始化网络,并且对整个网络上的所有从机进行控制,从机和从机之间不允许直接通讯,这就相当于一台PLC对它外接的设备进行控制了.
在使用TCP传输的时候就没有主机从机的概念了,对等技术通讯,也就是说,所有的节点的地位是对等的,控制器即可以接受数据并作出响应,也可以主动查询网络上另一个控制器的状态,当然,但是协议上,依然会有主机从机的数据定义
之所以这样是因为在232的网络上没有冲突检测,要是两个主机,那数据很容易就混乱了,但是到了tcp时代,底层的数据链路层已经做了冲突检测的工作,自然就可以同时传输不担心数据撞车了.
到这里我们看看modbus数据传输的协议模型
开头是地址帧,在modbus网络中,每一个从机都有一个地址,主机在访问从机的时候依靠这个唯一的地址识别,多个从机接收到主机的数据的时候,匹配接收到的数据和自身的地址,匹配上的那个从机作出响应,其他的都忽略.
第二个是功能码,决定这一帧数据主要是干嘛的,输入数据,输出数据,读取控制量等
第三是数据,可以有也可以没有
第四是差错校验,用来对之前发送的数据校验,防止发送过程中因为电磁干扰,数据出错.
上面只是简单地协议原型,接下来这个协议原型有两种实现,分别叫做ascii实现和RTU实现,我个人比较喜欢称之为命令行实现和代码实现,为什么这么叫后面你就会知道了.首先我们要知道,modbus是按byte传输的,也就是一次传输一个字节
RTU模式
在该模式下,传输是这样的
首先,数据已帧为单位传输,如果一byte数据的传输时间为T,那么没两帧之间的间隔最小应该要大于3.5T,否则从机不能分辨这是两帧,第二,同一帧连续的两个数据之间的间隔时间不能超过1.5T,否则节点会认为这一帧数据不完整,这说明我们在modbus传输的时候要使能一个定时器的工作.
其次,地址位一个字节 功能代码一个字节,数据n字节,crc校验2字节,那么这个n的限制是多少?协议规定一帧中数据最多是252字节,最少可以是0字节
Ascii模式
在该模式下,传输的帧中的数据的每一位只能是ascii码的0-9 a-f,因为rtu模式下一字节一个数据,也就是1字节0x00-0xff,所以在ascii模式下为了传送相同的数据,必须两个字节标识一个有效数据,也就是如下
可以看到,找ascii模式下,不是依靠时间间隔判定帧起始了,而是依靠特定字符判断,结束也是按照特定字符判断,起始的判断是’:’字符,结束的判断是windows下的回车换行,数据的最大长度被扩容到了2*252,这样,两种传输模式能传输相同的数据量,但是ascii传输的更慢了,
但是并不是说时间判据在ascii模式中就没有用了,还是有用的,字符间的间隔不能大于1s,大于1s认为这一帧数据丢失.同样我们可以计算出来ascii帧的最大长度是513字节
这个时候你能理解为什么这个叫命令行模式了,因为这种模式下发送的是可视化的字符串,可以人工的输入,而之前的rtu模式,手工输入多麻烦啊,一般程序输入,而且我们可以判定,他以回车换行作为结尾,应该早期主要是在windows上调试的,因为linux只需要回车就能实现windows的回车换行,在这种模式下可以把指令写在文本中直接输入.不过这两年acsii模式用的少了,因为调试软件的出现简化了手工输入的步骤.
说到这里,两种模式之间的不同还有一个校验方式的不同,RTU使用crc校验,ASCII使用LRC校验,首先看看crc
然后是LRC
前面说了,不符合时间规则的数据将会被丢掉,那主机怎么知道被丢掉了呢?而且假如主机向100设备发数据,网络里面没有100怎么办?
是这样的,modbus最多能支持255个子设备的接入,地址从0x01-0xff,而0x00是广播地址,也就是说,0x00发送的数据所有的设备都要接收,但是不能响应,而其他的节点的设备在收到数据之后,必须在有限的时间里面进行响应,或者说是应答,主机端会有一个超时管理,超过一定时间没有反应就会认为数据丢失,该时间可以*设置,设计者在设计的时候应当保证尽量使得超时时间大于任何一个外设的响应时间.
其实,当设备接收到了数据应该怎么应答,这个时候又分为正确应答和错误应答,正确应答很好说,还是这个格式的数据帧
地址是从机自己的地址,功能码和主机发送来的功能码保持一致,数据看需求(功能码的需求)
错误的请求的回应,还是在功能码上下功夫,之前忘了说,功能码是从0x00-0x7f,也就是最高位都是0,当请求出错的时候,将主机发送过来的功能码加上一个0x80,让最高位为1就OK了,数据部分可以定义一个异常码,比如请求获取温度,发现温度传感器离线了,定义一个异常码0x01,数据域放0x01,主机就知道出错的具体原因是什么了.
到这里基本上写一部分就说完了,最后附录上modbus预定义的功能码和异常码,具体可以参考modbus协议文档.
功能码有:
异常码为
分类: 设备驱动