菜单

ACP C#使用手册

概览

本案例用来演示,通过Visual Studio 2022创建C#的WPF工程,使用ACP的接口来读取变量、写入变量、批量读取变量、订阅变量、取消订阅的功能。

硬件示意如下图所示:

下表概述了本手册各个产品组件

产品组件 描述说明
Device Manager 0.0.1.9 插件管理工具
ACP_Project.projectarchive PLC工程存档(客户端)
WPF_ACP C#程序源文件

安装卸载

安装要求

  • 中科时代出厂的工智机的自带系统;
  • 个人电脑与工智机固定地址网口连接;
  • 个人电脑可以访问互联网;

安装过程
1、工智机安装acpplcaccess.deb组件

1.打开Device Manager软件

2.初次使用,需要安装ACP通讯服务。点击左下角“安装ACP服务”。

3.输入工智机固定IP地址、端口、用户名和密码后,点击“在线安装”。

IP地址 192.168.1.200
端口 2224
用户 sinsegye
密码 1

等待安装完成。

4.安装完成后,点击“扫描”,即可扫描出固定网口192.168.1.200连接的工智机。

点击进入工智机后,左下角显示“已连接”状态。

5.点击“安装RTE插件服务”

6.输入用户名:sinsegye,密码:1,点击“在线安装”

7.安装完成后,点击“软件”,在下拉菜单下选择“组件管理”

8.点击浏览,可以在线浏览可以安装的组件。

9.在组件中找到“SF1000-acpplcaccess”--点击“安装”

10.等待deb包传送到工智机中,传送完成后点击“确定”进行安装。

11.安装完成后,点击“确认”重启生效。

12.安装完成后,可以在“本地”页面浏览到SF1000-acpplcaccess已安装成功。

2、C#工程安装Sinsegye ACP的NuGet包

打开Visual Studio 2022新建C#的WPF应用程序:

添加工程名:

在工程中添加程序包源:

右键选择工程的“依赖项”—“管理NuGet程序包”

选择设置:

添加源:

名称:acp

源:http://gitlab.sinsegye.com.cn:8081/artifactory/api/nuget/v3/si-nuget-release-ecs

名称:api.nuget.org

源:https://api.nuget.org/v3/index.json

搜索到sinsegye.acpsharp程序包,选择最新稳定版——“安装”。

3、PLC示例程序编辑

本PLC程序示例可以从中科时代官网进行下载,也可以按如下方法进行创建。

打开中科时代IDE MetaFacture

选择“新建工程”

选择“标准工程”--命名为“ACP_Project”--点击“确定”。

设备选择“Sinsegye”--选择PLC_RRG编程语言,本例为ST语言,点击“确定”即可完成创建。

创建的新工程:

鼠标右键“Application”—“添加对象”—“DUT”。添加读写和订阅用的结构体类型。

命名为“CS_Struct”—点击“添加”

添加两个子成员:S1和S2。类型分别为DWORD和TIME。

再次鼠标右键“Application”—“添加对象”—“全局变量列表”。

命名为“GVL”—“添加”

添加如下变量,用于ACP订阅变量功能测试:

变量名 类型
Var11 BOOL
Var12 INT
Var13 REAL
Var14 STRING
Var15 ARRAY\[0..9] OF BYTE
Var16 CS_Struct

点击"PLC_PRG",声明如下变量,用于ACP读写功能测试:

