此测试工具用到了胡工科技的HslCommunication测试软件,GItHub:GitHub - dathlin/HslCommunication: A very popular industrial Internet of Things communication plug-in. Using this dll can be very convenient, stable, and fast to obtain data from PLC equipment of multiple brands, and also supports redis, mqtt, websocket, etc., which can let your data on the network Free transmission, reducing enterprise development costs.
此贴源代码已上传Gitee:(倍福、欧姆龙PLC测试工具)上位机和PLC通讯工具: 上位机和倍福PLC读写数据的测试工具 (gitee.com)
HslCommunication里有倍福PLC的虚拟服务器用于模拟与倍福PLC的通讯,如图:
以下是我查询官方文档查阅网络资料编写两种的读写数据的代码(第一种直接读写,第二种用到了特性),希望各大网友指点指点:
From1.cs
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 HslCommunication.Profinet.Beckhoff;
using HslCommunication;
using TwinCAT.Ads;
namespace 倍福PLC
{
public partial class Form1 : Form
{
private static BeckhoffAdsNet beckhoffAdsNet = new BeckhoffAdsNet();
private static OperateResult write;
private static plcAddress data;
private static OperateResult<plcAddress> readBool;
private static OperateResult<plcAddress> readFloat;
private static OperateResult<plcAddress> readDouble;
private static OperateResult<plcAddress> readByte;
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 连接倍福PLC
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnConnect_Click(object sender, EventArgs e)
{
try
{
//设置IP和Port
string Ip = ipTxt.Text;
int port = Convert.ToInt32(portTxt.Text);
beckhoffAdsNet = new BeckhoffAdsNet(Ip, port);
beckhoffAdsNet.SetTargetAMSNetId("192.168.182.131.1.1:801");
beckhoffAdsNet.SetSenderAMSNetId("192.168.235.128.1.1");
targetTxt.Text = "192.168.182.131.1.1:801";
senderTxt.Text = "192.168.235.128.1.1";
OperateResult connect = beckhoffAdsNet.ConnectServer();
if (connect.IsSuccess)//连接成功
{
MessageBox.Show("连接成功", "提示信息");
//(写死了,在plcAddress里配置的特性 [HslDeviceAddress("M100")] )
addressTxt1.Text = "M100";
addressTxt2.Text = "M100";
//打开按钮
readBoolBtn.Enabled = true;
readFloatBtn.Enabled = true;
readDoubleBtn.Enabled = true;
readByteBtn.Enabled = true;
writeBoolBtn.Enabled = true;
writeFloatBtn.Enabled = true;
writeDoubleBtn.Enabled = true;
writeByteBtn.Enabled = true;
}
else //连接失败
{
MessageBox.Show($"连接失败", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show($"连接失败,错误信息:{ex}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 窗口加载事件,打开窗体时会执行
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
//设置窗体名称
this.Text = "倍福PLC测试工具";
//设置为只读
targetTxt.ReadOnly = true;
senderTxt.ReadOnly = true;
//默认为本地地址 不用改,直接可以用
ipTxt.Text = "127.0.0.1";
portTxt.Text = "48898";
//连接PLC之前应该关闭的按钮
readBoolBtn.Enabled = false;
readFloatBtn.Enabled = false;
readDoubleBtn.Enabled = false;
readByteBtn.Enabled = false;
writeBoolBtn.Enabled = false;
writeFloatBtn.Enabled = false;
writeDoubleBtn.Enabled = false;
writeByteBtn.Enabled = false;
//加入addressList
addressTxt1.Items.Add("M100");
addressTxt2.Items.Add("M100");
addressTxt1.Items.Add("s=MAIN.bool1");
addressTxt2.Items.Add("s=MAIN.bool1");
addressTxt1.Items.Add("s=MAIN.dd");
addressTxt2.Items.Add("s=MAIN.dd");
addressTxt1.Items.Add("s=MAIN.double");
addressTxt2.Items.Add("s=MAIN.double");
addressTxt1.Items.Add("s=MAIN.byte");
addressTxt2.Items.Add("s=MAIN.byte");
//开启缓冲功能(据说可以实现缓存功能,加速标签的读写速度)
beckhoffAdsNet.UseTagCache = true;
}
/// <summary>
/// 读取Bool值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void readBoolBtn_Click(object sender, EventArgs e)
{
#region 方法1
OperateResult<bool> read = beckhoffAdsNet.ReadBool(addressTxt1.Text.Trim());
if (read.IsSuccess)
{
resultTxt.Text += read.Content + "\r\n";
resultTxt.SelectionStart = resultTxt.Text.Length; //在文本框中的选定文本的起始位置
resultTxt.ScrollToCaret(); //将控件内容滚动到当前插入符号位置
}
else
{
MessageBox.Show($"读取失败,错误原因:{read.Message}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
#endregion
#region 方法2
//readBool = beckhoffAdsNet.Read<plcAddress>();
//if (readBool.IsSuccess)
//{
// resultTxt.Text += readBool.Content.Bool + "\r\n";
// resultTxt.SelectionStart = resultTxt.Text.Length; //在文本框中的选定文本的起始位置
// resultTxt.ScrollToCaret(); //将控件内容滚动到当前插入符号位置
//}
//else
//{
// MessageBox.Show($"读取失败,错误原因:{readBool.Message}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
#endregion
}
/// <summary>
/// 读取Float值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void readFloatBtn_Click(object sender, EventArgs e)
{
#region 方法1
OperateResult<Single> read = beckhoffAdsNet.ReadFloat(addressTxt1.Text.Trim());
if (read.IsSuccess)
{
resultTxt.Text += read.Content + "\r\n";
resultTxt.SelectionStart = resultTxt.Text.Length; //在文本框中的选定文本的起始位置
resultTxt.ScrollToCaret(); //将控件内容滚动到当前插入符号位置
}
else
{
MessageBox.Show($"读取失败,错误原因:{read.Message}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
#endregion
#region 方法2
//readFloat = beckhoffAdsNet.Read<plcAddress>();
//if (readFloat.IsSuccess)
//{
// resultTxt.Text += readFloat.Content.Float + "\r\n";
// resultTxt.SelectionStart = resultTxt.Text.Length; //在文本框中的选定文本的起始位置
// resultTxt.ScrollToCaret(); //将控件内容滚动到当前插入符号位置
//}
//else
//{
// MessageBox.Show($"读取失败,错误原因:{readFloat.Message}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
#endregion
}
/// <summary>
/// 读取Double值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void readDoubleBtn_Click(object sender, EventArgs e)
{
#region 方法1
OperateResult<Double> read = beckhoffAdsNet.ReadDouble(addressTxt1.Text.Trim());
if (read.IsSuccess)
{
resultTxt.Text += read.Content + "\r\n";
resultTxt.SelectionStart = resultTxt.Text.Length; //在文本框中的选定文本的起始位置
resultTxt.ScrollToCaret(); //将控件内容滚动到当前插入符号位置
}
else
{
MessageBox.Show($"读取失败,错误原因:{read.Message}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
#endregion
#region 方法2
//readDouble = beckhoffAdsNet.Read<plcAddress>();
//if (readDouble.IsSuccess)
//{
// resultTxt.Text += readDouble.Content.Double + "\r\n";
// resultTxt.SelectionStart = resultTxt.Text.Length; //在文本框中的选定文本的起始位置
// resultTxt.ScrollToCaret(); //将控件内容滚动到当前插入符号位置
//}
//else
//{
// MessageBox.Show($"读取失败,错误原因:{readDouble.Message}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
#endregion
}
/// <summary>
/// 读取Byte值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void readByteBtn_Click(object sender, EventArgs e)
{
#region 方法1
OperateResult<byte> read = beckhoffAdsNet.ReadByte(addressTxt1.Text.Trim());
if (read.IsSuccess)
{
resultTxt.Text += read.Content + "\r\n";
resultTxt.SelectionStart = resultTxt.Text.Length; //在文本框中的选定文本的起始位置
resultTxt.ScrollToCaret(); //将控件内容滚动到当前插入符号位置
}
else
{
MessageBox.Show($"读取失败,错误原因:{readByte.Message}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
#endregion
#region 方法2
//readByte = beckhoffAdsNet.Read<plcAddress>();
//if (readByte.IsSuccess)
//{
// resultTxt.Text += readByte.Content.Byte + "\r\n";
// resultTxt.SelectionStart = resultTxt.Text.Length; //在文本框中的选定文本的起始位置
// resultTxt.ScrollToCaret(); //将控件内容滚动到当前插入符号位置
//}
//else
//{
// MessageBox.Show($"读取失败,错误原因:{readByte.Message}", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
#endregion
}
/// <summary>
/// 写入Bool值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void wirteBoolBtn_Click(object sender, EventArgs e)
{
try
{
#region 方法1
string str = writeTxt.Text;
switch (writeTxt.Text)
{
case "1":
str = "true"; break;
case "0":
str = "false"; break;
}
OperateResult writeBool = beckhoffAdsNet.Write(addressTxt2.Text, Convert.ToBoolean(str));
if (writeBool.IsSuccess)
{
MessageBox.Show("写入成功");
}
else
{
MessageBox.Show($"写入成功失败,错误信息:{writeBool.Message}");
}
#endregion
#region 方法2
//string str = writeTxt.Text;
//switch (writeTxt.Text)
//{
// case "1":
// str = "true"; break;
// case "0":
// str = "false"; break;
//}
//data = new plcAddress()
//{
// Bool = Convert.ToBoolean(str)
//};
//write = beckhoffAdsNet.Write(data);
//if (write.IsSuccess)
//{
// MessageBox.Show("写入成功");
//}
//else
//{
// MessageBox.Show($"写入成功失败:{write }");
//}
#endregion
}
catch (Exception ex)
{
MessageBox.Show($"写入失败,错误信息:{ex}");
}
}
/// <summary>
/// 写入Float值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void writeFloatBtn_Click(object sender, EventArgs e)
{
try
{
#region 方法1
OperateResult writeFloat = beckhoffAdsNet.Write(addressTxt2.Text, Convert.ToSingle(writeTxt.Text.Trim()));
if (writeFloat.IsSuccess)
{
MessageBox.Show("写入成功");
}
else
{
MessageBox.Show($"写入成功失败,错误信息:{writeFloat.Message}");
}
#endregion
#region 方法2
//data = new plcAddress()
//{
// Float = Convert.ToSingle(writeTxt.Text)
//};
//write = beckhoffAdsNet.Write(data);
//if (write.IsSuccess)
//{
// MessageBox.Show("写入成功");
//}
//else
//{
// MessageBox.Show($"写入成功失败:{write }");
//}
#endregion
}
catch (Exception ex)
{
MessageBox.Show($"写入失败,错误信息:{ex}");
}
}
/// <summary>
/// 写入Double值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void writeDoubleBtn_Click(object sender, EventArgs e)
{
try
{
#region 方法1
OperateResult writeDouble = beckhoffAdsNet.Write(addressTxt2.Text, Convert.ToDouble(writeTxt.Text.Trim()));
if (writeDouble.IsSuccess)
{
MessageBox.Show("写入成功");
}
else
{
MessageBox.Show($"写入成功失败,错误信息:{writeDouble.Message}");
}
#endregion
#region 方法2
//data = new plcAddress()
//{
// Double = Convert.ToDouble(writeTxt.Text)
//};
//write = beckhoffAdsNet.Write(data);
//if (write.IsSuccess)
//{
// MessageBox.Show("写入成功");
//}
//else
//{
// MessageBox.Show($"写入成功失败:{write }");
//}
#endregion
}
catch (Exception ex)
{
MessageBox.Show($"写入失败,错误信息:{ex}");
}
}
/// <summary>
/// 写入Byte值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void writeByteBtn_Click(object sender, EventArgs e)
{
try
{
#region 方法2
OperateResult writeByte = beckhoffAdsNet.Write(addressTxt2.Text, Convert.ToByte(writeTxt.Text.Trim()));
if (writeByte.IsSuccess)
{
MessageBox.Show("写入成功");
}
else
{
MessageBox.Show($"写入成功失败,错误信息:{writeByte.Message}");
}
#endregion
#region 方法2
//data = new plcAddress()
//{
// Byte = Convert.ToByte(writeTxt.Text)
//};
//write = beckhoffAdsNet.Write(data);
//if (write.IsSuccess)
//{
// MessageBox.Show("写入成功");
//}
//else
//{
// MessageBox.Show($"写入成功失败:{write }");
//}
#endregion
}
catch (Exception ex)
{
MessageBox.Show($"写入失败,错误信息:{ex}");
}
}
}
}
plcAddress.cs
using HslCommunication.Reflection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 倍福PLC
{
class plcAddress
{
/// <summary>
/// 设备是否启动
/// </summary>
[HslDeviceAddress("M100")]
public double Double { get; set; }
/// <summary>
/// 产量信息
/// </summary>
[HslDeviceAddress("M100")]
public bool Bool { get; set; }
/// <summary>
/// 温度信息
/// </summary>
[HslDeviceAddress("M100")]
public float Float { get; set; }
/// <summary>
/// 连续的位报警信息
/// </summary>
[HslDeviceAddress("M100")]
public byte Byte { get; set; }
}
}