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的输出信号:
写入位(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
写入前:
写入后:
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
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个。
相关博客
评论
随笔分类
Powered by .NET 6.0 陕ICP备2020018176号-4