简介

采用java的方式实现西门子S7协议

链接地址:iot-communication
github: https://github.com/xingshuangs/iot-communication
gitee: https://gitee.com/xingshuang/iot-communication

  • 支持单数据读写,多数据读写,大数据量自动分包读写
  • 支持序列化批量多地址且地址不连续的读写
  • 支持读取DB区,I区,Q区,M区,V
  • 支持读取西门子S1200,200Smart
  • 支持PLC自动重连

引入依赖包

<dependency><groupId>com.github.xingshuangs</groupId><artifactId>iot-communication</artifactId><version>1.2.6</version>
</dependency>

简单入门示例

class Demo {public static void main(String[] args) {// 创建PLC对象S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");// 读写booleans7PLC.writeBoolean("DB1.2.0", true);boolean boolData = s7PLC.readBoolean("DB1.2.0");// 读写字节s7PLC.writeByte("DB2.1", (byte) 0x11);byte byteData = s7PLC.readByte("DB2.1");}
}

知识点1:地址读写格式以及对应含义(兼容大小写)

简写 区域 字节索引 位索引 PLC
DB1.1.2 DB1区 1 2 1200
DB2 DB2区 0 0 1200
DB3.3 DB3区 3 0 1200
D1.1.2 DB1区 1 2 1200
Q1.6 Q区 1 6 1200
Q1 Q区 1 0 1200
I2.5 I区 2 5 1200
I2 I区 2 0 1200
M3.2 M区 3 2 1200
M3 M区 3 0 1200
V2.1 V区 2 1 200Smart
V2 V区 2 0 200Smart

知识点2:访问数据类型与JAVA数据类型和PLC数据类型对应关系

访问数据类型 数据类型名称 数据大小(位) 数据大小(字节) 对应JAVA数据类型 对应PLC数据类型 示例
boolean 布尔类型 1 1/8 Boolean BOOL true
byte 字节类型 8 1 Byte BYTE 0x11
uint16 无符号2字节整型 16 2 Integer WORD/UINT 65535
int16 有符号2字节整型 16 2 Short WORD/INT -32760
uint32 无符号4字节整型 32 4 Long DWORD/UDINT 70000
int32 有符号4字节整型 32 4 Integer DWORD/DINT -70000
float32 4字节浮点型 32 4 Float REAL 3.14
float64 8字节浮点型 64 8 Double LREAL 3.14
string 字符型 8 1 String String ABC

多种方式PLC数据访问示例

1. 单地址数据读写

// 创建PLC对象
S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");// read boolean
boolean boolData = s7PLC.readBoolean("DB1.2.0");
// read byte
byte byteData = s7PLC.readByte("DB14.0");
byte iByteData = s7PLC.readByte("I0");
byte qByteData = s7PLC.readByte("Q0");
byte mByteData = s7PLC.readByte("M0");
byte vByteData = s7PLC.readByte("V0"); // 200smart有V区
// read byte
byte[] byteDatas = s7PLC.readByte("DB14.0", 4);
// read UInt16
int intData = s7PLC.readUInt16("DB14.0");
// read UInt32
long int32Data = s7PLC.readUInt32("DB1.0");
// read float32
float float32Data = s7PLC.readFloat32("DB1.0");
// read float64
double float64Data = s7PLC.readFloat64("DB1.0");
// read String
String strData = s7PLC.readString("DB14.4");// write boolean
s7PLC.writeBoolean("DB2.0.7", true);
s7PLC.writeBoolean("Q0.7", true);
s7PLC.writeBoolean("M1.4", true);
// write byte
s7PLC.writeByte("DB2.1", (byte) 0x11);
s7PLC.writeByte("M1", (byte) 0x11);
s7PLC.writeByte("V1", (byte) 0x11); // 200smart有V区
// write UInt16
s7PLC.writeUInt16("DB2.0", 0x2222);
// write UInt32
s7PLC.writeUInt32("DB2.0", 0x11111122);
// write float32
s7PLC.writeFloat32("DB2.0", 12);
// write float64
s7PLC.writeFloat64("DB2.0", 12.02);
// write String
s7PLC.writeString("DB14.4", "demo");

2. 多地址数据读写

// 创建PLC对象
S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");// read boolean
List<Boolean> boolDatas = s7PLC.readBoolean("DB1.2.0", "DB1.2.1", "DB1.2.7");
List<Boolean> iDatas = s7PLC.readBoolean("I0.0", "I0.1", "I0.2", "I0.3", "I0.4", "I0.5");
List<Boolean> qDatas = s7PLC.readBoolean("Q0.0", "Q0.1", "Q0.2", "Q0.3", "Q0.4", "Q0.5", "Q0.6", "Q0.7");
List<Boolean> mDatas = s7PLC.readBoolean("M1.0", "M1.1", "M1.2", "M1.3", "M1.4", "M1.5", "M1.6", "M1.7");
List<Boolean> vDatas = s7PLC.readBoolean("V1.0", "V1.1", "V1.2", "V1.3", "V1.4", "V1.5", "V1.6", "V1.7"); // 200smart有V区
// read UInt16
List<Integer> intDatas = s7PLC.readUInt16("DB1.0", "DB1.2");
// read UInt32
List<Long> int32Datas = s7PLC.readUInt32("DB1.0", "DB1.4");
// read float32
List<Float> float32Datas = s7PLC.readFloat32("DB1.0", "DB1.4");
// read float64
List<Double> float64Datas = s7PLC.readFloat64("DB1.0", "DB1.4");
// read multi address
MultiAddressRead addressRead = new MultiAddressRead();
addressRead.addData("DB1.0", 1).addData("DB1.2", 3).addData("DB1.3", 5);
List<byte[]> multiByte = s7PLC.readMultiByte(addressRead);// write multi address
MultiAddressWrite addressWrite = new MultiAddressWrite();
addressWrite.addByte("DB2.0", (byte) 0x11).addUInt16("DB2.2", 88).addBoolean("DB2.1.0", true);
s7PLC.writeMultiData(addressWrite);

3. 序列化方式小数据量批量读写

小数据量是指单次数据请求的报文中PDU大小未超过指定PLC的最大值限制,例如单次请求PDULength小于240,不同PLC的限制各有不同,有240,480,960

先构建数据对象

@Data
public class DemoBean {@S7Variable(address = "DB1.0.1", type = EDataType.BOOL)private boolean bitData;@S7Variable(address = "DB1.1", type = EDataType.BYTE, count = 3)private byte[] byteData;@S7Variable(address = "DB1.4", type = EDataType.UINT16)private int uint16Data;@S7Variable(address = "DB1.6", type = EDataType.INT16)private short int16Data;@S7Variable(address = "DB1.8", type = EDataType.UINT32)private long uint32Data;@S7Variable(address = "DB1.12", type = EDataType.INT32)private int int32Data;@S7Variable(address = "DB1.16", type = EDataType.FLOAT32)private float float32Data;@S7Variable(address = "DB1.20", type = EDataType.FLOAT64)private double float64Data;
}

然后构建序列化对象,接着数据读写

class Demo {public static void main(String[] args) {S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");S7Serializer s7Serializer = S7Serializer.newInstance(s7PLC);// 小数据量批量读取DemoBean bean = s7Serializer.read(DemoBean.class);// 修改指定数据内容bean.setBitData(true);bean.setByteData(new byte[]{(byte) 0x01, (byte) 0x02, (byte) 0x03});bean.setUint16Data(42767);bean.setInt16Data((short) 32767);bean.setUint32Data(3147483647L);bean.setInt32Data(2147483647);bean.setFloat32Data(3.14f);bean.setFloat64Data(4.15);// 小数据量批量写入s7Serializer.write(bean);}
}

4. 序列化方式大数据量批量读写

大数据量是指单次数据请求的报文中PDU大小超过指定PLC的最大值限制,例如单次请求PDULength不得超过240,不同PLC的限制各有不同,有240,480,960

先构建数据对象

@Data
public class DemoLargeBean {@S7Variable(address = "DB1.0.1", type = EDataType.BOOL)private boolean bitData;@S7Variable(address = "DB1.10", type = EDataType.BYTE, count = 50)private byte[] byteData1;@S7Variable(address = "DB1.60", type = EDataType.BYTE, count = 65)private byte[] byteData2;@S7Variable(address = "DB1.125", type = EDataType.BYTE, count = 200)private byte[] byteData3;@S7Variable(address = "DB1.325", type = EDataType.BYTE, count = 322)private byte[] byteData4;@S7Variable(address = "DB1.647", type = EDataType.BYTE, count = 99)private byte[] byteData5;@S7Variable(address = "DB1.746", type = EDataType.BYTE, count = 500)private byte[] byteData6;@S7Variable(address = "DB1.1246", type = EDataType.BYTE, count = 44)private byte[] byteData7;
}

然后构建序列化对象,接着数据读写

class Demo {public static void main(String[] args) {S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");S7Serializer s7Serializer = S7Serializer.newInstance(s7PLC);// 大数据量批量读取DemoLargeBean bean = s7Serializer.read(DemoLargeBean.class);// 指定地址数据更改bean.getByteData2()[64] = (byte) 0x02;bean.getByteData3()[199] = (byte) 0x03;bean.getByteData4()[321] = (byte) 0x04;bean.getByteData5()[98] = (byte) 0x05;bean.getByteData6()[499] = (byte) 0x06;bean.getByteData7()[43] = (byte) 0x07;// 大数据量批量写入s7Serializer.write(bean);}
}

5. 自定义读写方式(开发效率低)

class Demo {public static void main(String[] args) {S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");// bit数据读写byte[] expect = new byte[]{(byte) 0x00};this.s7PLC.writeRaw(EParamVariableType.BIT, 1, EArea.DATA_BLOCKS, 1, 0, 3,EDataVariableType.BIT, expect);byte[] actual = this.s7PLC.readRaw(EParamVariableType.BIT, 1, EArea.DATA_BLOCKS, 1, 0, 3);// byte数据读写expect = new byte[]{(byte) 0x02, (byte) 0x03};this.s7PLC.writeRaw(EParamVariableType.BYTE, 2, EArea.DATA_BLOCKS, 1, 1, 0,EDataVariableType.BYTE_WORD_DWORD, expect);actual = this.s7PLC.readRaw(EParamVariableType.BYTE, 2, EArea.DATA_BLOCKS, 1, 1, 0);}
}

6. 控制指令

class Demo {public static void main(String[] args) {S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");// hot restarts7PLC.hotRestart();// cold restarts7PLC.coldRestart();// plc stops7PLC.plcStop();// copy ram to roms7PLC.copyRamToRom();// compresss7PLC.compress();}
}

字节数据解析

当采集的数据量比较大且都是字节数组数据时,需要将字节数据转换成所需的数据,可以采用ByteReadBuff工具;
该工具采用大端模式,4字节数据解析采用DCBA,可根据需求自行修改;

1. boolean数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x55});
// 直接字节解析获取,内部索引自动后移
boolean b1 = buff.getBoolean(0);
// 指定字节索引地址后解析获取
boolean b2 = buff.getBoolean(0, 1);

2. byte数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x55, (byte) 0x33, (byte) 0x22});
// 先提取第一个字节
buff.getByte();
// 再提取后两个字节
byte[] actual = buff.getBytes(2);
assertArrayEquals(new byte[]{(byte) 0x33, (byte) 0x22}, actual);buff = new ByteReadBuff(new byte[]{(byte) 0x55, (byte) 0x33, (byte) 0x22});
// 先提取第一个字节
buff.getByte();
// 再提取剩余所有字节
actual = buff.getBytes();
assertArrayEquals(new byte[]{(byte) 0x33, (byte) 0x22}, actual);

3. uint16数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x5F, (byte) 0xF5});
int actual = buff.getUInt16();
assertEquals(24565, actual);

