first commit
This commit is contained in:
29
DH.XinJEPLC/DH.Devices.PLC.csproj
Normal file
29
DH.XinJEPLC/DH.Devices.PLC.csproj
Normal file
@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<BaseOutputPath>..\</BaseOutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>output</AppendTargetFrameworkToOutputPath>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DH.Commons\DH.Commons.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="HslCommunication">
|
||||
<HintPath>..\libs\HslCommunication.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
81
DH.XinJEPLC/PLCBase.cs
Normal file
81
DH.XinJEPLC/PLCBase.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using System.IO.Ports;
|
||||
using DH.Commons.Enums;
|
||||
using HslCommunication;
|
||||
|
||||
namespace DH.Devices.PLC
|
||||
{
|
||||
public class PLCBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接状态
|
||||
/// </summary>
|
||||
public bool connected = false;
|
||||
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
public EnumPLCType PLCType=EnumPLCType.信捷XD_网口;
|
||||
|
||||
/// <summary>
|
||||
/// 串口号
|
||||
/// </summary>
|
||||
public string portName="COM1";
|
||||
|
||||
/// <summary>
|
||||
/// 波特率
|
||||
/// </summary>
|
||||
public int baudRate = 9600;
|
||||
|
||||
/// <summary>
|
||||
/// 数据位
|
||||
/// </summary>
|
||||
public int dataBit = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 停止位
|
||||
/// </summary>
|
||||
public StopBits stopBit = (StopBits)Enum.Parse(typeof(StopBits), "One");
|
||||
|
||||
/// <summary>
|
||||
/// 奇偶效验位
|
||||
/// </summary>
|
||||
public Parity parity = (Parity)Enum.Parse(typeof(Parity), "None");
|
||||
|
||||
/// <summary>
|
||||
/// IP地址
|
||||
/// </summary>
|
||||
public string IP = "192.168.6.6";
|
||||
|
||||
/// <summary>
|
||||
/// 端口号
|
||||
/// </summary>
|
||||
public int Port = 502;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool PLCConnect() { return false; }
|
||||
|
||||
public virtual bool PLCDisConnect() { return false; }
|
||||
|
||||
public virtual ushort ReadShort(string address) { return 0; }
|
||||
|
||||
public virtual int ReadInt(string address) { return 0; }
|
||||
|
||||
|
||||
public virtual float ReadFloat(string address) { return 0; }
|
||||
|
||||
public virtual bool ReadBool(string address) { return false; }
|
||||
|
||||
public virtual bool WriteShort(string address, short value, bool waitForReply = true) { return false; }
|
||||
|
||||
public virtual bool WriteInt(string address, int value, bool waitForReply = true) { return false; }
|
||||
|
||||
public virtual bool WriteDInt(string address, int value, bool waitForReply = true) { return false; }
|
||||
|
||||
public virtual bool WriteFloat(string address, float value, bool waitForReply = true) { return false; }
|
||||
|
||||
public virtual bool WriteBool(string address, bool value, bool waitForReply = true) { return false; }
|
||||
}
|
||||
}
|
540
DH.XinJEPLC/XinJEPLCTcpNet.cs
Normal file
540
DH.XinJEPLC/XinJEPLCTcpNet.cs
Normal file
@ -0,0 +1,540 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using DH.Commons.Enums;
|
||||
using HslCommunication;
|
||||
using HslCommunication.Enthernet;
|
||||
using HslCommunication.Profinet.XINJE;
|
||||
|
||||
namespace DH.Devices.PLC
|
||||
{
|
||||
public class XinJEPLCTcpNet : PLCBase
|
||||
{
|
||||
private static XinJEPLCTcpNet _instance;
|
||||
public static XinJEPLCTcpNet Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new XinJEPLCTcpNet();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private XinJETcpNet TcpNet = new XinJETcpNet();
|
||||
|
||||
public override bool PLCConnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
TcpNet.IpAddress = IP;
|
||||
TcpNet.Port = Port;
|
||||
TcpNet.ConnectTimeOut = 5000;
|
||||
TcpNet.ReceiveTimeOut = 10000;
|
||||
TcpNet.SleepTime = 0;
|
||||
TcpNet.AddressStartWithZero = true;
|
||||
TcpNet.IsStringReverse = false;
|
||||
TcpNet.DataFormat = HslCommunication.Core.DataFormat.ABCD;
|
||||
TcpNet.Station = 1;
|
||||
TcpNet.Series = XinJESeries.XD;
|
||||
OperateResult ret = TcpNet.ConnectServer();
|
||||
if (ret.IsSuccess)
|
||||
{
|
||||
connected = true;
|
||||
MonitorPieces();
|
||||
TurntableOpen(18000,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override ushort ReadShort(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取Int变量
|
||||
var result = TcpNet.ReadInt16(address);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
return (ushort)result.Content;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override int ReadInt(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取Int变量
|
||||
var result = TcpNet.ReadInt32(address);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
return result.Content;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override float ReadFloat(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取Float变量
|
||||
var result = TcpNet.ReadFloat(address);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
return result.Content;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ReadBool(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取Bool变量
|
||||
var result = TcpNet.ReadBool(address);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
return result.Content;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // 或者可以考虑返回其他的错误标识符
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false; // 或者返回其他的错误标识符
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 写单独地址 short 值
|
||||
/// </summary>
|
||||
/// <param name="address">地址</param>
|
||||
/// <param name="writeValue">要写入的 int 值</param>
|
||||
/// <param name="waitForReply">是否等待回复</param>
|
||||
public override bool WriteShort(string address, short writeValue, bool waitForReply = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(address))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int repeatTime = 3;
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start(); // 启动计时
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = TcpNet.Write(address, (short)writeValue);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
sw.Stop();
|
||||
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{Name} {address},写入 {writeValue} 完成,耗时:{sw.ElapsedMilliseconds} ms");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
repeatTime--;
|
||||
if (repeatTime <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (repeatTime > 0);
|
||||
|
||||
sw.Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 写单独地址 int 值
|
||||
/// </summary>
|
||||
/// <param name="address">地址</param>
|
||||
/// <param name="writeValue">要写入的 int 值</param>
|
||||
/// <param name="waitForReply">是否等待回复</param>
|
||||
public override bool WriteInt(string address, int writeValue, bool waitForReply = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(address))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int repeatTime = 3;
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start(); // 启动计时
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = TcpNet.Write(address, writeValue);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
sw.Stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
repeatTime--;
|
||||
if (repeatTime <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (repeatTime > 0);
|
||||
|
||||
sw.Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 写单独地址 Dint 值
|
||||
/// </summary>
|
||||
/// <param name="address">地址</param>
|
||||
/// <param name="writeValue">要写入的 Dint 值</param>
|
||||
/// <param name="waitForReply">是否等待回复</param>
|
||||
public override bool WriteDInt(string address, int writeValue, bool waitForReply = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(address))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int repeatTime = 3;
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start(); // 启动计时
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
string result = Regex.Replace(address, @"\D", "");
|
||||
int r = Convert.ToInt32(result) + 1;
|
||||
string address1 = "HD" + r.ToString();
|
||||
short high = (short)(writeValue >> 16); // 高 16 位
|
||||
short low = (short)(writeValue & 0xFFFF); // 低 16 位
|
||||
TcpNet.Write(address1, high);
|
||||
Thread.Sleep(10);
|
||||
var res = TcpNet.Write(address, low);
|
||||
if (res.IsSuccess)
|
||||
{
|
||||
sw.Stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
repeatTime--;
|
||||
if (repeatTime <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (repeatTime > 0);
|
||||
|
||||
sw.Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 写单独地址 float 值
|
||||
/// </summary>
|
||||
/// <param name="address">地址</param>
|
||||
/// <param name="writeValue">要写入的 float 值</param>
|
||||
/// <param name="waitForReply">是否等待回复</param>
|
||||
public override bool WriteFloat(string address, float writeValue, bool waitForReply = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(address))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int repeatTime = 3;
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start(); // 启动计时
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = TcpNet.Write(address, writeValue);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
sw.Stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
repeatTime--;
|
||||
if (repeatTime <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (repeatTime > 0);
|
||||
|
||||
sw.Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写单独地址 bool 值
|
||||
/// </summary>
|
||||
/// <param name="address">地址</param>
|
||||
/// <param name="writeValue">要写入的 bool 值</param>
|
||||
/// <param name="waitForReply">是否等待回复</param>
|
||||
public override bool WriteBool(string address, bool writeValue, bool waitForReply = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(address))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int repeatTime = 3;
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start(); // 启动计时
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = TcpNet.Write(address, writeValue);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
sw.Stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
repeatTime--;
|
||||
if (repeatTime <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (repeatTime > 0);
|
||||
|
||||
sw.Stop();
|
||||
Thread.Sleep(10);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public override bool PLCDisConnect()
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
TurntableStop();
|
||||
var res = TcpNet.ConnectClose();
|
||||
if (res.IsSuccess)
|
||||
{
|
||||
connected = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void MonitorPieces()
|
||||
{
|
||||
|
||||
ThreadStart ts = new ThreadStart(MonitorPiecesImpl);
|
||||
Thread th = new Thread(ts);
|
||||
th.Priority = ThreadPriority.AboveNormal;
|
||||
th.IsBackground = false;
|
||||
th.Start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
|
||||
private Dictionary<ushort, uint> piecesCountDic = new Dictionary<ushort, uint>();
|
||||
private uint piecesCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// int,int 轴号 捕获位置
|
||||
/// </summary>
|
||||
public event Action<int, uint> OnNewPieces;
|
||||
|
||||
public void NewPieces(int axisIndex, uint pieceNumber)
|
||||
{
|
||||
_taskFactory.StartNew(() =>
|
||||
{
|
||||
Thread.CurrentThread.Priority = ThreadPriority.Highest;
|
||||
|
||||
OnNewPieces?.Invoke(axisIndex, pieceNumber);
|
||||
});
|
||||
}
|
||||
/// <summary>
|
||||
/// 入料监听
|
||||
/// </summary>
|
||||
/// <param name="axisIndex"></param>
|
||||
private void MonitorPiecesImpl()
|
||||
{
|
||||
|
||||
DateTime startTime = DateTime.Now;
|
||||
DateTime endTime = startTime;
|
||||
TimeSpan timeSpan = endTime - startTime;
|
||||
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
|
||||
//while (CurrentState != DeviceState.DSClose && CurrentState != DeviceState.DSExcept && CurrentState != DeviceState.DSUninit)
|
||||
while (connected)
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
uint tmpPieceNumber = 0;
|
||||
sw.Start();
|
||||
|
||||
var ret = TcpNet.ReadUInt16("D1016");
|
||||
|
||||
sw.Stop();
|
||||
if (ret.IsSuccess)
|
||||
{
|
||||
tmpPieceNumber = ret.Content;
|
||||
}
|
||||
|
||||
if (ret.IsSuccess && ret.Content > piecesCount)
|
||||
{
|
||||
sw.Start();
|
||||
// Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} 板卡{station}产品入列触发{tmpPieceNumber}");
|
||||
//LogAsync(DateTime.Now, LogLevel.Information, $"转盘{0}产品入列 {piecesCountDic[0]} size:{sum}");
|
||||
if (tmpPieceNumber != piecesCount + 1)
|
||||
{
|
||||
//LogAsync(DateTime.Now, LogLevel.Information, $"入列触发丢失\t{tmpPieceNumber}");
|
||||
// Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t板卡{station}产品入列触发丢失,{piecesCountDic[station]}\t{tmpPieceNumber}");
|
||||
|
||||
}
|
||||
piecesCount = tmpPieceNumber;
|
||||
//NewPieces(ai, piecesCountDic[station]);
|
||||
NewPieces(1, piecesCount);
|
||||
sw.Stop();
|
||||
startTime = DateTime.Now;
|
||||
//if (idalarm)
|
||||
//{
|
||||
// idalarm = false;
|
||||
// AlarmVibration(false);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 转盘开启操作
|
||||
/// </summary>
|
||||
public void TurntableOpen(int speed, bool Direction)
|
||||
{
|
||||
WriteBool("M122", true);
|
||||
Thread.Sleep(10);
|
||||
WriteBool("M10", false);
|
||||
Thread.Sleep(10);
|
||||
//速度
|
||||
TcpNet.Write("HD10", (ushort)speed);
|
||||
Thread.Sleep(10);
|
||||
//方向
|
||||
WriteBool("M1", Direction);
|
||||
Thread.Sleep(10);
|
||||
//使能
|
||||
WriteBool("M2", true);
|
||||
Thread.Sleep(10);
|
||||
//启动
|
||||
WriteBool("M0", true);
|
||||
Thread.Sleep(10);
|
||||
// _mainMotion.CurrentState = DeviceState.DSOpen;
|
||||
piecesCount = 0;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 转盘停止操作
|
||||
/// </summary>
|
||||
public void TurntableStop()
|
||||
{
|
||||
WriteBool("M122", true);
|
||||
Thread.Sleep(50);
|
||||
WriteBool("M0", false);
|
||||
Thread.Sleep(50);
|
||||
WriteBool("M2", false);
|
||||
Thread.Sleep(50);
|
||||
WriteBool("M50", false);
|
||||
piecesCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计数清零
|
||||
/// </summary>
|
||||
public void CountToZero()
|
||||
{
|
||||
WriteBool("M120", true);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user