抖音粉丝群1
『7x24小时有问必答』

摘要:本文介绍了ModbusTCP协议在PLC编程中的应用,包括其基本概念、数据帧结构、通信方式,以及在Codesys和OtoStudio中的编程示例,重点讲述了主站与从站如何通过ModbusTCP进行线圈、离散输入、保持寄存器和输入寄存器的读写操作。ModbusTCP学习笔记+PLC相关功能块编程

2023-07-18
PLC编程,Modbus TCP,Codesys V2.3,OtoStudio V2.3,ST语言


1、Modbus协议介绍
  • Modbus是一种工业总线协议标准,包括ASCII、RTU、TCP三种报文类型。

  • Modbus协议物理层接口有RS232、RS485、RS422和以太网接口,采用master/slave方式通信。

  • Modbus -TCP,是基于在以太网TCP/IP上,将数据以Modbus帧格式进行传输。
    具备数据准确性(帧头、帧尾),具有TCP传输快速性(物理层是RJ45网口、TCP传输层)。


图为Modbus数据帧内容:
0.jpg

  • MBAP为报文头,长度为7字节,组成如下:
0.jpg
  • 帧结构PDU

PDU由功能码+数据组成。功能码为1字节,数据长度不定,由具体功能决定。

Modbus的操作对象有四种:线圈、离散输入、保持寄存器、输入寄存器

0.jpg
0.jpg

  • 通信方式

Modbus分为主站和从站,主站给从站发送请求帧,从站响应。在使用TCP通信时,主站为client端,主动建立连接,从站为server端,等待连接。

Modbus TCP是较为特别的,举个例子,之前我们客户使用IDB3 控制器(PLC)与威纶通触摸屏通过Modbus TCP通信,IDB3就是作为Modbus从站,而Modbus从站作为TCP就是Server端。而触摸屏作为Modbus主站,Modbus主站在TCP就是Client端。

Modbus主站主动对Modbus从站发送消息请求,从站做回应。

这个在IDB3的Modbus TCP库里可以详细了解到,Modbus从站是需要或可以配置本机port(端口)、IP地址 的。而Modbus主站则需要设置远端IP,以及端口。

2、编程示例从站:
  • iDEABox 3控制器,在此文中简称IDB3,是PLC,是Softlink品牌的控制器,我使用的是固高科技的OtostudioV2.3进行编程,其内核也是CodysysV2.3版本。

ModbusTCP从站作为TCP主站。也即是其有TCPServer的属性。

从站使用的代码如下:

VAR_GLOBAL
    SlaveArrayBool:ARRAY [1..60] OF BOOL;// HMI布尔数据
    SlaveArrayReal:ARRAY [1..60] OF REAL;// HMI字数据
END_VAR

// 从站功能块调用
SlaveTcp(
pCoils:=ADR(SlaveArrayBool[1]),//指定线圈地址
pDiscreteInput:=,//离散量地址
pInputReg:=,//输入寄存器
pHoldingReg:=ADR(SlaveArrayReal),//保持寄存器
CMax:=32,//线圈大小
DIMax:=,
IRMax:=,
HRMax:=SIZEOF(SlaveArrayReal)/SIZEOF(REAL)*2,//保持寄存器大小
Enable:= bEnable,
port:=4455,//指定端口号
Enable_WatchDog:=,
tWatchDogTime:=,
ClientStatus=>,
wErrorId=>,
bError=>);

上述代码中,SlaveTcp是ModbusTcp 从站功能块实例。其需要的参数入代码中所示。主要可配置以下:
(1)指定 “Coils线圈、离散量、输入寄存器、保持寄存器” 4部分的地址及大小。
(2)指定端口
(3)看门狗配置(可以不用,不设置)

  • Coils配置

从站指定线圈地址 pCoils 是地址开头,CMax 是线圈大小,指的是以bool为单位的长度。

如上例子:pCoils:= ADR(aybyHMIData[1]) 指线圈从aybyHMIData[1]开始,长度32Bit(位),也就是4个Byte(字节)。

这里的线圈变量类型是 《布尔(BOOL)数组》

  • HoldingReg配置

指定保持寄存器地址开头 aywHMIData,也就是aywHMIData[1]的地址,长度位60*2=120,因为Real占4个字节,比word大2倍,所以要传real值时,要把地址乘以2。这个配置就占了保持寄存器120个地址。

这里的保持寄存器变量类型 是 《实数(REAL)数组》

主站:
  • 主站也是在IDB3中建立,因为ModbusTCP是基于TCP的通信,所以可以在本机上实现主从站并存。
  • 当有多个设备需要通过ModbusTCP协议通信,那么把主从站运行在不同设备上即可。
  • ModbusTCP作TCP从站,其有TCPClient的属性。

以下是主站用到的代码:

VAR_GLOBAL
    MasterArrayByte:ARRAY [1..60] OF BYTE;// HMI布尔数据
    MasterArrayReal:ARRAY [1..60] OF REAL;// HMI字数据
END_VAR

// ModbusTcp主站

