这是我项目的代码,算是真实业务实现,记录备份一下实现思路

因为业务就是简单的获取数据然后保存,所以还是容易理解的

1.任务详情

  • Java实现OPC通信的代码实现
  • 最终实现对西门子的S7-300的PLC变量的值读写

2.实现情况

说明

  • PC和PLC通信,PC用TAG1之类的地址,PLC用BD1.INT05之类的地址,个人总结的表格,方便说明
OPCServer上定义的地址名称 硬件PLC上的地址 数据类型 说明:这个地址做什么用的
TAG1 DB1.INT00 short 心跳
TAG2 DB1.INT02 short 控制字
TAG3 DB1.STRING4,10 string 箱体信息
TAG4 DB1.D14 float 结果
  • 地址定义在OPCServer上,实际截图

  • 制定交互流程:控制字的状态
  • 心跳变量:TAG1,表示软件和硬件(这里是PLC)连接状态,这个是自己随便定义的,我的是:PLC一直写1,PC收到1写2,5秒内一直收不到1就是断开了。
  • 控制字(状态变量):TAG2,作用是作为一个控制字,控制整个交互的流程,当是不同值时,PLC和PC要进行指定的读写动作。

这是我一开始画的

这是后来画的,就是PC和PLC的交互,比较清晰了

实际的PLC地址编辑界面截图

3. 代码实现

  • 按照官方例子写了一个通信类:通过配置信息,启动server,添加要读取的地址
  • 配置信息是单独一个类:从配置文件读取IP什么的
  • 然后是回调函数:某个地址,读到了某个值要怎么做,,在这就2个回调,心跳TAG1:读到1写入2,5秒超时,TAG2:是某个值时,怎么做。。。
  • 读值和写值可以单独算一个方法类:我用到的数据类型就是几个,short,string,Long Array,对应写了几个方法
  • OPCServer上的地址配置也算是一个单独的类:我写在配置文件了,当时犹豫是不是放到数据库,感觉差别不大
  • Utgard有两种数据访问方式——直接通过item的read/write方法或者使用AccessBase(读取数据)
  • 心跳TAG1:PC写2,PLC写1,逻辑是PC收到1写2,超时提示
  • 控制字TAG2:PLC写0,1,3,4,5,6/7,PC写2,8
    • PC在写TAG2=1时,同时写入TAG3值
    • PLC在写TAG2=6/7时,同时写入TAG4值
  • 读线程:每隔500ms读一次值,读到值后执行回调方法DataCallback()
    • 不用另起线程,直接用这个Access线程循环读取控制字的值,回调方法对应调用item的read/write方法读写值
final AccessBase access = new SyncAccess(server, 500);
access.addItem(itemId, new DataCallback() {
@Override
public void changed(Item item, ItemState state) {
System.out.println("-----" + state);
}
});
// start reading
access.bind();

4.代码:OPCserver连接配置类

