# Modbus Tcp Master操作手册

### 概述

Modbus 本身是一种信息交换的规范，Modbus TCP则是透过TCP/IP来实现Modbus 的一种方式，因此所有的信息都是通过TCP/IP来传输的；Modbus协议属于 C/S 架构，Modbus Tcp Master可以读写Rtu Slave的地址，实现数据交互；

使用场景

- 设备间数据采集和监控（如PLC与传感器、HMI的连接）。

- 过程自动化中的数据传输。

- 远程监控和控制系统。

整体架构

- 注： 本手册中用到的中科时代的软件包，均可以从官网的子页面获取。官网提供的版本可能比本手册中提到的版本更高，一般情况下这不会影响您按照本手册的例子执行相应的操作

- Modbus Tcp是透过TCP/IP来实现Modbus的一种方式，因此所有讯息是透过TCP/IP来传输的，Modbus Tcp Master可以对Slave发送读或者写的指令，Slave收到指令后会回复确认信息，整个Modbus的沟通建立在一来一回的讯息交换上；

- 下表概述了各个产品组件

| 产品组件 | 描述说明
--- | --- | ---
主站 | simodbusmaster_1.1.4_amd64.deb | Modbus tcp Master RTE组件
| SF4100_ModbusMaster_1.0.0.2.library | Modbus tcp Master Metafacture 库文件
从站 | modbusslave_1.1.3_amd64.deb | Modbus tcp Slave RTE组件
| sf4100_modbusslave_1.0.0.1.library | Modbus tcp Slave Metafacture 库文件

### 安装卸载

安装要求

- 中科时代出厂的工智机；

- 安装DeviceManager.exe (0.0.2.4)软件

安装过程

工智机端安装Modbus Tcp Master RTE组件

- 运行DeviceManager.exe 软件

- 安装ACP 服务（以工智机（192.168.105.20）为例），选择“在线安装”

- 选择工智机（192.168.105.20），点击“本地”，进入本地安装界面；

- 进入工智机设备管理器界面，点击"软件”下拉选择“组件管理”，进入“浏览页面”，选择"modbusmaster"查看安装版本并点击“安装”；

- 传输完成，弹窗选择确定安装；安装完成后，选择确认重启组件；

- 安装完成后，本地新增1.1.4版本的"modbusmaster"组件，

Metafacture安装library

- 打开Metafacture，点击“工具” -- “库存储”

- 点击“安装” -- 选中modbus master的库文件，点击“打开”

- 工程中点击“库管理器” -- “添加库” -- 选中modbus库点击“确定”

卸载过程

工智机端卸载Modbus Tcp Master RTE组件

- 进入工智机设备管理器->“组件管理界面”->"本地”，选择组件"modbusmaster" 点击“卸载”；

- 确认卸载组件且确定重新加载；

- 加载完成后，"modbusmaster" 组件被删除；

卸载MetaFacture侧的Modbus Tcp master library

- MetaFacture界面点击“工具” -- “库存储”

- 对话框中选中安装的modbus master的库，点击“卸载”

### 技术说明

#### 快速启动

本例实验要求及原理

硬件： | 软件：
--- | ---

本例实验要求及原理

实验要求：按照“安装卸载”部分中的“安装过程”配置完成Modbus Tcp Master环境

1、实验原理

- Metafacture Modbus Tcp主站通过 TCP 连接向第三方Modbus Tcp 从站发送请求，主要包含：功能码、目标寄存器的地址和数量、写操作时的数据；从站收到请求后先检查数据的合法性，然后执行请求的操作，响应主站请求；

- 上位机和工智机使用EtherNet连接；

- 上位机上，MetaFacture下装工程到工智机。工程中会包含下面的试验操作步骤中的配置；

- 工智机与第三方TCPIP客户端通过EtherNet连接；

#### 本例实验操作步骤

读操作

测试环境

SX21工智机作为主站，助手作为从站：

从站助手配置：

Connection 选择：Modbus TCP/IP

Ip Address ：本机电脑IP地址（与工智机在同一网段）

Port :502（示例使用默认端口号）

操作步骤

1、创建工程ModbusTCPMaster 工程；

2、按照如下操作完成读功能操作；