ModbusTcpMaster(
        Client:=ADR(Client),
        StationID:=1,// 设置站号
        IP:= remoteIP,// 远端服务器的IP
        Port:= remotePort,// 远端服务器端口
        Enable:= bMasterEnable,
        Enable_WatchDog:=,
        WatchDogTime:=,
        wErrorId=>,
        bError=>);

IF bMasterEnable THEN
        IF bReadEnable THEN
                bReadEnable:=FALSE;
        ELSE
                bReadEnable:=TRUE;
        END_IF
        IF bWriteEnable THEN
                bWriteEnable:=FALSE;
        ELSE
                bWriteEnable:=TRUE;
        END_IF
END_IF

MasterTcpRead(
        Execute:= bReadEnable,
        Client:=ADR(client),
        Watch_Time:=,
        ReSendTimes:=,
        DataModel:=4,// 读取保存寄存器模式
        DataAddress:=0,// 地址 0 ~ 8
        DataLength:=4*2,// 共读出 8/2 = 4 个REAL
        pData:=ADR(MasterArrayReal),// 存放地址
        ResponseDone=>,
        Exception=>,
        ExceptionCode=>,
        ExceptionCnt=>,
        SendCnt=>,
        TimeOut=>,
        Error=>,
        ErrCode=>);

MasterTcpReadB(
        Execute:= bReadEnable,
        Client:=ADR(client),
        Watch_Time:=,
        ReSendTimes:=,
        DataModel:=0,// 读取线圈模式
        DataAddress:=0,// 地址 0 ~ 8
        DataLength:=8,// 共读出 8/8 = 1 个BYTE
        pData:=ADR(MasterArrayByte[1]),// 存放地址
        ResponseDone=>,
        Exception=>,
        ExceptionCode=>,
        ExceptionCnt=>,
        SendCnt=>,
        TimeOut=>,
        Error=>,
        ErrCode=>);

MasterTcpWrite(
        Execute:= bWriteEnable,
        Client:=ADR(client),
        Watch_Time:=,
        ReSendTimes:=,
        DataModel:=4,// 写保持寄存器
        DataAddress:=60,// 地址 60 ~ 120
        DataLength:=60,// 共写入 60/2 = 30 个REAL
        pData:=ADR(MasterArrayReal[31]),// 要写入的变量地址
        ResponseDone=>,
        Exception=>,
        ExceptionCode=>,
        ExceptionCnt=>,
        SendCnt=>,
        TimeOut=>,
        Error=>,
        ErrCode=>);

MasterTcpWriteB(
        Execute:= bWriteEnable,
        Client:=ADR(client),
        Watch_Time:=,
        ReSendTimes:=,
        DataModel:=0,// 写线圈
        DataAddress:=8,// 地址 8 ~ 24
        DataLength:=24,// 共写入 24/8 = 3 个BYTE
        pData:=ADR(MasterArrayByte[2]),// 要写入的变量地址
        ResponseDone=>,
        Exception=>,
        ExceptionCode=>,
        ExceptionCnt=>,
        SendCnt=>,
        TimeOut=>,
        Error=>,
        ErrCode=>);

上述代码中,ModbusTcpMaster是ModbusTCP主站功能块。而主站并不是只用这一个功能块,还需要使用 “读/写” 的功能块。MasterTcpRead、MasterTcpReadB是 ”ModbusTCP主站读“ 功能块,MasterTcpWrite、MasterTcpWriteB是 ”ModbusTCP主站写“ 功能块。

在读写功能块里面,每个功能块实例只能同时对一个区域进行操作,所以上面代码就调用了2个读写功能块进行对线圈的读写、保持寄存器的读写。

在读写功能块中,也需要像从站那样配置其数据地址及大小。

主站需要配置的内容:
(1)要读写的内容( Coils线圈、离散量、输入寄存器、保持寄存器)的地址和大小。
(2)配置从站(TCP服务器)的IP地址,和端口。
(3)看门狗(可以不用,不配置)

  • Coils线圈读写

读写的都是同一个 字节BYTE数组 MasterArrayByte[] ,区别在于,读取的是第一个元素,MasterArrayByte[1],而要写入的是MasterArrayByte[2…4] 第2~4个元素。

这里用到的数组类型是 字节BYTE数组 ,和Slave站的不一致?为什么?

上面从站配置的线圈,配置地址从0开始,32长度,就是第031位,也就是第03 个BYTE。

而主站读功能块配置的线圈,配置地址从0开始,8长度,指的是第0~7个位,也就是第0个BYTE。但是其指定的需要用Byte数组来处理,这里试过用BOOL数组,就会有异常。

而同理,主站写功能块配置线圈,地址从8开始,24长度,指的是831个位,也就是第13个BYTE。也同样用byte数组来操作。

  • HoldingReg保持寄存器读写

读写保持寄存器也都是用同一个 实数REAL数组 MasterArrayReal[],区别在于,读取的是MasterArrayReal[0…3]共4个real。写入的是MasterArrayReal[31…60]共30个real。

以上主从站线圈的对应图如下:

0.jpg

主从站保持寄存器对应图如下:

0.jpg

布置好以上内容后,启动功能块,即可实现ModbusTCP主从站的通信了。



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码