4. int16数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x5F, (byte) 0xF5});
short actual = buff.getInt16();
assertEquals(24565, actual);

5. uint32数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x00, (byte) 0x20, (byte) 0x37, (byte) 0x36});
long actual = buff.getUInt32();
assertEquals(2111286L, actual);

6. int32数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x00, (byte) 0x20, (byte) 0x37, (byte) 0x36});
int actual = buff.getInt32();
assertEquals(2111286, actual);

7. float32数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x42, (byte) 0x04, (byte) 0xA3, (byte) 0xD7});
float actual = buff.getFloat32();
assertEquals(33.16f, actual, 0.001);

8. float64数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x41, (byte) 0x03, (byte) 0x1F, (byte) 0xCA, (byte) 0xD6, (byte) 0x21, (byte) 0x39, (byte) 0xB7});
double actual = buff.getFloat64();
assertEquals(156665.35455556, actual, 0.001);

9. string数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x33});
String actual = buff.getString(4);
assertEquals("0123", actual);

Springboot中简单使用

1. 普通模式

先构建Springboot的工程,添加maven依赖

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/com.github.xingshuangs/iot-communication --><dependency><groupId>com.github.xingshuangs</groupId><artifactId>iot-communication</artifactId><version>1.2.6</version></dependency></dependencies>

