抖音粉丝群1
『7x24小时有问必答』

AI浪潮下的计算机行业——从业者现状与未来展望

大家好,我是Edison。

作为一个工业自动化领域的程序员,不懂点PLC和上位机,貌似有点说不过去。这里我用两篇小文带你快速进入上位机开发领域。后续,我会考虑再出一个系列文章一起玩工控上位机。
上一篇:搭建PLC模拟仿真环境
复习一下
在上一篇中,我们通过PLCSIM Advanced软件创建了一个虚拟的西门子S7-1500 PLC如下所示:

1.png

然后,我们创建了一个博途的自动化项目,和我们的虚拟PLC进行了组态。在编译完成后,我们创建的数据块中的数据字段就得到了偏移量,如下图所示,0,2,4, 260就是所谓的偏移量,会在后面用到。
2.png

创建Windows Form项目

这里开始我们就开始使用C#创建一个Windows Form项目,然后通过S7NetPlus库来连接PLC,并读取和写入数据块中的数据,这是一个典型的上位机数据采集的场景。
这里我们创建一个.NET Framework 4.8的Windows Form项目,并拖控件完成一个如下图所示的窗体应用界面:

3.png

这个窗体提供了连接和断开PLC,以及读取 和 写入 文本框中的数据,接下来我们就来实现这几个功能。

实现PLC的连接与断开

要实现S7 PLC的连接和操作,目前已经有很多较为成熟的组件了,我们这里使用S7NetPlus组件,直接通过NuGet安装最新版本即可。

4.png

