1.连接PLC
public static S7Connector initConnect(){ S7Connector s7Connector; try { s7Connector = S7ConnectorFactory .buildTCPConnector() .withHost("xx.xx.xx.xx")//PLC对应的ip地址 .withPort(102) //端口号,默认的是102 .withRack(0) //机架号 .withSlot(1) //槽位号 .withTimeout(2000) //连接超时时间 .build(); }catch (Exception e){ log.error("PLC连接失败,请检查"); return null; } return s7Connector; }
/** * 关闭plc连接 */ public static void closeConnect(S7Connector connector){ try { connector.close(); }catch (Exception ex){ log.error("plc关闭异常==={}",ex.getMessage()); } } /** * 写入值 * dbNum--DB编码,offset--偏移量,value--写入的值,length--写入值占用的字节长度 * type: * int(java--Integer类型):1 * Dint(java--Long类型):2 * Real(java--Double):3 * LReal(java--长浮点数,没有对应的类型):4 */ public static void writeValue(int dbNum,int offset,int value,int type){ //创建连接 initConnect() 对应的连接PLC方法 S7Connector s7Connector = initConnect(); //将参数转换成对应格式的byte数组 byte[] bytes = getByte(value,0,type); //写入PLC //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:偏移量 //第四个参数:写入的数据 二进制数组byte[] s7Connector.write(DaveArea.DB,dbNum, offset,bytes); log.info("写入参数成功,offset--{},value--{}",offset,value); //关闭连接 closeConnect(s7Connector); } public static void writeValue(int dbNum,int offset,double value,int type){ //创建连接 S7Connector s7Connector = initConnect(); //将参数转换成对应格式的byte数组 byte[] bytes = getByte(0,value,type); //写入PLC //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:偏移量 //第四个参数:写入的数据 二进制数组byte[] s7Connector.write(DaveArea.DB,dbNum, offset,bytes); log.info("写入参数成功,offset--{},value--{}",offset,value); //关闭连接 closeConnect(s7Connector); } /** * 获取对应类型的byte[]数组 * type: * 1-int * 2-Dint * 3-LReal * 4-Real */ public static byte[] getByte(int value1,double value2,int type){ byte[] bytes = new byte[0]; if ( type == 1 ){ bytes = ByteBuffer.allocate(2).putShort((short)value1).array(); } if ( type == 2 ){ bytes = ByteBuffer.allocate(4).putInt(value1).array(); } if ( type == 3 ){ bytes = ByteBuffer.allocate(4).putFloat((float) value2).array(); } if ( type == 4 ){ bytes = ByteBuffer.allocate(8).putDouble(value2).array(); } return bytes; } public static void writeValue(S7Connector s7Connector,int dbNum,int offset,int value,int length){ //将参数转换成对应格式的byte数组 byte[] bytes = ByteBuffer.allocate(length).putShort((short) value).array(); //写入PLC //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:偏移量 //第四个参数:写入的数据 二进制数组byte[] s7Connector.write(DaveArea.DB,dbNum, offset,bytes); log.info("写入参数成功,offset--{},value--{}",offset,value); } //读取PLC中的int类型 public static Integer readInt(int dbNum,int offset){ //创建连接 S7Connector s7Connector = initConnect(); //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:数据长度 //第四个参数:偏移量 byte[] getBytes = s7Connector.read(DaveArea.DB, dbNum, 2, offset); S7Serializable converter = new IntegerConverter(); Integer data = converter.extract(Integer.class, getBytes, 0, 0); closeConnect(s7Connector); return data; } //读取PLC中的Real类型 public static float readReal(int dbNum,int offset){ //创建连接 S7Connector s7Connector = initConnect(); //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:数据长度 //第四个参数:偏移量 byte[] getBytes = s7Connector.read(DaveArea.DB, dbNum, 4, offset); float getValue = ByteBuffer.wrap(getBytes).getFloat(); closeConnect(s7Connector); return getValue; }
//读取word类型,点位信息里面存储的是16进制数 public void testReadPlcDIntData() { S7Connector s7Connector = initConnect(); //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:数据长度,这个长度为2,因为当前点位信息里面存储的是2位,相当于有4位16进制数,对应的是16位的二进制数 //第四个参数:偏移量 byte[] getBytes = s7Connector.read(DaveArea.DB, 63, 2, 4); //创建字符串,用于存储对应的每位上面的十六进制数 StringBuilder sb = new StringBuilder(); //遍历byte数组,解析出对应的16进制数 for ( byte item : getBytes ){ sb.append(Integer.toHexString((item & 0xFF) | 0x100),1,3); } //打印出读取到的点位信息数据,例如会读取出来0000,fe11的十六进制数 //0000-转换成2进制就是0000 0000 0000 0000 System.out.println(sb); try { s7Connector.close(); } catch (IOException e) { e.printStackTrace(); } }
/** * 批量读取 */ public void batchRead(){ //连接PLC S7Connector s7Connector = initConnect(); //PLC实例化 S7Serializer s7Serializer = S7SerializerFactory.buildSerializer(s7Connector); //PlcDuo是对应映射出来的实体对象,相当于PLC里面对应的点位信息,101-是指读取的那个DB块,例如DB101,就写入101,0-相当于就是当前点位信息什么的第一个bit PlcDuo plcScanData = s7Serializer.dispense(PlcDuo.class, 101,0); //打印出实体 System.out.println(plcScanData); }
/** * 获取plc扫描过程中,获取的参数信息 * S7Type.REAL--对应Double类型 * S7Type.WORD--对应Integer类型 * S7Type.BOOL--对应Boolean类型 * type是这个点位在PLC中设置的类型,源码会解析其长度; * byteOffset对应PLC偏移量中的整数部分; * bitOffset指偏移量的小数部分,bitOffset指第几个bit. * byteOffset和bitOffset 也可理解为返回的byte[]中第byteOffset到bitOffset */ @Data public class PlcDuo { @S7Variable(byteOffset = 218, type = S7Type.REAL) public Integer startScan; @S7Variable(byteOffset = 186, type = S7Type.REAL) public Double yInterval; @S7Variable(byteOffset = 136,bitOffset = 0,type = S7Type.BOOL) public Boolean var1; }
/** * 批量写 */ @Test public void batchWrite(){ //创建plc连接 S7Connector s7Connector = initConnect(); //PLC实例化 S7Serializer s7Serializer = S7SerializerFactory.buildSerializer(s7Connector); //创建实体对象 PlcDuo plcScanData = new PlcDuo(); //给对象属性赋值,相当于点位信息赋值 plcScanData.setVar1(true); //进行批量的写入,100-对应的DB块100 s7Serializer.store(plcScanData,100,0); }
/** * 读取PLC中的浮点型Double(8字节)数据 * java float : plc Real 4 字节 * java double : plc LReal 8 字节 **/ @Test public void testReadPlcLRealData() { S7Connector s7Connector = initConnect(); //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:数据长度 //第四个参数:偏移量 byte[] getBytes = s7Connector.read(DaveArea.DB, 102, 4, 178); //读取LReal类型的必须进行特殊处理,不然读取到的小数会失去精度 double getValue = ByteBuffer.wrap(getBytes).getDouble(); NumberFormat nf = NumberFormat.getInstance(); nf.setGroupingUsed(false); System.out.println("getDoubleData:"+nf.format(getValue)); try { s7Connector.close(); } catch (IOException e) { e.printStackTrace(); } }
注意点:如果需要进行批量写入的话,需要将当前DB块儿上面所有的点位信息都要进行赋值,不然的话,没有赋值到的点位信息(对应的实体某个属性值),将会在批量写入之后变成默认值,int类型的会置0,boolean类型的会置为false。
批量读取的话,int,Real,Boolean都是可以批量读取的,但是LReal是不能进行批量读取的。而且单独读取的话,也必须将读取的byte数组进行特殊的处理,才能将读取到的数据不丢失精度。
其余的类型S7Connector中都内置了对应的转置方法,对应引用就行,例如读取int类型,就可以使用new IntegerConverter()内置方法来进行byte数组的处理。
S7Connector s7Connector = initConnect(); //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:数据长度 //第四个参数:偏移量 byte[] getBytes = s7Connector.read(DaveArea.DB, 101, 2, 146); //公共方法 S7Serializable converter = new IntegerConverter(); Integer data = converter.extract(Integer.class, getBytes, 0, 0); System.out.println(data);