RS-485软件层协议之Modbus-RTU

RS-485软件层协议之Modbus-RTU

RS-485概述

RS-485 采用差分信号传输方式。发送端将原始信号分成两个相位相反的信号,在两条传输线上同时发送;接收端通过比较这两条线上的信号差值来确定传输的逻辑状态。例如,当两线间的电压差为+(2 ~ 6)V时表示逻辑“1”,电压差为-(2 ~ 6)V时表示逻辑“0”。

特点:

· RS-485接口信号电平相比 RS-232 降低了,不易损坏接口电路的芯片。

· 在短距离(10米)时,数据最高传输速率可达35Mbps;在较远传输距离(1200 米)时,传输速度可达100Kbps。

· 由于采用平衡驱动器和差分接收器的组合,抗共模干扰能力强,适合在电磁环境复杂的工业场景中使用。

· RS-485总线最长可以传输1200米以上(速率≤100Kbps)。一般最大支持32个节点,如果使用特制的485芯片,可以达到128个或者256个节点,甚至最大可支持到400个节点。

· RS-485通讯使用双绞线或四线电缆进行连接,接线相对简单,安装方便。并且其通信协议相对简单,系统的稳定性较高,维护成本也相对较低。在一些对通信系统的安装和维护要求不高的场景中,RS485 能够快速搭建起可靠的通信网络。

· RS-485通讯遵循一定的标准和规范,具有较好的兼容性和互操作性,能够与多种设备和系统进行无缝连接和通信。这使得不同厂家生产的设备可以通过RS-485进行通信,方便了系统的集成和扩展。

接线方式与拓扑结构:

RS-485有两线制和四线制两种接线方式,但四线制只能实现点对点的通信方式,现很少采用,目前多采用两线制接线方式,这种接线方式为总线式拓扑结构。在构建网络时,应采用一条双绞线电缆作总线,将各个节点串接起来,并且注意总线特性阻抗的连续性和终端负载电阻的问题。

注意:在连接RS-485通信链路时,需要注意信号地的连接以及终端匹配电阻的设置。终端匹配电阻一般为120Ω,相当于电缆特性阻抗的电阻。如果没有正确连接信号地或设置终端匹配电阻,可能会影响通信的稳定性和可靠性 。

常见的 RS-485 软件层协议

· Modbus-RTU:远程终端单元模式。采用二进制数据表示,消息中的每个8位字节含有两个4位十六进制字符。通常用于串口通信,在RS-485上应用广泛。它具有较高的通信效率和可靠性,适用于对数据传输实时性要求较高的工业自动化场景。

· Modbus-ASCII:报文使用ASCII字符。每个8位字节作为两个ASCII字符发送。其数据传输效率较低,但可读性较强,适用于对通信速率要求不高,但需要方便调试和查看数据的场合。

· Modbus-TCP/IP:这是一种基于TCP/IP网络协议的Modbus变体。虽然RS-485是串口通信,但Modbus-TCP/IP可以将RS-485设备通过以太网进行通信,实现了跨网络的远程通信,支持大规模的分布式系统。

其中Modbus-RTU是使用最广泛的一种Modbus协议,采用CRC-16_Modbus校验算法。

小结

Modbus如上所说,是一种串行协议,起始是Modicon在1979年为了使用PLC所发表,但现在已成为一种工业标准的协议。而Modbus-RTU因其简单易用,更是在物联网、工业控制领域被广泛使用。

Modbus-RTU详述

· Modbus-RTU总线上的设备分为主设备和从设备,采用并联的方式接入总线;

· 每个设备都有自己的地址;

· Modbus RTU收发主要流程很简单,即主设备针对不同从设备地址发送读取或者写入(控制)命令及要操作的数据,从设备判断地址是否是自己地址,若是则根据具体命令做出不同响应,不是的话则一般情况下会忽略此数据。

举个不太恰当例子帮助大家理解:你和B、C在同一个关了灯的房间里,你在房间里喊:C,借给我一样东西,橡皮。B:这是和C说的,不是和我说的,我什么都没听见。而C一听是在和自己对话,于是就回复:我是C,借给你一样东西,给你橡皮;
对你你说的话:其中C相当于从设备的地址,这里“借给我一样东西”相当于功能码,起到命令、控制的作用,“橡皮”相当于主机对于从机发出的具体控制内容,告诉C你借的是橡皮;
对于C的回复:“我是C“也是地址码,在Modbus RTU中与你说的“C”是一样的数据,是告诉你现在是C在和你说话,“借给你一样东西”在Modbus RTU与“借给我一样东西”是同样的数据,可以理解成与你所说的话做个确认、对应,“给你橡皮”是从机针对主机发出功能码+有效数据(借给我一块橡皮)做出的具体响应。

