@通过OPC开发MES防错程序
通过OPC开发MES防错程序
公司的MES系统缺少一个防错,经常有操作员防错零件,导致客户投诉,要求增加一个防错步骤。
本来应该是MES系统内置的一个配置就可以实现的功能,无奈这家MES提供商把配置写死了,不允许用户增加防错站,只能另想办法了。
通过观察发现,当托盘经过工位时候,工位会将读取到的RFID信息传送到PLC,而PLC是提供OPC服务的,这样,思路就有了,通过读取OPC的信息,取到总成零件号,然后到数据库去读取总成-零件的对应关系表就可以判断了。
首先建立一个opc服务器,采用KEPServerEx添加需要引入的OPC Tag,名字自己起
采用c#开发,.net自带一个叫做OPCAutomation的组件,添加引用
然后using OPCAutomation。
因为这个程序只是为了解决此工位的单一问题,所有配置也都写死了,贴代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using OPCAutomation;
using System.Net;
using System.Data.OleDb;
using System.Threading.Tasks;
namespace 小护板防错
{
public partial class Form1 : Form
{
static string path = Directory.GetCurrentDirectory();
static string filename = path + "\\" + "m.xls";
string ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source=" + filename + ";Extended Properties=Excel 8.0";
static OPCServer server = new OPCServer();
static IPHostEntry host = Dns.GetHostEntry("127.0.0.1");
object progIds = server.GetOPCServers(host.HostName);
int j = 0;
public Form1()
{
InitializeComponent();
}
private void txtBarcode_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13)
{
btnScan_Click(sender, e);
}
}
private void btnQuery_Click(object sender, EventArgs e)
{
if (txtProduct.Text != "")
{
txtMaterial.Enabled = true;
txtMaterial.Focus();
string product = txtProduct.Text.Substring(8, 8).ToString();
string sql = "select config from [sheet1$] where product={0}";
sql = string.Format(sql, product);
OleDbConnection oleconn = new OleDbConnection(ConnectionString);
oleconn.Open();
OleDbCommand cmd = new OleDbCommand(sql, oleconn);
OleDbDataReader reader = cmd.ExecuteReader();
{
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
this.lblDisplay.Text = reader[i].ToString();
}
}
}
reader.Close();
oleconn.Close();
}
else
{
clearItems();
}
}
private void Form1_Activated(object sender, EventArgs e)
{
this.ActiveControl = this.txtMaterial;
}
private void Group_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
{
//此处注意i是从1开始,因为getvalue没有0.下面输出分别为数据的ClientHandles(就是上文AddItem方法的第二个参数。),Itemvalue就是值,Qualities为质量,timestamps为时间。
for (int i = 1; i < NumItems + 1; i++)
{
//Console.WriteLine(ClientHandles.GetValue(i).ToString() + "--" + ItemValues.GetValue(i).ToString() + "--" + Qualities.GetValue(i).ToString() + "--" + TimeStamps.GetValue(i).ToString());
try
{
j++;
WriteLog("读取了" + j.ToString() + "次OPC,当前值是"+ItemValues.GetValue(i).ToString());
this.txtProduct.Text = ItemValues.GetValue(i).ToString();
}
catch (Exception)
{
WriteLog("运行了" + j.ToString() + "次以后出错了");
throw;
}
}
}
private void txtSerial_TextChanged(object sender, EventArgs e)
{
btnQuery_Click(sender, e);
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
private void btnScan_Click(object sender, EventArgs e)
{
if (this.txtProduct.Text!="" && this.txtMaterial.Text != "")
{
string material = txtMaterial.Text.Trim();
string product = txtProduct.Text.Substring(8, 8).ToString();
string sql = "select count(name) from [sheet1$] where product={0} and material={1}";
sql = string.Format(sql, product,material);
OleDbConnection oleconn = new OleDbConnection(ConnectionString);
oleconn.Open();
OleDbCommand cmd = new OleDbCommand(sql, oleconn);
OleDbDataReader reader = cmd.ExecuteReader();
{
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
if (Convert.ToInt32(reader[i]) > 0)
{
picAllow.Load(path + "\\" + "OK.jpg");
WriteLog("匹配正确:"+txtProduct.Text + "--" + txtMaterial.Text);
}
else
{
picAllow.Load(path + "\\" + "NOK.jpg");
WriteLog("匹配错误:" + txtProduct.Text + "--" + txtMaterial.Text);
txtMaterial.Text = "";
txtMaterial.Focus();
}
}
}
}
reader.Close();
oleconn.Close();
}
else
{
clearItems();
}
}
public void WriteLog(string msg)
{
string filePath = AppDomain.CurrentDomain.BaseDirectory + "Log";
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
string logPath = AppDomain.CurrentDomain.BaseDirectory + "Log\\" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
try
{
using (StreamWriter sw = File.AppendText(logPath))
{
sw.WriteLine("消息:" + msg);
sw.WriteLine("时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
sw.WriteLine("**************************************************");
sw.WriteLine();
sw.Flush();
sw.Close();
sw.Dispose();
}
}
catch (IOException e)
{
using (StreamWriter sw = File.AppendText(logPath))
{
sw.WriteLine("异常:" + e.Message);
sw.WriteLine("时间:" + DateTime.Now.ToString("yyy-MM-dd HH:mm:ss"));
sw.WriteLine("**************************************************");
sw.WriteLine();
sw.Flush();
sw.Close();
sw.Dispose();
}
}
}
private void btnReadOPC_Click(object sender, EventArgs e)
{
foreach (string progId in (Array)progIds)
{
server.Connect(progId);
}
OPCGroups groups = server.OPCGroups;
OPCGroup group = groups.Add("myGroup");
group.IsSubscribed = true;
group.DataChange += Group_DataChange;
List<string> ItemIds = new List<string>(){
"MES.TEST.Product_VIN",
};
for (int i = 0; i < ItemIds.Count; i++)
{
OPCItem myItem = group.OPCItems.AddItem(ItemIds[i], i);
}
}
private void clearItems()
{
txtMaterial.Clear();
txtMaterial.Enabled = false;
picAllow.Image = null;
lblDisplay.Text = "等待中...";
}
private void timer1_Tick(object sender, EventArgs e)
{
btnReadOPC_Click(sender, e);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
timer1.Stop();
}
}
}