读多线圈的实验步骤如下：

POU中声明区域调用modbus tcp master读线圈功能块

    bRead                          : BOOL ;
    ReadCoils                    : FB_MBTcpReadCoils;
    ReadCoilData            : ARRAY[0..9] OF BYTE;

- POU中程序区域调用ReadCoils

    c

- 工程运行后触发ReadCoils中的bExecute上升沿执行读取线圈的值，即写入bRead为True；

- 工程中调用功能块的nUnitID必须写为当前从站设置的ID值，不然会报错，并且读不到数据，后面调用其他功能块也是必须写nUnitID。

- Modbus Slave 工具配置模式如下：

- MetaFacture配置程序暂停并重新运行，获取结果如下：

b读取离散输入的实验步骤如下：

- POU中声明区域调用modbus tcp master读离散输入功能块

    bRead                               : BOOL ;
    ReadInputs                       : FB_MBTcpReadInputs;
    ReadInputData : ARRAY[0..9] OF BYTE;

- POU中程序区域调用ReadInputs

    ReadInputs(sIPAddr:=ipaddr ,
    nTCPPort:=502 ,
    nUnitID:= 1,
    nQuantity:=10 ,
    nMBAddr:=0 ,
    cbLength:=SIZEOF(ReadInputData) , pDestAddr:=ADR(ReadInputData) ,
    bExecute:=bRead ,
    tTimeout:= , bBUSY=> , bError=> , nErrId=> );

- 工程运行后触发ReadInputs中的bExecute上升沿执行读取离散输入的值，即写入bRead为True；

- Modbus Slave工具配置模式如下：

- MetaFacture配置程序暂停并重新运行，获取结果如下：

c. 读取保持寄存器的实验步骤如下：

- POU中声明区域调用modbus tcp master读保持寄存器功能块

    bRead                           : BOOL ;
    ReadRegs                     : FB_MBTcpReadRegs;
    ReadRegsData     : ARRAY[0..9] OF WORD;

- POU中程序区域调用ReadRegs

    ReadRegs(sIPAddr:=ipaddr ,
    nTCPPort:=502 ,
    nUnitID:= 1,
    nQuantity:=10 ,
    nMBAddr:=0 ,
    cbLength:=SIZEOF(ReadRegsData) , pDestAddr:=ADR(ReadRegsData) ,
    bExecute:=bRead ,
    tTimeout:= , bBUSY=> , bError=> , nErrId=> );

- 工程运行后触发ReadRegs中的bExecute上升沿执行读取保持寄存器的值，即写入bRead为True；

- Modbus Slave工具配置模式如下：

- MetaFacture配置程序暂停并重新运行，获取结果如下

d. 读取输入寄存器的实验步骤如下：

- POU中声明区域调用modbus tcp master读输入寄存器功能块

    bRead                              : BOOL ;
    ReadInputRegs                : FB_MBTcpReadInputRegs;
    ReadInputRegsData: ARRAY[0..9] OF WORD;

- POU中程序区域调用ReadInputRegs

    ReadInputRegs(sIPAddr:=ipaddr ,
    nTCPPort:=502 ,
    nUnitID:=1 ,
    nQuantity:=10 ,
    nMBAddr:=0 ,
    cbLength:=SIZEOF(ReadInputRegsData) , pDestAddr:=ADR(ReadInputRegsData) , bExecute:=bRead ,
    tTimeout:= , bBUSY=> , bError=> , nErrId=> );

- 工程运行后触发ReadInputRegs中的bExecute上升沿执行读取输入寄存器的值，即写入bRead为True；

- Modbus Slave工具配置模式如下：

- MetaFacture配置程序暂停并重新运行，获取结果如下：

写操作

测试环境

SX21工智机作为主站，助手作为从站。

操作步骤

1、创建工程ModbusTCP Master 工程；

2、按照如下操作完成写功能操作；

a. 写多线圈的实验步骤如下：

- POU中声明区域调用ModbusTCP Master写线圈功能块

    bWrite                           : BOOL ;
    WriteCoils                     : FB_MBTcpWriteCoils;
    WriteCoilsData     : ARRAY[0..9] OF BOOL:=[1,1,1,1,1];

