XS_YOUYOU
已于 2023-12-12 13:26:10 修改
阅读量7.8k
收藏 85
点赞数 23
分类专栏: 通信协议 文章标签: java 开发语言 网络协议
版权
通信协议
专栏收录该内容
3 篇文章4 订阅
订阅专栏
简介
采用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自动重连
引入依赖包
1
2
3
4
5
简单入门示例
class Demo {
public static void main(String[] args) {
// 创建PLC对象
S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");
// 读写boolean
s7PLC.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
2
3
4
5
6
7
8
9
10
11
12
知识点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数据访问示例
- 单地址数据读写
// 创建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");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
- 多地址数据读写
// 创建PLC对象
S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");
// read boolean
List
List
List
List
List
// read UInt16
List
// read UInt32
List
// read float32
List
// read float64
List
// 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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 序列化方式小数据量批量读写
小数据量是指单次数据请求的报文中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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
然后构建序列化对象,接着数据读写
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 序列化方式大数据量批量读写
大数据量是指单次数据请求的报文中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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
然后构建序列化对象,接着数据读写
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-
自定义读写方式(开发效率低)
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 -
控制指令
class Demo {
public static void main(String[] args) {
S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");
// hot restart
s7PLC.hotRestart();
// cold restart
s7PLC.coldRestart();
// plc stop
s7PLC.plcStop();
// copy ram to rom
s7PLC.copyRamToRom();
// compress
s7PLC.compress();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
字节数据解析
当采集的数据量比较大且都是字节数组数据时,需要将字节数据转换成所需的数据,可以采用ByteReadBuff工具;
该工具采用大端模式,4字节数据解析采用DCBA,可根据需求自行修改; -
boolean数据类型
ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x55});
// 直接字节解析获取,内部索引自动后移
boolean b1 = buff.getBoolean(0);
// 指定字节索引地址后解析获取
boolean b2 = buff.getBoolean(0, 1);
1
2
3
4
5 -
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);
1
2
3
4
5
6
7
8
9
10
11
12
13
- uint16数据类型
ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x5F, (byte) 0xF5});
int actual = buff.getUInt16();
assertEquals(24565, actual);
1
2
3 - int16数据类型
ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x5F, (byte) 0xF5});
short actual = buff.getInt16();
assertEquals(24565, actual);
1
2
3 - uint32数据类型
ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x00, (byte) 0x20, (byte) 0x37, (byte) 0x36});
long actual = buff.getUInt32();
assertEquals(2111286L, actual);
1
2
3 - int32数据类型
ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x00, (byte) 0x20, (byte) 0x37, (byte) 0x36});
int actual = buff.getInt32();
assertEquals(2111286, actual);
1
2
3 - 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);
1
2
3 - 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);
1
2
3 - string数据类型
ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x33});
String actual = buff.getString(4);
assertEquals("0123", actual);
1
2
3
Springboot中简单使用 -
普通模式
先构建Springboot的工程,添加maven依赖
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok true
org.springframework.boot
spring-boot-starter-test
test
com.github.xingshuangs
iot-communication
1.4.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
添加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 {@Bean
public S7PLC s7PLC() {
return new S7PLC(EPlcType.S1200, "127.0.0.1");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
添加控制层业务
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();@Autowired
private 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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
- 序列化模式
添加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 {@Bean
public S7PLC s7PLC() {
return new S7PLC(EPlcType.S1200, "127.0.0.1");
}@Bean
public S7Serializer s7Serializer(S7PLC s7PLC) {
return new S7Serializer(s7PLC);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
添加数据采集类,添加注解配置
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
添加控制层业务
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 {@Autowired
private S7Serializer s7Serializer;@GetMapping("/bean")
public ResponseEntitydemoBean() {
DemoBean bean = this.s7Serializer.read(DemoBean.class);
return ResponseEntity.ok(bean);
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/XS_YOUYOU/article/details/127775881
未经允许不得转载:lxfamn » JAVA采用S7通信协议访问西门子PLC