TwinCAT3 Modbus-TCP Client/Server使用

2023-12-15 00:15

本文主要是介绍TwinCAT3 Modbus-TCP Client/Server使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、环境配置和准备

1、PLC中安装TF6250-Modbus-TCP库

2、勾选TF6250的license

3、PLC工程中添加Tc2_ModbusSrv库文件

4、分别创建测试ModbusTCP测试的Server和Client程序

二、PLC作为Client端

1、设置测试电脑IP地址

2、运行MobusTCP测试工具

3、PLC端程序编写

(1)读取离散量输入

(2)读取线圈

(3)单个线圈写操作

(4)多个线圈写操作

(5)读取输入寄存器值

(6)读取保持寄存器值

(7)单个保持寄存器写操作

(8)多个保持寄存器写操作

三、PLC作为Server端

1、PLC程序

(1)寄存器变量定义

2、Client客户端工具

3、通讯测试

(1)客户端写操作

四、PLC中使用服务端和客户端程序进行寄存器操作

1、PLC程序

(1)服务端程序

(2)客户端程序

2、通讯测试

(1)寄存器说明

(2)PLC的Client程序读操作

(3)PLC的Client程序写操作

五、测试工程下载


一、环境配置和准备

1、PLC中安装TF6250-Modbus-TCP库

PLC地址

安装库文件

PLC硬件环境设置、库文件安装、防火墙设置等,参见博客文章:TwinCAT3中ModbusTCP Server和C# Client连接-CSDN博客

2、勾选TF6250的license

3、PLC工程中添加Tc2_ModbusSrv库文件

4、分别创建测试ModbusTCP测试的Server和Client程序

将创建的程序添加到Task中。

二、PLC作为Client端

1、设置测试电脑IP地址

测试电脑IP地址和PLC的IP地址在一个网段内。

2、运行MobusTCP测试工具

使用测试工具ModSim32,创建ModbusTCP Server服务端。端口号默认502,测试软件默认IP地址是计算机本地地址。

3、PLC端程序编写

定义变量:ModbusTCP Server服务端ip地址

Server_IpAddress	:STRING:='192.168.1.33';        //ModbusTCP Server服务端ip地址

(1)读取离散量输入

定义变量

	02: Input Status 读取//fbReadInputs      : FB_MBReadInputs;						(*读取离散量输入功能块*)bReadInputs       : BOOL;									(*读取离散量输入执行条件*)nQuantityinput    : WORD:=1 ;								(*读取离散量输入个数*)nMBAddrinput      : WORD:=1 ;								(*读取离散量输入起始地址*)arrDatainput      : BYTE;									(*存放离散量输入的值*)

程序

nUnitID:Modbus-Tcp从站号。如果实际中不知道从站号多少,默认写1就行。

