一文讲透Modbus通信协议,以及RS485、SCI三者的区别
侧边栏壁纸
  • 累计撰写 30 篇文章
  • 累计收到 1 条评论

一文讲透Modbus通信协议,以及RS485、SCI三者的区别

pagegrass
2025-07-25 / 0 评论 / 8 阅读 / 正在检测是否收录...

本文将简单梳理工业上嵌入式的常见的通信方式,并详细讲解Modbus RTU、RS485与SCI通信。

1 通信是什么

通信其实很简单,说白了就是设备与设备之间的交流,这个交流需要:

1.传输媒介,可分为有线传输与无线传输,例如蓝牙、5G、WIFI等都是无线传输,有线传输例如USB等。这个概念比较简单,它是物理上的有无通信线。

2.通信方式,其实就是设备与设备之间交流的规则,只有规则对应上了,才能实现正常的交流。

【注】

通信方式是如何确定的呢?我们可以举个例子,比如中国人和中国人说话,该说什么话呢?这个什么话就是规则。我们都知道可以选择中文,当然如果两个人英文都好,也可以选择外文。

所以说,通信方式的确定,是要看具体的设备而言的,设备会说什么话?设备说的话安不安全?需不需要加密?设备和设备之间的距离有多远,说的话能不能顺利抵达?这都是通信方式要考虑的问题。

2 通信方式

2.1 通信方式的分类

1.按照通信数据传输的行为分:串行通信和并行通信

要知道,在二进制的世界里,所有数据传输的底层一定是0和1的传输。因此,在最底层,0和1究竟是如何传输的,这便是“bit”传输的行为。

【串行通信】数据一位一位的按顺序传输,一次只发送一个0或者1。

【并行通信】数据各个位同时传输,一次可发送多个0或者1。

串行通信的优点是占用的引脚资源少,但速度相对较慢,而并行通信的速快,但相对于串行通信占用的引脚资源多。

2.按照通信数据的同步方式分:同步通信和异步通信

【同步通信】通信时会引入一条时钟线,对于参与通信的设备而言,时钟线都是一致的,我只要提前约定好,在什么情况下的数据是有效的,就可以了。

举个例子:在I2C通信中,我们规定在时钟线(SCL)为高电平时,数据线的一个下降沿表示一个I2C的START条件(开始信号),这部分在以EEPROM为例,详解I2C通信协议中有详细介绍。

【异步通信】异步通信不存在时钟线,这样就需要约定好更多的条件去传输数据,方法是对数据线上的数据信号进行处理,例如参与通信的设备同时约定好数据的传输速率、数据具备起始位、数据为、奇偶校验位、停止位等等。

我们一般用波特率(bps),也就是每秒能传输多少个bit,作为衡量数据传送速率的指标。

3.按照数据传输的方向分:单工、半双工、双工通信

【单工通信】设备只能固定一个方向传输,参与通信的设备要么只能发数据,要么只能接收数据。

【半双工通信】设备可以双向传输,但在同一段时间内,要么发送数据,要么接受数据。

【全双工通信】设备可以双向传输,在同一段时间内,可以同时发送数据或传输数据。

实现全双工通信的方式有很多,典型的是增加数据线路,比如从单个数据线拓展到两条数据线,一条用于发送,一条用于接收。如果不增加数据线路,可以采用在同一条数据线上发送不同频率的信号,再进行滤波,从而实现信号的同时传输。

2.2 分清通信接口与通信协议

通信方式是一个宏观的概念,通过上面的分类我们可以看到,有很多数据传输的细节还需要去确定。由于通信的广泛应用,以及其实现方式的繁杂,在实际中我们会听到好多的通信协议,诸如SCI协议,485协议,232协议,I2C协议,SPI协议,Modbus协议,Modbus RTU协议,Modbus TCP协议等。