变量名 类型 初始值
Var1 BOOL TRUE
Var2 INT -40
Var3 REAL 3.1415
Var4 STRING Sinsegye
Var5 ARRAY\[0..4] OF INT \[7,6,5,4,3]
Var6 CS_Struct (S1:=4294967295, S2:=T#5D22H37M28S7MS)
i LINT 0(用于订阅功能)

在PLC_PRG中编辑如下程序:

shell 复制代码
i:=i+1
GVL.Var11:=NOT GVL.Var11
GVL.Var12:=LINT\_TO\_INT(i)
GVL.Var13:=3.1415926\*LINT\_TO\_REAL(i)/1000
GVL.Var14:=CONCAT('Var i is ',LINT\_TO\_STRING(i))
GVL.Var15\[3]:=LINT\_TO\_BYTE(i)
GVL.Var16.S1:=LINT\_TO\_WORD(i)
GVL.Var16.S2:=LINT\_TO\_TIME(i)

再次鼠标右键“Application”—“添加对象”—“符号配置”。

默认设置,点击“添加”

添加完成后,点击“编译”

勾选如下变量:

双击“Device”—“扫描网络”—选择登录的ACP工智机—“确定”

点击“登录”

点击“启动”

三、更新安装

在插件管理器Device Mananger--组件管理--本地组件中,点击SF1000-acpplcaccess,选择可更新的版本后,点击“更新”。

四、卸载过程

卸载工智机deb组件

在插件管理器Device Mananger--组件管理--本地组件中,点击SF1000-acpplcaccess,选择“卸载”

点击“确定”

卸载成功后,点击“确定”重启生效。

卸载成功后,“本地”页面组件消失。


技术说明

快速启动

(一)本例软、硬件配置

硬件: 软件:
工智机SX21-A01 1.工智机PLC存档工程ACP_Project.projectarchive
个人电脑 2.中科时代MetaFacture V1.0.6.6
Visual Studio 2022

(二)本例实验操作步骤

1.实验要求

a.工智机成功安装SF1000-acpplcaccess组件;

b.个人电脑安装Visual Studio 2022和中科时代MetaFacture软件;

c.个人电脑可以联网且与工智机固定地址192.168.1.200网口连接。

2.实验原理图

3.实验步骤

3.1 解压官网下载的工程存档文件“ACP_Project.projectarchive”,登录工智机,下载运行程序。

其中,PLC_PGR中的变量Var1~Var6,作为测试读写变量使用。

GVL中的变量Var11~Var16作为测试订阅变量使用。

3.2 打开中科时代下载的C#源文件--“WPF_ACP.sln”

3.3 打开“MainWindow.xaml.cs”程序,修改成ACP工智机的IP地址。

3.4 完成IP地址修改后,点击运行“WPF_ACP”

3.5 点击“连接”—显示“连接成功”—点击“确定”

3.6点击“读取变量”,文本框显示PLC_PRG程序中的变量。

3.7 点击“订阅”,订阅PLC程序中的GVL变量,而且数值不断变化。

3.8 点击“取消订阅”,变量数值不再变化保持当前值。

3.9 双击左列文本框,可以修改变量值,修改完成后需要将鼠标焦点移除文本框。

3.10 修改完成后,点击“批量读取”,读取出的值与修改的值相同。

3.11 在线查看PLC程序,变量修改成功。


示例

连接客户端

按照上一章节《安装卸载》中的"C#工程安装Sinsegye ACP的Nuget包"中创建新工程并安装Nuget包。

打开创建的C#程序,点击左侧工具箱,添加一个Label和一个TextBox。

修改Label的属性Content="BOOL",TextBox的属性Name="Var1",Text=""

同理,将Label标签复制6个,竖向排列,修改Content属性为INT、Real、String、Array3、Struct1和Struct2

将TextBox复制6个,并与Label相对应,修改属性Name。

添加一个Button控件,修改属性Content=“连接”

双击按键,VS会自动跳转到CS程序,并生成按钮点击事件的方法。

创建客户端函数:

public AcpClient(string deviceID, uint Port, ConnectionType connectionType.Tcp, bool isReConnect = false, int send_timeout_ms = 500, int rec_timeout_ms = 500)

acpClient通过字段ConnState可以查看连接状态,输出提示:

ConnStat为枚举类型,有如下连接状态:

为了后续程序使用client实例,可以将client声明在方法外:

连接客户端代码如下:

shell 复制代码
AcpClient \_acpClient;
private void button\_Click(object sender, RoutedEventArgs e)
{
   _acpClient = new AcpClient("192.168.1.200.1.1", 600, ConnectionType.Tcp, false, 500, 500)
if (\_acpClient.ConnState == ConnState.SuccessfulConnection)
  {
MessageBox.Show("连接成功")
  }
else
  {
MessageBox.Show("连接失败")
  }
}

读取变量

在WPF界面增加一个读取变量的按钮,修改属性Name="btnread" Content="读取变量",双击进入按钮点击方法编辑:

双击进入方法:

使用读取变量接口

Errors ReadVar(string VarName, IPlcOpenType VarInstance, out string innerError);

PLC工程中所对应的IplcOpenType类型见附录二

对于PLC程序中结构体类型,需要在C#程序中新建与之相对应的结构体。本例中,PLC的结构体含有两个成员,分别是DWORD和TIME类型。在C#程序中也建立一个包含这两个类型成员的结构体。

设定读取变量名和对应的IPlcOpenType类型:

通过ReadVar方法读取相应的变量:

将读取的结果输出到WPF的Text文本框中:

运行程序,先点击“连接”按钮,再点击“读取变量”按钮:

读取变量成功:

读取变量的C#代码如下:

shell 复制代码
 class PLCStruct : STRUCT
 {
      public DWORD child1 = new DWORD()
      public TIME child2 = new TIME()
  }//结构体类型
      
      string ReadVar1 = "Application.PLC\_PRG.Var1";//读取变量1的路径
      string ReadVar2 = "Application.PLC\_PRG.Var2";//读取变量2的路径
      string ReadVar3 = "Application.PLC\_PRG.Var3";//读取变量3的路径
      string ReadVar4 = "Application.PLC\_PRG.Var4";//读取变量4的路径
      string ReadVar5 = "Application.PLC\_PRG.Var5";//读取变量5的路径
      string ReadVar6 = "Application.PLC\_PRG.Var6";//读取变量61的路径
      string errorUnmarshal;
      
BOOL bool1 = new BOOL();//实例IplcOpenType Bool类型
INT INT1 = new INT();//实例IplcOpenType Int类型
REAL REAL1 = new REAL();//实例IplcOpenType Real类型
STRING STRING1 = new STRING();//实例IplcOpenType String类型
ARRAY\<INT> intARRAY1 = new ARRAY\<INT>(new\[] { (0, 4) });//实例IplcOpenType一维int类型数组,数组起始角标为0,结束标为4.
PLCStruct Struct1 = new PLCStruct();//实例化结构体; 
private void btnread\_Click(object sender, RoutedEventArgs e)
{
     var ReadError = \_acpClient.ReadVar(ReadVar1, bool1, out errorUnmarshal);//开始读取变量1布尔
     ReadError = \_acpClient.ReadVar(ReadVar2, INT1, out errorUnmarshal);//开始读取变量2整数
     ReadError = \_acpClient.ReadVar(ReadVar3, REAL1, out errorUnmarshal);//开始读取变量3实数
     ReadError = \_acpClient.ReadVar(ReadVar4, STRING1, out errorUnmarshal);//开始读取变量4字符串
     ReadError = \_acpClient.ReadVar(ReadVar5, intARRAY1, out errorUnmarshal);//开始读取变量5数组
     ReadError = \_acpClient.ReadVar(ReadVar6, Struct1, out errorUnmarshal);//开始读取变量6结构体
     ;
             Var1.Text = bool1.ToString(); //将变量1的数据显示到界面Var1的文本框中
             Var2.Text = INT1.ToString();//将变量2的数据显示到界面Var2的文本框中
             Var3.Text = REAL1.ToString();//将变量3的数据显示到界面Var3的文本框中
             Var4.Text = STRING1;        //将变量4的数据显示到界面Var4的文本框中
             Var5.Text = intARRAY1\[2].ToString();//将变量5数组的第三个元素显示到界面Var5的文本框中
             Var6.Text = Struct1.child1.ToString();//将结构体的第一个子元素的显示到界面Var6的文本框中
             Var7.Text = Struct1.child2.ToString();//将结构体的第二个子元素的显示到界面Var7的文本框中
             } 

批量读取

在WPF界面复制一列TextBox控件,从上到下修改属性:Name="MultiVar1"到"MutiVar7"

新建一个按钮,修改属性Name="btnMultiRead" Content="批量读取"。双击按钮进入方法编程:

双击按钮进入方法编程:

新建批量读取的List

设置每个accessVarMode属性,包括读取路径和变量类型:

添加到List中:

使用批量读取方法AccessVars进行读取并显示到TextBox中:

运行程序,先后点击“连接”—“批量读取”按钮。

点击“批量读取”

批量读取C#代码如下:

shell 复制代码
private void btnMultiRead\_Click(object sender, RoutedEventArgs e)
{
List\<AccessVarModel> accessVarModels = new List\<AccessVarModel>()
     AccessVarModel accessVarModel = new AccessVarModel()
     AccessVarModel accessVarMode2 = new AccessVarModel()
     AccessVarModel accessVarMode3 = new AccessVarModel()
     AccessVarModel accessVarMode4 = new AccessVarModel()
     AccessVarModel accessVarMode5 = new AccessVarModel()
     AccessVarModel accessVarMode6 = new AccessVarModel()
     
     
     accessVarModel.VarName = "Application.PLC\_PRG.Var1"
     accessVarModel.VarInstance = bool1
     
     accessVarMode2.VarName = "Application.PLC\_PRG.Var2";
     accessVarMode2.VarInstance = INT1
     
     accessVarMode3.VarName = "Application.PLC\_PRG.Var3"
     accessVarMode3.VarInstance = REAL1;
     
     accessVarMode4.VarName = "Application.PLC\_PRG.Var4";
     accessVarMode4.VarInstance = STRING1;&#xA;&#xA;     
     
     accessVarMode5.VarName = "Application.PLC\_PRG.Var5"
     accessVarMode5.VarInstance = intARRAY1
     
     accessVarMode6.VarName = "Application.PLC\_PRG.Var6"
     accessVarMode6.VarInstance = Struct1
     
     accessVarModels.Add(accessVarModel)
     accessVarModels.Add(accessVarMode2)
     accessVarModels.Add(accessVarMode3)
     accessVarModels.Add(accessVarMode4)
     accessVarModels.Add(accessVarMode5)
     accessVarModels.Add(accessVarMode6)
     var MultiReadError = \_acpClient.AccessVars(accessVarModels);//批量读取方法
     
     MultiVar1.Text = accessVarModel.VarInstance.ToString()
     MultiVar2.Text = accessVarMode2.VarInstance.ToString()
     MultiVar3.Text = accessVarMode3.VarInstance.ToString()
     MultiVar4.Text = accessVarMode4.VarInstance.ToString();
     MultiVar5.Text = ((ARRAY\<INT>)accessVarMode5.VarInstance)\[3].Value.ToString()
     MultiVar6.Text = ((PLCStruct)accessVarMode6.VarInstance).child1.Value.ToString()
     MultiVar7.Text = ((PLCStruct)accessVarMode6.VarInstance).child2.Value.ToString()
     }

订阅变量

在WPF界面复制一列TextBox控件,从上到下修改属性:Name="SubVar1"到"SubVar7"。

新建一个按钮,修改属性Name="btnSub" Content="订阅",

双击按钮进入方法编程:

在C#程序中添加如下变量:

初始化注册回调函数:

添加订阅变量:

其中,15代表订阅间隔周期15ms。

订阅变量C#代码如下:

shell 复制代码
int req = 0;//添加订阅的请求号
long \_Subid = new long(); //用于接受回调函数ID号
bool isReg = true;//用于初始化注册回调函数
string\[] strings = new string\[6];//用于订阅PLC程序变量
private void btnSub\_Click(object sender, RoutedEventArgs e)
 {
      if (isReg)          //如果初次调用程序,注册回调函数
      {
      var RegError = \_acpClient.RegisterRouterEvent(SubCallBack);//注册回调函数
      
      isReg = false;  //注册完成后,设为false,不再进行注册
      }
      
      strings\[0] = "Application.GVL.Var11"
      strings\[1] = "Application.GVL.Var12"
      strings\[2] = "Application.GVL.Var13"
      strings\[3] = "Application.GVL.Var14"
      strings\[4] = "Application.GVL.Var15"
      strings\[5] = "Application.GVL.Var16"
      var AddSubError = \_acpClient.AddBatchSubVar(strings, req, 15)
      } 

回调函数

当变量值发生变化时,会执行回调函数SubCallBack。

点击红色波浪线,选择下拉菜单—“生成方法SubCallBack”

自动生成SubCallBack:

在回调函数的方法中,先记录ID号,将来用于取消订阅:

当订阅的变量值发生改变时,dates的数据也会发生改变,使用foreach遍历dates的数据,来获得想要的变量:

添加剩余的PLC变量显示到TextBox文本框中:

运行程序,点击“连接”—连接成功。

点击“订阅”测试,可以看到变量不断在改变。

回调函数C#代码如下:

shell 复制代码
BOOL Subbool = new BOOL();      //创建订阅的BOOL类型
INT Subint = new INT();         //创建订阅的Int类型
REAL SubReal = new REAL();      //创建订阅的Real类型
STRING Substring = new STRING();//创建订阅的String类型
ARRAY\<BYTE> SubbyteArray = new ARRAY\<BYTE>(new\[] { (0, 9) });//创建订阅的一维BYTE类型数组,下角标从0\~9
PLCStruct Substruct = new PLCStruct();//创建订阅的结构体类型
private void SubCallBack(ValueChangeDates dates)
{
    \_Subid = dates.subid;//回调函数ID号
    
    foreach (var item in dates.ValueChangeDateList)
    {
    if (item.VarName == "Application.GVL.Var11")//如果数据变量名为Var1
    {
    Subbool.Unmarshal(item.Bytes);          //将数据转换为Bool类型
    Application.Current?.Dispatcher.InvokeAsync(new Action(() =>
    {
    
    SubVar1.Text = Subbool.ToString();  //输出到SubVar1的文本框中
    }));
    
    }
    if (item.VarName == "Application.GVL.Var12")//如果数据变量名为Var12
    {
    
    Subint.Unmarshal(item.Bytes);           //将数据转换为int类型
    Application.Current?.Dispatcher.InvokeAsync(new Action(() =>
    {
    SubVar2.Text = Subint.ToString();   //输出到SubVar2的文本框中
    }));
    }
    if (item.VarName == "Application.GVL.Var13")//如果数据变量名为Var13
    {
    
    SubReal.Unmarshal(item.Bytes);          //将数据转换为Real类型
    Application.Current?.Dispatcher.InvokeAsync(new Action(() =>
    {
    SubVar3.Text = SubReal.ToString();  //输出到SubVar3的文本框中
    }))
    }
    
    if (item.VarName == "Application.GVL.Var14")//如果数据变量名为Var14
    {
    
    Substring.Unmarshal(item.Bytes);        //将数据转换为string类型
    Application.Current?.Dispatcher.InvokeAsync(new Action(() =>
    {
    SubVar4.Text = Substring.ToString();//输出到SubVar4的文本框中
    }));
    
    }
    if (item.VarName == "Application.GVL.Var15")//如果数据变量名为Var15
    {
    
    SubbyteArray.Unmarshal(item.Bytes);     //将数据转换为一维BYTE数组SubbyteArra
    Application.Current?.Dispatcher.InvokeAsync(new Action(() =>
    {
    SubVar5.Text = SubbyteArray\[3].ToString();//将SubbyteArray的第4个元素输出到SubVar5的文本框中
    }));
    
    }
    
    if (item.VarName == "Application.GVL.Var16")//如果数据变量名为Var16
    {
    
    Substruct.Unmarshal(item.Bytes);        //将数据转换为结构体Substruct
    Application.Current?.Dispatcher.InvokeAsync(new Action(() =>
    {
    SubVar6.Text = Substruct.child1.ToString();//将Substruct的第一个子成员输出到SubVar6的文本框中
    SubVar7.Text = Substruct.child2.ToString();//将Substruct的第二个子成员输出到SubVar7的文本框中
    }));
    }
  }
 } 

取消订阅

在WPF界面新建一个按钮,修改属性Name="btnUnSub" Content="取消订阅"。

双击按钮进入方法编程:

使用DelBatchSubVar方法取消订阅,需要传递订阅时的ID号:

运行程序,点击“连接”—“订阅”变量值更新,点击“取消订阅”变量值停止更新。

取消订阅的C#代码如下:

shell 复制代码
 private void btnUnSub\_Click(object sender, RoutedEventArgs e)
 {
 
 var UnSubError = \_acpClient.DelBatchSubVar(\_Subid);//\_Subid为SubCallBack函数获取的ID号
 } 

写入变量

选择“Var1”的TextBox控件。

在属性中选择事件,在LostFocus中写入ValueWrite。C#自动创建ValueWrite方法。

C#自动创建ValueWrite方法。

当TextBox焦点丢失时,会执行ValueWrite方法。在ValueWrite方法中,使用WriteVar方法即可将TextBox的值写入PLC的变量中。

同理,将其余的6个TextBox控件的LostFocus事件都填入ValueWrite方法:

由于现在多个控件在焦点丢失时都使用ValueWrite方法。所以在ValueWrite方法中,需要先判断是哪一个TextBox控件触发的事件,再进行写变量:

使用TryParse将PLC类型转换为C#类型:

对于本例中的数组和结构体单一修改某一成员,需要先将数组和结构体整体读取,再单独修改成员值,否则其余成员值会变为空。

PLC类型转换为C#类型的TryParse见下表:

PLC中IEC类型 C#类型(小写)
Bool bool
Byte byte
Word ushort
Dword uint
Lword ulong
Sint sbyte
Usint byte
Int short
Uint ushort
Dint int
Udint uint
Lint long
Real float
Lreal double
String string
Array OF xxx 根据数组类型
Struct 根据成员类型
Time TimeSpan
Date TimeSpan

运行程序,“连接”—“读取变量”。鼠标点击文本框,修改变量值—当鼠标焦点丢失后,变量写入。

修改Struct2

写入变量的C#代码如下:

shell 复制代码
private void ValueWrite(object sender, RoutedEventArgs e)
{
     TextBox tb = (TextBox)sender;
     
     if (tb.Name == "Var1")
     {
         bool.TryParse(Var1.Text, out bool boolwrite);//将Text控件Var1的文本内容转成bool类型存入boolwrite变量
         bool1.Value = boolwrite;//将boolwrite赋值给IplcOpenType类型的实例bool1
         var WriteError = \_acpClient.WriteVar(ReadVar1, bool1, out errorUnmarshal);//写入变量
         }
         else if (tb.Name == "Var2")
         {
         short.TryParse(Var2.Text, out short shortwrite);&#xA;         
         INT1.Value = shortwrite
         var WriteError = \_acpClient.WriteVar(ReadVar2, INT1, out errorUnmarshal)
         }
         else if (tb.Name == "Var3")
         {
         float.TryParse(Var3.Text, out float floatwrite)
         REAL1.Value = floatwrite
         var WriteError = \_acpClient.WriteVar(ReadVar3, REAL1, out errorUnmarshal)
         }
         else if (tb.Name == "Var4")
         {
         STRING1.Value = Var4.Text.Replace("\0", "");
         var WriteError = \_acpClient.WriteVar(ReadVar4, STRING1, out errorUnmarshal);
         }
         else if (tb.Name == "Var5")
         
         var ReadError = \_acpClient.ReadVar(ReadVar5, intARRAY1, out errorUnmarshal);//读取数组intARRAY1
         short.TryParse(Var5.Text, out short intArray2write);//将Text文本转换成Int类型&
         intARRAY1\[2].Value = intArray2write;//修改数组intARRAY1\[2]的值
         var WriteError = \_acpClient.WriteVar(ReadVar5, intARRAY1, out errorUnmarshal);//写入数组intARRAY1
         }
         else if (tb.Name == "Var6")
         {
         var ReadError = \_acpClient.ReadVar(ReadVar6, Struct1, out errorUnmarshal);//读取结构体
         uint.TryParse(Var6.Text, out uint StuctChild1write);//将文本转换为成员1类型
         Struct1.child1.Value = StuctChild1write;//修改成员1的值
         var WriteError = \_acpClient.WriteVar(ReadVar6, Struct1, out errorUnmarshal);//写入
         }
         else if (tb.Name == "Var7")
         {
         var ReadError = \_acpClient.ReadVar(ReadVar6, Struct1, out errorUnmarshal);//读取结构体
         TimeSpan timechange = new TimeSpan();  //新建TimeSpan类型用于接收修改值
         TimeSpan.TryParse(Var7.Text, out timechange);//将Text文本转成TimeSpan类型
         Struct1.child2.Value = timechange;//赋值结构体成员2
         var WriteError = \_acpClient.WriteVar(ReadVar6, Struct1, out errorUnmarshal);//写入
         }
   } 

