02、RS485 通信与 Modbus 协议

0、前言


  在工业控制、电力通讯、智能仪表等领域,通常情况下是采用串口通信的方式进行数据交换。最初采用的方式是 RS232 接口,由于工业现场比较复杂,各种电气设备会在环境中产生比较多的电磁干扰,会导致信号传输错误。除此之外,RS232 接口只能实现点对点通信,不具备联网功能,最大传输距离也只能达到十几米,不能满足远距离通信要求。而 RS485 则解决了这些问题,数据信号采用差分传输方式,可以有效的解决共模干扰问题,最大距离可达 1200 米,并且允许多个收发设备接到同一条总线上。随着工业应用通信越来越多,1979年施耐德电气制定了一个用于工业现场的总线协议 Modbus 协议,现在工业中使用 RS485 通信场合很多都采用 Modbus 协议,下面我们就来讲解一下 RS485 通信和 Modbus 协议。

1、RS485通信


  RS232 标准是诞生于 RS485 之前的,但是 RS232 有几处不足的地方:

   1、接口的信号电平值较高,达到十几 V,使用不当容易损坏接口芯片,电平标准也与 TTL 电平不兼容。

  2、传输速率有局限,不可以过高,一般到一两百千比特每秒(Kb/s)就到极限了。

  3、接口使用信号线和 GND 与其它设备形成共地模式的通信,这种共地模式传输容易产生干扰,并且抗干扰性能也比较弱。

  4、传输距离有限,最多只能通信几十米。

  5、通信的时候只能两点之间进行通信,不能够实现多机联网通信。

  针对 RS232 接口的不足,就不断出现了一些新的接口标准,RS485 就是其中之一,它具备以下的特点:

  1、采用差分信号。差分输入信号的好处,最大的优势是可以抑制共模干扰。尤其当工业现场环境比较复杂,干扰比较多时,采用差分方式可以有效的提高通信可靠性。RS485 采用两根通信线,通常用 A 和 B 或者 D+和 D-来表示。逻辑“1”以两线之间的电压差为+(0.2~6)V 表示,逻辑“0”以两线间的电压差为-(0.2~6)V 来表示,是一种典型的差分通信。

  从严格意义上来讲,其实所有的信号都是差分信号,因为所有的电压只能是相对于另外一个电压而言。但是大多数系统,我们都是把系统的 GND 作为基准点。而对于差分输入,通常情况下是除了 GND 以外,另外两路幅度相同,极性相反的输入信号,其实理解起来很简单,就如同跷跷板一样。如图下图所示。

在这里插入图片描述
  差分输入的话,就不是单个输入,而是由 2 个输入端构成的一组输入。PCF8591 一共是
4 个模拟输入端,可以配置成 4 种模式,最典型的是 4 个输入端构造成的两路差分模式,如
图下图所示。
在这里插入图片描述
4 路模拟被配置成 2 路差分模式输入channel 0 和 channel 1。我们以 channel 0 为例,其中 AIN0 是正向输入端,AIN1 是反向输入端,它们之间的信号输入是幅度相同,极性相反的信号,通过减法器后,得到的是两个输入通道的差值,如图下图所示。

  通常情况下,差分输入的中线是基准电压的一半,我们的基准电压是 2.5V,假如 1.25V作为中线,V+是 AIN0 的输入波形,V-是 AIN1 的输入波形,Signal Value 就是经过减法器后的波形。很多 A/D 都采用差分的方式输入,因为差分输入方式比单端输入来说,有更强的抗干扰能力。
  单端输入信号时,如果一线上发生干扰变化,比如幅度增大 5mv,GND 不变,测到的数据会有偏差;而差分信号输入时,当外界存在干扰信号时,只要布线合理,大都同时被耦合到两条线上,幅度增大 5mv 会同时增大 5mv,而接收端关心的只是两个信号的差值,所以外界的这种共模噪声可以被完全抵消掉。由于两根信号的极性相反,它们对外辐射的电磁场可以相互抵消,有效的抑制释放到外界的电磁能量。

  2、RS485 通信速率快,最大传输速度可以达到 10Mb/s 以上。

  3、RS485 内部的物理结构,采用的是平衡驱动器和差分接收器的组合,抗干扰能力也大大增加。

  4、传输距离最远可以达到 1200 米左右,但是它的传输速率和传输距离是成反比的,只有在 100Kb/s 以下的传输速度,才能达到最大的通信距离,如果需要传输更远距离可以使用中继。

  5、可以在总线上进行联网实现多机通信,总线上允许挂多个收发器,从现有的 RS485 芯片来看,有可以挂 32、64、128、256 等不同个设备的驱动器。

  6、RS485 的接口非常简单,与 RS232 所使用的 MAX232 是类似的,只需要一个 RS485转换器,就可以直接与单片机的 UART 串口连接起来,并且使用完全相同的异步串行通信协议。但是由于 RS485 是差分通信,因此接收数据和发送数据是不能同时进行的,也就是说它是一种半双工通信。

  那我们如何判断什么时候发送,什么时候接收呢?

  RS485 转换芯片很多,这节课我们以典型的 MAX485 为例讲解 RS485 通信,如图下图所示。
