草庐IT

Modbus通讯协议常用功能码解释

Lee139499 2023-04-11 原文

 Modbus是一种单主站的主/从通讯模式。Modbus网络上只有一个主站,主站在Modbus网络上没有地址,从站的地址范围为0-247,其中0为广播地址,从站的实际地址范围为1-247。

代码名称作用
01读取线圈状态

取得一组逻辑线圈的当前状态(ON/OFF)

02读取输入状态取得一组开关输入的当前状态(ON/OFF)
03读取保持寄存器在一个或多个保持寄存器中取得当前的二进制值
04读取输入寄存器在一个或多个输入寄存器中取得当前的二进制值
05强制单线圈强置一个逻辑线圈的通断状态
06预置单寄存器放置一个热定特定的二进制值到一个单寄存器中
07读取异常状态取得8个内部线圈的通断状态
15强置多线圈强置一串连续逻辑线圈的通断
16预置多寄存器放置一系列特定的二进制值到一系列多寄存器中
17报告从机标识可使主机判断编址从机的类型及该从机运行指示灯的状态

1.读取线圈状态(功能码01)

        读取从机离散量输出口的(ON/OFF)状态,不支持广播。

        查询:查询信息规定了要起始线圈线圈量,线圈的起始地址为0000H,1-16个线圈的寻址地址分为0000H-0015H(DO1=0000H,DO2=0001H,以此类推)。

        例子:从地址为17的从机读取D01至D06的状态。

读取线圈状态----查询
addrFunD0 start reg hiD0 start reg loD0 #of regs hiD0 #of regs loCRC16 hiCRC16 lo
地址功能码起始线圈地址高8位起始线圈地址低8位线圈量高8位线圈量低8位校验高8位校验低8位
11H01H00H00H00H

06H

XXHXXH

        响应:响应信息中的各线圈的状态与数据区的每一位的值相对应,即每个D0占用一位(1=ON,0=OFF),第一个数据字节的LSB为查询中的寻址地址,其他的线圈按顺序在该字节中由低位向高位排序,直至8个为止,下一个字节也是从低位向高位排列。若返回的线圈数不是8的倍数,则在最后的数据字节中的剩余位至字节的最高位全部填0,字节数区说明全部的字节数。

读取线圈状态----响应
addrFunByte countDataCRC16 hiCRC16 lo
地址功能码字节数数据位校验高8位校验低8位
11H01H01H

2AH

XXHXXH

                                                                                        数据:

000000D02D01
MSB765432LSB

2.读取输入状态(功能码02)

        读取从机离散量输入信号(ON/OFF)的状态,不支持广播。

        查询:查询信息规定了要输入起始地址,以及输入信号的数量。输入的起始地址为0000H,1-16个输入口的地址分别为0-15(DO1=0000H,DO2=0001H,以此类推)。

        例子:从地址为17的从机读取D01至D16的状态。

读取输入状态----查询
addrFunD0 start reg hiD0 start reg loD0 #of regs hiD0 #of regs loCRC16 hiCRC16 lo
地址功能码起始线圈地址高8位起始线圈地址低8位线圈量高8位线圈量低8位校验高8位校验低8位
11H02H00H00H00H

10H

XXHXXH

        响应:响应信息中的各输入口的状态,分别对应于数据区中的每一位值,1=ON,0=OFF,第一个数据字节的LSB为查询中的寻址地址,其他输入口按顺序在该字节中由低位向高位排序,直至8个为止,下一个字节中的8个输入位也是从低位向高位排列。若返回的输入位数不是8的倍数,则在最后的数据字节中的剩余位直至字节的最高位全部填0,字节数区说明了全部数据的字节数。

读取输入状态----响应
addrFunByte countData1Data2CRC16 hiCRC16 lo
地址功能码字节数数据位数据位校验高8位校验低8位
11H02H02H

33H

CCHXXHXXH

                                                                                         数据1:

DI8DI7DI6DI5DI4DI3DI2DI1
MSBLSB

                                                                                         数据2:

DI16DI15DI14DI13DI12DI11DI10DI9
MSBLSB

3.读取保持寄存器(功能码03)

        读取从机保持寄存器的二进制数据,不支持广播。

        查询:查询信息规定了要的保持寄存器起始地址及保持寄存器的数量,保持寄存器寻址其实地址为0000H,寄存器1-16所对应的地址分别为0000H-0015H。

        例子:从17号从机读3个采集到的基本数据U1、U2、U3,U1的地址为0000H,U2的地址为0001H,U3的地址为0002H。