C# 接口介绍

1、初始化客户端

shell 复制代码
AcpClient \_acpClient= new AcpClient(string deviceID, uint Port, ConnectionType.Tcp,
bool isReConnect, int send\_timeout\_ms, int rec\_timeout\_ms)

2、读取变量

shell 复制代码
Errors ReadVar(string VarName, IPlcOpenType VarInstance,out string innerError);

3、写入变量

shell 复制代码
Errors WriteVar(string VarName, IPlcOpenType VarInstance, out string innerError); 

4、批量读写

shell 复制代码
//实例化一个AccessVarModel列表
List\<AccessVarModel> accessVarModels = new List\<AccessVarModel>();

//实例化一个AccessVarModel对象
AccessVarModel accessVarModel = new AccessVarModel()

//设定AccessVarModel对象的路径和类型
accessVarModel.VarName = "Application.PLC\_PRG.Var1"
accessVarModel.VarInstance = bool1

//设定处理方式,默认为读取变量不需要设定,写入变量需要设定
accessVarModel.AccessType = acp\_idl.PlcAccess.AccessType.Write

//将accessVarModel对象添加到列表中
accessVarModels.Add(accessVarModel)

//批量读写
var Error = \_acpClient.AccessVars(accessVarModels)

5、读写结构体

shell 复制代码
//定义一个结构体,成员变量的类型,定义顺序必须与PLC中结构体一样
class PLCStruct : STRUCT                   //创建结构体,用于读写和订阅结构体数据
public DWORD child1 = new DWORD(); //结构体子成员1类型与PLC类型DWORD相同
public TIME child2 = new TIME(); //结构体子成员2类型与PLC类型TIME相同
}
//结构体类型
//定义string变量来存储PLC中结构体的路径string ReadStruPath = "Application.PLC\_PRG.Var5";/
/设置读取结构体路径
//实例化结构体
PLCStruct Struct1 = new PLCStruct();
//实例化结构体
//读写结构体
Var Error=\_acpClient.ReadVar(ReadStruPath, Struct1, out errorUnmarshal);
Var Error=\_acpClient.WriteVar(ReadStruPath, Struct1, out errorUnmarshal); 