但是这些协议真的是协议吗?当然,由于中华文字的博大精深,协议本身二字可以是一个广泛的概念。通信协议可以指代很多东西,但是这会误导我们,在众多的信息流中,我们自己要分清本质,什么是通信接口,什么是通信协议?

【通信接口】通信接口是通信设备之间的接口,它指的其实是物理层面上的,通信接口一般会规定逻辑电平,即什么样的信号算是1,什么样的信号算是0;还会规定通信线的根数,比如0根是无线传输,大于0根是有线传输;还会规定通信线的最大通信距离、通信线的要求等,都是针对于物理上。

【通信协议】通信协议其实指的是数据传输的规则,专注于数据的结构,数据传输的速度等,都是针对于bit位的传输上。

2.3 通信接口

通信接口种类有很多,例如DP接口、HDMI接口,工业上常用的RS232接口、RS485接口、以太网接口、USB接口等。本文我们主要对RS485接口进行详解。

RS485接口也会被成为RS485标准,其中RS指的是Recommended Standard。

·所属分类:串行通信、异步通信、半双工通信。

·线路数量:2条,一条用于发送,一条用于接收,使用双绞线,一根定义为A,一根定义为B。

·逻辑定义:两根信号之间的电平差(差分信号):逻辑1:+2V to +6V;逻辑0:-6V to -2V

【拓展】差分信号的优势:差分信号是两个电位差,假设两条线上同时受到了干扰,那么做差时将会将干扰信号也减去。因此差分信号的抗干扰能力强。

·支持设备:支持一主机,多从机。

2.4 通信协议

通信协议是五花八门的,通信协议本质上是参与通信设备的约定和规则,这个规则是五花八门的,由于设备是多种多样的,想实现的功能也是多种多样的,同样为了不混乱,我将通信协议分为基于bit位的通信协议和基于数据的通信协议。

先进行如下定义。

【bit位】bit位只有1位,要么是1要么是0.

【数据】要传输的一组bit位,例如我要传输十进制的2,那么我用bit传输的时候就是10,是一组由1和0组成的两个bit的数据。

2.4.1 基于Bit位的通信协议——SCI通信协议

在SCI通信中,数据线空闲时为“逻辑1”,即高电平。

SCI通信的基本格式:

【空闲线模式】1位起始位+1-8位数据位+1个奇偶校验位+1位或者2位停止位+附加位

【地址位模式】1位起始位+1-8位数据位+1个奇偶校验位+1位地址位+1位或者2位停止位+附加位

如图1所示。
图片

图1 SCI典型数据格式

图1中,Start为起始信号,可以看SCI对起始位的定义:当信号处于空闲状态时的一个低电平,即为起始信号。

但在实际中,一定连续时间内的低电平表示有效的起始位,因此,在此我们不过多叙述实际硬件是如何判定为1或0的,而我们在进行编程的时候,硬件已经做好了这些处理,我们只需要懂得基本的通信结构。

MSB和LSB码是数字电子领域中常用的两种比特表示方法,分别代表“Most Significant Bit”和“Least Significant Bit”,MSB定义着在多位数中的最高有效位,LSB:定义:多位数中的最低有效位。

Addr/data表示的是地址位,仅在SCI通信配置为地址位模式时才有,在这种模式下,发送节点发送信息的第一个字节是一个地址字节,所有接收节都读取该地址字节。只有接收数据的地址字节与接收节点的地址字节相符合时,才能产生接收节点数据。如果接收节点的地址和接收数据的地址不符,接收节点将等待接收下一个地址。

Parity指的就是奇偶校验,该奇偶指的包括数据位和校验位在内的这一串bit中“逻辑1”个数的奇偶。例如,若采用奇校验,则要保证这一串bit中“1”的总数为奇数;如果是偶校验,则要保证这一串bit中“1”的总数为偶数。例如,对于数据位“10011010”,若采用偶校验,校验位应为“0”,使得数据位和校验位中“1”的个数为偶数(4个);若采用奇校验,校验位则应为“1”,使得“1”的总数为奇数(5个)。

