[西门子] S7.Net与西门子PLC通讯——纯新手必看

[复制链接]
查看141 | 回复0 | 2024-4-16 07:52:08 | 显示全部楼层 |阅读模式
前言
本文档适合从未接触过PLC的.NET开发程序员入门查看。(其实看完了之后,PLC开发也就那样)
PLC通讯入门比较难,需要关注的细节比较多。一边学习一边举一反三多思考,一定要自己创建Demo跟着步骤

由于项目还未开发完成,准备空抽补充陆续完成这篇博客,更好的设计思路也能给自己加深印象。
近期公司有一个跟雷达、光电、干扰炮等设备通讯的项目,让我来负责,整个项目只有我一个人且没有PLC开发经验的同事,这对于从未接触过PLC开发的我来说,无疑是一团迷雾,不知从何入手。公司之前也没有PLC开发经验和项目, 头大。。。
正所谓“没有撤退可言,只有活下来的人才有资格清兵线!”


开始在网上找各种资料,在此记录一下学习的过程和踩过的坑
1. 快速锁定有效文章,对于初学来说,先看理论,有些花里胡哨且乱的资料直接关闭
2. 尽量能找到可以理解的demo,觉得有用但还看不懂的可以先notepad做下笔记
3. 如果有人在看 WinTcpS7_1K.dll 的,赶紧关闭,并送到回收站快速清理,收费的。1500授权3台电脑(这个家伙广告特别多,涉及各个论坛,还要CSDN下载积分,注意看评论),最主要封装的还很难用
4. 最后的最后找到 S7NetPlus ,成功实现了PLC的通讯,博客也会总结对 S7NetPlus 的使用
5. 要有中心思路,不要一会这个,一会看那个
开发环境准备
同时由于设备还未采购,没有设备进行测试开发,会安装一个仿真模拟器进行调试。(真心的,谁想到还能仿真模拟设备)
需要安装的软件包括
◦TIA Portal V14
◦S7-PLCSIM V14
◦NetToPLCsim-S7o-v-1-2-2-0

TIA Portal
西门子官方管理设备数据块的客户端,每一个项目等同于一个设备型号,可以理解为是我们经常使用的数据块客户端


S7-PLCSIM
创建一个仿真的模拟环境,使用TIA Portal进行调用,控制仿真设备的运行停止


NetToPLCsim
提供本地服务去连接到仿真设备,和PLCsim之间建立网络通讯


安装完TIA之后,有两处需要进行设置(重要!)
1. 选中组态的PLC设备,常规下找到防护与安全,选择允许从远程伙伴使用PUT/GET通信访问


2. 建立的数据块文件,右键属性,需要取消优化的块访问选项,使用绝对地址



软件交互使用
第一步:TIA Portal 新建项目,选择需要通讯的设备型号


第二步:添加数据块


第三步:添加数据类型之后,点击编辑,生成偏移量(Offset),后面获取单个数值时需要


第四步:开始仿真,点击之后会自动打开S7-PLCSIM,根据提示点击“装载”,点“完成”


第五步:在S7-PLCSIM上点击RUN,运行设备仿真环境


第六步:设置 NetToPLCsim
  6.1 点击 Add,添加连接到PLCSIM环境
  6.2 NetWork IP Address 手写填为本机(127.0.0.1)
  6.3 Plcsim Ip Address 点击后面两点,选择192.168.0.1 TCP/IP,必须要在仿真环境运行之后才能选择
  6.4 根据不同设备型号设置 Rack / Slot ,我是S7-1200,设置 0 / 1


第七步:开启服务,这里也很坑! 如果没有按顺序操作,也能Start Server,但是编码时连接不到。最开始不懂仿真设备,在这里研究了好久,Demo硬是连不上



ok ! 现在就可以开始进行编码了,这里重点介绍从[连接]到[读写]的集中方式和介绍

创建连接
以前的历史版本 plc.Open(); 会有一个返回值,可以通过返回值获取 ErrorCode 和 ErrorMessage
我使用了当前最新版(V0.4.0),没有返回值使用 try-catch

using (var plc = new Plc(CpuType.S71200, "127.0.0.1", 0, 1))    {                try                {                    plc.Open();                }                catch (Exception)                {                    Console.WriteLine($"连接到PLC设备失败:IsConnect={plc.IsConnected},IsAvailable={plc.IsAvailable}");                    return;                }    }读取单个数据项【Read】
代码中用到三种数据获取方式:DBX、DBW、DBD,深入理解的可以查一下网上资料
简单理解就是 DBX读取位,比如bool类型;DBW读取字;DBD读取数值
注释中是对应的 TIA Portal 数据块类型

#region 单个数据项读取                var db1Bool1 = plc.Read("DB1.DBX0.0");                Console.WriteLine("DB1.DBX0.0: " + db1Bool1);
                bool db1Bool2 = (bool)plc.Read("DB1.DBX0.1");                Console.WriteLine("DB1.DBX0.1: " + db1Bool2);
                // Int                int intVariable = (ushort)plc.Read("DB1.DBW2.0");                Console.WriteLine("DB1.DBW2.0: " + intVariable);                // Real                var realVariabl = ((uint)plc.Read("DB1.DBD4.0")).ConvertToFloat();                Console.WriteLine("DB1.DBD4.0: " + realVariabl);                // DInt                var dIntVariable = (uint)plc.Read("DB1.DBD8.0");                Console.WriteLine("DB1.DBD8.0: " + dIntVariable);                // DWord                var dWordVariable = (uint)plc.Read("DB1.DBD12.0");                Console.WriteLine("DB1.DBD12.0: " + dWordVariable);                // Word                var wordVariable = (ushort)plc.Read("DB1.DBW16.0");                Console.WriteLine("DB1.DBW16.0: " + wordVariable);                #endregion另一种方式,通过ReadBytes读取单个数据

