這是我項目的代碼,算是真實業務實現,記錄備份一下實現思路
由於業務就是簡單的獲取數據而後保存,因此仍是容易理解的html
- Java實現OPC通訊的代碼實現
- 最終實現對西門子的S7-300的PLC變量的值讀寫
- 使用utgard實現通訊:Java實現OPC通訊
- OPCserver:KEPserver6
- 配置DCOM:OPC和DCOM配置
- 制定變量列表:規定名稱和類型
示例java
OPCServer標記名稱 | 地址 | 數據類型 | 說明 |
---|---|---|---|
TAG1 | DB1.INT00 | short | 心跳 |
TAG2 | DB1.INT02 | short | 控制字 |
TAG3 | DB1.STRING4,10 | string | 箱體信息 |
TAG4 | DB1.D14 | float | 結果 |
實際spring
PLC地址數據庫
通訊上:定義了地址變量,包括數據類型,就能拿到數。數組
不一樣client之間通訊:確定有個心跳,你寫什麼,我寫什麼,斷了能看出來。還要有控制字,讀到控制字某個值,去讀取或者寫入一些變量服務器
- 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();
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)); } }
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; } }
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; } }
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); } } }
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; } }
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; } } }
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"); }
地址寫在了配置文件裏dom
opc_list.propertieside
#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
另外一個項目的,配置地址寫在了代碼裏函數
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); // } }