[英]Creating a program to establish connection to PLC through PVI and another program
正如标题所述,我需要帮助来编写将连接到PVI的程序和另一个程序 ( 我不确定是否可以与原始机器制造商编写的此类程序建立通信,我将提供尽可能多的详细信息如果需要,我可以。 )然后它将信息从PLC交换到正在运行的程序,并允许冻结该程序的框架,截取其屏幕截图以及在之后解冻 。
我将使用贝加莱(B&R)提供的培训手册编写到目前为止所写的代码,这仅仅是为了建立与PVI和PLC上运行的自动化工作室程序的连接。
这是一本过时的培训手册,但这是我可以解决此问题的唯一信息来源。 我编写的程序确实可以编译并运行,似乎确实可以连接到我连接到笔记本电脑的PLC上,也可以在没有PLC的情况下运行仿真程序。 但是,它不会从程序中读取数据,因为培训手册说明它将读取我在Automation Studio中所做的某些变量的值。
另外,当尝试单击我做出的任何按钮时,我会说实话,我不是100%肯定他们应该做什么,这会给我一个错误(System.NullReferenceException: 'Object reference not set to an instance of an object.' myStructPV was null.)
。 我以为是要告诉我,按下按钮时使用的变量为null,但是这些变量是PVI服务名称空间的一部分,我不确定在初始化时会给它们提供什么值。
如果这没有什么意义,我会道歉,因为我提到我在开发中是一个新手,自从大学毕业后就没有使用过Visual Studio或C#。
非常感谢您的任何建议或帮助。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using BR.AN.PviServices;
namespace PVITestApp
{
public partial class Form1 : Form
{
public Service myService;
public Cpu myCpu;
public BR.AN.PviServices.Task myTask;
public Variable myVariable;
public Module myModule;
public Variable myVariablePV1;
public Variable myStructPV;
public Form1()
{
InitializeComponent();
// txtStatus.Text = "text box is functioning!";
}
private void MyStructPV_Error(object sender, PviEventArgs e)
{
throw new NotImplementedException();
}
private void MyStructPV_ValueChanged(object sender, VariableEventArgs e)
{
throw new NotImplementedException();
}
private void Form1_Load(object sender, EventArgs e)
{
myService = new Service("service");
myService.Connected += MyService_Connected;
myService.IsStatic = true;
myService.Connect();
}
private void MyService_Connected(object sender, PviEventArgs e)
{
this.txtStatus.Text += "Service Connected\r\n";
if (myCpu == null)
{
myCpu = new Cpu(myService, "cpu");
//myCpu.Connection.DeviceType = BR.AN.PviServices.DeviceType.TcpIp;
myCpu.Connection.DeviceType = DeviceType.TcpIp;
myCpu.Connection.TcpIp.DestinationStation = 2;
myCpu.Connection.TcpIp.DestinationPort = 11160;
myCpu.Connection.TcpIp.DestinationIpAddress = "192.168.0.1";
//myCpu.Connection.TcpIp.DestinationIpAddress = "127.0.0.1";
myCpu.Connected += MyCpu_Connected;
myCpu.Error += MyCpu_Error;
myCpu.Connect(ConnectionType.CreateAndLink);
// maybe need to use this one - myCpu.Connect(ConnectionType.Create);
}
// throw new NotImplementedException();
}
private void MyCpu_Error(object sender, PviEventArgs e)
{
this.txtStatus.Text += e.Name + " Error:" + e.ErrorCode + "\r\n";
// throw new NotImplementedException(txtStatus.Text = "Error connecting.");
}
private void MyCpu_Connected(object sender, PviEventArgs e)
{
this.txtStatus.Text += "CPU Connected\r\n";
myTask = new BR.AN.PviServices.Task(myCpu, "pvitest");
myTask.Connected += MyTask_Connected;
myTask.Error += MyTask_Error;
myTask.Connect();
//throw new NotImplementedException();
}
private void MyTask_Error(object sender, PviEventArgs e)
{
this.txtStatus.Text += e.Name + " Error:" + e.ErrorCode + "\r\n";
//throw new NotImplementedException();
}
private void MyTask_Connected(object sender, PviEventArgs e)
{
this.txtStatus.Text += "Task " + e.Name + " Connected\r\n";
if (myVariable == null)
{
myVariable = new Variable(myTask, "Lifesign");
myVariable.Active = true;
myVariable.RefreshTime = 200;
myVariable.ValueChanged += MyVariable_ValueChanged;
myVariable.Error += MyVariable_Error;
myVariable.Connect();
}
if (myVariablePV1 == null)
{
myVariablePV1 = new Variable(myTask, "VarCreateOnly");
myVariablePV1.Address = "PV1";
myVariablePV1.Connect(ConnectionType.Create);
}
// throw new NotImplementedException();
}
private void MyVariable_Error(object sender, PviEventArgs e)
{
txtStatus.Text += e.Name + " E#" + e.ErrorCode.ToString();
//throw new NotImplementedException();
}
private void MyVariable_ValueChanged(object sender, VariableEventArgs e)
{
if (myStructPV == null) //PG35 stuff may need to move
{
myStructPV = new Variable(myTask, "Pv_Struct");
myStructPV.Active = true;
myStructPV.RefreshTime = 1000;
myStructPV.ValueChanged += MyStructPV_ValueChanged;
myStructPV.Error += MyStructPV_Error;
myStructPV.Connect();
}
// /\ above may need to be moved back.
if (e.Name == "Lifesign")
{
lblValLifesign.Text = ((Variable)sender).Value.ToString();
}
if (e.Name == "linkVarPV1")
{
lblPV1.Text = ((Variable)sender).Value.ToString();
}
Variable tmpVar = (Variable)sender; //PG 36 - 37
if(e.Name == "Pv_Struct")
{
if (tmpVar.Value.DataType == DataType.Structure)
{
foreach (Variable member in tmpVar.Members.Values)
{
txtStatus.Text += member.Value.ToString() + "\r\n";
}
}
}
foreach (String membername in e.ChangedMembers)
{
if (membername != null)
{
txtStatus.Text += tmpVar.Value[membername].ToString() + "\r\n";
}
}
//throw new NotImplementedException();
}
private void CmdConnectPV1_Click(object sender, EventArgs e)
{
Variable myLinkPV1 = new Variable(myVariable, "linkVarPV1");
myLinkPV1.LinkName = myVariablePV1.FullName;
myLinkPV1.Active = true;
myLinkPV1.ValueChanged += MyLinkPV1_ValueChanged;
myLinkPV1.Error += MyLinkPV1_Error;
myLinkPV1.Connect(ConnectionType.Link);
}
private void MyLinkPV1_Error(object sender, PviEventArgs e)
{
//throw new NotImplementedException();
}
private void MyLinkPV1_ValueChanged(object sender, VariableEventArgs e)
{
// throw new NotImplementedException();
}
private void CmdReadVar_Click(object sender, EventArgs e)
{
myVariable.ValueRead += MyVariable_ValueRead;
myVariable.ReadValue();
}
private void MyVariable_ValueRead(object sender, PviEventArgs e)
{
this.lblReadVar.Text = ((Variable)sender).Value.ToString();
//throw new NotImplementedException();
}
private void CmdReadTime_Click(object sender, EventArgs e)
{
myCpu.DateTimeRead += MyCpu_DateTimeRead;
myCpu.ReadDateTime();
}
private void MyCpu_DateTimeRead(object sender, CpuEventArgs e)
{
DateTime dt;
dt = e.DateTime;
this.Text = dt.ToString();
//throw new NotImplementedException();
}
private void CmdWriteVal_Click(object sender, EventArgs e)
{
myVariable.Value = 0;
myVariable.ValueWritten += MyVariable_ValueWritten;
}
private void MyVariable_ValueWritten(object sender, PviEventArgs e)
{
//throw new NotImplementedException();
}
private void CmdSetStruct_Click(object sender, EventArgs e)
{
myStructPV.WriteValueAutomatic = false;
myStructPV.Value["Member1"] = 10;
myStructPV.Value["Member2"] = 20;
myStructPV.Value["Member3"] = myVariable.Value;
myStructPV.WriteValue();
}
}
}
myStructPV
为null,因为您在未创建myStructPV
情况下调用CmdSetStruct_Click()
。 您需要MyVariable_ValueChanged()
首先运行,或者至少将其中创建myStructPV
的代码放入CmdSetStruct_Click()
。
只要在运行初始化程序时进入状态“ Task pvitest Connected”,那么所有PVI连接都可以正常工作(如果您的PLC上没有名为pvitest
的任务,但仍将其CPU Connected
到CPU Connected
那么您可以还在做还可以)。 您只需要调试与实际标签的连接即可。
就与OEM编写的现有Windows程序进行通信而言,这不太可能。 您将不得不使用某种调试器来获取其内存,或者希望它们创建了某种不太可能的API。
我认为Isaac正确地假设您在实际初始化myStruct Pv之前单击执行CmdSetStruct_Click()
的按钮。 这可能是因为直到可以从Lifebit变量获取valueChanged
事件为止,您与PLC的连接才起作用。
您在PLC上的Lifebit变量可以是全局变量吗? 很高兴看到VS的控制台输出能够查明问题,直到崩溃。
对于在PVI试用模式下运行,这是正确的,它可能会给初始连接带来一些问题,但是在那种情况下,如果您只是停止PVI管理器并再次启动它,那应该没问题。
无论如何,我还是建议您只有一种结构来处理PLC外部的通讯。 例如:
gComm.ToPlc.Status.someVariable
gComm.FromPlc.Cmd.startDoingSth
这样,您将只需要执行两次PVI变量连接过程。 一次连接到ToPlc结构,一次连接到FromPlc结构。 这样,您的代码将更容易管理。
最后,您可以使用变量的onConnected
事件,而不是使用valueChanged
。 这样,在允许您的应用继续运行之前,您可以等待直到在变量上获得有效连接并捕获从变量连接引发的错误并优雅地处理它们。 这样可以防止您的应用崩溃。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.