6、读写数组

shell 复制代码
//支持一维至三维数组,定义一个与PLC类型、维度、始末数字相同的数组
ARRAY\<INT> ArrayName = new ARRAY\<INT>(new\[] { (0,4) });
//一维数组
ARRAY\<INT> ArrayName = new ARRAY\<INT>(new\[] { (3, 10), (3, 10) })
//二维数组
ARRAY\<INT> ArrayName = new ARRAY\<INT>(new\[] { (2, 5), (0, 9),(0, 9) });
//三维数组
//定义string变量来存储PLC中数组的路径
string ReadArrayPath = "Application.PLC\_PRG.Var6"

//读写数组
Var Error=\_acpClient.ReadVar(ReadArrayPath, ArrayName, out errorUnmarshal)
Var Error=\_acpClient.WriteVar(ReadArrayPath, ArrayName, out errorUnmarshal); 

7、订阅变量

shell 复制代码
| //使用RegisterRouterEvent方法注册回调函数SubCallBack 
var RegError = \_acpClient.RegisterRouterEvent(SubCallBack);//注册回调函数

//添加字符串数组用于设定订阅变量的路径
string\[] strings = new string\[10];//string类型数组
strings\[0] = "Application.GVL.Var11";//订阅变量路径1
strings\[1] = "Application.GVL.Var12";//订阅变量路径2
strings\[2] = "Application.GVL.Var13";//订阅变量路径3

