精华内容
下载资源
问答
  • esp32ModbusRTU:ESP32的Modbus RTU客户端
  • 在串口连接设备时,何时选择MODBUS RTU Extend这样的通讯类型,合适选择MODBUS RTU
  • TIA V13 SP1版本软件中提供了2个版本的Modbus RTU指令:图1. 两个版本Modbus RTU指令早期版本的Modbus RTU指令(图1. 中 MODBUS (V2.2))仅可通过CM1241通信模块或CB1241通信板进行Modbus RTU通信。新版本的 Modbus ...

    TIA V13 SP1版本软件中提供了2个版本的Modbus RTU指令:

    df7c6f7d7407c5abfead0a379e0ed38c.png

    图1. 两个版本Modbus RTU指令

    早期版本的Modbus RTU指令(图1. 中 MODBUS (V2.2))仅可通过CM1241通信模块或CB1241通信板进行Modbus RTU通信。

    新版本的 Modbus RTU指令(图1. 中 MODBUS(RTU) V3.0)扩展了Modbus RTU的功能,该指令除了支持CM1241通信模块、CB1241通信板,还支持 PROFINET 或 PROFIBUS 分布式 I/O 机架上的PTP通信模块实现Modbus RTU通信。

    新版本 Modbus RTU指令所支持的PTP模块如下图2.所示:

    b904c5c4519b2190111c159b0648fd36.png

    图2. 新版本 Modbus RTU指令所支持的PTP模块 新版本Modbus RTU指令的使用

    新版本Modbus RTU指令中包含Modbus RTU 主站指令和从站指令。本文以 CPU1217C+CM1241 RS422/485+ET200SP CM PTP 模块为例,介绍新版本 Modbus RTU 指令主从通信的编程步骤。

    其中CPU 机架CM1241 RS422/485作为Modbus RTU从站,分布式机架ET200SP 中 CMPTP 模块作为Modbus RTU主站。网络结构图如下:

    e31b2a0c3690ae65170a3ab223e74d97.png

    图3. Modubus RTU 网络通信结构图本项目中使用到的硬件和软件如下:

    硬件:

    ① CPU1217C (订货号: 6ES7 217-1AG40-0XB0),固件版本V4.1.3

    ② CM1241 RS422/485模块 (订货号:6ES7 241-1CH32-0XB0),固件版本V2.1

    ③ 24V 电源PS307(订货号:6ES7307-1KA02-0AA0)

    ④ ET200 SP IM155-6PN HF(订货号:6ES7155-6AU00-0CN0)

    ⑤ CM PTP模块(订货号:6ES7137-6AA00-0BA0)

    软件:

    ① TIA V13 SP1 UP 9

    1.设备组态

    a.组态CM1241 RS422/485模块

    打开设备视图,添加S7-1200CPU,并在硬件目录里找到“通信模块”→“点到点”→“CM1241(RS422/485)”,拖拽此模块至CPU左侧即可,如下图4.所示:

    70dd3d2abad67f807df0e3686d7f20ef.png

    图4. 添加 CM 1241 RS422/485模块

    注意:

    固件版本>=V2.1 的CM 1241 RS422/485模块,才支持新版本Modbus RTU指令。

    接下来,在“设备视图”中用鼠标选中CM1241(RS422/485)模块,在“属性”→“端口组态”中配置此模块硬件接口参数,

    本例以传输率=9.6Kbps,奇偶校验=无奇偶校验,数据位=8位字符,停止位=1为例。如CM 1241 端口组态设置如下图5.所示:

    08f0b1f5bea69a077e76c135357387b3.png

    图5. CM1241 RS422/485 模块端口组态

    最后在“硬件标识符”里确认一下硬件标识符为269(该参数在程序编程中会被使用),如下图6.所示:

    1250441973f810e93d220fa6360f83d5.png

    图6 硬件标识符

    另外,S7-1200 还提供了系统和时钟存储器功能,为了便于后续指令,建议使能该功能。在CPU “属性”→“常规”→“系统和时钟存储器”使能系统和时钟存储器功能,如图7. 所示。

    bb086834e52a761baddf029950fb2e5f.png

    图7. 系统和时钟存储器功能

    b.组态ET200 SP CM PtP 模块

    (1)、插入一个ET200SP分布式站点。

    打开网络视图并拖入一个ET200SP站点,并将其分配给相应的IO 控制器(本例CPU1217C 为 IO 控制器),如图8.所示。

    f48a2d5284111fb09672d63cd5221dd0.png

    图8. 插入ET200SP站点

    (2)、组态ET200SP 站点。

    在ET200SP的"设备视图"环境下,为ET200SP 站点添加信号、通信模块和服务器模块,在本例中只添加了CM PTP模块和服务器模块。

    注意:

    ET200SP站点中,服务器模块是必须组态的。服务器模块随接口模块一起采购,无需单独购买。

    ET200SP接口模块需要为其分配IP地址和Device Name, 有关ET200 SP 分布式IO 组态详细步骤,请参考《ET200 SP 使用快速入门》,本例不再描述Profinet IO通信的相关设置与步骤。

    在ET200SP"设备视图"中用鼠标选中CM PTP,在“属性”→“常规”→“接口”→“操作模式”中配置此模块硬件接口参数,

    本例设定“指定工作模式":"半双工(RS485)2线制操作";"接收线路的初始状态":"无"。如下图9.所示:

    7077b406679fe9049aa5c47638b83c92.png

    图9. CM PTP 操作模式

    接下来,在“属性”→“常规”→“接口”→“端口组态”中配置此模块端口组态参数,

    本例设定"协议":"Freeport/Modbus";"端口参数"设置:传输率=9.6Kbps,奇偶校验=无奇偶校验,数据位=8位字符,停止位=1为例。端口组态设置如下图10.所示:

    ab002c64d4b291f26bc35de24d992851.png

    图10. CM PTP 端口组态

    最后需要在“硬件标识符”里确认一下CM PTP 模块硬件标识符,该参数在程序编程中会被使用。

    2.软件编程

    a.Modbus RTU 主站编程

    Modbus RTU主站编程需要调用Modbus_Comm_Load 指令和Modbus_Master 指令,其中Modbus_Comm_Load 指令通过 Modbus RTU 协议对通信模块进行组态,Modbus_Master 指令可通过由 Modbus_Comm_Load 指令组态的端口作为 Modbus 主站进行通信, Modbus_Comm_Load 指令的 MB_DB 参数必须连接到 Modbus_Master 指令的(静态)MB_DB 参数。

    本例中分布式机架ET200SP 中 CM PTP 模块作为Modbus RTU主站,其相关编程步骤如下:

    (1)、OB1 中插入一个FC函数,并在函数中拖入Modbus_Comm_Load 指令和Modbus_Master 指令。如图11. 所示

    151a5565e30cc781cb1d1f86b5bce387.png

    图11. 拖入Modbus RTU 主站指令

    Modbus_Comm_Load指令各参数意义如下表1所示:

    a36f8dbe72f2167669f9d061430f566a.png

    表1 MB_COMM_LOAD指令参数意义

    Modbus_Master指令各参数意义如下表2所示:

    850962736bb88955d6aa4b34b3c28328.png

    表2 Modbus_Master指令参数意义

    注意:

    ①Modbus_Comm_Load指令不建议在启动组织块OB100中调用,建议在OB1中调用。Modbus_Comm_Load指令在OB1中调用时,其输入位“REQ”需使用上升沿触发,本例中该输入位采用 “FirstScan” 系统存储器位。

    ②Modbus_Comm_Load指令背景数据块中的静态变量“MODE”用于描述PTP模块的工作模式,有效的工作模式包括:

    • 0 = 全双工 (RS232)
    • 1 = 全双工 (RS422) 四线制模式(点对点)
    • 2 = 全全双工 (RS 422) 四线制模式(多点主站,CM PtP (ET 200SP))
    • 3 = 全全双工 (RS 422) 四线制模式(多点从站,CM PtP (ET 200SP))
    • 4 = 半双工 (RS485) 二线制模式

    该静态变量“MODE”默认数据为0(RS232 全双工模式),需要根据CM PTP模块实际组态修改该数值,本例中CM PTP模块工作在RS485半双工模式需要将该数值修改为4,如图12.所示。

    93599a12368c447a54a49e0b164ea2f6.png

    图12. Modbus_Comm_Load背景数据块静态变量“MODE”修改为4

    ③Modbus_Master指令的“DATA_PTR”参数用于指向要进行数据写入或数据读取的数据区域地址,该数据区域支持优化访问的数据块或者非优化(标准的)数据块,建议采用非优化访问的数据块。

    本例中使用的数据区为非优化访问的数据块,在数据块的属性中取消“优化的块访问”即可将数据块修改为非优化访问的数据块(鼠标右键数据块,选择“属性”,取消“优化的块访问”),如图13. 所示。

    0984bbccee7282ed2bd6e321f013b69f.png

    图13. 设置数据块为非优化访问

    当Modbus_Master指令的“DATA_PTR”指向非优化访问的数据块时,该输入参数需要使用指针方式填写如P#DB3.DBX0.0 WORD 5 方式填写。

    ④当Modbus RTU网络中存在多个modbus RTU从站或一个modbus RTU从站同时需要读操作和写操作,则需要调用多个Modbus_Master指令,Modbus_Master指令之间需要采用轮询方式调用。

    下图14. 用于描述两个Modbus_Master指令轮询调用的方式。

    7c4fdda55713d186d08d62b0e45482a7.png

    图14.Modbus_Master轮询调用方式

    (2)、插入"Pull or plug of modules" 中断OB83。

    本例中Modbus RTU主站模块安装在分布式IO站点上,因此程序中需要考虑分布式IO站点故障、CM PTP 模块插拔模块等故障。

    分布式IO站点中插出、拔入模块时,操作系统都会调用一次OB83。通过OB83接口区的输入变量“16#Event_Class”判断故障的模块和类型:事件类型16#39表示模块被拔出,事件类型16#38表示模块被插入。

    CM PTP 模块被重新插入的时候,需要在中断OB83中调用Modbus_Comm_Load 指令对通信模块进行重新组态,如图15. 所示。

    de00d6847a47fbda71150135078717a5.png

    图15. OB83中再次调用Modbus_Comm_Load 指令

    注意:

    ①OB83 中调用Modbus_Comm_Load指令的背景数据块需要与OB1中调用的Modbus_Comm_Load指令的背景数据块相同。

    ②CM PTP模块的硬件标识符也可以在"PLC变量"--->"系统常数"中查询,如图16. 所示。

    554391c071da1e1f12e75ff88b3ef20f.png

    图16. 系统常量

    (3)、插入"Rack or Station failure" 中断OB86。

    分布式IO站点故障和恢复时,操作系统都会调用一次OB86。通过OB86接口区的输入变量“16#Event_Class”判断故障的模块和类型:事件类型16#39表示站点故障,事件类型16#38表示站点恢复。

    CM PTP 模块所在的IO站点恢复时,需要在中断OB86中调用Modbus_Comm_Load 指令对通信模块进行重新组态,如图17. 所示。

    f1e33ec0012df795a952d84ffb7da1e8.png

    图17. OB86中调用Modbus_Comm_Load 指令

    注意:

    ①OB86 中调用Modbus_Comm_Load指令的背景数据块需要与OB1中调用的Modbus_Comm_Load指令的背景数据块相同。

    ②分布式IO 站点的硬件标识符也可以在"PLC变量"--->"系统常数"中查询。

    b.Modbus RTU 从站编程

    Modbus RTU从站编程需要调用Modbus_Comm_Load 指令和Modbus_Slave 指令,其中Modbus_Comm_Load 指令通过 Modbus RTU 协议对通信模块进行组态,Modbus_Slave 指令可通过由 Modbus_Comm_Load 指令组态的端口作为 Modbus 从站进行通信, Modbus_Comm_Load 指令的 MB_DB 参数必须连接到 Modbus_Slaver 指令的(静态)MB_DB 参数。

    本例中CPU 机架CM1241 RS422/485作为Modbus RTU从站,其相关编程步骤如下:

    OB1 中插入一个FC函数,并在函数中拖入Modbus_Comm_Load 指令和Modbus_Slave 指令。如图18. 所示

    19b3fd964feb498e402974821b7d2e30.png

    图18. 拖入Modbus RTU 从站指令

    Modbus_Slave指令各参数意义如下表3所示:

    e4e6a7040fd9fcf488e4c69891d3b8f8.png

    表3 Modbus_Slave指令参数意义

    注意:

    ①Modbus_Comm_Load指令不建议在启动组织块OB100中调用,建议在OB1中调用。Modbus_Comm_Load指令在OB1中调用时,其输入位“REQ”需使用上升沿触发,本例中该输入位采用 “FirstScan” 系统存储器位。

    ②Modbus_Comm_Load指令背景数据块中的静态变量“MODE”用于描述PTP模块的工作模式,有效的工作模式包括:

    • 0 = 全双工 (RS232)
    • 1 = 全双工 (RS422) 四线制模式(点对点)
    • 2 = 全全双工 (RS 422) 四线制模式(多点主站,CM PtP (ET 200SP))
    • 3 = 全全双工 (RS 422) 四线制模式(多点从站,CM PtP (ET 200SP))
    • 4 = 半双工 (RS485) 二线制模式

    该静态变量“MODE”默认数据为0(RS232 全双工模式),需要根据CM1241 RS422/485模块实际组态修改该数值,本例中CM1241 RS422/485模块工作在RS485半双工模式需要将该数值修改为4,如何修改“MODE”静态变量见图12.所示。③Modbus_Slave指令的“MB_HOLD_REG”用于指向Modbus 保持寄存器的数据区域地址,该数据区域支持优化访问的数据块或者非优化(标准的)数据块,建议采用非优化访问的数据块。

    本例中使用的数据区为非优化访问的数据块,固该输入参数需要使用指针方式填写如P#DB6.DBX0.0 WORD 100 方式填写。

    如何在数据块的属性中取消“优化的块访问”,见图13. 所示。

    将程序下载到PLC中,并使用Profibus DP通信电缆将CM1241 RS422/485与CM PTP串口模块连接起来,即可测试Modbus RTU通信了。

    3.常见问题FAQ

    1. 新版本 Modbus RTU指令的使用是否存在些限制条件?

    新版本 Modbus RTU指令通过CM1241通信模块或CB1241通信板进行Modbus RTU通信时,需要满足如下条件:

    a. S7-1200 CPU 的固件版本不能低于V4.1;

    b. CM1241通信模块或CB1241通信板的固件不能低于V2.1。

    S7-1200 V4.0 固件CPU可以通过固件更新到V4.1版本,V2.0固件的CM1241通信模块也可以通过固件更新的方式更新到V2.1版本。

    相关固件更新的方法请参考 S7-1200 固件更新 。

    2 .Modbus_Comm_Load指令背景数据块中的静态变量“MODE”的作用是什么?为什么一般项目中,都需要对该变量进行修改?

    新版本的 Modbus RTU指令扩展了Modbus RTU的功能,该指令除了支持CM1241通信模块、CB1241通信板还支持 PROFINET 或 PROFIBUS 分布式 I/O 机架上的PTP通信模块实现Modbus RTU通信。

    而分布式 I/O 机架上的PTP通信模块可以支持多种工作模式,以ET200SP CM PtP模块(订货号:6ES7137-6AA00-0BA0)为例,其可以支持RS232、RS485以及RS422等多种工作模式。

    Modbus_Comm_Load指令背景数据块中的静态变量“MODE”则用于定义PTP模块的工作模式。

    “MODE”的默认数值为0,代表“全双工 (RS232)”工作模式,实际项目组态中则需要根据实际工作模式对该变量进行修改。

    3. Modbus_Comm_Load指令能否在启动组织块OB100中调用?

    Modbus_Comm_Load指令不建议在启动组织块OB100中调用。新版本的Modbus RTU指令扩展了Modbus RTU的功能,该指令支持 PROFINET 或 PROFIBUS 分布式 I/O 机架上的PtP通信模块实现Modbus RTU通信。

    操作系统需要调用读取数据记录和写入数据记录等指令来实现与分布式I/O机架上PtP模块的Modbus RTU通信。读取数据记录和写入数据记录指令为异步读写指令,指令的执行需要N个扫描周期,所以不建议Modbus_Comm_Load指令在启动组织块OB100中调用。

    4. 如何查询Modbus RTU通信错误时的错误代码?

    以Modbus_Master指令为例,当通信出现错误时,Modbus_Master指令的“ERROR”输出位将变为 TRUE 但是只保持一个扫描周期,所以通过TIA 软件程序监控时无法查询到错误。

    Modbus_Master指令“STATUS” 参数中的错误代码仅在“ERROR” = TRUE 的扫描周期内有效,为了获取了Modbus RTU通信错误的错误代码我们可以采用下图19. 方式编程。

    cdc547ec2faf7014dfe1766041890e63.png

    图19. 获取STATUS

    展开全文
  • ModBus RTU-通讯测试软件
  • Modbus RTU

    2018-07-27 09:50:54
    Modbus协议是主从站通讯协议,用异步串行口完成通讯,...其他特性属于用户可选的,如传输介质、波特率、字符奇偶校验、停止位的个数等等,传输模式为RTU。用户所选择的参数对于各个站必须一致,在系统运行时不能改变。
  • MODBUS RTU

    2018-06-30 11:48:53
    40000之后的数据显示出来,读用0x03,写用0x06和0x10命令,完全参数化显示,为个人原创,非网络上可以下载的,和常见的软件差异化很大。需要认真阅读说明后才能使用。有任何疑问可以留言沟通
  • FreeModbus RTU是开源的一个协议,并且使用FreeModbus RTU 只能当做从机Slave,RTU协议中的指令由地址码(一个字节),功能码(一个字节),起始地址(两个字节),数据(N个字节),校验码(两个字节)五个部分组成...

    一、FreeModbus RTU 协议数据格式

    FreeModbus RTU是开源的一个协议,并且使用FreeModbus RTU 只能当做从机Slave,RTU协议中的指令由地址码(一个字节),功能码(一个字节),起始地址(两个字节),数据(N个字节),校验码(两个字节)五个部分组成,其中数据又由数据长度(两个字节,表示的是寄存器个数,假定内容为M)和数据正文(M乘以2个字节)组成,而RTU协议是采用3.5个字节的空闲时间作为指令的起始和结束。

    1100486-20180130105750921-1307916875.png

    Modbus 数据的请求及应答

    1100486-20180130110013265-1433529525.png

    其中3.5个字节的空闲时间是指从接收到第一个字节数据到最后一个字节数据所有的时间,如下所示程序中是50us的定时时基,

    那么3.5个字节的空闲时间 = 50us * usTimerT35_50us

     /* If baudrate > 19200 then we should use the fixed timer values
             * t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
             */
            if( ulBaudRate > 19200 )
            {
                usTimerT35_50us = 35;       /* 1800us. */
            }
            else
            {
                /* The timer reload value for a character is given by:
                 *
                 * ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )
                 *             = 11 * Ticks_per_1s / Baudrate
                 *             = 220000 / Baudrate
                 * The reload for t3.5 is 1.5 times this value and similary
                 * for t3.5.
                 */
                usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
            }

    调试modbus 工具

    Modbus 调试精灵或者Modbus Poll模拟当做 主机
    Modbus Slave 模拟当做 从机

    http://www.modbustools.com/download.html//工具下载

    二、参考文档

    Modbus 协议文档

    http://www.modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf

    http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf

    FreeModbus Slave

    //FreeModbus 源代码:

    https://sourceforge.net/projects/freemodbus.berlios/files/

    //FreeModbus 移植参考:

    https://www.dhlx.wang/STM32F411VET6/Porting_FreeModbus_to_STM32F411VET6_based_on_STM32CubeF4.html

    http://blog.csdn.net/dldw8816/article/details/44563749

    http://blog.csdn.net/liu236141068/article/details/51841245

    Modbus RTU Master

    //移植源代码

    https://github.com/LittleBigQi/ModBus-Master

    https://github.com/4-20ma/ModbusMaster

    by 羊羊得亿
    2018-01-30 ShenZhen

    转载于:https://www.cnblogs.com/yangxuli/p/8384028.html

    展开全文
  • 本文章使用modbus4j和rxtxcomm进行modbus rtu通讯串口通讯:rxtxcomm的使用:下载地址:http://fizzed.com/oss/rxtx-for-javarxtx解压包中的rxtxParallel.dll,rxtxSerial.dll 这两个文件复制到C:\Windows\System32 ...

    本文章使用modbus4j和rxtxcomm进行modbus rtu通讯

    串口通讯:rxtxcomm的使用:

    下载地址:http://fizzed.com/oss/rxtx-for-java

    rxtx解压包中的 rxtxParallel.dll,rxtxSerial.dll 这两个文件复制到 C:\Windows\System32 目录下

    添加maven依赖

    false

    true

    ias-snapshots

    Infinite Automation Snapshot Repository

    https://maven.mangoautomation.net/repository/ias-snapshot/

    true

    false

    ias-releases

    Infinite Automation Release Repository

    https://maven.mangoautomation.net/repository/ias-release/

    org.bidib.jbidib.org.qbang.rxtx

    rxtxcomm

    2.2

    com.infiniteautomation

    modbus4j

    3.0.4

    Modbus4j工具类

    package com.example.modbus_rtu;

    import java.util.ArrayList;

    import java.util.List;

    import com.serotonin.modbus4j.BatchRead;

    import com.serotonin.modbus4j.BatchResults;

    import com.serotonin.modbus4j.ModbusFactory;

    import com.serotonin.modbus4j.ModbusMaster;

    import com.serotonin.modbus4j.code.DataType;

    import com.serotonin.modbus4j.exception.ErrorResponseException;

    import com.serotonin.modbus4j.exception.ModbusInitException;

    import com.serotonin.modbus4j.exception.ModbusTransportException;

    import com.serotonin.modbus4j.ip.IpParameters;

    import com.serotonin.modbus4j.locator.BaseLocator;

    public class ModbusUtils {

    /**

    * 工厂。

    */

    static ModbusFactory modbusFactory;

    static {

    if (modbusFactory == null) {

    modbusFactory = new ModbusFactory();

    }

    }

    /**

    * 获取master

    *

    * @return

    * @throws ModbusInitException

    */

    public static ModbusMaster getMaster(String host, int port) throws ModbusInitException {

    IpParameters params = new IpParameters();

    params.setHost(host);

    params.setPort(port);

    //

    // modbusFactory.createRtuMaster(wapper); //RTU 协议

    // modbusFactory.createUdpMaster(params);//UDP 协议

    // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议

    ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议

    master.init();

    return master;

    }

    public static ModbusMaster getRtuIpMaster(String host, int port) throws ModbusInitException {

    IpParameters params = new IpParameters();

    params.setHost(host);

    params.setPort(port);

    //这个属性确定了协议帧是否是通过tcp封装的RTU结构,采用modbus tcp/ip时,要设为false, 采用modbus rtu over tcp/ip时,要设为true

    params.setEncapsulated(true);

    ModbusMaster master = modbusFactory.createTcpMaster(params, false);

    try {

    //设置超时时间

    master.setTimeout(1000);

    //设置重连次数

    master.setRetries(3);

    //初始化

    master.init();

    } catch (ModbusInitException e) {

    e.printStackTrace();

    }

    return master;

    }

    public static ModbusMaster getRtuComMaster(String com,int port) throws ModbusInitException {

    //

    // modbusFactory.createRtuMaster(wapper); //RTU 协议

    // modbusFactory.createUdpMaster(params);//UDP 协议

    // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议

    ModbusMaster master = modbusFactory.createRtuMaster(new SerialPortWrapperImpl(com,port));

    master.setTimeout(2000);

    master.init();

    return master;

    }

    /**

    * 读取[01 Coil Status 0x]类型 开关数据

    *

    * @param slaveId slaveId

    * @param offset 位置

    * @return 读取值

    * @throws ModbusTransportException 异常

    * @throws ErrorResponseException 异常

    * @throws ModbusInitException 异常

    */

    public static Boolean readCoilStatus(ModbusMaster master, int slaveId, int offset)

    throws ModbusTransportException, ErrorResponseException, ModbusInitException {

    // 01 Coil Status

    BaseLocatorloc = BaseLocator.coilStatus(slaveId, offset);

    Boolean value = master.getValue(loc);

    return value;

    }

    /**

    * 读取[02 Input Status 1x]类型 开关数据

    *

    * @param slaveId

    * @param offset

    * @return

    * @throws ModbusTransportException

    * @throws ErrorResponseException

    * @throws ModbusInitException

    */

    public static Boolean readInputStatus(ModbusMaster master, int slaveId, int offset) throws ModbusTransportException, ErrorResponseException {

    // 02 Input Status

    BaseLocatorloc = BaseLocator.inputStatus(slaveId, offset);

    Boolean value = master.getValue(loc);

    return value;

    }

    /**

    * 读取[03 Holding Register类型 2x]模拟量数据

    *

    * @param slaveId slave Id

    * @param offset 位置

    * @param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType

    * @return

    * @throws ModbusTransportException 异常

    * @throws ErrorResponseException 异常

    * @throws ModbusInitException 异常

    */

    public static Number readHoldingRegister(ModbusMaster master, int slaveId, int offset, int dataType)

    throws ModbusTransportException, ErrorResponseException, ModbusInitException {

    // 03 Holding Register类型数据读取

    BaseLocatorloc = BaseLocator.holdingRegister(slaveId, offset, dataType);

    Number value = master.getValue(loc);

    return value;

    }

    /**

    * 读取[04 Input Registers 3x]类型 模拟量数据

    *

    * @param slaveId slaveId

    * @param offset 位置

    * @param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType

    * @return 返回结果

    * @throws ModbusTransportException 异常

    * @throws ErrorResponseException 异常

    * @throws ModbusInitException 异常

    */

    public static Number readInputRegisters(ModbusMaster master, int slaveId, int offset, int dataType)

    throws ModbusTransportException, ErrorResponseException, ModbusInitException {

    // 04 Input Registers类型数据读取

    BaseLocatorloc = BaseLocator.inputRegister(slaveId, offset, dataType);

    Number value = master.getValue(loc);

    return value;

    }

    /**

    * 批量读取使用方法

    *

    * @throws ModbusTransportException

    * @throws ErrorResponseException

    * @throws ModbusInitException

    */

    public static ListbatchRead(ModbusMaster master, ArrayListdata) throws ModbusTransportException, ErrorResponseException, ModbusInitException {

    BatchReadbatch = new BatchRead();

    for (int i=0;inumbers = new ArrayList<>();

    batch.setContiguousRequests(false);

    BatchResultsresults = master.send(batch);

    for (int i=0;i

    写数据:

    import com.serotonin.modbus4j.ModbusFactory;

    import com.serotonin.modbus4j.ModbusMaster;

    import com.serotonin.modbus4j.exception.ErrorResponseException;

    import com.serotonin.modbus4j.exception.ModbusInitException;

    import com.serotonin.modbus4j.exception.ModbusTransportException;

    import com.serotonin.modbus4j.msg.*;

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    public class Modbus4jWriteUtils {

    static Log log = LogFactory.getLog(Modbus4jWriteUtils.class);

    /**

    * 工厂。

    */

    static ModbusFactory modbusFactory;

    static {

    if (modbusFactory == null) {

    modbusFactory = new ModbusFactory();

    }

    }

    /**

    * 写 [01 Coil Status(0x)]写一个 function ID = 5

    *

    * @param slaveId slave的ID

    * @param writeOffset 位置

    * @param writeValue 值

    * @return 是否写入成功

    * @throws ModbusTransportException

    * @throws ModbusInitException

    */

    public static boolean writeCoil(ModbusMaster master, int slaveId, int writeOffset, boolean writeValue)

    throws ModbusTransportException, ModbusInitException {

    // 获取master

    ModbusMaster tcpMaster = master;

    // 创建请求

    WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);

    // 发送请求并获取响应对象

    WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);

    if (response.isException()) {

    return false;

    } else {

    return true;

    }

    }

    /**

    * 写[01 Coil Status(0x)] 写多个 function ID = 15

    *

    * @param slaveId slaveId

    * @param startOffset 开始位置

    * @param bdata 写入的数据

    * @return 是否写入成功

    * @throws ModbusTransportException

    * @throws ModbusInitException

    */

    public static boolean writeCoils(ModbusMaster master, int slaveId, int startOffset, boolean[] bdata)

    throws ModbusTransportException, ModbusInitException {

    // 获取master

    ModbusMaster tcpMaster = master;

    // 创建请求

    WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);

    // 发送请求并获取响应对象

    WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);

    if (response.isException()) {

    return false;

    } else {

    return true;

    }

    }

    /***

    * 写[03 Holding Register(4x)] 写一个 function ID = 6

    *

    * @param slaveId

    * @param writeOffset

    * @param writeValue

    * @return

    * @throws ModbusTransportException

    * @throws ModbusInitException

    */

    public static boolean writeRegister(ModbusMaster master, int slaveId, int writeOffset, short writeValue)

    throws ModbusTransportException, ModbusInitException {

    // 获取master

    ModbusMaster tcpMaster = master;

    // 创建请求对象

    WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);

    WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);

    if (response.isException()) {

    log.error(response.getExceptionMessage());

    return false;

    } else {

    return true;

    }

    }

    /**

    * 写入[03 Holding Register(4x)]写多个 function ID=16

    *

    * @param slaveId modbus的slaveID

    * @param startOffset 起始位置偏移量值

    * @param sdata 写入的数据

    * @return 返回是否写入成功

    * @throws ModbusTransportException

    * @throws ModbusInitException

    */

    public static boolean writeRegisters(ModbusMaster master, int slaveId, int startOffset, short[] sdata)

    throws ModbusTransportException, ModbusInitException {

    // 获取master

    ModbusMaster tcpMaster = master;

    // 创建请求对象

    WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);

    // 发送请求并获取响应对象

    ModbusResponse response = tcpMaster.send(request);

    if (response.isException()) {

    log.error(response.getExceptionMessage());

    return false;

    } else {

    return true;

    }

    }

    /**

    * 写入数字类型的模拟量(如:写入Float类型的模拟量、Double类型模拟量、整数类型Short、Integer、Long)

    *

    * @param slaveId

    * @param offset

    * @param value

    * 写入值,Number的子类,例如写入Float浮点类型,Double双精度类型,以及整型short,int,long

    * @param registerCount

    * ,com.serotonin.modbus4j.code.DataType

    * @throws ModbusTransportException

    * @throws ErrorResponseException

    * @throws ModbusInitException

    */

    }

    SerialPortWrapper 实现类

    package com.example.modbus_rtu;

    import com.serotonin.modbus4j.serial.SerialPortWrapper;

    import gnu.io.CommPortIdentifier;

    import gnu.io.PortInUseException;

    import gnu.io.SerialPort;

    import gnu.io.UnsupportedCommOperationException;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

    import java.util.Enumeration;

    public class SerialPortWrapperImpl implements SerialPortWrapper {

    //枚举类型

    EnumerationportList;

    // 检测系统可用端口

    private CommPortIdentifier portIdentifier;

    // 端口

    private SerialPort comPort;

    //波特率

    private int port;

    //Com地址

    private String com;

    // 输入/输出流

    private InputStream inputStream;

    private OutputStream outputStream;

    public SerialPortWrapperImpl(String com,int port){

    this.com = com;

    this.port = port;

    }

    @Override

    public void close() throws Exception {

    }

    @Override

    public void open() throws Exception {

    //获得系统支持的所有端口(串口,并口)

    portList = CommPortIdentifier.getPortIdentifiers();

    while(portList.hasMoreElements()) {

    portIdentifier = (CommPortIdentifier)portList.nextElement();

    // CommPortIdentifier.PORT_SERIAL :串口

    // CommPortIdentifier.PORT_PARALLEL :并口

    // CommPortIdentifier.PORT_RS485 :RS485

    // CommPortIdentifier.PORT_I2C :I2C

    // CommPortIdentifier.PORT_RAW

    if (portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL) {

    // System.out.println(portIdentifier.getName()); 获取串口名字

    if (portIdentifier.getName().equals(this.com)) {

    try {

    // open:打开串口,第一个参数应用程序名称 字符串可随意填写,第二个参数阻塞时等待多少毫秒

    comPort = (SerialPort)portIdentifier.open(this.com, 2000);

    // 串口设置监听

    // port.addEventListener(this);

    // 设置可监听

    comPort.notifyOnDataAvailable(true);

    // 设置串口通信参数

    // 波特率,数据位,停止位,校验方式

    comPort.setSerialPortParams(port,

    SerialPort.DATABITS_8,

    SerialPort.STOPBITS_1,

    SerialPort.PARITY_NONE);

    outputStream = comPort.getOutputStream();

    inputStream = comPort.getInputStream();

    System.out.println("打开串口成功");

    } catch (PortInUseException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }catch (UnsupportedCommOperationException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    } catch (IOException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }catch (Exception e){

    e.printStackTrace();

    }

    }

    }

    }

    }

    @Override

    public InputStream getInputStream() {

    return inputStream;

    }

    @Override

    public OutputStream getOutputStream() {

    return outputStream;

    }

    @Override

    public int getBaudRate() {

    return 0;

    }

    @Override

    public int getFlowControlIn() {

    return 0;

    }

    @Override

    public int getFlowControlOut() {

    return 0;

    }

    @Override

    public int getDataBits() {

    return 0;

    }

    @Override

    public int getStopBits() {

    return 0;

    }

    @Override

    public int getParity() {

    return 0;

    }

    }

    测试类

    public class Test {

    public static void main(String[] args){

    //modbus rtu

    try {

    ModbusMaster master = ModbusUtils.getRtuComMaster("COM4",9600);

    while (true){

    System.out.println(ModbusUtils.readHoldingRegister(master,1,14, DataType.FOUR_BYTE_FLOAT));

    System.out.println(ModbusUtils.readHoldingRegister(master,1,16, DataType.FOUR_BYTE_FLOAT));

    }

    } catch (ModbusInitException e) {

    e.printStackTrace();

    } catch (ModbusTransportException e) {

    e.printStackTrace();

    } catch (ErrorResponseException e) {

    e.printStackTrace();

    }

    }

    }

    展开全文
  • STM32移植FreeModbus RTU从机教程1(ModbusRTU协议简要说明)ModbusRTU说明RTU模式特点及基本术语、公共功能码Modbus RTU通信报文格式 ModbusRTU说明 Modbus 协议是应用于电子控制器上的一种通用语言, 实现控制器...

    STM32移植FreeModbus RTU从机教程1(ModbusRTU协议简要说明)

    ModbusRTU说明

    Modbus 协议是应用于电子控制器上的一种通用语言, 实现控制器之间、控制器由网络和其
    它设备之间的通信,支持传统的RS232/RS422/RS485 和最新发展的以太网设备,最常用的是
    TIA/EIA-485 (RS485) 两线制接口。它已经成为一种通用工业标准。有了它, 不同厂商生产的控制设备可以连成工业网络, 进行集中控制。此协议定义了一个控制器能认识使用的消息结构。
    Modbus 协议是一种请求——应答方式的协议。
    有两种串行传输模式分为ASCII与RTU两种模式,通常使用RTU(Remote Terminal Unit)模式。

    RTU模式特点及基本术语、公共功能码

    1. RTU模式特点
      ① 消息中每个8bit 字节包含两个4bit 的十六进制字符,因此,在波特率相同的情况下,传输效率比ascii 传输方式大
      ② 1 个起始位、8 个数据位、1 个奇偶校验位和1 个停止位(或者两个停止位)
      ③ 错误检测域是CRC 检验
      ④ 消息发送至少要以3.5 个字符时间的停顿间隔开始。整个消息帧必须作为一连续的流传输。如果在帧完成之前有超过1.5 个字符时间的停顿时间, 接收设备将刷新不完整的消息并假定下一个字节是一个新消息的地址域。同样地, 如果一个新消息在小于3.5 个字符时间内接着前个消息开始,接收的设备将认为它是前一消息的延续。1.5~3.5 个字符间隔就算接收异常,只有超过3.5 个字符间隔才认为帧结束。

    2. 基本术语 ,字word 、字节byte 、位bit
      1 word = 2 byte;
      1 byte = 8 bit.;
      CRC校验码:校验码是由前面的数据通过某种算法得出的,用以检验该组数据的正确性。

    3. 公共功能码及相关寄存器地址
      MODBUS 数据模型有四种,通过不同的功能码来读写这些数据对象。

    对象类别 对象类型 访问类型 内容说明
    离散量输入 单个bit 只读 相当于开关量,每个bit对应一个开关信号状态(只能读取输入的开关量,无法通过应用程序进行更改,列如读取外部拨码开关的值。)
    线圈 单个bit 读写 相当于开关量,每个bit对应一个开关信号状态(可进行读写,列如通过1byte可控制8个IO口输出高低电平,此8个IO口电平可控可读)
    输入寄存器 16bit 只读 I/O 系统提供这种类型数据(无法通过应用程序进行更改的外部设备模拟量数据,如温度、气体浓度值等)
    保持寄存器 16bit 读写 通过应用程序改变这种类型数据(例如可通过应用程序进行读写的当前设备RTC时钟值、设备运行模式等。)

    常用的功能码有:01H、02H、03H、04H、05H、06H、0FH、10H。
    但在实际应用中, 厂家通常会根据实用性做些变通,但并不影响数据的读写,如当前设备开关量较少的情况下,将离散量输入值(如读取到的拨码开关8421码)归入04H输入寄存器中,将线圈开关量(输出高低电平控制继电器的通断)读写归入03H 06H 10H保持寄存器中。
    最常用的功能码有:03H、04H、06H、10H。

    Modbus 协议定义的寄存器地址是5 位十进制地址,即:
    线圈( DO)地址: 00001~09999
    触点( DI)地址: 10001~19999
    输入寄存器( AI)地址: 30001~39999
    输出寄存器( AO)地址: 40001~49999

    由于上述各类地址是唯一对应的,因此有些资料就以其第一个数字区分各类地址,
    即: 0x 代表线圈( DO)类地址, 1x 代表触点( DI)类地址、3x 代表输入寄存器( AI)类地
    址、4x 代表输出寄存器( AO)类地址。
    在实际编程中, 由于前缀的区分作用, 所以只需说明后4 位数, 而且需转换为4 位十六进制地址。*

    Modbus 协议中寄存器地址从1 开始,而实际存储中地址从0 开始。
    计算公式为:实际报文寄存器地址(16进制) = PLC地址位低四位(10进制) - 1;
    如要读取寄存器编号为40005 (4 为块编号, 5 为modbus 中寄存器地址)的寄存器的数据,则应把00 04 放入报文的地址域。

    功能码 描述 寄存器编号(10进制) 实际报文寄存器地址(16进制)
    01H 读线圈寄存器 00001~09999 0x0000~0xFFFF
    02H 读离散量输入寄存器 10001~19999 0x0000~0xFFFF
    03H 读保持寄存器 40001~49999 0x0000~0xFFFF
    04H 读输入寄存器 30001~39999 0x0000~0xFFFF
    05H 写单个线圈寄存器 00001~09999 0x0000~0xFFFF
    06H 写单个保持寄存器 40001~49999 0x0000~0xFFFF
    0FH 写多个线圈寄存器 00001~09999 0x0000~0xFFFF
    10H 写多个保持寄存器 40001~49999 0x0000~0xFFFF

    MODBUS功能码与Modbus 协议定义的寄存器地址对应关系:
    一般厂商的码表或者信息点表、地址映射表里面有相对地址(实际发送报文寄存器地址)及寄存器号(Modbus 协议定义的寄存器地址)的说明。

    地址位00001-09999 用01H/05H/0FH功能码读写,报文寄存器地址(即相对地址)为0x0000~0xFFFF
    地址位10001-19999 用02H功能码读取,报文寄存器地址(即相对地址)为0x0000~0xFFFF
    地址位30001-39999 用04H功能码读取,报文寄存器地址(即相对地址)为0x0000~0xFFFF
    地址位40001-49999 用03H/06H/10H功能码读取,报文寄存器地址(即相对地址)为0x0000~0xFFFF

    4. 最常用功能代码报文格式说明

    功能码03H
    描述:读保持寄存器。可读取单个或多个保持寄存器。报文格式如下+CRC校验低字节+CRC校验高字节
    在这里插入图片描述
    N=读取寄存器个数;
    在这里插入图片描述
    功能码04H
    描述:读输入寄存器命令。该命令支持单个寄存器访问也支持多个寄存器访问。报文格式如下+CRC校验低字节+CRC校验高字节
    在这里插入图片描述
    功能码06H
    描述:读输入寄存器命令。该命令支持单个寄存器访问也支持多个寄存器访问。报文格式如下+CRC校验低字节+CRC校验高字节
    在这里插入图片描述
    功能码10H
    描述:写多个保持寄存器。报文格式如下+CRC校验低字节+CRC校验高字节
    在这里插入图片描述

    Modbus RTU通信报文格式

    读数据:假如读40001 、40002 两个寄存器,假设从机地址为1

    从机地址范围: 1~247,0 为广播地址,占一个字节。
    理论上Modbus 协议可以接247 个从机,但若用于485 接口上则由于485 接口的限制,在没有中继情况下,最多可以接32 个从机。

    下行报文:

    从机地址 功能码 寄存器起始地址高字节 寄存器起始地址低字节 读取寄存器个数高字节 读取寄存器个数低字节 CRC校验低字节 CRC校验高字节
    0x01 0x03 0x00 0x00 0x00 0x02 0xC4 0x0B

    上行报文:

    从机地址 功能码 返回数据字节数 05寄存器数据高字节 05寄存器数据低字节 06寄存器数据高字节 06寄存器数据低字节 CRC校验低字节 CRC校验高字节
    0x01 0x03 0x04 0x00 0x00 0x0B 0xB8 0xFD 0x71

    写数据:假如向42001寄存器中写入数据 00 40,假设从机地址为1

    下行报文:

    从机地址 功能码 寄存器起始地址高字节 寄存器起始地址低字节 要写的数据高字节 要写的数据低字节 CRC校验低字节 CRC校验高字节
    0x01 0x06 0x07 0xD0 0x00 0x40 0x88 0xB7

    上行报文:

    从机地址 功能码 寄存器起始地址高字节 寄存器起始地址低字节 写入的数据高字节 写入的数据低字节 CRC校验低字节 CRC校验高字节
    0x01 0x06 0x07 0xD0 0x00 0x40 0x88 0xB7

    从机若正常返回,则功能不变,若错误返回,则功能码的最高位为1,且从机会将一独特的代码(错误代码由厂家定义说明)放到回应消息的数据域中, 以便于告诉主设备发生了什么错误。主设备应用程序得到异议的回应后, 典型的处理过程是重发消息, 或者诊断发给从设备的消息并报告给操作员。如03 功能码,错误返回为83 。
    设备异常返回信息(03功能码):01地址 + 03|0x80 + ErrCode + CRC
    如下表某厂家设备的错误代码说明:

    错误代码( ErrCode) 内容 说明
    0x00 成功 没有错误
    0x01 功能码错误 指定了不存在的功能代码。请确认功能代码。
    0x02 寄存器地址错误 指定了指定功能代码不能使用的寄存器号地址。
    0x03 数据值域错误 寄存器中被提交存储的数据项有一个应用程序期望之外的值
    0x04 写入失败 正在设法执行请求的操作时,产生不可重新获得的差错。
    展开全文
  • Modbus RTUModbus TCP模块,RS232/485转以太网模块,IBF102 (多功能高性价比串口服务器模块) 产品特点: ● Modbus RTU协议自动转换成Mobus TCP协议 ● 100M高速网卡,10/100M 自适应以太网接口 ● 支持 ...
  • ModBusTCP 和 ModBusRtu

    2020-10-11 00:42:55
    找了好多ModBus 的资源,只有这个可以真的用起来了。包含了ModBusTCP 和 ModBusRtu 两个部分。
  • java modbus rtu通讯

    2020-12-02 09:27:53
    demo内含有modbus rtu的通讯,主要使用了rxtxcommon和modbus 4j进行modbus rtu通讯。如有需要,请自行下载。
  • modbusRtu.zip

    2020-04-03 00:49:48
    最简单的Modbus RTU实现读写寄存器数值,实现了modbus RTU03和06功能码的功能,直接可以上手使用
  • modbus rtu.rar

    2020-03-07 07:58:25
    STM32F103 modbus rtu 从站协议,已测试多从站无错误STM32F103 modbus rtu 从站协议,已测试多从站无错误
  • DSP modbus rtu

    2018-11-22 20:39:08
    dsp28335 modbus rtu 通讯 亲测 可以用 , 简单 易懂
  • modbus rtu通讯

    2018-05-31 16:47:45
    modbus rtu通讯,有需要的同学可以下载来使用。是源码,没有废话。
  • Modbus RTU 协议

    2017-03-17 11:40:22
    Modbus RTU协议 完整版
  • 莫迪康ModbusRTU

    2018-09-21 10:12:52
    本驱动构件用于MCGS软件通过ModbusRTU协议读写Modicon PLC设备的各种寄存器的数据; 同时也可用于对支持ModbusRTU标准协议的各类PLC、仪表、控制器数据的读写。
  • ModBusRTU串口调试助手

    2020-09-26 10:59:40
    ModBusRTU串口调试助手,ModBusRTU,免安装, win10可用。Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。
  • Modbus RTU c#

    千次下载 热门讨论 2014-05-29 09:15:41
    Modbus Rtu c# 相关代码(CRC生成,数据发送,数据接收与验证)
  • ModbusRTU.zip

    2020-07-07 16:56:26
    Visual studio 2012 C#语言,ModbusRTU通信,读取保持寄存器的值,两个按钮,连接串口 读取数据
  • Proface-Modbus RTU.zip

    2021-03-23 09:39:29
    Proface-Modbus RTU
  • ModbusRTU通信协议

    2018-11-06 18:04:16
    ModbusRTU通信协议 简单易懂 。。。
  • Modbus RTU HMI 解决方案pdf,Modbus RTU HMI 解决方案
  • PC上位机和PLC Modbus rtu CRC计算
  • labview modbus rtu 主站源代码 可用于与MODBUS RTU 从站设备通讯 读取传感器参数等
  • Modbus协议包括ASCII、RTU、TCP等,并没有规定物理层。此协议定义了控制器能够认识和使用的消息结构,而不管它们是经过何种网络进行通信的。标准的Modicon控制器使用RS232C实现串行的ModbusModbus的ASCII、RTU协议...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,165
精华内容 1,266
热门标签
关键字:

modbusrtu