您现在的位置是:首页 > C# > C#使用S7.Net读写PLC全套完整教程

C#使用S7.Net读写PLC全套完整教程

王递杰 2023年12月6日 C#

https://github.com/S7NetPlus/s7netplus

这里以PLC1500举例

1.连接plc

Plc S7 = new Plc(CpuType.S71500,"192.168.101.99", 0, 0);
S7.Open();

完整代码:

public static Plc S7;
//plc连接
public static int plcS7NetConn(string plcIp, short rack, short slot)
{
	try
	{
		S7 = new Plc(CpuType.S71500, plcIp, rack, slot);
		ErrorCode errorCode = S7.Open();
		if (errorCode != ErrorCode.NoError)
		{
			LogHelper.AddLog("连接失败:" + S7.LastErrorString + ",时间:" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
		}
		return S7.IsConnected ? 0 : -1;
	}
	catch (Exception ex)
	{
		MessageBox.Show("连接异常:"+ex.Message);
		return -1;
	}
}

断开连接:

if (S7 != null && S7.IsConnected)
{
	S7.Close();
	LogHelper.AddLog("断开连接,时间:" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
	return 0;
}

2.读写数据(单个数据)

读取DB块数据(DB200为例),其中txtDB.Text为DB块,txtStart.Text为起始位:

//浮点
if (comDataType.Text == "Real")
{
	string variable = $"DB{txtDB.Text}.DBD{txtStart.Text}"; // DB200.DBD2
	double myPlcData = ((uint)mdlWinTcpS7Net.S7.Read(variable)).ConvertToDouble();
	txtReturn.Text = myPlcData.ToString();
}
//整数
else if (comDataType.Text == "Int")
{
	string variable = $"DB{txtDB.Text}.DBW{txtStart.Text}"; // DB200.DBW2
	short myPlcData = ((ushort)mdlWinTcpS7Net.S7.Read(variable)).ConvertToShort();
	txtReturn.Text = myPlcData.ToString();
}
//双整数
else if (comDataType.Text == "DInt")
{
	string variable = $"DB{txtDB.Text}.DBD{txtStart.Text}"; // DB200.DBD2
	int myPlcData = ((uint)mdlWinTcpS7Net.S7.Read(variable)).ConvertToInt();
	txtReturn.Text = myPlcData.ToString();
}

另一种方式读取DB块:

VarType varType = (VarType)Enum.Parse(typeof(VarType), comDataType.Text);
object obj = S7.Read(DataType.DataBlock, int.Parse(txtDB.Text), txtStart.Text, varType, 1);

写入DB块数据,其中txtDB.Text为DB块,txtStart.Text为起始位,txtWrite.Text为写入的值:

//浮点
if (comDataType.Text == "Real")
{
	double MyData = Convert.ToDouble(txtWrite.Text);
	string variable = $"DB{txtDB.Text}.DBD{txtStart.Text}";
	ErrorCode result = mdlWinTcpS7Net.S7.Write(variable, MyData.ConvertToUInt());
	txtReturn.Text = result.ToString(); //写入结果
}
//整数
else if (comDataType.Text == "Int")
{
	short MyData = Convert.ToInt16(txtWrite.Text);
	string variable = $"DB{txtDB.Text}.DBW{txtStart.Text}";
	ErrorCode result = mdlWinTcpS7Net.S7.Write(variable, MyData.ConvertToUshort());
	txtReturn.Text = result.ToString();
}
//双整数
else if (comDataType.Text == "DInt")
{
	int myData = Convert.ToInt32(txtWrite.Text);
	string variable = $"DB{txtDB.Text}.DBD{txtStart.Text}";
	ErrorCode result = mdlWinTcpS7Net.S7.Write(variable, myData);
	txtReturn.Text = result.ToString();
}

另一种方式写入DB块:

ErrorCode result = S7.Write(DataType.DataBlock, int.Parse(txtDB.Text), int.Parse(txtStart.Text), txtWrite.Text);


读取位(I、Q、M),其中txtAAStart.Text为起始位,txtAAbIt.Text为偏移量:

//读取某个位
private void btnReadSingleBit_Click(object sender, EventArgs e)
{
	if (mdlWinTcpS7Net.S7 == null || !mdlWinTcpS7Net.S7.IsConnected)
	{
		MessageBox.Show("plc未连接!");
		return;
	}
	DataType dataType = DataType.DataBlock;
	if (cbbAAType.Text == "I") dataType = DataType.Input;
	else if (cbbAAType.Text == "Q") dataType = DataType.Output;
	else if (cbbAAType.Text == "M") dataType = DataType.Memory;

	byte[] rbArr = mdlWinTcpS7Net.S7.ReadBytes(dataType, 0, int.Parse(txtAAStart.Text), 1);

	for (int i = 0; i < rbArr.Length; i++)
	{
		string temP1 = Convert.ToString(rbArr[i], 2);
		string temP2 = temP1.PadLeft(8, '0');
		//如果bit位空,则显示所有的位(逆向)
		if (txtAAbIt.Text == "")
		{
			txtAAResult.Text = temP2;
			break;
		}
		int b2 = int.Parse(txtAAbIt.Text);
		for (int j = 0; j <= 7; j++)
		{
			if (b2 == j)
			{
				if (cbbAAType.Text == "I")
				{
					txtAAResult.Text = Convert.ToInt16(temP2.Substring(7 - j, 1)).ToString();
				}
				else if (cbbAAType.Text == "Q")
				{
					txtAAResult.Text = Convert.ToInt16(temP2.Substring(7 - j, 1)).ToString();
				}
				else if (cbbAAType.Text == "M")
				{
					txtAAResult.Text = Convert.ToInt16(temP2.Substring(7 - j, 1)).ToString();
				}
			}
		}
	}
}

比如我想读取起始为89,偏移量为2的输出信号:

null

null

写入位(I、Q、M),其中cbbIQMValue.Text为写入的值是true还是false

//写入I/Q/M
private void btnWriteIQM_Click(object sender, EventArgs e)
{
	if (mdlWinTcpS7Net.S7 == null || !mdlWinTcpS7Net.S7.IsConnected)
	{
		MessageBox.Show("plc未连接!");
		return;
	}
	DataType dataType = DataType.DataBlock;
	if (cbbAAType.Text == "I") dataType = DataType.Input;
	else if (cbbAAType.Text == "Q") dataType = DataType.Output;
	else if (cbbAAType.Text == "M") dataType = DataType.Memory;

	byte b2 = (byte)mdlWinTcpS7Net.S7.Read(dataType, 0, int.Parse(txtAAStart.Text), VarType.Byte, 1);

	//最终写入值
	b2 = Convert.ToBoolean(cbbIQMValue.Text) ? ((byte)(b2 | (byte)Math.Pow(2.0, short.Parse(txtAAbIt.Text)))) : ((byte)(b2 & (b2 ^ (byte)Math.Pow(2.0, short.Parse(txtAAbIt.Text)))));

	ErrorCode result = mdlWinTcpS7Net.S7.Write(dataType, 0, int.Parse(txtAAStart.Text), b2);

	if (result == ErrorCode.NoError)
		MessageBox.Show(result.ToString() + "--写入成功!");
	else
		MessageBox.Show(result.ToString());
}

比如我想把M信号起始位为1205的偏移量2的信号写为TRUE

写入前:

null

写入后:

null

3.批量读取数据:

private void btnMulRead_Click(object sender, EventArgs e)
{
	if (mdlWinTcpS7Net.S7 == null || !mdlWinTcpS7Net.S7.IsConnected)
	{
		MessageBox.Show("plc未连接!");
		return;
	}
	if (txtMulCount.Text == "" || int.Parse(txtMulCount.Text) <= 0)
	{
		MessageBox.Show("读取数量必须大于0");
		return;
	}

	lbResult.Items.Clear();
	DataType dataType = DataType.DataBlock;
	if (cbbMulDataType.Text == "I") dataType = DataType.Input;
	else if (cbbMulDataType.Text == "Q") dataType = DataType.Output;
	else if (cbbMulDataType.Text == "M") dataType = DataType.Memory;
	else if (cbbMulDataType.Text == "DB") dataType = DataType.DataBlock;

	VarType varType = (VarType)Enum.Parse(typeof(VarType), cbbMulVarType.Text);

	int start = int.Parse(txtMulStart.Text);

	var res = mdlWinTcpS7Net.S7.Read(dataType, int.Parse(txtMulDB.Text), start, varType, int.Parse(txtMulCount.Text));
	List<string> list = new List<string>();
	if (varType == VarType.String)//字符串类型
	{
		string str = Convert.ToString(res);
		list.Add(str);
	}
	else
	{
		foreach (var item in res as Array)//item为十进制
		{
			if (dataType == DataType.DataBlock)
				list.Add(Convert.ToString(item));
			else
			{
				string temP1 = Convert.ToString((byte)item, 2);
				string temP2 = temP1.PadLeft(8, '0');
				list.Add(cbbMulDataType.Text + (start++) + "--" + temP2);
			}
		}
	}
	//界面展示
	lbResult.Items.AddRange(list.ToArray());
}

4.使用结构读写DB数据:

使用结构读取数据要先在DB块中定义好要读取的变量,然后在C#中添加一个与Db块中类似的结构,注意一定要是struct

null


public struct TestStruct
{
	public Int32 MM_LL;
	public Int32 JM_LL;
	public Int32 F0_LL;
	public Int32 F1_LL;
	public Int32 F2_LL;
	public Int32 F3_LL;
	public Int32 F4_LL;
	public Int32 CF_LL;
	public Int32 Fp_LL;
	public Int32 Xp_LL;
	public Int32 ZZ_LL;
}
//读取结构
TestStruct res = (TestStruct)mdlWinTcpS7Net.S7.ReadStruct(typeof(TestStruct), 400);

如果不想读取全部的结构数据,可以只定义想要的数据属性,然后在ReadStruct方法中传递startByteAdr参数

res.F0_LL = 51;
res.F2_LL = 60;

//写入结构
mdlWinTcpS7Net.S7.WriteStruct(res, 400);

读写类与结构一样,这里不再详述,读者可自行研究。

5.结语

这里基本上是完整的C#使用S7.Net开发PLC的基本功能,其中各功能点文档上都有,如果仔细研究定能融会贯通,根据自己的业务开发对应的功能。

温馨提示:S7.Net批量读取字节最多可读200个字节,超出200可使用循环读取。也就是说,如果读取信号位,每次可读取200个,如果读取DB,DBW一次最多可读取100个,DBD/DBR一次最多可读取50个,DBB一次最多可读取200个。


评论

暂无评论