Stop指的就是恢复到空闲线状态,若设置为1位停止位,则结构末尾仅包含1个“逻辑1”,若设置为2位停止位,则结构末尾包含2个“逻辑1”。

我们把Start到Stop这段数据称作为“帧”。

【例如】

在空闲线模式下,我想给设备发送“6”这个数字,设置为1位停止位,那么它的数据格式该是怎么样的呢?

首先将6转为二进制为110,一般我们设置数据长度为8位,因此实际上数据为0000 0110若采用偶校验,其奇偶校验位就应为0,若采用奇校验,其奇偶检验位就应为1。LSB是最低有效位为0,MSB是最高有效位为0。

因此采用偶校验:【起始位】0+【数据位】01100000+【奇偶校验位】0+【停止位】1

若是采用奇校验:【起始位】0+【数据位】01100000+【奇偶校验位】1+【停止位】1

在地址位模式下,第一个字节发送的是地址,在这里我们假设要给设备地址为“217”的设备发送“6”这个数字,设置为2位停止位,那么它的数据格式该是怎么样的呢?

我们将要发送两帧数据,第一帧为地址,第二帧为数据:

我们先将地址217转为二进制:1000 1111,若采用偶校验,则这一帧数据的奇偶校验位为1,若采用奇校验,则这一帧数据的奇偶校验位为0。LSB为最低有效位为1,MSB为最高有效位为1。

因此采用偶校验:

第1帧:【起始位】0+【数据位】11110001+【奇偶校验位】1+【地址位】1+【停止位】11

第2帧:【起始位】0+【数据位】01100000+【奇偶校验位】0+【地址位】0+【停止位】11

若是采用奇校验:

第1帧:【起始位】0+【数据位】11110001+【奇偶校验位】0+【地址位】1+【停止位】11

第2帧:【起始位】0+【数据位】01100000+【奇偶校验位】1+【地址位】0+【停止位】11

一定要好好体会这两个示例!

2.4.2 基于数据的通信协议——Modbus协议

在Modbus Poll的使用界面,我们点击Connection时,会出现图2所示界面。

图片

图2 Modbus Poll设置界面

这是一个典型的设置界面,我们一般会采用Serial Port 串口通信,然后设置波特率、数据位长度、有无校验位、以及停止位,还有Advanced高级设置中的一些DSR、CTS、DTR等,我们在此不拓展,只讲解最基本功能。

在右方我们可以看到在串口模式下有RTU和ASCII两种模式,RTU模式应用最广泛,掌握了RTU,自然而然就能看懂ASCII。

1.Modbus-RTU通信结构

RTU,全称Remote Terminal Unit,意为远程终端设备。它的通信结构:

地址+功能码+数据+校验

其中地址占用1个字节,这与设备的地址相对应,每个设备都具有一个唯一的地址,相当于“门牌号”。

功能码占用1个字节,功能码就代表着我当前发送的数据的功能是干什么,比如说修改从机的数据,查询从机的数据等。常见的功能码定义有:

0x01:读线圈状态;0x02:读离散输入状态;0x03:读保持寄存器;0x04:读输入寄存器;0x05:写单线圈;0x06:写单寄存器;0x07:读取异常状态······

我们常用的功能码就是0x03与0x07,一个是读当前从设备的信息,一个是修改当前从设备的信息。

数据占用的字节不定,主要依据功能码的定义来确定。

校验占用2个字节,为循环冗余校验方式,主要是为了保证数据不出错。

2.Modbus-RTU通信实例——读数据

现在我们以具体的实例来进行讲解。

【主机发送数据】

比如现在我们想在从设备上读数据,那我们是肯定已知设备地址的,要注意,设备地址占用一个字节,一个字节是8bit,二进制表示范围为0~255,其中有效的地址范围是1-247,其余的有特殊用途,比如249-254是预留为未来拓展,255是广播地址,也就是说所有设备只要接收到了广播地址都会认为有效。