//添加订阅,req代表请求号,15代表订阅周期15
var AddSubError = \_acpClient.AddBatchSubVar(strings,0,15); 

8、回调函数

复制代码
//创建订阅的变量类型以及回调函数ID号
BOOL Subbool = new BOOL();  //创建回调函数接收的Bool类型
INT  Subint = new INT();    //创建回调函数接收的Int类型
REAL Subreal = new REAL(); //创建回调函数接收的Real类型
long \_Subid = new long(); //用于接受回调函数ID号
//回调函
private void SubCallBack(ValueChangeDates dates)
{
 _Subid = dates.subid;//保存回调ID号
 foreach (var item in dates.ValueChangeDateList)//遍历找到变量,接收数据
 
 {
 if (item.VarName == "Application.GVL.Var11")//如果数据变量名为Var11&
 {
 Subbool.Unmarshal(item.Bytes);          //将数据转换为Bool类型
 }
 if (item.VarName == "Application.GVL.Var12")//如果数据变量名为Var12
 {
 Subint.Unmarshal(item.Bytes);          //将数据转换为Int类型
 }
 if (item.VarName == "Application.GVL.Var13")//如果数据变量名为Var13
 {
 Subreal.Unmarshal(item.Bytes);          //将数据转换为Real类型
 
 }
 }

9、取消订阅

shell 复制代码
//使用DelBatchSubVar方法取消订阅,需要传递回调函数ID
var UnSubError = \_acpClient.DelBatchSubVar(\_Subid);//\_Subid为SubCallBack方法获取的ID号
最近修改: 2025-04-18