一、PLC部分
将电脑与PLC连接的网口IP设置到同一网段,192.168.1.X,已台达为例。
将关心的数据进行监视
AS系列装置通讯地址
二、C#上位机部分
在NuGet安装包中添加Nmodbus4库,并引用命名空间。
代码如下 :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Modbus;
namespace ReadAndwriteDelta
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Modbus.Device.ModbusIpMaster ipMaster;
TcpClient tcpClient;
bool isConnect;//连接状态
/// <summary>
/// 建立连接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Btn_Connect_Click(object sender, EventArgs e)
{
if (!isConnect)
{
try
{
tcpClient = new TcpClient();
tcpClient.Connect(IPAddress.Parse("192.168.1.5"), 502);
ipMaster = Modbus.Device.ModbusIpMaster.CreateIp(tcpClient);
isConnect = true;
this.btn_Connect.BackColor = Color.Green;
}
catch (Exception ex)
{
isConnect = false;
MessageBox.Show("连接失败:" + ex.ToString());
return;
}
}
else
{
MessageBox.Show("已建立连接");
}
}
/// <summary>
/// 断开连接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Btn_DisConnect_Click(object sender, EventArgs e)
{
if (isConnect)
{
try
{
tcpClient.Close();
ipMaster.Dispose();
isConnect = false;
this.btn_Connect.BackColor = DefaultBackColor;
}
catch (Exception ex)
{
isConnect = true;
MessageBox.Show("断开失败:" + ex.ToString());
return;
}
}
else
{
MessageBox.Show("已断开连接");
}
}
/// <summary>
///读数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Btn_Read_Click(object sender, EventArgs e)
{
if (isConnect)//判断tcp连接
{
switch (cbbox_ReadDevicetype.Text)
{
case "M":
try
{
//此位置固定读一个长度
bool[] res = ipMaster.ReadCoils(ushort.Parse(txtb_ReadAddress.Text), 1);
txtb_ReadPara.Text = res[0].ToString();
}
catch (Exception)
{
MessageBox.Show("M区数据读取失败");
return;
}
break;
case "D":
//数据初始化
try
{
//默认读2个长度,共32位
var res = ipMaster.ReadHoldingRegisters(ushort.Parse(txtb_ReadAddress.Text), 2);
// 读取数据个数个数不能太大,大于100个会报错
if (res.Length == 2)
{
float res1 = GetFloatFromUshortArray(new ushort[] { res[1], res[0] });
txtb_ReadPara.Text = Math.Round(res1, 2).ToString("0.0");
}
}
catch (Exception)
{
MessageBox.Show("D区数据读取失败");
}
break;
default:
break;
}
}
}
private float GetFloatFromUshortArray(ushort[] p)
{
List<byte> result = new List<byte>();
result.AddRange(BitConverter.GetBytes(p[0]));
result.AddRange(BitConverter.GetBytes(p[1]));
byte[] b = new byte[4];
b[0] = result[2];
b[1] = result[3];
b[2] = result[0];
b[3] = result[1];
//高位在后,低位在前
return BitConverter.ToSingle(b, 0);
}
/// <summary>
/// 写数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Btn_Write_Click(object sender, EventArgs e)
{
if(isConnect)//判断tcp连接
{
switch (cbbox_WriteDeviceType.Text)
{
case "M":
try
{
ipMaster.WriteSingleCoil(ushort.Parse(txtb_WriteAddress.Text), bool.Parse(txtb_WritePara.Text));
}
catch (Exception)
{
MessageBox.Show("M区写入失败");
return;
}
break;
case "D":
try
{
ipMaster.WriteMultipleRegisters(ushort.Parse(txtb_WriteAddress.Text), GetUshortArrayFromFloat(float.Parse(txtb_WritePara.Text)));
}
catch (Exception)
{
MessageBox.Show("D区写入失败");
return;
}
break;
default:
break;
}
}
}
private ushort[] GetUshortArrayFromFloat(float val)
{
var bytearray = BitConverter.GetBytes(val);
ushort[] res = new ushort[2];
res[1] = BitConverter.ToUInt16(new byte[] { bytearray[2], bytearray[3] }, 0);
res[0] = BitConverter.ToUInt16(new byte[] { bytearray[0], bytearray[1] }, 0);
return res;
}
}
}
读写M区
由于使用的Nmodbus4库中的方法,每一个方法对应一个modbus通讯功能码,填写地址时直接填写M区或D区地址即可。
读写D区
该实例为简单的读写plc数据实例,其余功能,可尽情发挥。