然后编写Connect按钮的Click事件如下:
    private static Plc s7Instance;

    public MainForm()
    {
      InitializeComponent();
    }

    private void btnConnect_Click(object sender, System.EventArgs e)
    {
      if (btnConnect.Text == "Connect")
      {
        if (s7Instance == null)
          s7Instance = new Plc(CpuType.S71500, txtPlcIPAddress.Text.Trim(), 01);

        s7Instance.Open();
        btnConnect.Text = "Disconnect";
      }
      else
      {
        s7Instance.Close();
        btnConnect.Text = "Connect";
        txtBool01.Clear();
        txtInt01.Clear();
        txtStr01.Clear();
        txtStr02.Clear();
      }
    }
    实现PLC数据块的读取
    由于我们在博途项目中设置的数据块是DB01,且只有4个字段,所以这里我们编写ReadData按钮的Click事件如下,它通过指定参数读取到指定类型的数据并绑定到文本框的Text中。
      private void btnReadData_Click(object sender, System.EventArgs e)
      {
        if (s7Instance == null || !s7Instance.IsConnected)
        {
          MessageBox.Show("Your PLC is not connected now!", "Error", MessageBoxButtons.OK);
          return;
        }

        // bool
        var boolData = (bool)s7Instance.Read(DataType.DataBlock, 1, 0, VarType.Bit, 1);
        txtBool01.Text = boolData ? "1" : "0";
        // int
        var intData = (short)s7Instance.Read(DataType.DataBlock, 1, 2, VarType.Int, 1);
        txtInt01.Text = intData.ToString();
        // string
        var count = (byte)s7Instance.Read(DataType.DataBlock, 1, 4 + 1, VarType.Byte, 1); // +1表示读取偏移值的长度
        var str01Data = Encoding.Default.GetString(s7Instance.ReadBytes(DataType.DataBlock, 1, 4 + 2, count)); // +2表示读取偏移值(跳过)的字符
        txtStr01.Text = str01Data;
        // wstring
        var str02Data = (string)s7Instance.Read(DataType.DataBlock, 1, 260, VarType.S7WString, 254);
        txtStr02.Text = str02Data;
      }
      (1)针对bool和int类型,我们可以直接通过Read方法快速读取到,但需要告诉PLC准确的读写位置和数据类型,主要是偏移量一定要给正确。

      Read方法的参数分别为数据块类型,数据块,偏移量,读取类型,读取长度

      (2)针对string和wstring类型,就稍微麻烦一些了:
      针对string,需要先获取string值的所占长度。再拿到具体byte值。转换为utf8格式的ascci码,具体代码中有体现。

      +1 表示获取到长度

      +2 表示获取到跳过偏移长度的字符

        var count = (byte)s7Instance.Read(DataType.DataBlock, 1, 4 + 1, VarType.Byte, 1); // +1表示读取偏移值的长度
        var str01Data = Encoding.Default.GetString(s7Instance.ReadBytes(DataType.DataBlock14 + 2count)); // +2表示读取偏移值(跳过)的字符

        特别注意:string类型只能存储ascci码,需要注意,不能存储中文

        针对wstring,稍微简单点,但是需要注意的是获取的字符需要为254个,因为符号占用了4个字节。

        实现PLC数据块的写入

        和读取一样,通过Write方法即可轻松实现写入,但针对string和wstring仍然是复杂一些,这里我封装了一个S7DataWriter的静态类,提供了两个方法来获取要写入的bytes,因为它无法直接接收C#程序中的string类型。
          public static class S7DataWriter
          {
            /// 
            /// 获取西门子PLC字符串数组--String类型
            /// 
            public static byte[] GetPlcStringByteArray(string str)
            {
              byte[] value = Encoding.Default.GetBytes(str);
              byte[] head = new byte[2];
              head[0] = Convert.ToByte(254);
              head[1] = Convert.ToByte(str.Length);
              value = head.Concat(value).ToArray();
              return value;
            }

            /// 
            /// 获取西门子PLC字符串数组--WString类型
            /// 
            public static byte[] GetPlcWStringByteArray(string str)
            {
              byte[] value = Encoding.BigEndianUnicode.GetBytes(str);
              byte[] head = BitConverter.GetBytes((short)508);
              byte[] length = BitConverter.GetBytes((short)str.Length);
              Array.Reverse(head);
              Array.Reverse(length);
              head = head.Concat(length).ToArray();
              value = head.Concat(value).ToArray();
              return value;
            }
          }
          然后,我们就可以编写Write Data按钮的Click事件了:
            private void btnWriteData_Click(object sender, System.EventArgs e)
            {
              if (s7Instance == null || !s7Instance.IsConnected)
              {
                MessageBox.Show("Your PLC is not connected now!", "Error", MessageBoxButtons.OK);
                return;
              }

              // bool
              var boolValue = txtBool01.Text.Trim() == "1" ? true : false;
              s7Instance.Write(DataType.DataBlock, 1, 0, boolValue);
              // int
              var intValue = Convert.ToInt16(txtInt01.Text);
              s7Instance.Write(DataType.DataBlock, 1, 2, intValue);
              // string
              s7Instance.Write(DataType.DataBlock, 1, 4, S7DataWriter.GetPlcStringByteArray(txtStr01.Text.Trim()));
              // wstring
              s7Instance.Write(DataType.DataBlock, 1, 260, S7DataWriter.GetPlcWStringByteArray(txtStr02.Text.Trim()));

              MessageBox.Show("Write data successfully!", "Info", MessageBoxButtons.OK);
            }

            效果演示

            和读取一样,通过Write方法即可轻松实现写入,但针对string和wstring仍然是复杂一些,这里我封装了一个S7DataWriter的静态类,提供了两个方法来获取要写入的bytes,因为它无法直接接收C#程序中的string类型。
            (1)读取数据

            5.png

            (2)写入数据

            6.png

            小结

            本文通过使用C#开发了一个简单的WindowsForm窗体程序,实现了S7 PLC的连接、数据读取和写入。虽然只是一个简单的Demo,但是从中可以看见上位机的基本思想,就是对PLC的数据采集和监控。当然,实现这个目的,不止S7协议一条路,我们还可以通过ModBus、OPC UA等协议,这些就留到后面的专题吧,如果你感兴趣的话,就保持关注哦!

            源码

            GitHub:https://github.com/Coder-EdisonZhou/PLC-Connectors


            本地下载
            请点击此处下载

            查看状态:已购买或有权限

            您的用户组是:游客

            文件名称:PLC-Connectors-main.zip 
            下载次数:0  文件大小:18.41 KB 
            下载权限: 不限 
            以上资料整理不易! 打赏楼主 ,也可赚取金币!


            免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
            您需要登录后才可以回帖 登录 | 立即注册

            本版积分规则

            上一主题上一主题         下一主题下一主题
            QQ手机版小黑屋粤ICP备17165530号

            关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

            法律保护:PLC技术网,plcjs.com,plcjs.net等字样
            Copyright 2010-2030. All rights reserved. 


            微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码