假设我们现在的设备地址是247,我们想要读取设备信息,那么功能码我们选择0x03;在0x03的功能下,对于数据字节,我们首先要发送读取信息对应寄存器的首地址,一个寄存器的地址是2字节数据,然后再紧接着包括2字节的寄存器数量。

例如,我们要对设备地址为247的设备,从寄存器地址为4的寄存器开始,读取26个寄存器的值。那么它要发送的Modbus-RTU数据为:

F70301 0000 1A8E 6F

注意:Modbus-RTU的数据结构都用16进制来表示。

【地址】因此247转为16进制为F7,表示从机地址

【功能码】03为功能码,读取寄存器信息

【数据】4转为16进制为0100,因此寄存器首地址为0100,26转为16进制为1A,因此读取的寄存器数量为001A

【CRC校验】CRC校验是循环冗余校验,其校验方法为:

第一步:处理第一个字节0xF7

当前字节与CRC低8位异或:

CRC = 0xFFFF ^ 0xF7 = 0xFF08(二进制:11111111 00001000)

8 次移位操作(每次右移1位,检查最低位):

第 1 次:最低位为 0 →直接右移→ 0x7F84(01111111 10000100)

第 2 次:最低位为 0 →直接右移→ 0x3FC2(00111111 11000010)

第 3 次:最低位为 0 →直接右移→ 0x1FE1(00011111 11100001)

第 4 次:最低位为 1 →右移后与 0xA001 异或→

右移:0x0FF0(00001111 11110000)

异或:0x0FF0 ^ 0xA001 = 0xAFF1(10101111 11110001)

第 5 次:最低位为 1 →右移后与 0xA001 异或→

右移:0x57F8(01010111 11111000)

异或:0x57F8 ^ 0xA001 = 0xF7F9(11110111 11111001)

第 6 次:最低位为 1 →右移后与 0xA001 异或→

右移:0x7BFC(01111011 11111100)

异或:0x7BFC ^ 0xA001 = 0xDBFD(11011011 11111101)

第 7 次:最低位为 1 →右移后与 0xA001 异或→

右移:0x6DFE(01101101 11111110)

异或:0x6DFE ^ 0xA001 = 0xCDFF(11001101 11111111)

第 8 次:最低位为 1 →右移后与 0xA001 异或→

右移:0x66FF(01100110 11111111)

异或:0x66FF ^ 0xA001 = 0xC6FE(11000110 11111110)

处理后 CRC 值:0xC6FE

第二步:处理第二个字节 0x03

异或操作:

CRC = 0xC6FE ^ 0x03 = 0xC6FD(11000110 11111101)

8 次移位操作:

第 1 次:最低位为 1 →右移后异或→ 0x637E ^ 0xA001 = 0xC37F

第 2 次:最低位为 1 →右移后异或→ 0x61BF ^ 0xA001 = 0xC1BE

第 3 次:最低位为 0 →直接右移→ 0x60DE

第 4 次:最低位为 0 →直接右移→ 0x306F

第 5 次:最低位为 1 →右移后异或→ 0x1837 ^ 0xA001 = 0xB836

第 6 次:最低位为 0 →直接右移→ 0x5C1B

第 7 次:最低位为 1 →右移后异或→ 0x2E0D ^ 0xA001 = 0x8E0C

第 8 次:最低位为 0 →直接右移→ 0x4706

处理后 CRC 值:0x4706

第三步:处理第三个字节 0x01

异或操作:

CRC = 0x4706 ^ 0x01 = 0x4707(01000111 00000111)

8 次移位操作:

(过程略,最终结果)

处理后 CRC 值:0x8E0E

第四步:处理第四个字节 0x00

异或操作:

CRC = 0x8E0E ^ 0x00 = 0x8E0E(10001110 00001110)

8 次移位操作:

