PLC内部数据的传统读写方式是利用触摸屏组态。PLC可以和HMI轻易建立起连接并传输数据。而S7netplus为我们提供了另一种连接思路,让我们可以利用C#读写PLC内部的数据。这样做的优点是显而易见的:可以做出比WinCC更漂亮更强大的界面;可以对数据更好地利用;可以以更高频率获取PLC数据而不是10Hz等等。

上图是我用S7netplus做的调试小工具。虽然只有简单的功能,却可以在现场调试时省的抱着笔记本等博途启动。顺便吐槽一下西门子,自己的软件互相之间都不兼容,安装麻烦得要死。就算运气好都安上了,稍微差点的电脑还带不动,一启动就等很久。不过谁让人家是业界巨头呢,难用也只能忍着。

回到正题。S7netplus使用起来非常简单,但是它的文档不太好。只有英文版倒是问题不大,主要是不全,只介绍了一部分内容,还和实际操作不太一样。也可能是我没找到最新版的文档吧。

安装与连接

前提

硬件方面只需要用网线把PLC与电脑相连,处于同一网段即可。本次测试使用的是西门子S7-1200 1215C DC/DC/DC以及西门子Tp700 Comfort面板。

与PLC通讯前首先要让PLC处于可访问状态。设置方法如下:

第一步:打开博途,在项目树找到PLC打开属性。将保护设置为完全访问权限,并将下面连接机制的选项打钩。

选第一个,下面打钩

第二步:在PLC下面依次打开每一个用到的DB块的属性。关闭“优化块的访问”这个选项。否则没有偏移量不能访问。点击确定后编译DB块即可。

去掉第三项的钩

更改完成之后需要在设备组态中编译并下载才能使设置生效。

在此页面编译下载

S7netplus目前最新的版本是0.4.0,需要Visual Studio 2015及以上版本。框架要求.Net Framework 4.5.2。支持使用Nuget安装:

PM> Install-Package S7netplus -Version 0.4.0

安装好之后不需要其他操作,添加:

using S7.Net;

之后就可以用了。

连接

S7netplus支持的CPU包括:LOGO!0BA8,S7-200,S7-300,S7-400,S7-1200,S7-1500。

plc连接的定义为:

public Plc(CpuType cpu, string ip, short rack, short slot);

四个参数分别是:CPU类型,CPU的IP地址,CPU的机架号(Rack)与插槽号(Slot)。

机架号与插槽号

连接与断开方式如下:

namespace s7netplus
{
    public partial class Form1 : Form
    {
        private Plc plc = null;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            toolStripStatusLabel2.Text = "就绪";
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (plc.IsConnected)
            {
                plc.Close();
            }
        }

        private void connbtn_Click(object sender, EventArgs e)
        {
            try
            {
                plc = new Plc(CpuType.S71200, "192.168.0.1", 0, 1);
                plc.Open();
                if (plc.IsConnected)
                {
                    toolStripStatusLabel2.Text = "已建立连接";
                }
                else
                {
                    toolStripStatusLabel2.Text = "连接失败";
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message);
            }
        }

        private void cutbtn_Click(object sender, EventArgs e)
        {
            if (plc.IsConnected)
            {
                plc.Close();
                toolStripStatusLabel2.Text = "连接已断开";
            }
        }
    }
}

文档中的Open();函数类型为ErrorCode,可以使用ErrorCode state = plc.Open();来获取连接的状态码。但在0.4.0版本实际使用中发现状态码仍然存在,但Open();函数声明为void。因为查不到更多资料,此处获取状态码的方式未知。

数据操作

数字读写

S7netplus提供了对五种数据的读写方法:Word,Int,DWord,DInt,Real。每一种类型需要不同的转换方式。具体方法如下:

private void readbtn_Click(object sender, EventArgs e)
{
	if (plc == null)
	{
		MessageBox.Show("尚未建立与PLC的连接");
	}
	else
	{
		if (plc != null)
		{
			switch (typebox.Text)
			{
				case "Word":
					ushort result1 = (ushort)plc.Read("DB1.DBW0");
					readtxt.Text = result1.ToString();
					break;
				case "Int":
					short result2 = ((ushort)plc.Read("DB1.DBW0")).ConvertToShort();
					readtxt.Text = result2.ToString();
					break;
				case "DWord":
					uint result3 = (uint)plc.Read("DB1.DBD0");
					readtxt.Text = result3.ToString();
					break;
				case "DInt":
					int result4 = ((uint)plc.Read("DB1.DBD0")).ConvertToInt();
					readtxt.Text = result4.ToString();
					break;
				case "Real":
					double result5 = ((uint)plc.Read("DB1.DBD0")).ConvertToFloat();
					readtxt.Text = result5.ToString();
					break;
				default:
					break;
			}
			toolStripStatusLabel2.Text = "读取成功";
		}
	}
}