读取保持寄存器----查询
addrFunData start addr hiData start addr loD0 #of regs hiD0 #of regs loCRC16 hiCRC16 lo
地址功能码寄存器起始地址高8位寄存器起始地址低8位寄存器数量高8位寄存器数量低8位校验高8位校验低8位
11H03H00H00H00H

03H

XXHXXH

        响应:响应信息中的寄存器数据位二进制数据,每个寄存器分别对应2个字节,第一个字节为高位值数据,第二个字节为低位数据。

        读取U1、U2、U3(U1=03E8H,U2=03E7H,U3=03E9H)的响应。

读取保持寄存器----响应
addrFunByte countData1 hiData1 loData2 hiData2 loData3 hiData3 loCRC16 hiCRC16 lo
地址功能码字节数数据1高8位数据1低8位数据2高8位数据2低8位数据3高8位数据3低8位校验高8位校验低8位
11H03H06H

03H

E8H03HE7H03HE6HXXHXXH

4.读取输入寄存器(功能码04)

        读取从机输入寄存器中的二进制数据,不支持广播。

        查询:查询信息规定了要寄存器起始地址及寄存器的数量,寻址起始地址为0,寄存器1-16所对应的地址分别为0000H-0015H。

        例子:请求17号从机的0009寄存器。

读取输入寄存器----查询
addrFunD0 addr hiD0 addr loD0 #of regs hiD0 #of regs loCRC16 hiCRC16 lo
地址功能码寄存器起始地址高8位寄存器起始地址低8位寄存器数量高8位寄存器数量低8位校验高8位校验低8位
11H04H00H08H00H

03H

XXHXXH

        响应:响应信息中的寄存器为每个寄存器分别对应2个字节,第一个字节为高位数据,第二个字节为低位数据。

读取输入寄存器----响应
addrFunByte countData hiData loCRC16 hiCRC16 lo
地址功能码字节数数据位数据位校验高8位校验低8位
11H04H02H

00H

0AHXXHXXH

5.强制单线圈(功能码05)

        强制单个线圈为ON或OFF状态,广播时,该功能可强制所有从机中同一类型的线圈均为ON或OFF状态。

        该功能可跨过控制器内存的保护状态和线圈的禁止状态。线圈强制状态一直保持有效直至下一个控制逻辑作用于线圈为止。控制逻辑中无线圈程序时,则线圈处于强制状态。

        查询:查询信息规定了需要强制一个单独线圈的类型,线圈的起始地址为0000H,1-16个线圈的寻址地址分为0000H-0015H(DO1=0000H,DO2=0001H,以此类推)。

        由查询数据区中的一个常量,规定请求线圈的ON/OFF状态,FF00H值请求线圈处于ON状态,0000H值请求线圈处于OFF状态,其他值对线圈无效,不起作用。

        例子:请求17号从机开D01的ON状态。

强制单线圈----查询
addrFunD0 addr hiD0 addr loValue hiValue loCRC16 hiCRC16 lo
地址功能码寄存器地址高8位寄存器地址低8位寄存器值高8位寄存器值低8位校验高8位校验低8位
11H05H00H00HFFH

00H

XXHXXH

          响应:对这个命令请求的正常响应是在D0状态改变后传送接收到的数据。

强制单线圈----响应
addrFunD0 addr hiD0 addr loValue hiValue loCRC16 hiCRC16 lo
地址功能码寄存器地址高8位寄存器地址低8位寄存器值高8位寄存器值低8位校验高8位校验低8位
11H05H00H00HFFH

00H

XXHXXH

6.预置单寄存器(功能码06) 

        把一个值预置到一个保持寄存器中,广播时,该功能把值预置到所有从机的相同类型的寄存器中。

        该功能可跨过控制器的内存保护。使寄存器中的预置值保持不变。只能由控制器的下一个逻辑信号来处理该预置值。若控制逻辑中无寄存器程序时,则寄存器中的值保持不变。

        查询:查询信息规定了要预置寄存器的类型,寄存器寻址起始地址为0000H,寄存器1所对应的地址为0000H。

        例子:请求17号从机0040H的值为2177.

预设单寄存器----查询
addrFunData start addr hiData start addr loValue hiValue loCRC16 hiCRC16 lo
地址功能码寄存器地址高8位寄存器地址低8位数据高8位数据低8位校验高8位校验低8位
11H06H00H40H0AH

9DH

XXHXXH

        响应:对于预置单寄存器请求的正常响应是在寄存器值改变以后 将接受到的数据传送回去。

预设单寄存器----响应
addrFunData start addr hiData start addr loValue hiValue loCRC16 hiCRC16 lo
地址功能码寄存器地址高8位寄存器地址低8位数据高8位数据低8位校验高8位校验低8位
11H06H00H40H0AH

9DH

