[英]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.