import java.io.IOException;
import java.util.Properties;
import org.openscada.opc.lib.common.ConnectionInformation;
/**
* 配置文件工具类
*/
public final class OPCConfiguration {
private final static ConnectionInformation ci;
private final static Properties prop;
public final static String CONFIG_USERNAME = "username";
public final static String CONFIG_PASSWORD = "password";
public final static String CONFIG_HOST = "host";
public final static String CONFIG_DOMAIN = "domain";
public final static String CONFIG_CLSID = "clsid";
public final static String CONFIG_PROGID = "progid";
private final static String CONFIG_FILE_NAME = "opc.properties";
/**
* 加载配置文件
*/
static {
ci = new ConnectionInformation();
prop = new Properties();
try {
prop.load(OPCConfiguration.class.getClassLoader().getResourceAsStream(CONFIG_FILE_NAME));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 通过名字获得配置的值
*/
public static String getEntryValue(String name) {
return prop.getProperty(name);
}
/**
* 获得包含ClsId的连接信息
*/
public static ConnectionInformation getCLSIDConnectionInfomation() {
ci.setProgId(null);
getConnectionInfomation();
ci.setClsid(prop.getProperty(CONFIG_CLSID));
return ci;
}
/**
* 获得包含ProgId的连接信息
*/
public static ConnectionInformation getPROGIDConnectionInfomation() {
ci.setClsid(null);
getConnectionInfomation();
ci.setProgId(prop.getProperty(CONFIG_PROGID));
return ci;
}
/**
* 获得基础的连接信息
*/
private static void getConnectionInfomation() {
ci.setHost(prop.getProperty(CONFIG_HOST));
ci.setDomain(prop.getProperty(CONFIG_DOMAIN));
ci.setUser(prop.getProperty(CONFIG_USERNAME));
ci.setPassword(prop.getProperty(CONFIG_PASSWORD));
}
}

5.代码:通信实现类

package cn.com.tcb.assembly.management.listener;
import static cn.com.tcb.assembly.management.listener.OPCConfiguration.getCLSIDConnectionInfomation;
import java.util.concurrent.Executors;
import org.jinterop.dcom.common.JIException;
import org.openscada.opc.lib.common.ConnectionInformation;
import org.openscada.opc.lib.da.AccessBase;
import org.openscada.opc.lib.da.Group;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.Server;
import org.openscada.opc.lib.da.SyncAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 功能:OPC通信线程 描述:通过循环读取心跳和状态控制字,按照商议好的交互流程读写变量
*/
public class OPCComm {
private static Logger logger = LoggerFactory.getLogger(OPCComm.class);
private Item item_heartbeat;
private Item item_status;
private Item item_ordernum;
private Item item_sn;
private Item item_boxnum;
private Item item_abnormal;
private Item item_finish;
private Item item_result;
private Server server;
/**
* 单例模式
*/
private static class SingletonHolder {
static final OPCComm doOPCComm = new OPCComm();
}
public static OPCComm getInstance() {
return SingletonHolder.doOPCComm;
}
/**
* 启动server 创建一个监控线程 创建一个写入线程
*/
public void init() throws Exception {
// 加载配置文件
final ConnectionInformation ci = getCLSIDConnectionInfomation();
// 创建server
final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
try {
// 启动server
server.connect();
logger.info("This is {} message.", "OPCserver connect success");
this.server = server;
// 同步读取,500ms一次
final AccessBase access = new SyncAccess(server, 500);
access.addItem(OPCElement.ITEMID_HEARTBEAT, new DataCallBack_HeartBeat());
access.addItem(OPCElement.ITEMID_STATUS, new DataCallBack_Status());
// 添加一个组
final Group group = server.addGroup("sew");
item_heartbeat = group.addItem(OPCElement.ITEMID_HEARTBEAT);
item_status = group.addItem(OPCElement.ITEMID_STATUS);
item_ordernum = group.addItem(OPCElement.ITEMID_ORDERNUM);
item_sn = group.addItem(OPCElement.ITEMID_SN);
item_boxnum = group.addItem(OPCElement.ITEMID_BOXNUM);
item_abnormal = group.addItem(OPCElement.ITEMID_ABNORMAL);
item_finish = group.addItem(OPCElement.ITEMID_FINISH);
item_result = group.addItem(OPCElement.ITEMID_RESULT);
// start reading
access.bind();
} catch (final JIException e) {
System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
}
}
public Item getItem_heartbeat() {
return item_heartbeat;
}
public Item getItem_status() {
return item_status;
}
public Item getItem_ordernum() {
return item_ordernum;
}
public Item getItem_sn() {
return item_sn;
}
public Item getItem_boxnum() {
return item_boxnum;
}
public Item getItem_abnormal() {
return item_abnormal;
}
public Item getItem_finish() {
return item_finish;
}
public Item getItem_result() {
return item_result;
}
public Server getServer() {
return server;
}
}

6.代码:工具类:读写值

package cn.com.tcb.assembly.management.listener;

import java.text.DecimalFormat;

import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIArray;
import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.ItemState; public class OPCUnit { /**
* 写值到变量
*/
public static void write(Item item, String val) {
try {
JIVariant value = new JIVariant(val);
item.write(value);
} catch (JIException e) {
e.printStackTrace();
}
} /**
* 写值到变量:数组
*/
public static void write(Item item, String[] snArray) {
try { /** 构造写入数据 */
Long[] integerData = new Long[snArray.length];
for (int i = 0; i < snArray.length; i++) {
integerData[i] = Long.valueOf(snArray[i]);
}
final JIArray array = new JIArray(integerData, false);
final JIVariant value = new JIVariant(array); item.write(value);
} catch (JIException e) {
e.printStackTrace();
}
} /**
* 读变量的值 如果是short和int直接返回字符串; 如果是long类型的数组,返回数字内容间加点,对应long,数组,大小为6
* 如果是float类型的数组,返回数字内容间加逗号,对应float,数组,大小为20
*/
public static String read(Item item) {
String result = "";
try {
ItemState state = item.read(true);
int type = state.getValue().getType(); if (type == JIVariant.VT_UI4) {
int value = state.getValue().getObjectAsInt();
return value + "";
} else if (type == JIVariant.VT_I2) {
short value = state.getValue().getObjectAsShort();
return value + "";
} else if (type == 8195) {
JIArray jarr = state.getValue().getObjectAsArray();
Integer[] arr = (Integer[]) jarr.getArrayInstance();
String value = "";
for (Integer i : arr) {
value = value + i + ".";
}
String res = value.substring(0, value.length() - 1);
// "25.36087601.1.1.18.36"-->"25.36087601.01.0001.18.36"
String[] array = res.split("[.]");
String ress = array[0] + "." + array[1] + "." + new DecimalFormat("00").format(Long.valueOf(array[2]))
+ "." + new DecimalFormat("0000").format(Long.valueOf(array[3])) + "." + array[4] + "."
+ array[5];
return ress; } else if (type == 8196) {
JIArray jarr = state.getValue().getObjectAsArray();
Float[] arr = (Float[]) jarr.getArrayInstance();
String value = "";
for (Float f : arr) {
value = value + f + ",";
}
return value.substring(0, value.length() - 1);
} } catch (JIException e) {
e.printStackTrace();
}
return result;
} }

7.代码:回调函数:实现心跳

package cn.com.tcb.assembly.management.listener;
import java.awt.Color;
import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.lib.da.DataCallback;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.ItemState;
import cn.com.tcb.assembly.base.core.AppContext;
import cn.com.tcb.assembly.base.utils.GlobalVariable;
import cn.com.tcb.assembly.management.ui.main.MainFrame;
public class DataCallBack_HeartBeat implements DataCallback {
private OPCComm opc = OPCComm.getInstance();
private int count = 0;@
Override
public void changed(Item item, ItemState state) {
// 读取心跳变量的值
try {
if (state.getValue().getType() == JIVariant.VT_I2) {
short n = state.getValue().getObjectAsShort();
setHeartbeat(n);
}
} catch (JIException e) {
e.printStackTrace();
}
}
/**
* 设置心跳标志位,保存到全局变量
*/
public void setHeartbeat(short n) {
MainFrame main = (MainFrame) AppContext.getParam(GlobalVariable.MAIN_UI);
if (n == 1) {
OPCUnit.write(opc.getItem_heartbeat(), "2");
GlobalVariable.heartbeat = true;
main.getHeartbeat().setBackground(Color.GREEN);
count = 0;
} else {
count++;
}
// 循环读取频率是:500ms一次,如果超过6次,也就是3s认定超时
if (count > 6) {
GlobalVariable.heartbeat = false;
main.getHeartbeat().setBackground(Color.RED);
}
}
}

8.代码:回调函数:实现业务

package cn.com.tcb.assembly.management.listener;

import java.awt.Color;

import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.lib.da.DataCallback;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.ItemState;
import cn.com.tcb.assembly.base.core.AppContext;
import cn.com.tcb.assembly.base.core.BeanContainer;
import cn.com.tcb.assembly.base.model.JobCard;
import cn.com.tcb.assembly.base.model.TestResult;
import cn.com.tcb.assembly.base.service.JobCardService;
import cn.com.tcb.assembly.base.service.TestResultService;
import cn.com.tcb.assembly.base.utils.GlobalVariable;
import cn.com.tcb.assembly.base.utils.StringUtil;
import cn.com.tcb.assembly.management.ui.main.MainFrame; /**
* 根据控制字:向PLC写入工单信息,保存结果
*/
public class DataCallBack_Status implements DataCallback {
private OPCComm opc = OPCComm.getInstance();
private TestResultService testResultService = (TestResultService) BeanContainer.getBean("testResultService");
private MainFrame main = (MainFrame) AppContext.getParam(GlobalVariable.MAIN_UI); @Override
public void changed(Item item, ItemState itemState) { // 读取状态变量的值
try {
if (itemState.getValue().getType() == JIVariant.VT_I2) {
short n = itemState.getValue().getObjectAsShort(); // 前提是有心跳
if (GlobalVariable.heartbeat) {
doProcess(n);
}
}
} catch (JIException e) {
e.printStackTrace();
}
} /**
* 状态控制字: 0:PLC上电,1:允许新工单,2:新任务,3:收到任务,4:准备执行,5:开始执行 6:正常完成,7:异常玩常完成,8:收到完成信号
*/
private void doProcess(short n) {
if (n == 0) {
setStatus(Color.GREEN, "等待设备初始化");
GlobalVariable.isAllowInput = true;
} else if (n == 1) {
setStatus(Color.GREEN, "请输入工单");
GlobalVariable.isAllowInput = true;
} else if (n == 2) {
setStatus(Color.GREEN, "发送成功,等待设备处理");
} else if (n == 3) {
setStatus(Color.GREEN, "设备收到工单");
GlobalVariable.isAllowInput = false;
} else if (n == 4) {
setStatus(Color.GREEN, "设备准备执行");
GlobalVariable.isAllowInput = false;
} else if (n == 5) {
setStatus(Color.GREEN, "设备开始执行");
GlobalVariable.isAllowInput = false;
// 写入初始结果,记录开始时间
if (!GlobalVariable.isHaveOrder) {
reconnectAction();
} else {
saveStartResult();
} } else if (n == 6) {
setStatus(Color.GREEN, "正常完成"); // 写入最终结果,记录结束时间
if (!GlobalVariable.isHaveOrder) {
reconnectAction();
}
saveEndResult(OPCControllerState.NORMALEND); } else if (n == 7) {
setStatus(Color.RED, "异常完成"); // 写入最终结果,记录结束时间
if (!GlobalVariable.isHaveOrder) {
reconnectAction();
}
saveEndResult(OPCControllerState.ABNORMALEND); } else if (n == OPCControllerState.SAVESUCCESS) {
setStatus("结果保存成功");
} else {
setStatus(Color.RED, "异常");
}
} /**
* 设置主界面状态信息
*/
private void setStatus(Color color, String status) {
main.getStatus().setText(status);
main.getStatus().setBackground(color);
} private void setStatus(String status) {
main.getStatus().setText(status);
} /**
* 保存初始结果:5
*/
private void saveStartResult() {
if (!GlobalVariable.isSaveStartSuccess) {
// 从全局变量获取结果表
TestResult t = (TestResult) AppContext.getParam(GlobalVariable.PARAM_KEY_TESTRESULT); // 开始时间
String startTime = testResultService.getDate();
t.setStartTime(startTime);
main.getStartTime().setText(startTime); // 装配日期
t.setDate(startTime.split("[ ]")[0]); // 保存结果表到全局变量
AppContext.setParam(GlobalVariable.PARAM_KEY_TESTRESULT, t); // 保存结果到数据库
int n = testResultService.getSqlServerCountBySerialNumber(t.getSerialNumber());
if (n == 0) {
testResultService.saveResult(t);
} else {
testResultService.updateResult(t);
} GlobalVariable.isSaveStartSuccess = true;
}
} /**
* 保存最终结果:6或者7
*/
private void saveEndResult(int n) {
if (!GlobalVariable.isSaveEndSuccess) { // 从全局变量获取结果表
TestResult t = (TestResult) AppContext.getParam(GlobalVariable.PARAM_KEY_TESTRESULT); // 保存结果到界面
String endTime = testResultService.getDate();
t.setEndTime(endTime);
main.getEndTime().setText(endTime); String time = StringUtil.getTimeBetween(t.getStartTime(), endTime);
t.setTime(time);
main.getTime().setText(time); String value = OPCUnit.read(opc.getItem_result());
String result = "";
String[] arr = value.split("[,]");
result = arr[0] + "-" + arr[1];
for (int i = 2; i < arr.length; i = i + 2) {
result = result + dealWith(arr[i], arr[i + 1]);
}
main.getResult01().setText(dealWithShow(arr[0], arr[1]));
main.getResult02().setText(dealWithShow(arr[2], arr[3]));
main.getResult03().setText(dealWithShow(arr[4], arr[5]));
main.getResult04().setText(dealWithShow(arr[6], arr[7]));
main.getResult05().setText(dealWithShow(arr[8], arr[9]));
main.getResult06().setText(dealWithShow(arr[10], arr[11]));
main.getResult07().setText(dealWithShow(arr[12], arr[13]));
main.getResult08().setText(dealWithShow(arr[14], arr[15]));
main.getResult09().setText(dealWithShow(arr[16], arr[17]));
main.getResult10().setText(dealWithShow(arr[18], arr[19])); t.setResult(result); // 异常
if (n == OPCControllerState.NORMALEND) {
t.setAbnormal("否");
} else {
t.setAbnormal("是");
} // 保存最终结果到数据库
testResultService.updateResult(t); // 当前工单已经完成
GlobalVariable.isHaveOrder = false; // 写入状态字
OPCUnit.write(opc.getItem_status(), “8”); // 读取成功后不再重复读取
GlobalVariable.isSaveEndSuccess = true;
}
} /**
* 断线重连动作
*/
private void reconnectAction() {
String sn = OPCUnit.read(opc.getItem_sn());
// 根据序列号查询初始保存的结果
TestResult t = testResultService.getOneDataBySerialNumber(sn);
AppContext.setParam(GlobalVariable.PARAM_KEY_TESTRESULT, t); // 工单恢复
JobCardService jcs = (JobCardService) BeanContainer.getBean("jobCardService");
JobCard job = jcs.getJobCardData(t.getOrderNum());
job.setSerialNumber(t.getSerialNumber());
AppContext.setParam(GlobalVariable.PARAM_KEY_JOBCARD, job); // 保存工单信息到全局变量 // 界面恢复
main.getOrderNumber().setText(t.getOrderNum());
main.getSn().setText(t.getSerialNumber());
main.getUnitType().setText(t.getUnitSize());
main.getBoxNumber().setText(t.getUnitSize().split(" ")[0]);
main.getSn_count().setText(Integer.parseInt(t.getSerialNumber().split("[.]")[3]) + "");
main.getCount().setText(job.getCount());
main.getStartTime().setText(t.getStartTime()); GlobalVariable.isHaveOrder = true;
} /**
* 处理结果字符串
*/
private String dealWith(String str1, String str2) {
if (str1.equals("0.0") && str2.equals("0.0")) {
return "";
}
return ", " + str1 + "-" + str2;
} private String dealWithShow(String str1, String str2) {
if (str1.equals("0.0") && str2.equals("0.0")) {
return "";
}
return str1 + "-" + str2;
}
}

9.配合业务:发送信息到PLC

package cn.com.tcb.assembly.management.action.main;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import cn.com.tcb.assembly.base.core.AppContext;
import cn.com.tcb.assembly.base.core.BeanContainer;
import cn.com.tcb.assembly.base.core.LocalDataStore;
import cn.com.tcb.assembly.base.core.ui.PopupDialog;
import cn.com.tcb.assembly.base.core.ui.PopupManager;
import cn.com.tcb.assembly.base.model.JobCard;
import cn.com.tcb.assembly.base.model.TestResult;
import cn.com.tcb.assembly.base.model.User;
import cn.com.tcb.assembly.base.service.TestResultService;
import cn.com.tcb.assembly.base.utils.GlobalVariable;
import cn.com.tcb.assembly.management.listener.OPCComm;
import cn.com.tcb.assembly.management.listener.OPCUnit;
import cn.com.tcb.assembly.management.ui.main.MainFrame; /**
* 发送按钮,发送工单信息到PLC
*/
public class SendAction implements ActionListener {
private TestResultService testResultService = (TestResultService) BeanContainer.getBean("testResultService");
private OPCComm opc = OPCComm.getInstance();
private MainFrame main; public SendAction(MainFrame mainFrame) {
main = mainFrame;
} @Override
public void actionPerformed(ActionEvent e) {
inputJobCard();
} private void inputJobCard() { // 如果设备正在运行,则不允许发送 // 如果有工单就能发送
if (GlobalVariable.isHaveOrder) { // 从全局变量获取工单信息
JobCard job = (JobCard) AppContext.getParam(GlobalVariable.PARAM_KEY_JOBCARD); // 判定是否重做
int n = testResultService.getSqlServerCountBySerialNumber(job.getSerialNumber());
if(n != 0 && !optionDialog("已有工单,是否重做?")) {
return;
} // 创建结果表
TestResult t = new TestResult(); // 写入工单号
String orderNum = job.getOrderNum();
t.setOrderNum(orderNum);
OPCUnit.write(opc.getItem_ordernum(), orderNum); // 写入序列号
String sn = job.getSerialNumber();
t.setSerialNumber(sn);
OPCUnit.write(opc.getItem_sn(), sn.split("[.]")); // 写入箱体号
String unitSize = job.getUnitSize();
t.setUnitSize(unitSize);
OPCUnit.write(opc.getItem_boxnum(), unitSize.split(" ")[0]); // 装配机
String assembly = LocalDataStore.read("localName");
t.setAssembly(assembly);
// 操作员
User user = (User) AppContext.getParam(GlobalVariable.PARAM_KEY_USER);
t.setOperator(user.getUserName());
// 异常
t.setAbnormal("是"); // 保存结果表到全局变量
AppContext.setParam(GlobalVariable.PARAM_KEY_TESTRESULT, t); // 写入状态字
OPCUnit.write(opc.getItem_status(), "2"); // 焦点返回扫码框
main.getScanCode().requestFocus(); // 状态信息
setStatus(Color.GREEN, "发送成功,等待设备处理");
}
} /**
* 设置主界面状态信息
*/
private void setStatus(Color color, String status) {
main.getStatus().setText(status);
main.getStatus().setBackground(color);
} /**
* @Title: optionDialog
* @Description: 选择弹窗,默认选择:是
*/
private boolean optionDialog(String message) {
int i = PopupDialog.open(PopupManager.DEFAULT, "提醒窗口", message, new String[] { "是", "否" }, new int[] { 1, 2 },
1, 2);
if (i == 1) {
return true;
} else {
return false;
}
}
}

10.地址变量

package cn.com.tcb.assembly.management.listener;

import java.io.IOException;
import java.util.Properties; /**
* @ClassName: OPCElement
* @Description: PC和PLC通信使用的OPCserver上的标记名称列表
*/
public class OPCElement {
private final static Properties prop;
private final static String CONFIG_FILE_NAME = "opc_list.properties"; /**
* 加载配置文件
*/
static {
prop = new Properties();
try {
prop.load(OPCElement.class.getClassLoader().getResourceAsStream(CONFIG_FILE_NAME));
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 心跳: 读到1,写入2
*/
public static final String ITEMID_HEARTBEAT = prop.getProperty("addr01"); /**
* 状态控制字: 0:PLC上电,1:允许新工单,2:新任务,3:收到任务,4:准备执行,5:开始执行 6:正常完成,7:异常玩常完成,8:收到完成信号
*/
public static final String ITEMID_STATUS = prop.getProperty("addr02"); /**
* 工单号:7位工单号,如:5332087
*/
public static final String ITEMID_ORDERNUM = prop.getProperty("addr03"); /**
* 序列号,长整型,数组[6]
*/
public static final String ITEMID_SN = prop.getProperty("addr04"); /**
* 箱体号:字符串,如:“R27”
*/
public static final String ITEMID_BOXNUM = prop.getProperty("addr12"); /**
* 异常代码:暂时没用
*/
public static final String ITEMID_ABNORMAL = prop.getProperty("addr06"); /**
* 完成信号:暂时没用
*/
public static final String ITEMID_FINISH = prop.getProperty("addr07"); /**
* 结果:浮点型,数组[20]
*/
public static final String ITEMID_RESULT = prop.getProperty("addr08"); /**
* 装配策略,内容:箱体号-轴s数量:字符串,如:“R107-2”
*/
public static final String ITEMID_STRATEGY = prop.getProperty("addr05"); /**
* 工单号:7位工单号,如:5332087,,用来扫码发送
*/
public static final String ITEMID_BARCODE = prop.getProperty("addr10"); /**
* 垫片值:浮点型,数组[8]
*/
public static final String ITEMID_GASKET = prop.getProperty("addr11"); /**
* 安装方式:字符串,如:“M1”
*/
public static final String ITEMID_MP = prop.getProperty("addr09"); /**
* 轴数量:字符串,如:“2”,“3”
*/
public static final String ITEMID_SHAFT = prop.getProperty("addr13");
}

地址写在了配置文件里

opc_list.properties

#heartbeat:short
addr01=PLC.S7-300.TAG1
#control:short
addr02=PLC.S7-300.TAG2
#orderNum:long
addr03=PLC.S7-300.TAG3
#sn:long,array[6]
addr04=PLC.S7-300.TAG4
#Strategy:string
addr05=PLC.S7-300.TAG5
#abnormal:short
addr06=PLC.S7-300.TAG6
#finish:short
addr07=PLC.S7-300.TAG7
#result:float,array[20]
addr08=PLC.S7-300.TAG8
#MP:string
addr09=PLC.S7-300.TAG9
#barcode:long
addr10=PLC.S7-300.TAG10
#gasket:float,array[8]
addr11=PLC.S7-300.TAG11
#boxNum:string
addr12=PLC.S7-300.TAG12
#shaft:string
addr13=PLC.S7-300.TAG13

11.其他

另一个项目的,配置地址写在了代码里

OPCClient.java

package cn.com.tcb.uavpcs.datacenter.comm.plc.opcclient;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors; import org.jinterop.dcom.common.JIException;
import org.openscada.opc.lib.common.ConnectionInformation;
import org.openscada.opc.lib.da.AccessBase;
import org.openscada.opc.lib.da.Group;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.Server;
import org.openscada.opc.lib.da.SyncAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import cn.com.tcb.uavpcs.datacenter.comm.plc.opcclient.callbacks.OvenCrossCallback;
import cn.com.tcb.uavpcs.datacenter.comm.plc.opcclient.callbacks.CrossCallbackFactory;
import cn.com.tcb.uavpcs.datacenter.comm.plc.opcclient.callbacks.OvenMoveCallBackFactory;
import cn.com.tcb.uavpcs.datacenter.comm.plc.opcclient.callbacks.StationCallBack;
import cn.com.tcb.uavpcs.datacenter.comm.plc.opcclient.items.OPCItems;
import cn.com.tcb.uavpcs.datacenter.linecontrol.LineModel; /**
* OPC客户端,用于同PLC通信,通过OPC服务器,
*
*/
@Component
public class OPCClient {
private static Logger logger = LoggerFactory.getLogger(OPCClient.class); public final static Map<String, Item> ITEMS = new HashMap<String, Item>();// 所有的变量对象
@Autowired
private OPCConfig config; private AccessBase access; public void start() throws Exception {
logger.info("OPC客户端初始化启动"); // 连接信息
ConnectionInformation ci = new ConnectionInformation();
ci.setHost(config.getHost());// 主机地址
ci.setUser(config.getUser());// 用户名
ci.setPassword(config.getPassword());// 密码
ci.setClsid(config.getClsid());// clsId,使用DCOM组件的clsId连接OPC服务器
// 连接服务器
Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
server.connect();
// 变量组
Group group = server.addGroup(); // 变量统一加入组,方便以后读写
// 路口动作
addItem(group, OPCItems.ITEM_CROSS_ACTION_1);
addItem(group, OPCItems.ITEM_CROSS_ACTION_2);
addItem(group, OPCItems.ITEM_CROSS_ACTION_3);
addItem(group, OPCItems.ITEM_CROSS_ACTION_4);
addItem(group, OPCItems.ITEM_CROSS_ACTION_5);
addItem(group, OPCItems.ITEM_CROSS_ACTION_6);
addItem(group, OPCItems.ITEM_CROSS_ACTION_7);
addItem(group, OPCItems.ITEM_CROSS_ACTION_8);
// 托盘进出gongwei
addItem(group, OPCItems.ITEM_CROSS_FROM_1);
addItem(group, OPCItems.ITEM_CROSS_FROM_2);
addItem(group, OPCItems.ITEM_CROSS_FROM_3);
addItem(group, OPCItems.ITEM_CROSS_FROM_4);
addItem(group, OPCItems.ITEM_CROSS_FROM_5);
addItem(group, OPCItems.ITEM_CROSS_FROM_6);
addItem(group, OPCItems.ITEM_CROSS_FROM_7);
addItem(group, OPCItems.ITEM_CROSS_FROM_8);
// 线体1烘箱存取
addItem(group, OPCItems.ITEM_OVEN_ACTION_1);
addItem(group, OPCItems.ITEM_OVEN_COLUMN_1);
addItem(group, OPCItems.ITEM_OVEN_LAYER_1);
addItem(group, OPCItems.ITEM_OVEN_ROW_1);
addItem(group, OPCItems.ITEM_OVEN_STATE_1);
// 线体2烘箱存取
addItem(group, OPCItems.ITEM_OVEN_ACTION_2);
addItem(group, OPCItems.ITEM_OVEN_COLUMN_2);
addItem(group, OPCItems.ITEM_OVEN_LAYER_2);
addItem(group, OPCItems.ITEM_OVEN_ROW_2);
addItem(group, OPCItems.ITEM_OVEN_STATE_2); access = new SyncAccess(server, 500); // 路口动作
access.addItem(OPCItems.ITEM_CROSS_1, CrossCallbackFactory.build(LineModel.CROSS_ID_1));
access.addItem(OPCItems.ITEM_CROSS_2, CrossCallbackFactory.build(LineModel.CROSS_ID_2));
access.addItem(OPCItems.ITEM_CROSS_3, CrossCallbackFactory.build(LineModel.CROSS_ID_3));
access.addItem(OPCItems.ITEM_CROSS_4, new OvenCrossCallback(LineModel.LINE_ID_1));// 烘箱路口,线体1 access.addItem(OPCItems.ITEM_CROSS_5, CrossCallbackFactory.build(LineModel.CROSS_ID_5));
access.addItem(OPCItems.ITEM_CROSS_6, CrossCallbackFactory.build(LineModel.CROSS_ID_6));
access.addItem(OPCItems.ITEM_CROSS_7, CrossCallbackFactory.build(LineModel.CROSS_ID_7));
access.addItem(OPCItems.ITEM_CROSS_8, new OvenCrossCallback(LineModel.LINE_ID_2));// 烘箱路口,线体2 // 线体1,烘箱存取
access.addItem(OPCItems.ITEM_OVEN_STATE_1, OvenMoveCallBackFactory.build(LineModel.LINE_ID_1));// 烘箱存取托盘,线体1 // 线体2,烘箱存取
access.addItem(OPCItems.ITEM_OVEN_STATE_2, OvenMoveCallBackFactory.build(LineModel.LINE_ID_2));// 烘箱存取托盘,线体2 // 工位按钮动作
access.addItem(OPCItems.ITEM_STATION_1, new StationCallBack(LineModel.STATION_ID_1));
access.addItem(OPCItems.ITEM_STATION_2, new StationCallBack(LineModel.STATION_ID_2));
access.addItem(OPCItems.ITEM_STATION_3, new StationCallBack(LineModel.STATION_ID_3));
access.addItem(OPCItems.ITEM_STATION_4, new StationCallBack(LineModel.STATION_ID_4));
access.addItem(OPCItems.ITEM_STATION_5, new StationCallBack(LineModel.STATION_ID_5));
access.addItem(OPCItems.ITEM_STATION_6, new StationCallBack(LineModel.STATION_ID_6));
access.addItem(OPCItems.ITEM_STATION_7, new StationCallBack(LineModel.STATION_ID_7));
access.addItem(OPCItems.ITEM_STATION_8, new StationCallBack(LineModel.STATION_ID_8));
access.addItem(OPCItems.ITEM_STATION_9, new StationCallBack(LineModel.STATION_ID_9));
access.addItem(OPCItems.ITEM_STATION_10, new StationCallBack(LineModel.STATION_ID_10));
access.addItem(OPCItems.ITEM_STATION_11, new StationCallBack(LineModel.STATION_ID_11));
access.addItem(OPCItems.ITEM_STATION_12, new StationCallBack(LineModel.STATION_ID_12)); // 绑定,开始读取
access.bind(); // Thread.sleep(100 * 1000);// 延时停止
// access.unbind();// 结束绑定
logger.info("OPC客户端初始化启动完成");
} private void addItem(Group group, String itemId) throws Exception {
Item item = group.addItem(itemId);
ITEMS.put(itemId, item);
} public void stop() {
try {
access.unbind();
} catch (JIException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

OPCItems.java

package cn.com.tcb.uavpcs.datacenter.comm.plc.opcclient.items;

import java.util.HashMap;
import java.util.Map; /**
* 相关PLC变量在OPC服务器上的标签
*
*/
public class OPCItems {
// 路口,状态,对应8个路口,int
public final static String ITEM_CROSS_1 = "u.u.cross1";
public final static String ITEM_CROSS_2 = "u.u.cross2";
public final static String ITEM_CROSS_3 = "u.u.cross3";
public final static String ITEM_CROSS_4 = "u.u.cross4";
public final static String ITEM_CROSS_5 = "u.u.cross5";
public final static String ITEM_CROSS_6 = "u.u.cross6";
public final static String ITEM_CROSS_7 = "u.u.cross7";
public final static String ITEM_CROSS_8 = "u.u.cross8";
// 路口,动作,对应8个路口,int
public final static String ITEM_CROSS_FROM_1 = "u.u.from1";
public final static String ITEM_CROSS_FROM_2 = "u.u.from2";
public final static String ITEM_CROSS_FROM_3 = "u.u.from3";
public final static String ITEM_CROSS_FROM_4 = "u.u.from4";
public final static String ITEM_CROSS_FROM_5 = "u.u.from5";
public final static String ITEM_CROSS_FROM_6 = "u.u.from6";
public final static String ITEM_CROSS_FROM_7 = "u.u.from7";
public final static String ITEM_CROSS_FROM_8 = "u.u.from8";
// 路口,条码,对应8个路口,String
// public final static String ITEM_CROSS_BARCODE_1 = "u.u.barcode1";
// public final static String ITEM_CROSS_BARCODE_2 = "u.u.barcode2";
// public final static String ITEM_CROSS_BARCODE_3 = "u.u.barcode3";
// public final static String ITEM_CROSS_BARCODE_4 = "u.u.barcode4";
// public final static String ITEM_CROSS_BARCODE_5 = "u.u.barcode5";
// public final static String ITEM_CROSS_BARCODE_6 = "u.u.barcode6";
// public final static String ITEM_CROSS_BARCODE_7 = "u.u.barcode7";
// public final static String ITEM_CROSS_BARCODE_8 = "u.u.barcode8";
// 路口,动作,对应8个路口,int
public final static String ITEM_CROSS_ACTION_1 = "u.u.action1";
public final static String ITEM_CROSS_ACTION_2 = "u.u.action2";
public final static String ITEM_CROSS_ACTION_3 = "u.u.action3";
public final static String ITEM_CROSS_ACTION_4 = "u.u.action4";
public final static String ITEM_CROSS_ACTION_5 = "u.u.action5";
public final static String ITEM_CROSS_ACTION_6 = "u.u.action6";
public final static String ITEM_CROSS_ACTION_7 = "u.u.action7";
public final static String ITEM_CROSS_ACTION_8 = "u.u.action8";
// 工位按钮,12个工位
public final static String ITEM_STATION_1 = "u.u.station1";
public final static String ITEM_STATION_2 = "u.u.station2";
public final static String ITEM_STATION_3 = "u.u.station3";
public final static String ITEM_STATION_4 = "u.u.station4";
public final static String ITEM_STATION_5 = "u.u.station5";
public final static String ITEM_STATION_6 = "u.u.station6";
public final static String ITEM_STATION_7 = "u.u.station7";
public final static String ITEM_STATION_8 = "u.u.station8";
public final static String ITEM_STATION_9 = "u.u.station9";
public final static String ITEM_STATION_10 = "u.u.station10";
public final static String ITEM_STATION_11 = "u.u.station11";
public final static String ITEM_STATION_12 = "u.u.station12";
// 线体1,烘箱存取控制
public final static String ITEM_OVEN_STATE_1 = "u.u.oven1";
public final static String ITEM_OVEN_ACTION_1 = "u.u.ovenaction1";
public final static String ITEM_OVEN_COLUMN_1 = "u.u.column1";
public final static String ITEM_OVEN_LAYER_1 = "u.u.layer1";
public final static String ITEM_OVEN_ROW_1 = "u.u.row1";
// 线体2,烘箱存取控制
public final static String ITEM_OVEN_STATE_2 = "u.u.oven2";
public final static String ITEM_OVEN_ACTION_2 = "u.u.ovenaction2";
public final static String ITEM_OVEN_COLUMN_2 = "u.u.column2";
public final static String ITEM_OVEN_LAYER_2 = "u.u.layer2";
public final static String ITEM_OVEN_ROW_2 = "u.u.row2"; // // 路口和条码的对应关系
// public final static Map<String, String> CROSS_BARCODES = new HashMap<String,
// String>();
// static {
// CROSS_BARCODES.put(ITEM_CROSS_1, ITEM_CROSS_BARCODE_1);
// CROSS_BARCODES.put(ITEM_CROSS_2, ITEM_CROSS_BARCODE_2);
// CROSS_BARCODES.put(ITEM_CROSS_3, ITEM_CROSS_BARCODE_3);
// CROSS_BARCODES.put(ITEM_CROSS_4, ITEM_CROSS_BARCODE_4);
// CROSS_BARCODES.put(ITEM_CROSS_5, ITEM_CROSS_BARCODE_5);
// CROSS_BARCODES.put(ITEM_CROSS_6, ITEM_CROSS_BARCODE_6);
// CROSS_BARCODES.put(ITEM_CROSS_7, ITEM_CROSS_BARCODE_7);
// CROSS_BARCODES.put(ITEM_CROSS_8, ITEM_CROSS_BARCODE_8);
// }
// // 路口和动作的对应关系
// public final static Map<String, String> CROSS_ACTIONS = new HashMap<String,
// String>();
// static {
// CROSS_BARCODES.put(ITEM_CROSS_1, ITEM_CROSS_ACTION_1);
// CROSS_BARCODES.put(ITEM_CROSS_2, ITEM_CROSS_ACTION_2);
// CROSS_BARCODES.put(ITEM_CROSS_3, ITEM_CROSS_ACTION_3);
// CROSS_BARCODES.put(ITEM_CROSS_4, ITEM_CROSS_ACTION_4);
// CROSS_BARCODES.put(ITEM_CROSS_5, ITEM_CROSS_ACTION_5);
// CROSS_BARCODES.put(ITEM_CROSS_6, ITEM_CROSS_ACTION_6);
// CROSS_BARCODES.put(ITEM_CROSS_7, ITEM_CROSS_ACTION_7);
// CROSS_BARCODES.put(ITEM_CROSS_8, ITEM_CROSS_ACTION_8);
// }
}

Java OPC 代码的更多相关文章

  1. pagebean pagetag java 后台代码实现分页 demo 前台标签分页 后台java分页

    java 后台代码实现分页 demo 实力 自己写的 标签分页 package com.cszoc.sockstore.util; import java.util.HashMap;import ja ...

  2. 经典KMP算法C++与Java实现代码

    前言: KMP算法是一种字符串匹配算法,由Knuth,Morris和Pratt同时发现(简称KMP算法).KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.比 ...

  3. 常用 Java 静态代码分析工具的分析与比较

    常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...

  4. 分享:根据webservice WSDL地址自动生成java调用代码及JAR包

    分享:根据webservice WSDL地址自动生成java调用代码及JAR包使用步骤:一.安装java 并配置JAVA_HOME 及 path二.安装ANT 并配置ANT_HOME三.解压WsdlT ...

  5. FastDFS搭建及java整合代码【转】

    FastDFS软件介绍 1.什么是FastDFS FastDFS是用C语言编写的一款开源的分布式文件系统.FastDFS为互联网量身定制,充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高 ...

  6. [原创]Java静态代码检查工具介绍

    [原创]Java静态代码检查工具介绍 一  什么是静态代码检查? 静态代码分析是指无需运行被测代码,仅通过分析或检查源程序的语法.结构.过程.接口等来检查程序的正确性,找出代码隐藏的错误和缺陷,如参数 ...

  7. 最近开始研究PMD(一款采用BSD协议发布的Java程序代码检查工具)

    PMD是一款采用BSD协议发布的Java程序代码检查工具.该工具可以做到检查Java代码中是否含有未使用的变量.是否含有空的抓取块.是否含有不必要的对象等.该软件功能强大,扫描效率高,是Java程序员 ...

  8. java集合框架之java HashMap代码解析

     java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...

  9. 在Jmeter中使用自定义编写的Java测试代码

    我们在做性能测试时,有时需要自己编写测试脚本,很多测试工具都支持自定义编写测试脚本,比如LoadRunner就有很多自定义脚本的协议,比如"C Vuser","Java ...

随机推荐

  1. 【AGC002F】Leftmost Ball DP 数学

    题目大意 有\(n\)种颜色的球,每种\(m\)个.现在zjt把这\(nm\)个球排成一排,然后把每种颜色的最左边的球染成第\(n+1\)种颜色.求最终的颜色序列有多少种,对\(1000000007\ ...

  2. CODEFORCES掉RATING记 #5

    ​ 比赛:Codeforces Round #429 (Div. 2) ​ 时间:2017.8.1晚 这次感觉状态不好,就去打div2了 ​ A:有\(26\)种颜色的气球,每种的数量不一样,你要把这 ...

  3. wstngfw openVpn站点到站点连接示例(SSL/TLS)

    wstngfw openVpn站点到站点连接示例(SSL/TLS) 在本例中,将假设以下设置: 站点 A 站点 B 名称 Beijing Office(北京办公室) 名称 Shenzheng Offi ...

  4. [SHOI2001]化工厂装箱员(dp?暴力:暴力)

    118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度 ...

  5. 51nod 1105(第K大数 二分套二分)

    题目链接:http://www.51nod.com/onlineJudge/submitDetail.html#!judgeId=620811 参考自:https://blog.csdn.net/f_ ...

  6. saltstack常用命令

    Salt通过公钥加密和认证minions.想要让minion从master端接受命令,minions的密钥需要被master接受 salt-key -L #列出master上的密钥; salt-key ...

  7. es6快速入门

    上次分享了es6开发环境的搭建,本次接着分享es6常用的特性. 1.变量声明let和const 我们都是知道在ES6以前,var关键字声明变量.无论声明在何处,都会被视为声明在函数的最顶部(不在函数内 ...

  8. [luogu3810][bzoj3262][陌上花开]

    题目链接 思路 听说可以CDQ分治,然后我不会,所以我写树套树 首先肯定先按照a拍个序.然后就成了在b,c这两个数组中查询了.用一个树状数组套treap来维护.当插入一个数的时候,就在树状数组的b这个 ...

  9. 斯坦福大学公开课机器学习: neural networks learning - autonomous driving example(通过神经网络实现自动驾驶实例)

    使用神经网络来实现自动驾驶,也就是说使汽车通过学习来自己驾驶. 下图是通过神经网络学习实现自动驾驶的图例讲解: 左下角是汽车所看到的前方的路况图像.左上图,可以看到一条水平的菜单栏(数字4所指示方向) ...

  10. Day29--Python--缓冲区, 粘包

    tcp: 属于长连接,与一个客户端进行连接了以后,其他的客户端要等待.要想连接另外一个客户端,需要优雅地断开当前客户端的连接 允许地址重用:server.setsockopt(socket.SOL_S ...