基恩士PLC KV7000,8000还是比较好用的,那如何和上位机通讯,我把源码写出来了。采用上位链路通讯,基恩士官方给我们留了8501端口,这个端口有意思刚好是我生日。基恩士的资料我觉得做的特别好,能快速写源代码得益于官方资料特别详细,对了,他的通讯采用是ASCII码直接通讯。比如你读到的ASCII码是666,那他的实际值也就是666。好了上代码,如果热度比较高,大家有不清楚的地方,我出视频讲解。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Net.Sockets;using System.Threading;using System.Net;namespace WDBaseCommuntionHelper{ public class KV7_8000Service { Socket KVTCPClicent; readonly object LockKVTCP = new object(); public enum DataType { /// /// 16位无符号 /// U, /// /// 16位有符号 /// S, /// /// 32位无符号 /// D, /// /// 32位有符号 /// L, /// /// 16位16进制数 /// H, /// /// 默认 /// N } #region 命令 /// /// 更改模式 /// const string Command1 = "M"; /// /// 清除错误 /// const string Command2 = "ER"; /// /// 检查错误编号 /// const string Command3 = "?E"; /// /// 查询机型 /// const string Command4 = "?K"; /// /// 检查运行模式 /// const string Command5 = "?M"; /// /// 时间设定 /// const string Command6 = "WRT"; /// /// 强制置位 /// const string Command7 = "ST"; /// /// 强制复位 /// const string Command8 = "RS"; /// /// 连续强制置位 /// const string Command9 = "STS"; /// /// 连续强制复位 /// const string Command10 = "RSS"; /// /// 读取数据 /// const string Command11 = "RD"; /// /// 读取连续数据 /// const string Command12 = "RDS"; /// /// 读取连续数据 /// const string Command13 = "RDE"; /// /// 写入数据 /// const string Command14 = "WR"; /// /// 写入连续数据 /// const string Command15 = "WRS"; /// /// 写入连续数据 /// const string Command16 = "WRE"; /// /// 写入设定值 /// const string Command17 = "WS"; /// /// 写入连续设定值 /// const string Command18 = "WSS"; /// /// 监控器登录 /// const string Command19 = "MBS"; /// /// 监控器登录 /// const string Command20 = "MWS"; /// /// 读取监控器 /// const string Command21 = "MBR"; /// /// 读取监控器 /// const string Command22 = "MWR"; /// /// 注释读取 /// const string Command23 = "RDC"; /// /// 存储体切换 /// const string Command24 = "BE"; /// /// 读取扩展单元缓冲存储器 /// const string Command25 = "URD"; /// /// 写入扩展单元缓冲存储器 /// const string Command26 = "UWR"; /// /// 回车 /// const string CR = ""; /// /// 空格 /// const string SP = " "; #endregion Encoding encoding = Encoding.ASCII; /// /// PLC连接状态 /// public bool IsConnected { get; private set; } /// /// 发送超时时间 /// public int SendTimeout { get; set; } = 2000; /// /// 接收超时时间 /// public int ReceiveTimeout { get; set; } = 2000; /// /// 等待PLC响应周期,这里一个周期10ms /// public int MaxDelayCycle { get; set; } = 5; string ip; int port; private Dictionary plcValue = new Dictionary(); /// /// PLC值键值对 /// public Dictionary PlcValue { get { return plcValue; } } /// /// 重连 /// /// public bool ReConnext() { if (ip == string.Empty || port == 0) { throw new Exception("没有IP和端口请调用Connect函数连接"); return false; } return Connect(ip,port); } /// /// 连接PLC /// /// /// /// public bool Connect(string ip, int port=8501) { if (this.ip != ip) this.ip = ip; if (this.port != port) this.port = port; KVTCPClicent = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); KVTCPClicent.SendTimeout = SendTimeout; KVTCPClicent.ReceiveTimeout = ReceiveTimeout; IAsyncResult asyncResult= KVTCPClicent.BeginConnect(new IPEndPoint(IPAddress.Parse(ip) ,port),null,null); asyncResult.AsyncWaitHandle.WaitOne(3000,true); if (!asyncResult.IsCompleted) { KVTCPClicent.Close(); return false; } return true; } /// /// 改变PLC运行状态 /// /// true让PLC运行false让PLC停止 /// public string ChangeCPU(bool run = true) { string str = Command1 + (run ? "1" : "0") + CR; return SendRecive(str); } /// /// 查看PLC运行状态 /// /// public string SeeCPUState() { string str = Command5 + CR; return SendRecive(str); } /// /// 强制置位复位 /// /// /// /// public string Put(string address, bool value) { string str; if (value) { str = Command7 + SP + address + CR; } else { str = Command8 + SP + address + CR; } return SendRecive(str); } /// /// 连续强制置位复位 /// /// /// /// /// public string Put(string address, bool Value, int count) { string str; if (Value) { str = Command9 + SP + address + count + CR; } else { str = Command10 + SP + address + count + CR; } return SendRecive(str); } /// /// 写入字数据 /// /// /// /// /// public string Put(string address, string value, DataType tpye = DataType.N) { string str = Command14 + SP + address + GetDataType(tpye) + SP + value + CR; return SendRecive(str); } /// /// 写入单精度浮点数 /// /// /// /// public string Put(string address, float value) { List result = CalFloatToInt16(value); return Put(address, result); } /// /// 写入连续字数据 /// /// /// /// /// public string Put(string address, List value, DataType tpye = DataType.N) { StringBuilder sb = new StringBuilder(Command15 + SP + address + GetDataType(tpye) + SP + value.Count); for (int i = 0; i < value.Count; i++) { sb.Append(SP + value[i]); } sb.Append(CR); return SendRecive(sb.ToString()); } /// /// 读取字数据 /// /// /// /// public string Get(string address, DataType tpye = DataType.N) { string str = Command11 + SP + address + GetDataType(tpye) + CR; return SendRecive(str); } /// /// 读取连续字数据 /// /// /// /// /// public string Get(string address, int count, DataType tpye = DataType.N) { string str = Command13 + SP + address + GetDataType(tpye) + SP + count + CR; return SendRecive(str); } public string CalRD(string str, string type, int address, int count) { string[] s1 = str.Split(' '); if (count > s1.Length) { throw new Exception("映射长度过长"); } for (int i = 0; i < count; i++) { plcValue[type + (address + i)] = s1[i].ToString(); } return "OK"; } /// /// 32位浮点转16位字 /// /// /// public List CalFloatToInt16(float value) { byte[] r1 = BitConverter.GetBytes(value); byte[] r2 = new byte[2] { r1[0], r1[1] }; byte[] r3 = new byte[2] { r1[2], r1[3] }; int r4 = BitConverter.ToUInt16(r2, 0); int r5 = BitConverter.ToUInt16(r3, 0); return new List() { r4.ToString(), r5.ToString() }; } /// /// 2个16位字转32位浮点 /// /// /// /// public float CalInt16ToFlaot(string[] value, int startIndex) { byte[] r1 = BitConverter.GetBytes(Convert.ToInt16(value[startIndex])); byte[] r2 = BitConverter.GetBytes(Convert.ToInt16(value[startIndex + 1])); byte[] r3 = new byte[4] { r1[0], r1[1], r2[0], r2[1] }; return BitConverter.ToSingle(r3, 0); } /// /// ASCII编码解码 /// /// /// public string SendRecive(string str) { return encoding.GetString(SendRecive(encoding.GetBytes(str))); } /// /// 发送接收字节数组报文 /// /// /// public byte[] SendRecive(byte[] arry) { try { Monitor.Enter(LockKVTCP); int delay = 0; int reslut = KVTCPClicent.Send(arry); while (KVTCPClicent.Available == 0) { Thread.Sleep(10); delay++; if (delay > MaxDelayCycle) { break; } } byte[] ResByte = new byte[KVTCPClicent.Available]; reslut = KVTCPClicent.Receive(ResByte); return ResByte; } catch (Exception) { IsConnected = false; return null; } finally { Monitor.Exit(LockKVTCP); } } /// /// 根据数据类型生成报文 /// /// /// public string GetDataType(DataType dataType) { string str = string.Empty; switch (dataType) { case DataType.U: str = ".U"; break; case DataType.S: str = ".S"; break; case DataType.D: str = ".D"; break; case DataType.L: str = ".L"; break; case DataType.H: str = ".H"; break; case DataType.N: str = ""; break; default: str = ""; break; } return str; } }}
#上位机# #PLC# #触摸屏# #电工交流圈#
如果对您有帮助,点赞关注转发,持续更新,帮大家解答工控问题