PLC是很多機床設備上都有的控制中心,和PLC通信是很多做工廠管理系統的必經之路。
一年前有個項目需要和PLC(西門子S200)通信,不僅讀取里面的數據,還需要寫數據需要控制機床的運行,當時不大了解,由於設備比較老,沒有以太網模塊,還是在設備供應商的提示下用串口rs485聯通pc,查資料了解modbus協議,完全手寫按照modbus協議和PLC通信,最后總算了磕磕絆絆完成項目,后來還有各種超時異常造成機床運行錯誤,哎。
現在是第二個階段,在老前輩的帶領下,雖說對PLC下位機程序還是了解甚少,但是對如何與PLC通信方面比以前了解更多。由於市面上PLC的品牌和型號比較多,如果是要求各種PLC都和服務器連接並受控制或集中管理,基本上都會安裝以太網擴展卡,然后在服務器上部署opc服務器,opc服務器的種類也比較多,西門子有自己的opc服務器,第三方的opc服務器也很好,能兼容很多種PLC種類和型號,自帶的各種驅動,就現在這個項目來說用的是kepserver,用這個管理軟件的人很多,只要知道想要的數據在PLC的正確地址,在kepserver做個配置即可。
剩余的事情就是寫程序,從kepserver里存取數據,就像訪問數據庫一樣,OPCDAAuto是個不錯的選擇,現在我用的dotnet,網上down一個OPCDAAuto.dll直接使用,如何使用OPCDAAuto.dll網上也有很多例子。下面是簡單例子:
1 using System; 2 using System.Windows.Forms; 3 using log4net; 4 using OPCAutomation; 5 6 namespace OpcDaAutoTest 7 { 8 public partial class FormReader : Form 9 { 10 private ILog _logger = LogManager.GetLogger(typeof(Form1)); 11 private System.Timers.Timer _timer = new System.Timers.Timer(5000); 12 13 private OPCGroups _kepGroups = null; 14 private OPCGroup _groupOmron = null; 15 private OPCItem _omronQty = null; 16 private OPCItem _omronStart = null; 17 private OPCItem _omronWarn = null; 18 private OPCGroup _groupSiemens = null; 19 private OPCItem _siemensQty = null; 20 private OPCItem _siemensStart = null; 21 private OPCItem _siemensWarn = null; 22 23 const string open = "正常"; 24 const string close = "關機"; 25 26 public FormReader() 27 { 28 InitializeComponent(); 29 } 30 31 private void FormReader_Load(object sender, EventArgs e) 32 { 33 GetLocalServer(); 34 btnConnLocalServer.Click += btnConnLocalServer_Click; 35 FormClosing += OnFormClosing; 36 } 37 38 private void OnFormClosing(object sender, FormClosingEventArgs formClosingEventArgs) 39 { 40 if (_kepServer != null) 41 { 42 _kepServer.Disconnect(); 43 _kepServer = null; 44 } 45 } 46 47 private bool ConnectRemoteServer(string remoteServerName) 48 { 49 try 50 { 51 _kepServer.Connect(remoteServerName); 52 53 if (_kepServer.ServerState == (int)OPCServerState.OPCRunning) 54 { 55 tsslServerState.Text = "已連接到-" + _kepServer.ServerName; 56 } 57 else 58 { 59 //這里你可以根據返回的狀態來自定義顯示信息,請查看自動化接口API文檔 60 tsslServerState.Text = "狀態:" + _kepServer.ServerState; 61 } 62 } 63 catch (Exception err) 64 { 65 MessageBox.Show("連接遠程服務器出現錯誤:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); 66 return false; 67 } 68 return true; 69 } 70 private void btnConnLocalServer_Click(object sender, EventArgs e) 71 { 72 try 73 { 74 if (!ConnectRemoteServer(cmbServerName.Text)) 75 { 76 return; 77 } 78 79 _kepGroups = _kepServer.OPCGroups; 80 _groupOmron = _kepGroups.Add("omron"); 81 _omronQty = _groupOmron.OPCItems.AddItem("Channel_Omron.Device1.Qty", 1001); 82 _omronStart = _groupOmron.OPCItems.AddItem("Channel_Omron.Device1.Start", 1002); 83 _omronWarn = _groupOmron.OPCItems.AddItem("Channel_Omron.Device1.Warn", 1003); 84 85 _groupSiemens = _kepGroups.Add("siemens"); 86 _siemensQty = _groupSiemens.OPCItems.AddItem("Channel_Siemens.Device1.Qty", 2001); 87 _siemensStart = _groupSiemens.OPCItems.AddItem("Channel_Siemens.Device1.Start", 2002); 88 _siemensWarn = _groupSiemens.OPCItems.AddItem("Channel_Siemens.Device1.Warn", 2003); 89 90 _timer.Elapsed += (o, args) => 91 { 92 _timer.Enabled = false; 93 try 94 { 95 object value = null; 96 object quality = null; 97 object timestamp = null; 98 _omronQty.Read(1, out value, out quality, out timestamp); 99 _logger.Debug(_omronQty.ItemID + "=" + value); 100 var yazhu7Qty = value; 101 _omronStart.Read(1, out value, out quality, out timestamp); 102 _logger.Debug(_omronStart.ItemID + "=" + value); 103 value = value ?? true; 104 var yazhu7Start = value.Equals(false) ? open : close; 105 _omronWarn.Read(1, out value, out quality, out timestamp); 106 _logger.Debug(_omronWarn.ItemID + "=" + value); 107 SaveData("Y7", yazhu7Start, yazhu7Qty);/*保存壓鑄7機台數據*/ 108 109 _siemensQty.Read(1, out value, out quality, out timestamp); 110 _logger.Debug(_siemensQty.ItemID + "=" + value); 111 var yazhu11Qty = value; 112 _siemensStart.Read(1, out value, out quality, out timestamp); 113 _logger.Debug(_siemensStart.ItemID + "=" + value); 114 value = value ?? true; 115 var yazhu11Start = value.Equals(false) ? open : close; 116 _siemensWarn.Read(1, out value, out quality, out timestamp); 117 _logger.Debug(_siemensWarn.ItemID + "=" + value); 118 SaveData("Y11", yazhu11Start, yazhu11Qty);/*保存壓鑄11機台數據*/ 119 } 120 catch (Exception exception) 121 { 122 _logger.Error(exception); 123 } 124 finally 125 { 126 _timer.Enabled = true; 127 } 128 }; 129 _timer.Enabled = true; 130 btnConnLocalServer.Enabled = false; 131 132 } 133 catch (Exception err) 134 { 135 MessageBox.Show("初始化出錯:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); 136 } 137 } 138 139 private void SaveData(string machineNo, string start, object qty) 140 { 141 try 142 { 143 using (var db = DbAccess.GetDbContext()) 144 { 145 if (start.Equals(close)) 146 { 147 db.Sql("update kbequipment set running=@0 where type=0 and name=@1") 148 .Parameters(start, machineNo) 149 .Execute(); 150 } 151 else 152 { 153 db.Sql("update kbequipment set running=@0, status=@1 where type=0 and name=@2") 154 .Parameters(start, qty, machineNo) 155 .Execute(); 156 } 157 } 158 } 159 catch (Exception e) 160 { 161 _logger.Error(e.Message, e); 162 } 163 } 164 165 private OPCServer _kepServer; 166 private void GetLocalServer() 167 { 168 try 169 { 170 _kepServer = new OPCServer(); 171 object serverList = _kepServer.GetOPCServers(Environment.MachineName); 172 173 foreach (string turn in (Array)serverList) 174 { 175 cmbServerName.Items.Add(turn); 176 } 177 178 cmbServerName.SelectedIndex = 0; 179 btnConnLocalServer.Enabled = true; 180 } 181 catch (Exception err) 182 { 183 MessageBox.Show("枚舉本地OPC服務器出錯:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); 184 } 185 186 } 187 } 188 }