Modbus是一种串行通讯协议,诞生于1979年,最初是为了解决PLC之间的通讯问题而发表的。目前Modbus是工业通讯领域的业界标准,是工控领域最常用的通讯协议之一。
2016年3月16日 - 初稿(未发布)
2020年4月24日 - 添加功能码对应寄存器等
作者:海伏科技——小涛(转载注明出处)
阅读原文 - https://www.hvtop.com/class/63
扩展阅读
Modbus是一种串行通讯协议,诞生于1979年,最初是为了解决PLC之间的通讯问题而发表的。目前Modbus是工业通讯领域的业界标准,是工控领域最常用的通讯协议之一。相信正在看这篇文章的您已经对Modbus协议有一定的了解,下面就让我们开始主题,聊一聊Modbus通讯协议的工作原理。
通讯即数据的交互,通讯协议规定了一种通讯的规则,类似于人类交流使用的语言。这样的解释可能过于抽象,让我们举一个具体的案例,来设计一款我们自己的通讯协议。
假设现在要设计一款智能的电灯,分析一下它的功能,最基础的功能就是开关了,规定当我发送指令1的时候就打开、发送指令0的时候关闭。最简单的协议就是这个样子:
- 指令功能:开灯
发送数据帧 | 01 |
---|---|
功能含义 | 灯的开关 |
这款电灯是集中控制的,也就是说一个控制器要同时控制很多盏灯,那么我们就要为灯编码了。0代表所有的灯;1代表第一盏;2代表第二盏等等…… 以此类推,现在协议就变成了这样:
- 指令功能:打开第三盏灯
发送数据帧 | 03 | 01 |
---|---|---|
功能含义 | 灯的序号 | 灯的开关 |
这款电灯不仅仅有开关,还能连续的调节亮度。那么我们规定0至100分别对应0%到100%亮度,这里又遇到一个问题:如何区分一条指令是调节亮度还是调节开关呢?
为了区分还要定义这条指令的功能码:01代表调节开关、02代表调节亮度,现在协议就变成了这样:
- 指令功能:打开第三盏灯
发送数据帧 | 03 | 01 | 01 |
---|---|---|---|
功能含义 | 灯的序号 | 调节的功能 | 灯的开关 |
- 指令功能:将第三盏灯的亮度调节至50%
发送数据帧 | 03 | 02 | 50 |
---|---|---|---|
功能含义 | 灯的序号 | 调节的功能 | 亮度调节 |
继续增加功能,如果这套控制系统中还有一个光照传感器,控制器需要从中读出现在的环境亮度,从而实现对所有灯的自动控制。这里就是一个读的指令,区别于上面的指令新定义个功能码:03代表读取光照传感器的亮度,同样用0-100表示最小-最大量程:
- 指令功能:读环境亮度
发送数据帧 | 05 | 03 | 00 |
---|---|---|---|
功能含义 | 照度传感器的序号 | 读取功能 | 要读取值的地址 |
传感器收到数据后将结果返回:
- 指令功能:传感器返回
发送数据帧 | 05 | 03 | 80 |
---|---|---|---|
功能含义 | 照度传感器的序号 | 读取功能 | 要读取值的亮度值 |
以上就是通讯协议的基本思路,像这样我们自己设计的协议由于不是通用的,我们称之为私有协议。私有协议能实现我们系统里想要的功能,只要在主站(Master)和从站(Slave)之间预先规定好通讯的规则即可进行通讯。
但是从上面可以看出,经常为了增加一个设计之初没有想到的功能就导致整个协议发生巨大的变化,非常不利于后续升级,而且私有协议的标准不统一,导致不同厂家的产品无法进行通讯,此时我们就需要一个通用的,能实现大部分场合的通讯协议。
Modbus协议是一主多从设计,也就是说一个标准的Modbus通信网络中只能有一个主站,采取一问一答的方式进行通信,从站不能与从站直接通信。实现更复杂的通信情况例如多主站等需要使用Modbus网关设备,其中可能运行不止一套Modbus协议,这种情况我们以后再详细讲解。
Modbus有两种串行通讯模式,ASCII Mode 和RTU Mode,这里重点介绍最常用的RTU模式。RTU模式是将数据直接以16进制的方式以串口传输,一个完整的RTU数据帧包含以下内容:
数据帧格式:
开始 | 从站地址 | 功能码 | 数据位 | CRC校验码 | 结束 |
---|---|---|---|---|---|
4个字符空闲 | 8bits | 8bits | n x 8bits | 16bits | 4个字符空闲 |
既然是一问一答那么就有发送帧和返回帧,返回帧和发送帧的格式是一样的,返回帧需要重复从站地址、功能码等信息。对于写入类指令数据位返回操作成功、失败的状态,对于读取类指令数据位返回需要读取的数据。
既然要实现所有设备通用,就不能按功能来区分。Modbus将设备要通讯的功能抽象成了寄存器。寄存器分为四类:
控制电灯明暗程度的,由主站下发模拟量指令,叫做 保持寄存器(Holding Registers),我们称之为 模拟量输出寄存器简称AO(Analog Output)。
读取环境光照程度的,由主站读取模拟量指令,叫做 输入寄存器(Input Registers),我们称之为 模拟量输入寄存器简称AI(Analog Input)。
每一类寄存器用两个字节代表寄存器编号,0x0000-0xFFFF(十六进制表示)或0-65535(十进制表示)。
Modbus协议最主要的任务就是保证主站与从站各个寄存器的数据同步
寄存器 | 功能码(十六进制表示) | 描述 |
---|---|---|
开关量输出寄存器(DO) | 01 | 读开关量输出寄存器(单个/多个) |
开关量输出寄存器(DO) | 05 | 写开关量输出寄存器(单个) |
开关量输出寄存器(DO) | 0F | 写开关量输出寄存器(多个) |
开关量输入寄存器(DI) | 02 | 读开关量输入寄存器(单个/多个) |
模拟量输入寄存器(AO) | 03 | 读模拟量输出寄存器(单个/多个) |
模拟量输入寄存器(AO) | 06 | 写模拟量输出寄存器(单个) |
模拟量输入寄存器(AO) | 10 | 写模拟量输出寄存器(多个) |
模拟量输入寄存器(AI) | 03 | 读模拟量输入寄存器(单个/多个) |
如何分析一帧数据的含义:
数据帧有以下几部分组成:从站地址 、功能码、数据位、CRC校验码。根据从站地址判断是广播帧(00)还是跟某一个从站通信的帧(01-EF)。再根据功能码判断是操作哪一类寄存器及执行什么动作。后面紧跟的一般是操作长度、起始地址等信息;最后两个字节(一个字节是8bit)是校验位。这样就可以分析每一帧数据都在执行什么动作。
了解到这些我们结合海伏科技的高压电源来介绍各类寄存器的用法:
海伏科技的每款支持通信的电源产品都会配备Modbus协议说明,指明了上述每一个寄存器对应的功能,操作时只需要向相应的寄存器中写入值就可以实现对高压电源的控制。
本文只是简单介绍Modbus协议及学习方法,让初学者对Modbus协议有一个框架性的认识。具体每一种功能码对应的帧格式由于篇幅关系这里就不一一介绍了,可以查看扩展阅读中的原版协议详细了解。