private void writebtn_Click(object sender, EventArgs e)
{
	if (plc == null)
	{
		MessageBox.Show("尚未建立与PLC的连接");
	}
	else
	{
		if (plc != null)
		{
			switch (typebox.Text)
			{
				case "Word":
					ushort value1 = ushort.Parse(writetxt.Text);
					plc.Write("DB1.DBW0", value1);
					break;
				case "Int":
					short value2 = short.Parse(writetxt.Text);
					plc.Write("DB1.DBW0", value2);
					break;
				case "DWord":
					uint value3 = uint.Parse(writetxt.Text);
					plc.Write("DB1.DBD0", value3);
					break;
				case "DInt":
					int value4 = int.Parse(writetxt.Text);
					plc.Write("DB1.DBD0", value4);
					break;
				case "Real":
					double value5 = double.Parse(writetxt.Text);
					plc.Write("DB1.DBD0", value5);
					break;
				default:
					break;
			}
			toolStripStatusLabel2.Text = "数据已写入";
		}
	}
}

布尔读写

S7netplus并没有直接提供单个位的查询。但是提供了字节查询,并附带了直接从字节提取位的方法:

byte[] myByte = plc.ReadBytes(...);
byte myByte[0] = 5; // 0000 0101
myByte.SelectBit(0) // true
myByte.SelectBit(1) // false

读写的定义如下:

public byte[] ReadBytes(DataType dataType, int db, int startByteAdr, int count);
public void WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, bool value);

int db默认为0,startByteAdr为开始地址,bitAdr为位。

//读辅助继电器M(从MB0读一个字节)
byte[] result = plc.ReadBytes(DataType.Memory, 0, 0, 1);
//读输入I(IB0)
byte[] result = plc.ReadBytes(DataType.Input, 0, 0, 1);
//读输出Q(QB0)
byte[] result = plc.ReadBytes(DataType.Output, 0, 0, 1);
//写辅助继电器M(置位M0.1)
plc.WriteBit(DataType.Memory, 0, 0, 1, true);
//写辅助继电器M(复位M0.2)
plc.WriteBit(DataType.Memory, 0, 0, 2, false);

字符(串)读写

字符串读取比较麻烦,因为其长度是不定的,S7netplus好像也没提供一个便捷的读写方法。我自己瞎琢磨出了读写方法,不算复杂。

DB块存String类型时默认分配256个字节,使用时只占用一部分。以DB1偏移量0.0为例:

该数据的第一个字节DB1.DBB016#FE。第二个字节DB1.DBB1存储的byte型数据为字符串长度n。从DB1.DBB2开始的n个字节是字符串的内容。依次读取这n字节,获取的是十进制数据,转化为字符后连接成字符串即可。Char类型读取方法类似:

private string GetString(int db, int addr)
{
    string addr1 = "DB" + db.ToString() + ".DBB" + (addr + 1).ToString();
    int len = int.Parse(plc.Read(addr1).ToString());
    string getstring = "";
    for (int i = 0; i < len; i++)
    {
        string addr2 = "DB" + db.ToString() + ".DBB" + (addr + 2 + i).ToString();
        string result = plc.Read(addr2).ToString();
        int value = Convert.ToInt32(result, 10);
        string stringValue = Char.ConvertFromUtf32(value);
        getstring += stringValue;
    }
    return getstring;
}

Char写入就比较简单了,不需要转换,直接对地址写入string类型的单个字符即可。String需要先写入长度,再依次写入每一个字符。第一位的16#FE至今不知含义,但不影响读写。String的拆分和写入如下:

private void PutString(int db, int addr, string data)
{
    byte len = Convert.ToByte(data.Length);
    string addr1 = "DB" + db.ToString() + ".DBB" + (addr + 1).ToString();
    plc.Write(addr1, len);
    char[] single = data.ToCharArray();
    for (int i = 0; i < data.Length; i++)
    {
        string addr2 = "DB" + db.ToString() + ".DBB" + (addr + 2 + i).ToString();
        plc.Write(addr2, single[i].ToString());
    }
}

偷偷放一个自己做的调试小工具

下载 “西门子PLC简易调试工具v2.0.0” Siemens PLC S7netplus.msi – 16 MB

说点什么
在"利用S7netplus通讯西门子S7系列PLC"已有10条评论
Loading...