// 读取int类型                    byte [] int0 = (byte[])plc.ReadBytes(DataType.DataBlock, 1, 2, 2);                    byte[] revint0 = int0.Reverse().ToArray();                    short f5 = BitConverter.ToInt16(revint0, 0);                     Console.WriteLine("DB1.DBD2: " + f5);

批量读取数据块【ReadBytes】
看注释

#region 批量数据项读取 / 读取整个DB                // DataType: 数据类型,DB或Memory等                // DB : DataBlock=1,Memory=0                // count : 偏移量(offset),设置多少就获取到具体位置的数据                // eg: 比如最后一个DBW是16,那么数据类型长度为2,count就需要传18才能获取到                var bytes = plc.ReadBytes(DataType.DataBlock, 1, 0, 18);                Console.WriteLine(bytes);
                var bool1 = bytes[0].SelectBit(0);                Console.WriteLine("DB1.DBX0.0: " + bool1);                var bool2 = bytes[0].SelectBit(1);                Console.WriteLine("DB1.DBX0.0: " + bool2);
                // Int                int intVariable = S7.Net.Types.Int.FromByteArray(bytes.Skip(2).Take(2).ToArray());                Console.WriteLine("DB1.DBD2.0: " + intVariable);                //  Real                Double realVariable = S7.Net.Types.Double.FromByteArray(bytes.Skip(4).Take(4).ToArray());                Console.WriteLine("DB1.DBD4.0: " + realVariable);
                // DWord                uint dWordVariable = S7.Net.Types.DWord.FromByteArray(bytes.Skip(12).Take(4).ToArray());                Console.WriteLine("DB1.DBD12.0: " + dWordVariable);                // Word                var wordVariable = S7.Net.Types.Word.FromByteArray(bytes.Skip(16).Take(2).ToArray());                Console.WriteLine("DB1.DBW16.0: " + wordVariable);                #endregion读取数据块到类对象【ReadClass】
创建一个Db1类,数据类型和变量名跟 TAI Portal 数据块里一一对应,这个很简单!
因为作者已经封装好了,底层实现也是上述原理

#region 读取数据块(DB)到实体类     var db1 = new Db1();     plc.ReadClass(db1, 1, 0);#endregion多个数据块同时读取 【ReadMultipleVars】
ReadMultipleVars()方法需要构造一个List作为参数,这里留作业

  #region 多个数据块(DB)同时读取
                plc.ReadMultipleVars();                #endregion

写入单个数据【Write】
看完上面的内容,就很容易理解这里

  #region 多个数据块(DB)同时读取
                plc.ReadMultipleVars();                #endregion
案例:


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 S7.Net;
namespace LinkPLC{    public partial class Form1 : Form    {        Plc S71200;//声明一个类型为PLC的内部变量        public Form1()        {            InitializeComponent();        }
        private void Form1_Load(object sender, EventArgs e)        {            comDT.Items.Add("Int");            comDT.Items.Add("DInt");            comDT.Items.Add("Real");            comDT.Text = "Real";        }        //连接        private void btnLink_Click(object sender, EventArgs e)        {            //创建连接对象            S71200 = new Plc(CpuType.S71200, txtAddress.Text, Convert.ToInt16(txtRack.Text), Convert.ToInt16(txtSlot.Text));
            S71200.Open();
        }        //断开        private void btnBreak_Click(object sender, EventArgs e)        {            S71200.Close();        }        //读数据        private void btnRead_Click(object sender, EventArgs e)        {            //浮点            if(comDT.Text=="Real")            {                double MyPlcData = ((uint)S71200.Read("DB" + txtDB.Text + "." + "DBD" + txtStart.Text)).ConvertToDouble();                MessageBox.Show(MyPlcData.ToString());            }              //整数            else if(comDT.Text == "Int")            {                short MyPlcData = ((ushort)S71200.Read("DB" + txtDB.Text + "." + "DBW" + txtStart.Text)).ConvertToShort();                MessageBox.Show(MyPlcData.ToString());            }             //双整数            else if(comDT.Text =="DInt")            {                int MyPlcData = ((uint)S71200.Read("DB" + txtDB.Text + "." + "DBD" + txtStart.Text)).ConvertToInt();                MessageBox.Show(MyPlcData.ToString());            }        }        //写PLC        private void btnWrite_Click(object sender, EventArgs e)        {            //浮点            if (comDT.Text == "Real")            {                double MyData = Convert.ToDouble(txtWrite.Text);                S71200.Write("DB" + txtDB.Text + "." + "DBD" + txtStart.Text,MyData.ConvertToUInt());
            }            //整数            else if (comDT.Text == "Int")            {                short MyData = Convert.ToInt16(txtWrite.Text);                S71200.Write("DB" + txtDB.Text + "." + "DBW" + txtStart.Text,MyData.ConvertToUshort());            }            //双整数            else if (comDT.Text == "DInt")            {                int myData = Convert.ToInt32(txtWrite.Text);                S71200.Write("DB" + txtDB.Text + "." + "DBD" + txtStart.Text,myData);            }         }    }}



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册哦

x
您需要登录后才可以回帖 登录 | 注册哦

本版积分规则