fbReadInputs(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502, 							//Modbus-Tcp端口号nUnitID:=1 , 							//Modbus-Tcp从站号nQuantity:=nQuantityinput , 			//读取离散量输入个数nMBAddr:= nMBAddrinput, 				//读取离散量输入 Modbus起始地址cbLength:= SIZEOF(arrDatainput), 		//存放离散量输入变量的个数pDestAddr:=ADR(arrDatainput), 			//存放离散量输入变量指针起始地址bExecute:=bReadInputs , 				//读取离散量输入执行条件tTimeout:=T#1S ,    bBusy=> , bError=> , nErrId=> , cbRead=> );

运行测试1,单个离散量读操作:

对10002写1

PLC读取

读取个数是1,nQuantityinput值为1

起始地址nMBAddrinput写1对应的寄存器是10002。离散变量实际地址=10001+nMBAddrinput

读取

运行测试2,多个离散量读操作:

对10002写1、10003写1、10004写1

PLC读取

设置读取个数是3。读取出来的值是7。(三个位都为1,就是7)

(2)读取线圈

定义变量

    fbReadCoils       			: FB_MBReadCoils;				(*读取线圈功能块*) bReadCoils        			: BOOL; 						(*读取线圈执行条件*)      nQuantitycoils    			: WORD :=3;  					(*读取线圈个数*) nMBAddrcoils      			: WORD :=1;  					(*读取线圈起始地址*) arrDatacoils      			: BYTE;							(*存放线圈的值*)

PLC程序

fbReadCoils(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502 ,							//Modbus-Tcp端口号 nUnitID:=1 , 							//Modbus-Tcp从站号nQuantity:=nQuantitycoils , 			//读取线圈个数nMBAddr:=nMBAddrcoils , 				//读取线圈 Modbus起始地址cbLength:=SIZEOF(arrDatacoils) , 		//存放线圈变量的个数pDestAddr:=ADR(arrDatacoils) , 			//存放线圈变量指针起始地址bExecute:=bReadCoils , 					//读取线圈执行条件tTimeout:= T#1S, bBusy=> , bError=>, nErrId=> , cbRead=> );

运行测试,多个线圈读操作:

对线圈00005/00006/0007/0008/00009写1操作

PLC

nMBAddrcoils:读取线圈的地址

nQuantitycoils:读取的线圈个数

线圈的实际地址=00001+nMBAddrcoils。

00005对应的nMBAddrcoils地址设置就是4。

5个线圈的值都是ON,即31

PLC中数据显示,2进制、10进制、16进制显示设置

(3)单个线圈写操作

定义变量

    fbWriteSingleCoil       	: FB_MBWriteSingleCoil;			(*写入单个线圈功能块*)bWriteSingleCoil            : BOOL;							(*写入单个线圈执行条件*)nMBAddrWriteSingleCoil      : WORD := 3;					(*写入单个线圈Modbus 地址*)nValueWriteSingleCoil       : WORD := 16#FF00;				(*16#FF00:True;16#0000:False*)

PLC程序

fbWriteSingleCoil(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:= 502, 						//Modbus-Tcp端口号nUnitID:= 1, 							//Modbus-Tcp从站号nMBAddr:=nMBAddrWriteSingleCoil , 		//写入单个线圈Modbus起始地址nValue:=nValueWriteSingleCoil , 		//写入单个线圈的值:16#FF00:True;16#0000:FalsebExecute:=bWriteSingleCoil , 			//写入单个线圈执行条件tTimeout:=T#1S , bBusy=> , bError=> , nErrId=> );

运行测试,单个线圈写操作:

对线圈00004写操作

线圈地址nMBAddrWriteSingleCoil值设置:3。(线圈地址=00001+nMBAddrWriteSingleCoil)

nValueWriteSingleCoil值设置:

TRUE:16#FF00,即10进制65280。

FALSE:16#0000,即10进制0。

(4)多个线圈写操作

变量定义

  	fbWriteCoils       			: FB_MBWriteCoils;				(*写入线圈功能块*)bWriteCoils      			: BOOL;							(*写入线圈执行条件*)nQuantityWriteCoils 		: WORD := 10;					(*写入离散量输入个数*)nMBAddrWriteCoils   		: WORD := 14;					(*写入离散量输入起始地址*)arrDataWriteCoils   		: ARRAY[1..2] OF  BYTE  := [16#11, 16#33];(*写入离散量输入的值*)

PLC程序

fbWriteCoils(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502, 							//Modbus-Tcp端口号nUnitID:=1 , 							//Modbus-Tcp从站号nQuantity:= nQuantityWriteCoils , 		//写入线圈个数nMBAddr:=nMBAddrWriteCoils , 			//写入线圈Modbus起始地址cbLength:=SIZEOF(arrDataWriteCoils), 	//写入线圈的变量个数pSrcAddr:=ADR(arrDataWriteCoils), 		//写入线圈的变量指针起始地址bExecute:=bWriteCoils , 				//写入线圈的执行条件tTimeout:=T#1S , bBusy=> , bError=> , nErrId=> );

运行测试,多个线圈写操作:

写16个线圈,线圈地址从00006开始。(00001+nMBAddrWriteCoils,nMBAddrWriteCoils设置值为5)。

1个BYTE是8位,8位都是1即BYTE值是255。

BYTE数组arrDataWriteCoils长度为2、即16位。最多可以写16个线圈操作。

注意:的线圈BYTE个数要和数组长度相同,16个线圈2个BYTE。对应否则会报错。)

(5)读取输入寄存器值

变量定义

    fbReadInputRegs    : FB_MBReadInputRegs;		(*读取输入寄存器功能块*)bReadInputRegs     : BOOL;						(*读取输入寄存器执行条件*)nQuantityInputRegs : WORD := 3;					(*读取输入寄存器个数*)nMBAddrInputRegs   : WORD:= 2;					(*读取输入寄存器起始地址*)arrDataInputRegs   : ARRAY [1..3] OF WORD;		(*存放输入寄存器的值*)

PLC程序

fbReadInputRegs(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502, 							//Modbus-Tcp端口号nUnitID:=1, 							//Modbus-Tcp从站号nQuantity:=nQuantityInputRegs, 			//读取输入寄存器个数nMBAddr:=nMBAddrInputRegs  , 			//读取输入寄存器Modbus起始地址cbLength:= SIZEOF(arrDataInputRegs),	//存放输入寄存器变量的个数和指针起始地址pDestAddr:=ADR(arrDataInputRegs), 		//存放输入寄存器变量指针起始地址bExecute:= bReadInputRegs  , 			//读取输入寄存器执行条件tTimeout:=T#1S , bBusy=> , bError=> , nErrId=> , cbRead=> );

运行测试,多个输入寄存器读操作:

给30003、30004、30005赋值

PLC读

寄存器地址30003=30001+nMBAddrInputRegs,nMBAddrInputRegs设置值2

多三个寄存器

注意:读的寄存器个数要和数组长度相同,否则会报错。)

(6)读取保持寄存器值

变量定义:

    fbReadRegs        			: FB_MBReadRegs;				(*读取保持寄存器功能块*)bReadRegs         			: BOOL;     					(*读取保持寄存器执行条件*) nQuantityregs     			: WORD:=2;   					(*读取保持寄存器个数*)nMBAddrregs       			: WORD:=24;   					(*读取保持寄存器起始地址*)arrDataregs       			: ARRAY [1..2] OF WORD;			(*存放保持寄存器的值*)

PLC程序:

fbReadRegs(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502,							//Modbus-Tcp端口号nUnitID:= 1, 							//Modbus-Tcp从站号nQuantity:=nQuantityregs, 				//读取保持寄存器个数nMBAddr:=nMBAddrregs , 					//读取保持寄存器Modbus起始地址cbLength:=SIZEOF(arrDataregs) , 		//存放保持寄存器变量的个数pDestAddr:=ADR(arrDataregs) , 			//存放保持寄存器变量指针起始地址bExecute:=bReadRegs, 					//读取保持寄存器执行条件tTimeout:= T#1S , bBusy=> , bError=> , nErrId=> , cbRead=> );

运行测试,多个保持寄存器读操作:

读保持寄存器40005、40006

寄存器首地址40005=40001+nMBAddrregs,设置nMBAddrregs值为4。读两个寄存器。

注意:读的寄存器个数要和数组长度相同,否则会报错。)

(7)单个保持寄存器写操作

变量定义:

 	fbWriteSingleReg            : FB_MBWriteSingleReg;			(*写入单个寄存器功能块*)bWriteSingleReg             : BOOL;							(*写入单个寄存器执行条件*)nMBAddrSingleReg            : WORD := 4;					(*写入单个寄存器Modbus 地址*)nValueSingleReg             : WORD := 16#1234;				(*写入单个寄存器数值*)

PLC程序:

fbWriteSingleReg(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502, 							//Modbus-Tcp端口号nUnitID:=1 , 							//Modbus-Tcp从站号nMBAddr:=nMBAddrSingleReg, 				//写入单个保持寄存器起始地址nValue:=nValueSingleReg, 				//写入单个寄存器数值bExecute:=bWriteSingleReg , 			//写入单个寄存器的执行条件tTimeout:=T#1S , bBusy=> , bError=> , nErrId=> );	

运行测试,单个保持寄存器写操作:

写保持寄存器40005。40005=40001+nMBAddrSingleReg,设置nMBAddrSingleReg值为4

(8)多个保持寄存器写操作

变量定义:

  	fbWriteRegs         		: FB_MBWriteRegs;				(*写入保持寄存器功能块*)bWriteRegs          		: BOOL;							(*写入保持寄存器个数*)nQuantityWriteRegs  		: WORD := 4;					(*写入保持寄存器个数*)nMBAddrWriteRegs    		: WORD := 4;					(*写入保持寄存器起始地址*)arrDataWriteRegs			: ARRAY[1..4] OF WORD := [1122, 3344, 5566, 7788];(*写入保持寄存器的值*)

PLC程序:

fbWriteRegs(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502, 							//Modbus-Tcp端口号nUnitID:=1 ,							//Modbus-Tcp从站号nQuantity:=nQuantityWriteRegs , 		//写入保持寄存器个数nMBAddr:= nMBAddrWriteRegs , 			//写入保持寄存器起始地址cbLength:= SIZEOF(arrDataWriteRegs), 	//写入变量的个数和指针起始地址pSrcAddr:=ADR(arrDataWriteRegs) , 		//写入变量指针起始地址bExecute:= bWriteRegs , 				//写入保持寄存器的执行条件tTimeout:=T#1S  , bBusy=> , bError=> , nErrId=> );

运行测试,多个保持寄存器写操作:

写保持寄存器40003、40004、40005,寄存器首地址40003=40001+nMBAddrWriteRegs,设置nMBAddrWriteRegs值2

注意:寄存器个数要和数组长度相同,否则会报错。)

三、PLC作为Server端

1、PLC程序

(1)寄存器变量定义

    arr1							AT%MB0			:ARRAY[1..5]		OF		WORD;		//起始地址是12289arr2							AT%MB10			:ARRAY[1..10]		OF		WORD;		//起始地址是12294

2、Client客户端工具

使用测试工具ModScan32模拟ModbusTCP Client客户端。

打开ModScan32

根据Server服务端PLC 中定义的寄存器,做如下设置

MB0对应的起始地址是12289。

寄存器说明:一个MW寄存器对应两个MB寄存器,比如MW0是MB0、MB1组成。一个12289对应一个MW0寄存器,即对应MB0、MB1。

3、通讯测试

(1)客户端写操作

客户端ModScan32对服务端PLC的寄存器写操作

PLC服务端接收的

(2)PLC服务端写操作

PLC寄存器写

客户端ModScan32接收的

四、PLC中使用服务端和客户端程序进行寄存器操作

1、PLC程序

(1)服务端程序

PLC服务端程序不变,就定义读写的寄存器变量

变量定义

    arr1							AT%MB0			:ARRAY[1..5]		OF		WORD;		//起始地址是12289arr2							AT%MB10			:ARRAY[1..10]		OF		WORD;		//起始地址是12294

(2)客户端程序

变量定义

Server_IpAddress	:STRING:='192.168.1.21';03: Holding Register 读取&写入fbReadRegs        			: FB_MBReadRegs;				(*读取保持寄存器功能块*)bReadRegs         			: BOOL;     					(*读取保持寄存器执行条件*) nQuantityregs     			: WORD:=5;   					(*读取保持寄存器个数*)nMBAddrregs       			: WORD:=12288;   				(*读取保持寄存器起始地址*)			//	寄存器地址=40001+nMBAddrregsarrDataregs       			: ARRAY [1..5] OF WORD;			(*存放保持寄存器的值*)fbWriteRegs         		: FB_MBWriteRegs;				(*写入保持寄存器功能块*)bWriteRegs          		: BOOL;							(*写入保持寄存器个数*)nQuantityWriteRegs  		: WORD := 10;					(*写入保持寄存器个数*)nMBAddrWriteRegs    		: WORD := 12294;				(*写入保持寄存器起始地址*)			//	寄存器地址=40001+nMBAddrWriteRegsarrDataWriteRegs			: ARRAY[1..10] OF WORD := [11, 22, 33, 44,55,66,77,88,99,100];		(*写入保持寄存器的值*)fbWriteSingleReg            : FB_MBWriteSingleReg;			(*写入单个寄存器功能块*)bWriteSingleReg             : BOOL;							(*写入单个寄存器执行条件*)nMBAddrSingleReg            : WORD := 4;					(*写入单个寄存器Modbus 地址*)nValueSingleReg             : WORD := 16#1234;				(*写入单个寄存器数值*)
//

PLC程序

fbReadRegs(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502,							//Modbus-Tcp端口号nUnitID:= 1, 							//Modbus-Tcp从站号nQuantity:=nQuantityregs, 				//读取保持寄存器个数nMBAddr:=nMBAddrregs , 					//读取保持寄存器Modbus起始地址cbLength:=SIZEOF(arrDataregs) , 		//存放保持寄存器变量的个数pDestAddr:=ADR(arrDataregs) , 			//存放保持寄存器变量指针起始地址bExecute:=bReadRegs, 					//读取保持寄存器执行条件tTimeout:= T#1S , bBusy=> , bError=> , nErrId=> , cbRead=> );fbWriteRegs(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502, 							//Modbus-Tcp端口号nUnitID:=1 ,							//Modbus-Tcp从站号nQuantity:=nQuantityWriteRegs , 		//写入保持寄存器个数nMBAddr:= nMBAddrWriteRegs , 			//写入保持寄存器起始地址cbLength:= SIZEOF(arrDataWriteRegs), 	//写入变量的个数和指针起始地址pSrcAddr:=ADR(arrDataWriteRegs) , 		//写入变量指针起始地址bExecute:= bWriteRegs , 				//写入保持寄存器的执行条件tTimeout:=T#1S  , bBusy=> , bError=> , nErrId=> );fbWriteSingleReg(//sIPAddr:='169.254.0.1' , 				//modsim32的IP地址sIPAddr:=Server_IpAddress , 				//modsim32的IP地址nTCPPort:=502, 							//Modbus-Tcp端口号nUnitID:=1 , 							//Modbus-Tcp从站号nMBAddr:=nMBAddrSingleReg, 				//写入单个保持寄存器起始地址nValue:=nValueSingleReg, 				//写入单个寄存器数值bExecute:=bWriteSingleReg , 			//写入单个寄存器的执行条件tTimeout:=T#1S , bBusy=> , bError=> , nErrId=> );	

2、通讯测试

(1)寄存器说明

一个MW寄存器对应两个MB寄存器,比如MW0对应12289、12289对应MB0、MB1

PLC 客户端程序中变量

读寄存器地址=40001+nMBAddrregs        则MB0对应设置nMBAddrregs12288

写寄存器地址=40001+nMBAddrWriteRegs        

(2)PLC的Client程序读操作

先给服务端的寄存器赋值

PLCServer程序读

(3)PLC的Client程序写操作

PLC客户端写寄存器

PLC服务端接收到客户端写的寄存器

五、测试工程下载

https://download.csdn.net/download/panjinliang066333/88609166

工程包括:

(1)客户端、服务端PLC程序

(2)TF6250-Modbus-TCP库文件安装软件

(3)ModbusTCP测试工具

模拟客户端:modscan32

模拟服务端:modsim32

(4)倍福官方简单测试参考

这篇关于TwinCAT3 Modbus-TCP Client/Server使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/494411

相关文章

Python使用Pandas对比两列数据取最大值的五种方法

《Python使用Pandas对比两列数据取最大值的五种方法》本文主要介绍使用Pandas对比两列数据取最大值的五种方法,包括使用max方法、apply方法结合lambda函数、函数、clip方法、w... 目录引言一、使用max方法二、使用apply方法结合lambda函数三、使用np.maximum函数

Qt 中集成mqtt协议的使用方法

《Qt中集成mqtt协议的使用方法》文章介绍了如何在工程中引入qmqtt库,并通过声明一个单例类来暴露订阅到的主题数据,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录一,引入qmqtt 库二,使用一,引入qmqtt 库我是将整个头文件/源文件都添加到了工程中进行编译,这样 跨平台

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本