添加PLC相关配置,主要是对连接对象实例化,创建bean

package com.github.xingshuangs.s7.demo.config;import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.serializer.S7Serializer;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author xingshuang*/
@Configuration
public class S7Config {@Beanpublic S7PLC s7PLC() {return new S7PLC(EPlcType.S1200, "127.0.0.1");}
}

添加控制层业务

package com.github.xingshuangs.s7.demo.controller;import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Random;/*** @author xingshuang*/
@RestController
@RequestMapping("/normal")
public class S7NormalComController {Random random = new Random();@Autowiredprivate S7PLC s7PLC;@GetMapping("/uint16")public ResponseEntity uint16() {this.s7PLC.writeUInt16("DB1.0", random.nextInt(255));int res = this.s7PLC.readUInt16("DB1.0");return ResponseEntity.ok(res);}@GetMapping("/boolean")public ResponseEntity booleanTest() {this.s7PLC.writeBoolean("DB1.0.0", random.nextInt(255) % 2 == 0);boolean res = this.s7PLC.readBoolean("DB1.0.0");return ResponseEntity.ok(res);}@GetMapping("/float32")public ResponseEntity float32Test() {this.s7PLC.writeFloat32("DB1.0", random.nextFloat());float res = this.s7PLC.readFloat32("DB1.0");return ResponseEntity.ok(res);}@GetMapping("/string")public ResponseEntity stringTest() {this.s7PLC.writeString("DB1.0", String.valueOf(random.nextInt(20)));String res = this.s7PLC.readString("DB1.0");return ResponseEntity.ok(res);}
}