XXHXXH

7.读取异常状态(功能码07) 

        读从机中8个不正常状态线圈的数据,某些线圈号已在不同型号的控制器中预定义,而其他的线圈由用户编程,作为有关控制器的状态信息,如“machien ON/OFF”,“heads retraced”,(缩回标题),“safeties satisfied”(安全性满意),“error conditions”(存在错误条件)或其它用户定义的标志等。该功能码不支持广播。

        该功能码为存取该类信息提供了一种简单的方法,不正常线圈的类型是已知的(在功能代码中不需要线圈类型)预定义的不正常线圈号如下:

控制器型号线圈设定
M84,184/384,584,9841-8用户定义
484257电池状态
258-264用户定义
884761电池状态
762内存保护状态
763R10工况状态
764-768用于预定义

          查询:请求读从机设备17中的不正常状态。

读取异常状态----查询
addrFunCRC16 hiCRC16 lo
地址功能码校验高8位校验低8位
11H06HXXHXXH

        响应:正常响应包含8个不正常的线圈状态,为一个数据字节,每个线圈一位。LSB对应为最低线圈类型的状态。

        按查询要求返回响应:

读取异常状态----响应
addrFunD0 DataCRC16 hiCRC16 lo
地址功能码数据校验高8位校验低8位
11H06H6DHXXHXXH

        该例子中,线圈数据为6DH(二进制0110,1101),从左到右(最高位至最低位)的线圈状态分别为:OFF-ON-ON-OFF-ON-ON-OFF-ON。若控制器型号为984,这些位表示线圈8至1的状态;若控制器型号为484则表示线圈264至257的状态。

8.强制多线圈(功能码15) 

        按线圈的顺序把各线圈强制成ON或OFF。广播时,该功能代码可对各从机中相同类型的线圈起强制作用。

        该功能代码可跨过内存能保护和线圈的进制状态线圈。保持强制状态有效,并只能由空、感知器的下一个逻辑来处理。若无线圈控制逻辑程序时,线圈将保持强制状态。

        查询:查询信息规定了被强制线圈的类型,线圈的起始地址为0000H,1-16个线圈的寻址地址分为0000H-0015H(DO1=0000H,DO2=0001H,以此类推)。

        查询数据区规定了被请求线圈的ON/OFF状态,如数据区的某位值为“1”表示请求的响应线圈状态为ON,位值为“0”,则为OFF状态。

        例子:请求从机设备17中一组10个线圈为强制状态,起始线圈为20(则寻址地址为19或13H),查询的数据为2个字节,CD01H(二进制1100 1101 0000 0001)响应线圈的二进制位排序如下:

Bit:1100110100000001
Coil:2726252423332120------2928

        传送的第一个字节CDH对应线圈为27-20,LSB对应线圈20,传送的第二个字节为01H,对应的线圈为29-28,LSB为对应线圈28,其余未使用的位均填“0”。

强制多线圈----查询
addrFunD0 addr hiD0 addr loD0 #of regs hiD0 #of regs loByte countValue hiValue loCRC16 hiCRC16 lo
地址功能码起始地址高8位起始地址低8位寄存器数量高8位寄存器数量低8位字节数数据高8位数据低8位校验高8位校验低8位
11H0FH00H13H00H

0AH

02HCDH01HXXHXXH

        响应:正常响应返回从机地址,功能码,起始地址以及强制线圈数。

强制多线圈----响应
addrFunD0 addr hiD0 addr loD0 #of regs hiD0 #of regs loCRC16 hiCRC16 lo
地址功能码寄存器地址高8位寄存器地址低8位寄存器值高8位寄存器值低8位校验高8位校验低8位
11H0FH00H13H00H

0AH

XXHXXH

9.预置多寄存器(功能码16) 

        把数据按顺序预置到各寄存器中,广播时该功能代码可把数据预置到全部从机中的相同类型King的寄存器中。

        该功能代码可跨过控制器的内存保护,在寄存器中的预置值一直保持有效,只能由控制器的下一个逻辑来处理寄存器的内容,控制逻辑中无该寄存器程序时,则寄存器中的值保持不变。

        查询:查询信息规定了要预置寄存器的类型,寄存器寻址起始地址为0000H,寄存器1所对应的地址为0000H。

        例子:请求17号从机0040H的值为178077833.(十六进制为 0A9D 4089)

预设多寄存器----查询
addrFunData start reg hiData start reg loD0 #of regs hiD0 #of regs loByte countValue hiValue loValue hiValue loCRC16 hiCRC16 lo
地址功能码寄存器起始地址高8位寄存器起始地址低8位寄存器数量高8位寄存器数量低8位字节数数据高8位数据低8位数据高8位数据低8位校验高8位校验低8位
11H10H00H40H00H