在这里插入图片描述
  MAX485 是美信(Maxim)推出的一款常用 RS485 转换器。其中 5 脚和 8 脚是电源引脚和GND引脚;6 脚和 7 脚就是 RS485 通信中的 A 和 B 两个引脚;1 脚和 4 脚分别接到单片机的 RXD 和 TXD 引脚上,直接使用单片机 UART 进行数据接收和发送;2 脚和 3 脚是方向引脚,其中 2 脚是低电平使能接收器,3 脚是高电平使能输出驱动器,我们把这两个引脚连到一起,平时不发送数据的时候,保持这两个引脚是低电平,让 MAX485 处于接收状态,当需要发送数据的时候,把这个引脚拉高,发送数据,发送完毕后再拉低这个引脚就可以了。为了提高 RS485 的抗干扰能力,需要在靠近 MAX485 的 A 和 B 引脚之间并接一个电阻,这个电阻阻值从 100欧到 1K 都是可以。

2、Modbus 通信协议介绍


  我们学习的UART、I2C、SPI 这些通信协议,都是最底层的协议,是“位”级别的协议。随着系统复杂性的增加,我们希望可以实现更多的指令。而指令越来越多,带来的后果就是非常杂乱无章,尤其是这个人喜欢写成 “buzz on”、“buzz off”,而另外一个人喜欢写成 “on buzz”、“off buzz”。导致不同开发人员写出来的程序代码不兼容,不同厂家的产品不能挂到一条总线上通信。

  随着这种矛盾的日益严重,就会有聪明人提出更合理的解决方案,提出一些标准来,今后我们的编程必须按照这个标准来,这种标准也是一种通信协议,但是和 UART、I2C、SPI通信协议不同的是,这种通信协议是字节级别的,叫做应用层通信协议。在 1979 年由 Modicon(现为施耐德电气公司的一个品牌)提出了全球第一个真正用于工业现场总线的协议,就是Modbus 协议

2.1、Modbus 协议特点


  Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其他设备之间可以通信,已经成为一种工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。这种协议定义了一种控制器能够认识使用的数据结构,而不管它们是经过何种网络进行通信的。它描述了控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误记录,它制定了通信数据的格局和内容的公共格式。

  在进行多机通信的时候,Modbus 协议规定每个控制器必须要知道它们的设备地址,识别按照地址发送过来的数据,决定是否要产生动作,产生何种动作,如果要回应,控制器将生成的反馈信息用 Modbus 协议发出。

  Modbus 协议允许在各种网络体系结构内进行简单通信,每种设备(PLC、人机界面、控
制面板、驱动程序、输入输出设备等)都能使用 Modbus 协议来启动远程操作,一些网关允许在几种使用 Modbus 协议的总线或网络之间的通信,如图下图所示。
在这里插入图片描述

  Modbus 协议的整体架构和格式比较复杂和庞大,在我们的课程里,我们重点介绍数据帧结构和数据通信控制方式,作为一个入门级别的了解。如果大家要详细了解,或者使用 Modbus 开发相关设备,可以查阅相关的国标文件再进行深入学习。

2.2、RTU 协议帧数据


  Modbus 有两种通信传输方式,一种是 ASCII 模式,一种是 RTU 模式。由于 ASCII 模式的数据字节是 7bit 数据位,51 单片机无法实现,而且实际应用的也比较少,所以这里我们只用 RTU 模式。两种模式相似,会用一种另外一种也就会了。一条典型的 RTU 数据帧如图下图所示。