2. 序列化模式

添加S7序列化对象

package com.github.xingshuangs.s7.demo.config;import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.serializer.S7Serializer;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author xingshuang*/
@Configuration
public class S7Config {@Beanpublic S7PLC s7PLC() {return new S7PLC(EPlcType.S1200, "127.0.0.1");}@Beanpublic S7Serializer s7Serializer(S7PLC s7PLC) {return new S7Serializer(s7PLC);}
}

添加数据采集类,添加注解配置

package com.github.xingshuangs.s7.demo.model;import com.github.xingshuangs.iot.protocol.common.enums.EDataType;
import com.github.xingshuangs.iot.protocol.s7.serializer.S7Variable;
import lombok.Data;/*** 测试对象** @author xingshuang*/
@Data
public class DemoBean {@S7Variable(address = "DB1.0.1", type = EDataType.BOOL)private boolean bitData;@S7Variable(address = "DB1.4", type = EDataType.UINT16)private int uint16Data;@S7Variable(address = "DB1.6", type = EDataType.INT16)private short int16Data;@S7Variable(address = "DB1.8", type = EDataType.UINT32)private long uint32Data;@S7Variable(address = "DB1.12", type = EDataType.INT32)private int int32Data;@S7Variable(address = "DB1.16", type = EDataType.FLOAT32)private float float32Data;@S7Variable(address = "DB1.20", type = EDataType.FLOAT64)private double float64Data;@S7Variable(address = "DB1.28", type = EDataType.BYTE, count = 3)private byte[] byteData;
}

添加控制层业务

package com.github.xingshuangs.s7.demo.controller;import com.github.xingshuangs.iot.protocol.s7.serializer.S7Serializer;
import com.github.xingshuangs.s7.demo.model.DemoBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author xingshuang*/
@RestController
@RequestMapping("/serializer")
public class S7SerializerComController {@Autowiredprivate S7Serializer s7Serializer;@GetMapping("/bean")public ResponseEntity<DemoBean> demoBean() {DemoBean bean = this.s7Serializer.read(DemoBean.class);return ResponseEntity.ok(bean);}
}

