TCP および UDP プロトコル:
TCP (伝送制御プロトコル) と UDP (ユーザー データグラム プロトコル) は、TCP/IP プロトコル スイートの 2 つのコア プロトコルです。これらはトランスポート層でデータ転送サービスを提供しますが、特徴や機能が異なります。
TCP プロトコルは、信頼性の高い接続指向のバイト ストリーム サービスを提供するトランスポート プロトコルです。データ送信を行う前に、送信者と受信者は TCP 接続を確立する必要があります。タイムアウト再送信、重複データの破棄、データ検証などの機能により、一方の端からもう一方の端までデータを確実に送信できます。
UDP プロトコルは、単純なデータグラム指向のトランスポート層プロトコルであり、非コネクション指向で信頼性の低いデータ ストリーム送信サービスを提供します。UDP はデータグラムを送信する前にクライアントとサーバーの間で接続を確立する必要がなく、タイムアウト再送などの仕組みがないため、通信速度が比較的高速です。しかしこれは、データ伝送の信頼性を保証できないことも意味します。
一般に、TCP と UDP にはそれぞれ独自の利点と使用シナリオがあります。TCP は主に、Web ブラウジング、ファイル転送など、高い信頼性要件が必要なアプリケーションで使用されます。一方、UDP は、ビデオ ストリーミング、ゲームなど、信頼性要件が低く、伝送速度と経済性に関する特定の要件があるアプリケーションに適しています。 。
RS-232 および RS-475 通信インターフェイス規格と Modbus プロトコル:
RS-232 は、電子工業会 (EIA)、ベル システムズ、モデム メーカー、コンピュータ端末メーカーによって 1970 年に共同開発された共通のシリアル通信インターフェイス規格です。正式名称は「データ端末装置(DTE)とデータ通信装置(DCE)間のシリアル・バイナリ・データ交換インターフェースの技術規格」です。これは、コンピュータ、モデム、およびさまざまな電子デバイス間の通信接続で一般的に使用されます。
RS-475 は、電子工業会 (EIA) によって開発された半二重通信インターフェイス規格で、通常は電子機器間のデータ伝送に使用されます。バランス駆動と差動受信を使用するため、優れた耐干渉性能があり、伝送距離が数百メートル、場合によってはキロメートルに達することもあります。RS-232 とは異なり、RS-475 は通常 9 ピン D タイプ コネクタを使用し、そのピン定義も RS-232 とは異なります。RS-475 は主に産業、科学、医療分野のデバイス間の通信に使用されますが、半二重の制限があるため、そのアプリケーション シナリオは RS-232 や RS-485 ほど広範囲ではありません。
Modbus は、プログラマブル ロジック コントローラー (PLC) 間の通信のために 1979 年に Modicon Corporation (現 Schneider Electric) によって最初に開発されたシリアル通信プロトコルです。このプロトコルは産業分野における通信プロトコルの業界標準となっており、現在では産業用電子機器間の接続方式として一般的に使用されています。Siemens の S1200 および S1500 は Modbus プロトコルを使用します
Modbus プロトコルは、通信に使用するネットワークに関係なく、コントローラーが理解できるメッセージ構造を定義します。コントローラーが他のデバイスへのアクセスを要求するプロセス、他のデバイスからの要求にコントローラーがどのように応答するか、エラーがどのように検出されログに記録されるかについて説明します。これは、メッセージ ドメインのレイアウトとコンテンツの共通形式を確立します。Modbus ネットワーク上で通信する場合、このプロトコルは、各コントローラがデバイス アドレスを認識し、そのアドレスによって送信されたメッセージを認識し、実行するアクションを決定する必要があることを判断します。応答が必要な場合、コントローラはフィードバック情報を生成し、Modbus プロトコルを使用して送信します。一般に、Modbus は電子コントローラ間で使用される汎用言語であり、これを介して、異なるメーカーが製造した制御機器を産業用ネットワークに接続し、集中監視を行うことができます。
1. HslCommunication アセンブリを使用します (公式 Web サイト: Hu Gong Technology)。
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using HslCommunication;
using HslCommunication.Profinet.Siemens;
using HslCommunication.Profinet.Omron;
using HslCommunication.Profinet.Keyence;
namespace PLC.Class
{
public class PLCHelper
{
#region 连接西门子PLC--SiemensS7Net
/// <summary>
/// 连接西门子PLC--SiemensS7Net
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <returns></returns>
private bool ConnectSiemens(SiemensS7Net siemens, string ip, int port)
{
try
{
IPAddress ipaddress;
bool flag = !IPAddress.TryParse(ip, out ipaddress);
if (flag)
{
return false;
}
else
{
siemens.IpAddress = ip;
siemens.Port = port;
OperateResult operateResult = siemens.ConnectServer();
bool isSuccess = operateResult.IsSuccess;
if (isSuccess)
{
return true;
}
else
{
return false;
}
}
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 给西门子PLC点位写信号
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <param name="flag">给点位传入的值</param>
/// <returns></returns>
public bool WriteFlagBySiemens(SiemensS7Net siemens, string ip, int port, string point, short flag)
{
if (ConnectSiemens(siemens, ip, port))
{
OperateResult result = siemens.Write(point, flag);
siemens.ConnectClose();
return result.IsSuccess;
}
else
{
return false;
}
}
/// <summary>
/// 读取西门子PLC的状态
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <returns></returns>
public bool ReadBoolBySiemens(SiemensS7Net siemens, string ip, int port, string point)
{
if (ConnectSiemens(siemens, ip, port))
{
OperateResult<bool> value = siemens.ReadBool(point);
siemens.ConnectClose();
return value.Content;
}
else
{
return false;
}
}
/// <summary>
/// 读取西门子PLC的值
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <param name="length">读取长度</param>
/// <returns></returns>
public string ReadStringBySiemens(SiemensS7Net siemens, string ip, int port, string point, ushort length)
{
if (ConnectSiemens(siemens, ip, port))
{
OperateResult<string> result = new OperateResult<string>();
result = siemens.ReadString(point, length);
string source = string.Empty;
if (!string.IsNullOrEmpty(result.Content))
{
source = result.Content;
}
else
{
for (int i = 0; i < 3; i++)
{
Thread.Sleep(10);
result = siemens.ReadString(point, length);
if (!string.IsNullOrEmpty(result.Content))
{
source = result.Content;
break;
}
}
if (string.IsNullOrEmpty(result.Content))
{
return "未读取到PLC信息";
}
}
siemens.ConnectClose();
return source;
}
else
{
return "false";
}
}
/// <summary>
/// 清空西门子PLC点位中的值
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="point"></param>
/// <param name="length">写入的长度</param>
/// <returns></returns>
public bool ClearPlcPocketBySiemens(SiemensS7Net siemens, string ip, int port, string point, int length, string flag = " ")
{
if (ConnectSiemens(siemens, ip, port))
{
OperateResult result = siemens.Write(point, flag, length);
siemens.ConnectClose();
return result.IsSuccess;
}
else
{
return false;
}
}
#endregion
#region 连接欧姆龙PLC--OmronFinsNet
/// <summary>
/// 连接欧姆龙PLC--OmronFinsNet
/// </summary>
/// <param name="omron"></param>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <returns></returns>
private bool ConnectOmron(OmronFinsNet omron, string ip, int port)
{
//OmronFinsUdp
try
{
IPAddress ipaddress;
bool flag = !IPAddress.TryParse(ip, out ipaddress);
if (flag)
{
return false;
}
else
{
omron.IpAddress = ip;
omron.Port = port;
omron.SA1 = 239;
//if (ip240.Contains(ip))
//{
// omron.SA1 = 240;
//}
//else
//{
// omron.SA1 = 239;
//}
//omron.DA1 = 24;
OperateResult operateResult = omron.ConnectServer();
if (!operateResult.IsSuccess)
{
for (int i = 0;i < 3;i++)
{
operateResult = omron.ConnectServer();
if (operateResult.IsSuccess)
{
break;
//return true;
}
}
//SA1使用239连接不上,则采取240连接
if (!operateResult.IsSuccess)
{
omron.SA1 = 240;
for (int i = 0; i < 3; i++)
{
operateResult = omron.ConnectServer();
if (operateResult.IsSuccess)
{
break;
//return true;
}
}
}
//if (!isSuccess)
//{
// return false;
//}
}
return operateResult.IsSuccess;
}
}
catch (Exception ex)
{
LogHelper.WriteErrLog(ex.ToString());
return false;
}
}
/// <summary>
/// 给欧姆龙PLC点位写信号
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <param name="flag">给点位传入的值</param>
/// <returns></returns>
public bool WriteShortByOmron(OmronFinsNet omron, string ip, int port, string point, short flag)
{
//if (ConnectOmron(omron, ip, port))
//{
OperateResult result = omron.Write(point, flag);
if (!result.IsSuccess)
{
for (int i = 0;i < 3;i++)
{
result = omron.Write(point,flag);
if (result.IsSuccess)
{
break;
//return true;
}
}
//if (!result.IsSuccess)
//{
// return false;
//}
}
//omron.ConnectClose();
return result.IsSuccess;
//}
//else
//{
// return false;
//}
}
//写入float值
public bool WriteFloatByOmron(OmronFinsNet omron, string ip, int port, string point, float flag)
{
//if (ConnectOmron(omron, ip, port))
//{
OperateResult result = omron.Write(point, flag);
if (!result.IsSuccess)
{
for (int i = 0; i < 3; i++)
{
result = omron.Write(point, flag);
if (result.IsSuccess)
{
break;
//return true;
}
}
//if (!result.IsSuccess)
//{
// return false;
//}
}
//omron.ConnectClose();
return result.IsSuccess;
//}
//else
//{
// return false;
//}
}
public string WritePointByOmron(OmronFinsNet omron, string ip, int port, List<string> pointlst, List<string> dataTypelst, List<string> valuelst,string type,List<string> filedlst)
{
//int sucNum = 0;
string errorFileds = "";
try
{
if (type == "EDIT")
{
//return 0;
return "";
}
//调用时以下6个点位不写入
List<string> addNotWritePoint = new List<string>() { "D200", "D202", "D210", "D212", "D0", "D469" };
if (ConnectOmron(omron, ip, port))
{
for (int i = 0; i < pointlst.Count; i++)
{
if (addNotWritePoint.Contains(pointlst[i]))
{
continue;
}
if (dataTypelst[i] == "FLOAT" && !string.IsNullOrEmpty(valuelst[i]))
{
float flag = Convert.ToSingle(valuelst[i]);
bool result = WriteFloatByOmron(omron, ip, port, pointlst[i], flag);
if (result)
{
//sucNum++;
}
else
{
if (errorFileds.Length > 0)
{
errorFileds += ",";
}
errorFileds += filedlst[i];
LogHelper.WriteErrLog($"IP:{ip},端口:{port},点位:{pointlst[i]},值:{valuelst[i]}写入失败!");
}
}
else if (dataTypelst[i] == "SHORT" && !string.IsNullOrEmpty(valuelst[i]))
{
short flag = Convert.ToInt16(valuelst[i]);
bool result = WriteShortByOmron(omron, ip, port, pointlst[i], flag);
if (result)
{
//sucNum++;
}
else
{
if (errorFileds.Length > 0)
{
errorFileds += ",";
}
errorFileds += filedlst[i];
LogHelper.WriteErrLog($"IP:{ip},端口:{port},点位:{pointlst[i]},值:{valuelst[i]}写入失败!");
}
}
}
//return sucNum;
}
//else
//{
// return sucNum;
//}
}
catch (Exception ex)
{
LogHelper.WriteErrLog(ex.ToString());
}
finally
{
omron.ConnectClose();
}
//return sucNum;
return errorFileds;
}
/// <summary>
/// 读取欧姆龙PLC的状态
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <returns></returns>
public bool ReadBoolByOmron1(OmronFinsNet omron, string ip, int port, string point)
{
if (ConnectOmron(omron, ip, port))
{
OperateResult<bool> value = omron.ReadBool(point);
omron.ConnectClose();
return value.Content;
}
else
{
return false;
}
}
//读取float型数据
public float ReadFloatByOmron(OmronFinsNet omron, string ip, int port, string point)
{
//if (ConnectOmron(omron, ip, port))
//{
OperateResult<float> value = omron.ReadFloat(point);
if (!value.IsSuccess)
{
for (int i = 0;i < 3;i++)
{
value = omron.ReadFloat(point);
if (value.IsSuccess)
{
break;
//return value.Content;
}
}
//if (!value.IsSuccess)
//{
// return 0;
//}
}
//omron.ConnectClose();
if (value.IsSuccess)
{
return value.Content;
}
else
{
return 0;
}
//}
//else
//{
// return 0;
//}
}
//读取short型数据
public short ReadShortByOmron(OmronFinsNet omron, string ip, int port, string point)
{
//if (ConnectOmron(omron, ip, port))
//{
OperateResult<short> value = omron.ReadInt16(point);
if (!value.IsSuccess)
{
for (int i = 0; i < 3; i++)
{
value = omron.ReadInt16(point);
if (value.IsSuccess)
{
break;
//return value.Content;
}
}
//if (!value.IsSuccess)
//{
// return 0;
//}
}
//omron.ConnectClose();
if (value.IsSuccess)
{
return value.Content;
}
else
{
return 0;
}
//}
//else
//{
// return 0;
//}
}
//读取Bool类型数据
public bool ReadBoolByOmron(OmronFinsNet omron, string ip, int port, string point)
{
OperateResult<bool> value = omron.ReadBool(point);
if (!value.IsSuccess)
{
for (int i = 0; i < 3; i++)
{
value = omron.ReadBool(point);
if (value.IsSuccess)
{
break;
}
}
}
if (value.IsSuccess)
{
return value.Content;
}
else
{
return false;
}
}
public string ReadPointByOmron(OmronFinsNet omron, string ip, int port, List<string> filedlst, List<string> pointlst, List<string> datatypelst)
{
string result = "0";
JObject jObj = new JObject();
try
{
if (ConnectOmron(omron, ip, port))
{
for (int i = 0; i < pointlst.Count; i++)
{
if (datatypelst[i] == "FLOAT")
{
result = ReadFloatByOmron(omron, ip, port, pointlst[i]).ToString();
}
else if (datatypelst[i] == "SHORT")
{
result = ReadShortByOmron(omron, ip, port, pointlst[i]).ToString();
}
else if (datatypelst[i] == "BOOL" && pointlst[i] == "H10")
{
//涂布单双面3个点位细分—00:单面,01:双面,01;02:连续
bool res = false;
List<string> H10s = new List<string>() { "H10.00", "H10.01", "H10.02" };
foreach (string h10 in H10s)
{
res = ReadBoolByOmron(omron, ip, port, h10);
if (res)
{
result = h10.Substring(h10.Length - 1,1);
break;
}
}
}
jObj.Add(new JProperty(filedlst[i], result));
}
}
}
catch (Exception ex)
{
LogHelper.WriteErrLog(ex.ToString());
}
finally
{
omron.ConnectClose();
}
return jObj.ToString();
}
/// <summary>
/// 读取欧姆龙PLC的值
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <param name="length">读取长度</param>
/// <returns></returns>
public string ReadStringByOmron(OmronFinsNet omron, string ip, int port, string point, ushort length)
{
if (ConnectOmron(omron, ip, port))
{
OperateResult<string> result = new OperateResult<string>();
result = omron.ReadString(point, length);
string source = string.Empty;
if (!string.IsNullOrEmpty(result.Content))
{
source = result.Content;
}
else
{
for (int i = 0; i < 3; i++)
{
Thread.Sleep(10);
result = omron.ReadString(point, length);
if (!string.IsNullOrEmpty(result.Content))
{
source = result.Content;
break;
}
}
if (string.IsNullOrEmpty(result.Content))
{
return "未读取到PLC信息";
}
}
omron.ConnectClose();
return source;
}
else
{
return "false";
}
}
/// <summary>
/// 清空欧姆龙PLC点位中的值
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="point"></param>
/// <param name="length">写入的长度</param>
/// <returns></returns>
public bool ClearPlcPocketByOmron(OmronFinsNet omron, string ip, int port, string point, int length, string flag = " ")
{
if (ConnectOmron(omron, ip, port))
{
OperateResult result = omron.Write(point, flag, length);
omron.ConnectClose();
return result.IsSuccess;
}
else
{
return false;
}
}
#endregion
#region 连接基恩士PLC--KeyenceMcNet
/// <summary>
/// 连接基恩士PLC--KeyenceMcNet
/// </summary>
/// <param name="omron"></param>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <returns></returns>
private bool ConnectKeyence(KeyenceMcNet keyence, string ip, int port)
{
try
{
IPAddress ipaddress;
bool flag = !IPAddress.TryParse(ip, out ipaddress);
if (flag)
{
return false;
}
else
{
keyence.IpAddress = ip;
keyence.Port = port;
OperateResult operateResult = keyence.ConnectServer();
bool isSuccess = operateResult.IsSuccess;
if (isSuccess)
{
return true;
}
else
{
return false;
}
}
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 给基恩士PLC点位写信号
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <param name="flag">给点位传入的值</param>
/// <returns></returns>
public bool WriteFlagByKeyence(KeyenceMcNet keyence, string ip, int port, string point, short flag)
{
if (ConnectKeyence(keyence, ip, port))
{
OperateResult result = keyence.Write(point, flag);
keyence.ConnectClose();
return result.IsSuccess;
}
else
{
return false;
}
}
/// <summary>
/// 读取基恩士PLC的状态
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <returns></returns>
public bool ReadBoolByKeyence(KeyenceMcNet keyence, string ip, int port, string point)
{
if (ConnectKeyence(keyence, ip, port))
{
OperateResult<bool> value = keyence.ReadBool(point);
keyence.ConnectClose();
return value.Content;
}
else
{
return false;
}
}
/// <summary>
/// 读取基恩士PLC的值
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
/// <param name="point">PLC点位</param>
/// <param name="length">读取长度</param>
/// <returns></returns>
public string ReadStringByKeyence(KeyenceMcNet keyence, string ip, int port, string point, ushort length)
{
if (ConnectKeyence(keyence, ip, port))
{
OperateResult<string> result = new OperateResult<string>();
result = keyence.ReadString(point, length);
string source = string.Empty;
if (!string.IsNullOrEmpty(result.Content))
{
source = result.Content;
}
else
{
for (int i = 0; i < 3; i++)
{
Thread.Sleep(10);
result = keyence.ReadString(point, length);
if (!string.IsNullOrEmpty(result.Content))
{
source = result.Content;
break;
}
}
if (string.IsNullOrEmpty(result.Content))
{
return "未读取到PLC信息";
}
}
keyence.ConnectClose();
return source;
}
else
{
return "false";
}
}
/// <summary>
/// 清空基恩士PLC点位中的值
/// </summary>
/// <param name="siemens"></param>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="point"></param>
/// <param name="length">写入的长度</param>
/// <returns></returns>
public bool ClearPlcPocketByKeyence(KeyenceMcNet keyence, string ip, int port, string point, int length, string flag = " ")
{
if (ConnectKeyence(keyence, ip, port))
{
OperateResult result = keyence.Write(point, flag, length);
keyence.ConnectClose();
return result.IsSuccess;
}
else
{
return false;
}
}
#endregion
}
}