在这里插入图片描述
  与之前我们讲解串口通信程序时用的原理相同,一次发送的数据帧必须是作为一个连续的数据流进行传输。我们在串口通信程序中采用的方法是定义 30ms,如果数据接收时超过了 30ms 还没有接收到下一个字节,我们就认为这次的数据结束。而 Modbus 的 RTU 模式规定不同数据帧之间的间隔是 3.5 个字节通信时间以上。如果在一帧数据完成之前有超过 3.5 个字节时间的停顿,接收设备将刷新当前的消息并假定下一个字节是一个新的数据帧的开始。同样的,如果一个新消息在小于 3.5 个字节时间内接着前边一个数据开始,接收设备将会认为它是前一帧数据的延续。这将会导致一个错误,因此大家看 RTU 数据帧最后还有 16bit 的 CRC 校验。

  **起始位和结束符:**图上代表的是一个数据帧,前后都至少有 3.5 个字节的时间间隔,起始位和结束符实际上没有任何数据,T1-T2-T3-T4 代表的是时间间隔 3.5 个字节以上的时间,而真正有意义的第一个字节是设备地址。

  **设备地址:**很多同学不理解,在多机通信的时候,数据那么多,我们依靠什么判断这个数据帧是哪个设备的呢?没错,就是依靠这个设备地址字节。每个设备都有一个自己的地址,当设备接收到一帧数据后,程序首先对设备地址字节进行判断比较,如果与自己的地址不同,则对这帧数据直接不予理会,如果与自己的地址相同,就要对这帧数据进行解析,按照之后的功能码执行相应的功能。如果地址是 0x00,则认为是一个广播命令,就是所有的从机设备都要执行的指令。

  **功能代码:**在第二个字节功能代码字节中,Modbus 规定了部分功能代码,此外也保留了一部分功能代码作为备用或者用户自定义,这些功能码大家不需要去记忆,甚至都不用去看,直到你用到的那天再过来查这个表格即可,如表下图所示。

功能码名称作用
01读取线圈状态取得一组逻辑线圈的当前状态(ON/OFF)
02读取输入状态取得一组开关输入的当前状态(ON/OFF)
03读取保持寄存器在一个或多个保持寄存器中取得当前的二进制值
04读取输入寄存器在一个或多个输入寄存器中取得当前的二进制值
05强制单线圈强置一个逻辑线圈的通断状态
06预置单寄存器把具体二进值装入一个保持寄存器
07读取异常状态取得 8 个内部线圈的通断状态,
这8个线圈的地址由控制器决定,
用户逻辑可以将这些线圈定义,
以说明从机状态,短报文适宜于迅速读取状态
08回送诊断校验把诊断校验报文送从机,以对通信处理进行评鉴
09编程(只用于 484)使主机模拟编程器作用,修改 PC 从机逻辑
10控询(只用于 484)可使主机与一台正在执行长程序任务从机通信,
探询该从机是否已完成其操作任务,
仅在含有功能码 9 的报文发送后,本功能码才发送
11读取事件计数可使主机发出单询问,并随即判定操作是否成功,
尤其是该命令或其它应答产生通信错误时
12读取通信事件记录可使主机检索每台从机的 ModBus 事务处理通信事件记录。
如果某项事务处理完成,记录会给出有关错误
13编程(184/384 484 584 )可使主机模拟编程器功能修改 PC 从机逻辑
14探询(184/384 484 584)可使主机与正在执行任务的从机通信,
定期控询该从机是否已完成其程序操作,
仅在含有功能 13 的报文发送后,本功能码才得发送
15强置多线圈强置一串连续逻辑线圈的通断
16预置多寄存器把具体的二进制值装入一串连续的保持寄存器
17报告从机标识可使主机判断编址从机的类型及该从机运行指示灯的状态
18884 和 MICRO 84可使主机模拟编程功能,修改 PC 状态逻辑
19重置通信链路发生非可修改错误后,是从机复位于已知状态,
可重置顺序字节
20读取通用参数(584L)显示扩展存储器文件中的数据信息
21写入通用参数(584L)把通用参数写入扩展存储文件,或修改
22~64保留作扩展功能备用
65~72保留以备用户功能所用留作用户功能的扩展编码
73~119非法功能
120~127保留留作内部作用
128~255保留用于异常应答

  程序对功能码的处理,就是来检测这个字节的数值,然后根据其数值来做相应的功能处理。

  数据:跟在功能代码后边的是 n 个 8bit 的数据。这个 n 值的到底是多少,是功能代码来确定的,不同的功能代码后边跟的数据数量不同。举个例子,如果功能码是 0x03,也就是读保持寄存器,那么主机发送数据 n 的组成部分就是:2 个字节的寄存器起始地址,加 2 个字节的寄存器数量 N。从机数据 n 的组成部分是:1 个字节的字节数,因为我们回复的寄存器的值是 2 个字节,所以这个字节数也就是 2N 个,再加上 2N 个寄存器的值,如图下图所示。