JAVA采用S7通信协议访问西门子PLC相关推荐

  1. Java使用S7协议连接西门子PLC1200、1500

    Java使用S7协议连接西门子PLC1200.1500 1.引入s7包 2.测试代码(可参考使用) 1.引入s7包 使用 https://github.com/s7connector/s7connec ...

  2. php读取西门子plc_基于Socket访问西门子PLC系列教程(二)

    本文是西门子开放式TCP通信的第2篇,上一篇我们讲了使用西门子1200PLC作为TCP服务器的程序编写,可以点击下方链接阅读:[公众号dotNet工控上位机:thinger_swj] 基于Socket ...

  3. 基于Socket访问西门子PLC系列教程(二)

    本文是西门子开放式TCP通信的第2篇,上一篇我们讲了使用西门子1200PLC作为TCP服务器的程序编写,可以点击下方链接阅读:[公众号dotNet工控上位机:thinger_swj] 基于Socket ...

  4. 西门子标准报文1常用_基于Snap7使用C#编程访问西门子PLC系列教程(2)-S7协议

    本文是Snap7软件包系列教程的第2篇,我们来介绍下S7协议,包括如下几个主题: 1.S7协议简介 2.S7协议命令简介 3.S7协议通信的角色与模式 1.S7协议简介 S7协议是西门子S7系列PLC ...

  5. 西门子smartclient怎么用_基于Snap7使用C#编程访问西门子PLC系列教程(3)-Snap7Client(建立连接)...

    本文是Snap7软件包系列教程的第3篇. 在上一篇文章中,我们介绍了S7通信协议中有三种角色:客户端/服务器/伙伴:有两种通信模式:客户端/服务器(Client/Server)模式和伙伴/伙伴(Par ...

  6. C#中使用S7.net与西门子PLC通讯

    最近因为工作的原因用到了西门子PLC,在使用过程中一直在思考上位机和PLC的通讯问题,后来上网查了一下,找到了一个专门针对S7开发的一个.net库–<S7netPlus>,PLC通讯方法比 ...

  7. .net通过S7.net读写西门子PLC中,字符串,bool,整数,小数及byte型

    注:.net中通过TCP/IP方式通过S7.net.dll动态库,连接到西门子PLC,西门子程序中许勾选优化块,程序读取需要 db块号+偏移量 一.使用VS项目,在项目中添加S7.net动态库 代码中 ...

  8. 基于MQTT通信协议的西门子PLC水塔水位远程监控系统

    水塔常见于高层建筑二次供水.蓄水.水处理.冷却水.化工厂.电子厂等场景中,是生产生活的重要组成部分.通过PLC可以保持给水管网中的水量和水压恒定,具备良好的经济效益,但各项数据存储于本地,导致无法及时 ...

  9. jetson nano上编译与使用西门子PLC通讯库snap7

    文章目录 一.西门子snap7介绍 二.西门子S7通讯介绍 三.jetson nano编译snap7库 四.Qt Cmake导入snap7库 五.snap7主要函数说明 1.与PLC建立连接 2.读写 ...

最新文章

  1. 95后女生坚持转数学专业,成功直博双一流!网友:这是高手……
  2. oracle数据库查询人员和岗位,oracle岗位需求收集
  3. iOS - Bundle 资源文件包
  4. 1.5 成员方法的声明和调用,形参,实参
  5. vue----第一个工程项目
  6. C# Hashtable和Dictionary区别
  7. linux mc服务器 mod_如何在linux搭建MC服务器
  8. Enterprise Services (COM+)服务组件开发异常分析
  9. ECMAScript6 ES6语法
  10. 一文看懂大数据领域的六年巨变
  11. 简单说 !![]==true 与 []==true 引发的思考
  12. cpri带宽不足的解决方法_CPRI基带数据的低损耗压缩
  13. 使用阿里云服务来部署云桌面
  14. 值得收藏:一份非常完整的MySQL规范
  15. selenium自动化测试环境搭建及启动safair浏览器(Mac)
  16. 计算机视觉中的MAP的理解(mean average precision)
  17. 正则表达式的贪婪型,勉强型,占有型
  18. 一个轻巧高效的多线程c++stream风格异步日志(一)
  19. Rust地图下载、Rust服务器地图下载教程、腐蚀地图下载攻略
  20. Setting property ‘source‘ to ‘org.eclipse.jst.jee.server

热门文章

  1. 亚马逊推出的「距离助手」,好像孙悟空给唐僧画的圈圈啊!
  2. js 当前时间减6个月
  3. 织梦主动提交_织梦发布文章主动推送(实时)给百度的方法
  4. Python图像处理(车牌识别)简单
  5. OpenSIPS介绍及模块||OpenSIPS介绍_安装_使用
  6. python评价指标_[Python人工智能] 六.神经网络的评价指标、特征标准化和特征选择...
  7. linux 驱动 device,driver ,bus 关系
  8. 接口测试—-工具篇,实现接口自动化
  9. python合并excel的多个sheet
  10. 【作用域、自由变量】