- POU中程序区域调用WriteCoils功能块

    WriteCoils(sIPAddr:=ipaddr ,
    nTCPPort:=502 ,
    nUnitID:=1 ,
    nQuantity:=10 ,
    nMBAddr:=0 ,
    cbLength:=SIZEOF(WriteCoilsData) ,
    pSrcAddr:=ADR(WriteCoilsData) ,
    bExecute:=bWrite ,
    tTimeout:= , bBUSY=> , bError=> , nErrId=> );

- 工程运行后触发WriteCoils中的bExecute上升沿执行写多线圈的值，即写入bWrite为True；

- 从站显示结果：

b. 写多保持寄存器的实验步骤如下：

- POU中声明区域调用modbus tcp master写多保持寄存器功能块

    bWrite                           : BOOL ;
    WriteRegs                     : FB_MBTcpWriteRegs;
    WriteRegsData     : ARRAY[0..9] OF WORD:=[16#FF,16#FE,16#FD,16#FC,16#FB,16#FA,16#F9,16#F8,16#F7,16#F6];

- POU中程序区域调用WriteRegs

    WriteRegs(sIPAddr:=ipaddr ,
    nTCPPort:=502 ,
    nUnitID:=1 ,
    nQuantity:=10 ,
    nMBAddr:=0 ,
    cbLength:=SIZEOF(WriteRegsData) , pSrcAddr:=ADR(WriteRegsData) ,
    bExecute:=bWrite ,
    tTimeout:= , bBUSY=> , bError=> , nErrId=> );

- 工程运行后触发WriteRegs中的bExecute上升沿执行写多保持寄存器的值，即写入bWrite为True；

- 从站显示结果：

#### 两台工智机相互访问

测试环境

SX20工智机作为主站，SX21工智机作为从站。

Modbus Slave 端使用说明：

- Modbus slaver 默认502 端口

- 新增M区 、Q区配置：

Q区---功能码：01 ，02 、05 位变量操作（读写）

M区---功能码：03 ，04 、06 寄存器变量操作（读写）

- 使用同一Slave功能块最多支持15个从站的创建。

操作步骤

1、创建工程ModbusTCPSlave 工程；

2、配置从站工程声明变量；

- POU中声明区域调用ModbusTCP Slave功能块

    PROGRAM ModbusTCPSlave
    VAR
    TCPslave                   : MetaCore_ModbusSlave.FB_ModbusTCPSlave;//Modbus TCP从站功能块
    Coil  : ARRAY[0..9] OF BOOL:=[1,0,1,0,1,0,1,0,1,0];//初始化线圈数据
    DiscreteInput  : ARRAY[0..9] OF BOOL:=[0,1,0,1,0,1,0,1,0,1];//初始化离散输入数据
    InputRegister  : ARRAY[0..9] OF WORD:=[11,22,33,44,55,66,77,88,99,16#AA];
    //初始化输入型寄存器数据
    HoldingRegister  : ARRAY[0..9] OF WORD:=[16#AA,99,88,77,66,55,44,33,22,11];
    //初始化保持型寄存器数据
    END_VAR

- POU中程序区域调用MetaCore_ModbusSlave.FB_ModbusTCPSlave

    TCPslave(
            bEnable:=TRUE ,                                       //Modbus TCP从站功能块使能
            ePort:= ,                                                     //Modbus RTU参数，Modbus TCP不填
            sIpAddr:='192.168.105.11' ,                       //Modbus TCP从站IP地址
            uiIpPort:=503 ,                                  //Modbus TCP从站端口，本例使用503端口
            udiTimeOut:= ,                                            //超时时间
            pbyCoil:=ADR(Coil) ,                                   //线圈指针
            pbyDiscreteInput:=ADR(DiscreteInput) ,     //离散输入指针
            pbyInputRegister:=ADR(InputRegister) ,    //输入型寄存器指针
            pbyHoldingRegister:=ADR(HoldingRegister) ,       //保持型寄存器指针
            udiRwBitSize:=SIZEOF(Coil) ,                              //线圈的个数
            udiInBitSize:=SIZEOF(DiscreteInput) ,                 //离散输入的个数
            udiInWordSize:=SIZEOF(InputRegister) ,             //输入型寄存器的个数
            udiRwWordSize:=SIZEOF(HoldingRegister) ,      //保持型寄存器的个数
            psMbTest:= ,                                                         //测试用，不可填
            bBusy=> , bActive=> , bConnect=> , bError=> , eError=> , ulRecvCounter=> , ulSendCounter=> , sLocalIp=> , sClientIP=> );

3、创建工程ModbusTCPMaster 工程;

4、按照如下操作完成写功能操作；

a. 写多线圈的实验步骤如下：

- POU中声明区域调用ModbusTCP Master写线圈功能块

    bWrite                           : BOOL ;
    WriteCoils                     : FB_MBTcpWriteCoils;
    WriteCoilsData     : ARRAY[0..9] OF BOOL:=[1,1,1,1,1];

- POU中程序区域调用WriteCoils功能块

    WriteCoils(sIPAddr:=ipaddr ,
    nTCPPort:=503 ,
    nUnitID:=1 ,
    nQuantity:=10 ,
    nMBAddr:=0 ,
    cbLength:=SIZEOF(WriteCoilsData) ,
    pSrcAddr:=ADR(WriteCoilsData) ,
    bExecute:=bWrite ,
    tTimeout:= , bBUSY=> , bError=> , nErrId=> );

- 工程运行后触发WriteCoils中的bExecute上升沿执行写多线圈的值，即写入bWrite为True；

- 主站数据

- 从站显示结果：

b. 写多保持寄存器的实验步骤如下：

- POU中声明区域调用modbus tcp master写多保持寄存器功能块

    bWrite                           : BOOL ;
    WriteRegs                     : FB_MBTcpWriteRegs;
    WriteRegsData     : ARRAY[0..9] OF WORD:=[16#FF,16#FE,16#FD,16#FC,16#FB,16#FA,16#F9,16#F8,16#F7,16#F6];

- POU中程序区域调用WriteRegs

    WriteRegs(sIPAddr:=ipaddr ,
    nTCPPort:=503 ,
    nUnitID:=1 ,
    nQuantity:=10 ,
    nMBAddr:=0 ,
    cbLength:=SIZEOF(WriteRegsData) , pSrcAddr:=ADR(WriteRegsData) ,
    bExecute:=bWrite ,
    tTimeout:= , bBUSY=> , bError=> , nErrId=> );

- 工程运行后触发WriteRegs中的bExecute上升沿执行写多保持寄存器的值，即写入bWrite为True；

- 主站数据

- 从站显示结果：

### 实验注意点

1、实验中用到的从站的IP、端口请改成实际使用的从站ip、端口；

2、实验中使用的从站配置案例如下：

- 配置PC 为从站：

- 安装工具ModbusSlave

- 配置模式：SlaveID、功能码（01，02，03，04）开始地址、队列

- 设置寄存器的值/状态

### 功能介绍

### 主站配置读取从站多线圈

功能块FB_MBTcpReadCoils介绍

参数介绍

- 输入参数

参数名称 | 参数类型 | 描述
--- | --- | ---
sIPAddr | string | 从站的IP
nTCPPort | UINT | 从站的端口
nUnitID | BYTE | 从站ID
nQuantity | WORD | 从线圈起始位置读取的长度,一次最多读取125位
nMBAddr | WORD | 线圈起始位置
cbLength | UDINT | 存储读取的字节大小
pDestAddr | POINTER TO BYTE | 要读的存放数据的存放地址
bExecute | BOOL | 上升沿触发执行
tTimeout | Time | 超时

- 输出参数

参数名称 | 参数类型 | 描述
--- | --- | ---
bBUSY | BOOL | 功能块激活时设置，直到确认接收
bError | BOOL | 如果命令在传输过程中出现错误，则设置true直到bBusy输出被重置
nErrId | UDINT | 当bError输出被设置，提供错误号

#### 主站配置读取从站输入寄存器

功能块FB_MBTcpReadInputRegs介绍

参数介绍

- 输入参数

参数名称 | 参数类型 | 描述
--- | --- | ---
sIPAddr | string | 从站ip
nTCPPort | UINT | 从站端口
nUnitID | UINT | 从站id
nQuantity | UINT | 读取多少位输入寄存器，一次最多读取125位
nMBAddr | UINT | 读取的输入寄存器起始位置
cbLength | UINT | 存储读取的字节大小
pDestAddr | POINTER TO WORD | 要读的存放数据的存放地址
bExecute | BOOL | 上升沿触发执行
tTimeout | TIME | 超时

- 输出参数

参数名称 | 参数类型 | 描述
--- | --- | ---
bBUSY | BOOL | 功能块激活时设置，直到确认接收
bError | BOOL | 如果命令在传输过程中出现错误，则设置true直到bBusy输出被重置
nErrId | UDINT | 当bError输出被设置，提供错误号

#### 主站配置读取从站离散输入

功能块FB_MBTcpReadInputs介绍

参数介绍

- 输入参数

参数名称 | 参数类型 | 描述
--- | --- | ---
sIPAddr | string | 从站ip
nTCPPort | UINT | 从站端口
nUnitID | UINT | 从站id
nQuantity | UINT | 读取多少位离散输入
nMBAddr | UINT | 读取的离散输入起始位置
cbLength | UINT | 存储读取的字节大小
pDestAddr | POINTER TO BYTE | 要读的存放数据的存放地址
bExecute | BOOL | 上升沿触发执行
tTimeout | TIME | 超时

- 输出参数

参数名称 | 参数类型 | 描述
--- | --- | ---
bBUSY | BOOL | 功能块激活时设置，直到确认接收
bError | BOOL | 如果命令在传输过程中出现错误，则设置true直到bBusy输出被重置
nErrId | UDINT | 当bError输出被设置，提供错误号

#### 主站配置读取从站保持寄存器

功能块FB_MBTcpReadRegs介绍

参数介绍

- 输入参数

参数名称 | 参数类型 | 描述
--- | --- | ---
sIPAddr | string | 从站ip
nTCPPort | UINT | 从站端口
nUnitID | UINT | 从站id
nQuantity | UINT | 读取多少位保持寄存器，一次最多读取125位
nMBAddr | UINT | 读取的保持寄存器起始位置
cbLength | UINT | 存储读取的字节大小
pDestAddr | POINTER TO word | 要读的存放数据的存放地址
bExecute | BOOL | 上升沿触发执行
tTimeout | TIME | 超时

- 输出参数

参数名称 | 参数类型 | 描述
--- | --- | ---
bBUSY | BOOL | 功能块激活时设置，直到确认接收
bError | BOOL | 如果命令在传输过程中出现错误，则设置true直到bBusy输出被重置
nErrId | UDINT | 当bError输出被设置，提供错误号

#### 主站配置写从站多线圈

功能块FB_MBTcpWriteCoils介绍

参数介绍

- 输入参数

参数名称 | 参数类型 | 描述
--- | --- | ---
sIPAddr | string | 从站ip
nTCPPort | UINT | 从站端口
nUnitID | UINT | 从站id
nQuantity | UINT | 写多少位线圈
nMBAddr | UINT | 要写入的线圈起始位置
cbLength | UINT | 存储写入的字节大小
pSrcAddr | POINTER TO BYTE | 要写入的数据的存放地址
bExecute | BOOL | 上升沿触发执行
tTimeout | TIME | 超时

- 输出参数

参数名称 | 参数类型 | 描述
--- | --- | ---
bBUSY | BOOL | 功能块激活时设置，直到确认接收
bError | BOOL | 如果命令在传输过程中出现错误，则设置true直到bBusy输出被重置
nErrId | UDINT | 当bError输出被设置，提供错误号

#### 主站配置写从站多保持寄存器

功能块FB_MBTcpWriteRegs介绍

参数介绍

- 输入参数

参数名称 | 参数类型 | 描述
--- | --- | ---
sIPAddr | string | 从站ip
nTCPPort | UINT | 从站端口
nUnitID | UINT | 从站id
nQuantity | UINT | 写多少位线圈，一次最多写123位
nMBAddr | UINT | 要写入的保持寄存器起始位置
cbLength | UINT | 存储写入的字节大小
pSrcAddr | POINTER TO WORD | 要写入的数据的存放地址
bExecute | BOOL | 上升沿触发执行
tTimeout | TIME | 超时

- 输出参数

参数名称 | 参数类型 | 描述
--- | --- | ---
bBUSY | BOOL | 功能块激活时设置，直到确认接收
bError | BOOL | 如果命令在传输过程中出现错误，则设置true直到bBusy输出被重置
nErrId | UDINT | 当bError输出被设置，提供错误号

#### 主站配置写从站单线圈

功能块FB_MBTcpWriteSingleCoil介绍

参数介绍

- 输入参数

参数名称 | 参数类型 | 描述
--- | --- | ---
sIPAddr | string | 从站ip
nTCPPort | UINT | 从站端口
nUnitID | UINT | 从站id
nMBAddr | UINT | 要写入的单线圈的位置
nValue | BOOL | 要写入的值
bExecute | BOOL | 上升沿触发执行
tTimeout | TIME | 超时

- 输出参数

参数名称 | 参数类型 | 描述
--- | --- | ---
bBUSY | BOOL | 功能块激活时设置，直到确认接收
bError | BOOL | 如果命令在传输过程中出现错误，则设置true直到bBusy输出被重置
nErrId | UDINT | 当bError输出被设置，提供错误号

#### 主站配置写从站单保持寄存器

功能块FB_MBTcpWriteSingleReg介绍

### 8.2． 参数介绍

- 输入参数

参数名称 | 参数类型 | 描述
--- | --- | ---
sIPAddr | string | 从站ip
nTCPPort | UINT | 从站端口
nUnitID | UINT | 从站id
nMBAddr | UINT | 要写入的单保持寄存器的位置
nValue | UINT | 要写入的值
bExecute | BOOL | 上升沿触发执行
tTimeout | TIME | 超时

- 输出参数

参数名称 | 参数类型 | 描述
--- | --- | ---
bBUSY | BOOL | 功能块激活时设置，直到确认接收
bError | BOOL | 如果命令在传输过程中出现错误，则设置true直到bBusy输出被重置
nErrId | UDINT | 当bError输出被设置，提供错误号

## 9 . 主站配置连接10从站

- 使用模拟软件配置10个从站（各个从站ID配置不一样），参考如下：

- 主站配置连接10个从站进行读写操作，测试读写正常

### 附录

#### Linux 指令安装/卸载指南

安装要求

- 中科时代出厂的工智机；

- 熟悉基础的Linux操作命令

安装过程

工智机端安装Modbus Tcp Master RTE组件

- 上传deb包到工智机Linux环境的/home/sinsegye目录下

- 上传完成后在工智机上执行命令安装（参考下方截图，如果模块文件名发生变化则命令行中的文件名做相应更改）

    cd $HOME sudo dpkg -i modbusmaster_1.1.4_amd64.deb

- 修改RTE的配置文件，ComponentManger模块下加入modbusmaster

     \[ComponentManager] Component.0=retainDeamon Component.1=CmpCanBusUtils Component.2=CmpSinsegyeLibs Component.3=SinsegyeCmp Component.4=modbusmaster

- 重启RTE服务，使新加入的modbusmaster被调用

    sudo systemctl restart sinsegyerte.service

更新安装

工智机端升级Modbus Tcp Master RTE组件

- 上传deb包到工智机Linux环境的/home/sinsegye目录下

- 上传完成后在工智机上执行命令安装（参考下方截图，如果模块文件名发生变化则命令行中的文件名做相应更改）

    cd $HOME sudo dpkg -i modbusmaster_1.1.4_amd64.deb

- 重启RTE服务，使新升级的modbusmaster生效

    sudo systemctl restart sinsegyerte.service

卸载过程

工智机端卸载Modbus Tcp Master RTE组件

- 工智机上执行命令卸载modbusmaster

    sudo dpkg -r simodbusmaster

- 修改RTE的配置文件，ComponentManger模块下去掉modbusmaster

    sudo vim /usr/local/etc/SinsegyeRTE/SinsegyeRTE.cfg

- 重启RTE服务

    sudo systemctl restart sinsegyerte.service

错误处理

1. 需要先确定网络通讯正常，确定主站要请求的从站地址都存在；

2. 确保主/从站的deb包与Library文件包一致；