在这里插入图片描述
  CRC 校验:CRC 校验是一种数据算法,是用来校验数据对错的。CRC 校验函数把一帧数据除最后两个字节外,前边所有的字节进行特定的算法计算,计算完后生成了一个 16bit的数据,作为 CRC 校验码,添加在一帧数据的最后。接收方接收到数据后,同样会把前边的字节进行 CRC 计算,计算完了再和发过来的 16bit 的 CRC 数据进行比较,如果相同则认为数据正常,没有出错,如果比较不相同,则说明数据在传输中发生了错误,这帧数据将被丢弃,就像没收到一样,而发送方会在得不到回应后做相应的处理错误处理。

  RTU 模式的每个字节的位是这样分布的:1 个起始位、8 个数据位,最小有效位先发送、
1 个奇偶校验位(如果无校验则没有这一位)、1 位停止位(有校验位时)或者 2 个停止位(无
校验位时)

3、Modbus 多机通信例程


  给从机下发不同的指令,从机去执行不同的操作,这个就是判断一下功能码即可,和我们前边学的实用串口例程是类似的。多机通信,无非就是添加了一个设备地址判断而已,难度也不大。我们找了一个 Modbus 调试精灵,通过设置设备地址,读写寄存器的地址以及数值数量等参数,可以直接替代串口调试助手,比较方便的下发多个字节的数据,如图下图所示。我们先来就图中的设置和数据来对 Modbus 做进一步的分析,图中的数据来自于调试精灵与我们接下来要讲的例程之间的交互。
在这里插入图片描述
  如图,我们的 USB 转 RS485 模块虚拟出的是 COM5,波特率 9600,无校验位,数据位是 8 位,1 位停止位,设备地址假设为 1。

  写寄存器的时候,如果我们要把 01 写到一个地址是 0000 的寄存器地址里,点一下“写入”,就会出现发送指令:01 06 00 00 00 01 48 0A。我们来分析一下这帧数据,其中 01 是设备地址,06 是功能码,代表写寄存器这个功能,后边跟 00 00 表示的是要写入的寄存器的地址,00 01 就是要写入的数据,48 0A 就是CRC 校验码,这是软件自动算出来的。而根据Modbus协议,当写寄存器的时候,从机成功完成该指令的操作后,会把主机发送的指令直接返回,我们的调试精灵会接收到这样一帧数据:01 06 00 00 00 01 48 0A。

  假如我们现在要从寄存器地址 0002 开始读取寄存器,并且读取的数量是 2 个。点一下“读出”,就会出现发送指令:01 03 00 02 00 02 65 CB。其中 01 是设备地址,03 是功能码,代表读寄存器这个功能,00 02 就是读寄存器的起始地址,后一个 00 02 就是要读取 2 个寄存器的数值,65 CB 就是 CRC 校验。而接收到的数据是:01 03 04 00 00 00 00 FA 33。其中 01是设备地址,03 是功能码,04 代表的是后边读到的数据字节数是 4 个,00 00 00 00 分别是地址为 00 02 和 00 03 的寄存器内部的数据,而 FA 33 就是 CRC 校验了。

  似乎越来越明朗了,所谓的 Modbus 通信协议,无非就是主机下发了不同的指令,从机根据指令的判断来执行不同的操作而已。由于我们的开发板没有 Modbus 功能码那么多相应的功能,我们在程序中定义了一个数组 regGroup[5],相当于 5 个寄存器,此外又定义了第 6个寄存器,控制蜂鸣器,通过下发不同的指令我们改变寄存器组的数据或者改变蜂鸣器的开关状态。在 Modbus 协议里寄存器的地址和数值都是 16 位的,即 2 个字节,我们默认高字节是0x00,低字节就是数组regGroup 对应的值。其中地址0x0000 到0x0004 对应的就是regGroup数组中的元素,我们写入的同时把数字又显示到1602 液晶上,而0x0005 这个地址,写入0x00,蜂鸣器就不响,写入任何其它数值,蜂鸣器就报警。我们单片机的主要工作也就是解析串口接收的数据执行不同操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Geek@Yang

码字不易,来点鼓励~~~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值