02H

04H40H89H0AH9DHXXHXXH

         响应:对于预置单寄存器请求的正常响应是在寄存器值改变以后将接受到的数据传送回去。

预设多寄存器----响应
addrFunData start reg hiData start reg loD0 #of regs hiD0 #of regs loCRC16 hiCRC16 lo
地址功能码寄存器起始地址高8位寄存器起始地址低8位寄存器数量高8位寄存器数量低8位校验高8位校验低8位
11H10H00H40H00H

02H

XXHXXH

10.报告从机标识(功能码17) 

        返回一个从机地址控制器的类型,从机的当前状态,以及有关从机的其他说明,不支持广播。

        查询:请求报告从机设备17的表示ID和状态。

报告从机标识----查询
addrFunCRC16 hiCRC16 lo
地址功能码校验高8位校验低8位
11H11HXXHXXH

        响应:正常响应格式,数据内容对应每台控制器的类型。

addrFunbyte CountSlave IDRun Indicator StatusAdditfional DataCRC16 hiCRC16 lo
地址功能码字节数校验高8位校验低8位
11H11HXXHXXHXXHXXHXXH

XXH

         从机ID总结

                数据区第一个字节为Modicon控制器返回的从机ID

Slave IDController
0Micro 84
1484
2184/384
3584
8884
9984

                特注:详细信息见Modbus协议英文版或中文版。

有关Modbus通讯协议常用功能码解释的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  3. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

    只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

  4. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  5. ruby - 解释为局部变量会覆盖方法名称吗? - 2

    如thisquestion,当在其自己的赋值中使用未定义的局部变量时,它的计算结果为nil。x=x#=>nil但是当局部变量的名称与现有的方法名称冲突时,就比较棘手了。为什么下面的最后一个示例返回nil?{}.instance_eval{a=keys}#=>[]{}.instance_eval{keys=self.keys}#=>[]{}.instance_eval{keys=keys}#=>nil 最佳答案 在Ruby中,因为可以在没有显式接收器和括号的情况下调用方法,所以在局部变量引用和无接收器无参数方法调用之间存在语法歧义:f

  6. 语法类似于 GitHub Flavored Markdown 的 Ruby markdown 解释器? - 2

    我使用Jekyll运行博客,并认为我会解决RedcarpetMarkdown解释器,因为它是developedandusedbyGitHub.好吧,我只是碰巧遇到了一个错误,去检查问题,然后foundthis.Maintainersays,"Asyouprobablyhavenoticed(harharharhar)Idon'thavetimetomaintainRedcarpetanymore.It'snotapriorityforme(IfindMarkdownthoroughlyboring)andit'snotapriorityforGitHub,becausewenolong

  7. ruby-on-rails - rails 功能测试 - 2

    在Rails自动生成的功能测试(test/functional/products_controller_test.rb)中,我看到以下代码:classProductsControllerTest我的问题是:方法调用products()在哪里/如何定义?products(:one)到底是什么意思?看代码,大概意思是“创建一个产品”,但是它是如何工作的呢?注意我是Ruby/Rails的新手,如果这些是微不足道的问题,我深表歉意。 最佳答案 如果您查看test/fixtures文件夹,您会看到一个products.yml文件。这是在您创建

  8. ruby - 有人可以解释一下在 Ruby 中注入(inject)的真实、通俗易懂的用法吗? - 2

    我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有

  9. ruby-on-rails - 功能测试 Authlogic? - 2

    在我的一些Controller中,我有一个before_filter检查用户是否登录?用于CRUD操作。application.rbdeflogged_in?unlesscurrent_userredirect_toroot_pathendendprivatedefcurrent_user_sessionreturn@current_user_sessionifdefined?(@current_user_session)@current_user_session=UserSession.findenddefcurrent_userreturn@current_userifdefine

  10. ruby - 一种语言如何被自身解释(如 Rubinius)? - 2

    我使用Ruby编程已经有一段时间了,现在只使用Ruby的标准MRI实现,但我一直对我经常听到的其他实现感到好奇。前几天我在读有关Rubinius的文章,这是一个用Ruby编写的Ruby解释器。我试着在不同的地方查找它,但我很难弄清楚这样的东西到底是如何工作的。我在编译器或语言编写方面从来没有太多经验,但我真的很想弄明白。一门语言究竟如何才能被自己解释?编译中是否有一个我不明白这有意义的基本步骤?有人可以像我是个白痴一样向我解释这个吗(因为无论如何这都不会太离谱) 最佳答案 它比你想象的要简单。Rubinius并非100%用Ruby编

随机推荐