(过程略,最终结果)

处理后 CRC 值:0x4707

第五步:处理第五个字节 0x00

异或操作:

CRC = 0x4707 ^ 0x00 = 0x4707(01000111 00000111)

8 次移位操作:

(过程略,最终结果)

处理后 CRC 值:0x8E0E

第六步:处理第六个字节 0x1A

异或操作:

CRC = 0x8E0E ^ 0x1A = 0x8E14(10001110 00010100)

8 次移位操作:

(过程略,最终结果)

处理后 CRC 值:0x6F8E

最终结果

计算得到的 CRC 值为 0x6F8E

按照 Modbus 协议要求(低字节在前),校验码在帧中表示为 8E 6F

【从机回复数据】

从机回复也类似,其数据结构为:

从机地址+主机发送的功能码+要发送给主机数据的字节数+数据+CRC校验码

例如,回复F70301 0000 1A8E 6F,假设从机每个寄存器有两字节数据,被读了26个寄存器,需要恢复52字节的数据,52转为16进制为34,则从机需回复:

F703 34 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX [CRC_L] [CRC_H]

其中XX XX代表数据,按照高字节在前的格式进行传输。

从机地址+主机发送的功能码0x03+要读取的寄存器的首地址+要读取的寄存器数量+CRC校验码

从机地址+主机发送的功能码0x03+要发送给主机数据的字节数+数据+CRC校验码

这便是Modbus-RTU 0x03的通信协议。

3.Modbus-RTU通信实例——改数据

该数据所用的功能码为0x06,其结构与读数据类似,不过0x06功能码一次只能改一个寄存器的数据,因此其通信结构为:

从机地址+功能码+要改的寄存器地址+要更改为的数据+CRC校验

例如

F7 06 01 00 00 1A 01 9C

相关不再多做解释。

如何判断是否修改成功呢?——答案是返回相同的数据即可。因此,从机要回复的数据结构为:

F7 06 01 00 00 1A 01 9C

从机地址+功能码+要改的寄存器地址+要更改为的数据+CRC校验

从机地址+功能码+要改的寄存器地址+已改为的数据+CRC校验

这便是Modbus-RTU 0x06的通信协议。

2.5 所以SCI协议和Modbus协议到底有啥关系?

这也是本文要讲的重点。

SCI是基于数据位的,Modbus是基于数据的,二者的关系就是,Modbus是在SCI通信上,进行了一次封装。

【举个例子你就明白】

我们要发送的数据为:F70301 0000 1A8E 6F

那么怎么发送呢?我们是要用到SCI的。想一下如何用SCI发送“F7”?

假设在空闲线模式下,我们设置为1位停止位,偶校验,那么我们实际发送的bit位是什么情况呢?

将16进制的F7转为二进制:1111 0111

此时SCI发送的bit情况:

【起始位】0+【数据位】1110 1111+【奇偶校验位】1+【停止位】1

拓展到所有的数据:

F7:【起始位】0+【数据位】1110 1111+【奇偶校验位】1+【停止位】1

03:【起始位】0+【数据位】1100 0000+【奇偶校验位】0+【停止位】1

01:【起始位】0+【数据位】1000 0000+【奇偶校验位】1+【停止位】1

00:【起始位】0+【数据位】0000 0000+【奇偶校验位】0+【停止位】1

00:【起始位】0+【数据位】0000 0000+【奇偶校验位】0+【停止位】1

1A:【起始位】0+【数据位】0101 1000+【奇偶校验位】1+【停止位】1

8E:【起始位】0+【数据位】0111 0001+【奇偶校验位】0+【停止位】1

6F:【起始位】0+【数据位】1111 0110+【奇偶校验位】0+【停止位】1

然后SCI在使用RS485通信线,去进行具体“逻辑1”与“逻辑0”的传输。

数据传输的巧妙,是不是有一种恍然大悟的感觉?

[本文完]

0

评论 (0)

取消