当主机发送广播地址数据时,所有设备应当都有所响应。

下面将对Modbus-RTU的具体使用做出介绍。

帧格式

Modbus RTU的帧格式也是简单易懂的,具体组成如下:

地址功能码数据CRC校验
1 Byte1 ByteN Byte2 Byte

地址:占用一个字节,范围0-255,但有效地址范围是1-247,其他地址有特殊用途,例如广播地址;

功能码:占用一个字节,功能码的意义就是,告诉目标地址我要做什么操作,比如你可以查询从机的数据,也可以修改数据,所以不同功能码对应不同功能;

数据:根据功能码不同,有不同的数据结构,在下面的实例中将有说明;

CRC校验:验证数据用,把前面的数据进行CRC-16_Modbus计算,将结果填入此位置,接收方可通过此校验验证数据正确性。

功能码

Modbus RTU常用功能码如下:

0x010x020x030x040x050x060x0F0x10
读从机线圈寄存器,位操作,可读单个或者多个读离散输入寄存器,位操作,可读单个或多个,协议类似功能码0X01协议读保持寄存器,字节操作,可读单个或者多个读输入寄存器,字节操作,可读单个或者多个写单个线圈,位操作,只能写一个,写0xff00表示设置线圈状态为ON,写0x0000表示设置线圈状态为OFF写单个保持寄存器,字节操作,只能写一个写多个线圈寄存器,位操作,若数据区的某位值为“1”表示被请求的相应线圈状态为ON,若某位值为“0”,则为状态为OFF写多个保持寄存器,字节操作,可写多个

位操作:最小单位为一位,包括读线圈状态、读离散输入状态、写单个线圈、写多个线圈。

字操作:最小单位为一个字节,包括读保持寄存器、读输入寄存器、写单个保持寄存器、写多个保持寄存器。

寄存器

因为起初Modbus-RTU是应用在PLC中,数据存储在不同类型的寄存器里。每种类型的寄存器都有其特定的用途。就像上面提到的一些线圈、寄存器,下面对这些名词做下介绍,方便理解:

线圈寄存器(输出线圈)离散输入寄存器(输入线圈)输入寄存器保持寄存器(输出寄存器)
可读可写;用于读取和写入某位的值,通常代表开/关状态。线圈寄存器通常用于控制一个设备的继电器、开关等二进制设备。输出端口,可设定端口的输出状态,也可以读取该位的输出状态只读;用于只读单个位的值,通常代表外部设备的状态。离散输入寄存器常用来读取传感器或其他输入设备的二进制状态,例如门是否关闭、按钮是否被按下。输入端口,通过外部设定改变输入状态只读;用于只读存储模拟输入如温度、压力等的16位值。输入寄存器常用于保存模拟信号转换后的数字值,输入参数。控制器运行时从外部设备获得的参数可读可写;用于读写存储模拟输出或可变参数的16位值。输出参数或保持参数,控制器运行时被设定的某些参数。

帧详解

下面将分节针对上述功能码进行详细介绍。

0x01

读线圈寄存器当前状态,位操作,可读单个或者多个。

发送:

1 Byte1 Byte1 Byte1 Byte1 Byte1 Byte2 Byte
从机地址功能码寄存器起始地址高八位寄存器起始地址低八位寄存器数量高八位寄存器数量低八位CRC16
0x0C0x010x000x150x000x140xXX 0xXX

读取的从机地址为0x0C,从0x0015开始读取20个线圈的数据。

响应:

1 Byte1 Byte1 ByteN Byte2 Byte
从机地址功能码返回字节数返回数据CRC16
0x0C0x010x030xCD 0xB2 0x080xXX 0xXX

返回数据中每一位代表一个线圈状态,即线圈0x001C~0x0015分别为0xCD=1100 1101,线圈0x0024~0x001D分别为0xB2=1011 0010,线圈0x0028~0x0025分别为0x8=1000。可以看到第三组数据,只读了四个线圈,但数据是按字节发送,于是该字节剩余位是用“0”填充。

注:注意线圈地址与数据位的对应关系。
0x02

读离散输入寄存器状态,位操作,可读单个或多个。

协议与功能码0x01相似,只不过功能码为0x02,此处不再赘述。

0x03

读保持寄存器,字节操作,可读单个或多个。

发送:

1 Byte1 Byte1 Byte1 Byte1 Byte1 Byte2 Byte
从机地址功能码寄存器起始地址高八位寄存器起始地址低八位寄存器数量高八位寄存器数量低八位CRC16
0x0C0x030x000x750x000x030xXX 0xXX

读取的从机地址为0x0C,从0x0075开始读取3个保持寄存器

响应:

1 Byte1 Byte1 ByteN Byte2 Byte
从机地址功能码返回字节数返回数据CRC16
0x0C0x030x060x00 0x06 0xA5 0xD4 0x00 0x000xXX 0xXX

返回数据中每两个字节代表一个保持寄存器,即保持寄存器0x0075~0x0077分别为0x0006,0xA5D4,0x0000。

注:注意保持寄存器地址、高低字节与返回数据字节的对应关系。
0x04

读输入寄存器,字节操作,可读单个或多个。

协议与功能码0x03相似,只不过功能码为0x04,此处不再赘述。

0x05

写单个线圈,位操作,只能写一个

发送:

1 Byte1 Byte1 Byte1 Byte1 Byte1 Byte2 Byte
从机地址功能码线圈地址高八位线圈地址低八位数据高八位数据低八位CRC16
0x0C0x050x000xAC0xFF0x000xXX 0xXX

对从机地址为0x0C的线圈0x00AC进行写操作,写0xFF00表示设置线圈状态为ON,写0x0000表示设置线圈状态为OFF

响应:

与发送帧一致。

0x06

写单个保持寄存器,字节操作,只能写一个。

发送:

1 Byte1 Byte1 Byte1 Byte1 Byte1 Byte2 Byte
从机地址功能码保持寄存器地址高八位保持寄存器地址低八位数据高八位数据低八位CRC16
0x0C0x060x000x000x320x120xXX 0xXX

对从机地址为0x0C的保持寄存器0x0000的值设置为0x3212。

响应:

与发送帧一致。

0x0F

写多个线圈寄存器,位操作,若数据区的某位值为“1”表示相应线圈状态为ON,若某位值为“0”,则为状态为OFF。

发送:

1 Byte1 Byte1 Byte1 Byte1 Byte1 Byte1 ByteN Byte2 Byte
从机地址功能码线圈寄存器起始地址高八位线圈寄存器起始地址第八位线圈寄存器数量高八位线圈寄存器数量低八位写入数据字节数写入数据CRC16
0x0C0x0F0x000x180x000xA00x020x8C 0x020xXX 0xXX

对从机地址为0x0C的多个线圈寄存器进行写操作,从线圈寄存器地址0x0018开始写10个,即线圈寄存器从0x001F~0x0018的分别为0x8C=1000 1100,0x0021~0x0020分别为10。可以看到第二组数据,只写了两个线圈,但数据是按字节发送,于是该字节剩余位是用“0”填充。

注:注意线圈地址与数据位的对应关系

响应:

1 Byte1 Byte1 Byte1 Byte1 Byte1 Byte2 Byte
从机地址功能码线圈寄存器起始地址高八位线圈寄存器起始地址第八位线圈寄存器数量高八位线圈寄存器数量低八位CRC16
0x0C0x0F0x000x180x000xA00xXX 0xXX

返回的帧对应位置与发送帧一致。

0x10

写多个保持寄存器,字节操作,可写多个。

发送:

1 Byte1 Byte1 Byte1 Byte1 Byte1 Byte1 ByteN Byte2 Byte
从机地址功能码保持寄存器起始地址高八位保持寄存器起始地址第八位保持寄存器数量高八位保持寄存器数量低八位写入数据字节数写入数据CRC16
0x0C0x100x000x200x000x020x040x8C 0x02 0x45 0xA00xXX 0xXX

对从机地址为0x0C的多个保持寄存器进行写操作,从保持寄存器地址0x0020开始写入2个寄存器,0x0020寄存器的值为0x8C02,0x0021寄存器的值为0x45A0。

响应:

1 Byte1 Byte1 Byte1 Byte1 Byte1 Byte2 Byte
从机地址功能码保持寄存器起始地址高八位保持寄存器起始地址第八位保持寄存器数量高八位保持寄存器数量低八位CRC16
0x0C0x100x000x200x000x020xXX 0xXX

返回的帧对应位置与发送帧一致。

总结

Modbus-RTU是一种比较简单、可靠的协议,本文梳理了一下标准中一些常用的功能码,并举例介绍了具体使用方法,其中寄存器数据代表的含义可以根据实际情况进行自适应。

希望本文可以对大家学习Modbus-RTU协议起到帮助。

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值