找回密码
 立即注册
首页 业界区 业界 C#实现欧姆龙 HostLink 通讯协议库

C#实现欧姆龙 HostLink 通讯协议库

拴茅劾 2025-6-15 06:34:15
目录

  • C#实现欧姆龙 HostLink 通讯协议库

    • 背景介绍

      • 欧姆龙 PLC 内存区域介绍
      • 欧姆龙 PLC 数据类型对应
      • 欧姆龙 PLC 与 PC 的 RS232 接线线序

    • HostLink通讯报文分析

      • C-Mode通讯报文分析
      • FINS-Mode通讯报文分析

    • HostLink通讯协议库的C#实现

      • 核心实现(FCS校验码生成、串口收发)
      • C-Mode实现
      • FINS-Mode实现

    • C#控制台测试功能

      • 测试结果



C#实现欧姆龙 HostLink 通讯协议库

运行环境:VS2022 .net framework4.8
通讯库项目地址(Gitee):通讯库项目Gitee 仓库
控制台测试项目地址(Gitee):控制台测试项目Gitee 仓库
HostLink 通讯手册链接(蓝奏云):SYSMAC Series Communications Commands
官方的 HostLink 串口通讯示例(蓝奏云):C-Mode || FINS-Mode
通讯工具(蓝奏云):Commix 1.4
概要:根据欧姆龙的 HostLink 通讯协议手册内容,使用串口实现了 PC 与 PLC 的通讯,能够通过C-ModeFINS-Mode两种模式实现 PC 读写 PLC 的CIO、WR、HR、DM 四个内存区的内容(同步/异步方法),而且可以以较高的通讯效率获取所需数据、错误代码等信息,最后用一个 C#控制台项目测试了通讯库功能
背景介绍

HostLink 协议是欧姆龙 PLC 与主机通讯的一种公开协议,PC 可通过 HostLink 命令对 PLC 的运行状态、I/O 点位的读写
HostLink 分为 C-Mode 和 FINS-Mode 两种模式
C-Mode 命令是专门的主机链路通信命令,它们由主机发出并发送至 CPU 单元。可连接用于串行通信的设备有 CPU 单元、串行通信单元和串行通信板。
FINS-Mode 命令是报文服务通信命令,它们不依赖于特定的传输路径。它们可用于各种网络(控制器链路、以太网等)和串行通信(主机链路)。它们可以从 CPU 单元、特殊 I/O 单元或主机发出,也可以发送到其中任何一个单元。可发送的具体命令取决于目的地。
1.png

欧姆龙 PLC 内存区域介绍

内存区域名区域说明CIOI/O 继电器区WR内部辅助继电器区HR保持继电器区DM数据存储区TIM定时器区CNT计数器区IR变址寄存器区DR数据寄存器AR特殊辅助继电器区TR暂存区TK状态标志、时钟脉冲、任务标志欧姆龙 PLC 数据类型对应

PLC 数据类型PC 数据类型BitboolByteushortDWorduintIntshortDintintfloatfloatStringstring欧姆龙 PLC 与 PC 的 RS232 接线线序

2.png

HostLink通讯报文分析

根据C-Mode和FINS的报文进行分析
C-Mode通讯报文分析

发送报文如下图所示
3.png

正常接收报文如下图所示
4.png

通讯出错接收报文如下图所示
5.png

使用串口工具Commix进行测试如下图所示
TS命令:
6.png

RD、WD命令:
7.png

FINS-Mode通讯报文分析

发送报文如下图所示
8.png

接收报文如下图所示
9.png

FINS指令配置如下图所示
10.png

使用串口工具Commix进行测试如下图所示
0101、0102命令:
11.png

HostLink通讯协议库的C#实现

核心实现(FCS校验码生成、串口收发)

HostLinkCore.cs
在这里我本来想给异步的方法加上一个SemaphoreSlim来限制通讯的信号量的,但是后来想了想还是让使用者在外面自己加好了
SemaphoreSlim具体的使用方法可以参考文章的C#控制台项目
  1. /// <summary>
  2. /// 通过命令帧计算FCS异或校验码并加上结束符
  3. /// </summary>
  4. /// <param name="CommandFrame">命令帧</param>
  5. /// <returns>4位字节数组,包含FCS校验码与结束符</returns>
  6. public static List<byte> HostLinkEndCode(List<byte> CommandFrame)
  7. {
  8.     try
  9.     {
  10.         List<byte> EndCode = new List<byte>();
  11.         short FCSNum = HostLinkFCS(CommandFrame);
  12.         string HexString = FCSNum.ToString("X2");
  13.         EndCode.AddRange(Encoding.ASCII.GetBytes(HexString));
  14.         EndCode.AddRange(new List<byte> { 0x2A, 0x0D });
  15.         return EndCode;
  16.     }
  17.     catch (Exception)
  18.     {
  19.         throw;
  20.     }
  21. }
  22. /// <summary>
  23. /// 对字节数组进行异或运算得到数值
  24. /// </summary>
  25. /// <param name="CommandFrame">命令帧</param>
  26. /// <returns>异或运算结果(short类型)</returns>
  27. public static short HostLinkFCS(List<byte> CommandFrame)
  28. {
  29.     try
  30.     {
  31.         short CheckNum = 0;
  32.         foreach (byte FrameNum in CommandFrame)
  33.         {
  34.             CheckNum ^= FrameNum;
  35.         }
  36.         return CheckNum;
  37.     }
  38.     catch (Exception)
  39.     {
  40.         throw;
  41.     }
  42. }
  43. /// <summary>
  44. /// 检查回复帧是否完整
  45. /// </summary>
  46. /// <param name="frame">回复帧</param>
  47. /// <returns>完整结尾:返回True;不完整:返回False</returns>
  48. private static bool CheckResponseFrame(List<byte> frame)
  49. {
  50.     if (frame.Count > 0 && frame[frame.Count - 1] == (byte)0x0D)
  51.     {
  52.         return true;
  53.     }
  54.     else
  55.     {
  56.         return false;
  57.     }
  58. }
  59. /// <summary>
  60. /// HostLink报文发送与接收代码
  61. /// </summary>
  62. /// <param name="serialPort">串口实例</param>
  63. /// <param name="CommandFrame">命令帧</param>
  64. /// <returns>回复帧</returns>
  65. public static List<byte> HostLinkCommCore(SerialPort serialPort, List<byte> CommandFrame)
  66. {
  67.     try
  68.     {
  69.         List<byte> ResponseFrame = new List<byte>();
  70.         //发送报文
  71.         serialPort.Write(CommandFrame.ToArray(), 0, CommandFrame.Count);
  72.         //循环读取数据
  73.         while (serialPort.IsOpen)
  74.         {
  75.             if (serialPort.BytesToRead > 0)
  76.             {
  77.                 byte[] buffer = new byte[serialPort.BytesToRead];
  78.                 serialPort.Read(buffer, 0, buffer.Length);
  79.                 ResponseFrame.AddRange(buffer);
  80.                 if (CheckResponseFrame(ResponseFrame))
  81.                 {
  82.                     return ResponseFrame;
  83.                 }
  84.             }
  85.         }
  86.         return null;
  87.     }
  88.     catch (Exception)
  89.     {
  90.         throw;
  91.     }
  92. }
  93. /// <summary>
  94. /// HostLink报文发送与接收代码(异步方法)
  95. /// </summary>
  96. /// <param name="serialPort">串口实例</param>
  97. /// <param name="CommandFrame">命令帧</param>
  98. /// <returns>回复帧</returns>
  99. public static async Task<List<byte>> HostLinkCommCoreAsync(SerialPort serialPort, List<byte> CommandFrame)
  100. {
  101.     try
  102.     {
  103.         List<byte> ResponseFrame = new List<byte>();
  104.         //发送报文
  105.         await serialPort.BaseStream.WriteAsync(CommandFrame.ToArray(), 0, CommandFrame.Count);
  106.         //循环读取数据
  107.         while (serialPort.IsOpen)
  108.         {
  109.             if (serialPort.BytesToRead > 0)
  110.             {
  111.                 byte[] buffer = new byte[serialPort.BytesToRead];
  112.                 await serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length);
  113.                 ResponseFrame.AddRange(buffer);
  114.                 if (CheckResponseFrame(ResponseFrame))
  115.                 {
  116.                     return ResponseFrame;
  117.                 }
  118.             }
  119.         }
  120.         return null;
  121.     }
  122.     catch (Exception)
  123.     {
  124.         throw;
  125.     }
  126. }
复制代码
C-Mode实现

CmodeEndCode.cs
  1. /// <summary>
  2. /// 对比回复帧中的EndCode,看内容是否相符
  3. /// </summary>
  4. /// <param name="ResponseFrame">回复帧</param>
  5. /// <returns>返回结束代码</returns>
  6. public static string CatchEndCode(List<byte> ResponseFrame, int EndCodeAdr)
  7. {
  8.     try
  9.     {
  10.         List<byte> ResponseEndCode = ResponseFrame.GetRange(EndCodeAdr, 2);
  11.         string EndCodeContents = null;
  12.         if (ResponseEndCode.SequenceEqual(new List<byte> { 0x30, 0x30 }))
  13.         {
  14.             EndCodeContents = "00";
  15.         }
  16.         else
  17.         {
  18.             foreach (var EndCodeMap in EndCodeMapSeq)
  19.             {
  20.                 if (ResponseEndCode.SequenceEqual(EndCodeMap.Key))
  21.                 {
  22.                     EndCodeContents = EndCodeMap.Value;
  23.                     break;
  24.                 }
  25.             }
  26.         }
  27.         return EndCodeContents;
  28.     }
  29.     catch (Exception ex)
  30.     {
  31.         throw ex;
  32.     }
  33. }
  34. private static readonly Dictionary<List<byte>, string> EndCodeMapSeq = new Dictionary<List<byte>, string>
  35. {
  36.     {new List<byte> { 0x30, 0x31 },"EndCode: 01;  Contents: Not executable in RUN mode" },
  37.     {new List<byte> { 0x30, 0x32 },"EndCode: 02;  Contents: Not executable in MONITOR mode" },
  38.     {new List<byte> { 0x30, 0x33 },"EndCode: 03;  Contents: UM write-protected" },
  39.     {new List<byte> { 0x30, 0x34 },"EndCode: 04;  Contents: Address over" },
  40.     {new List<byte> { 0x30, 0x42 },"EndCode: 0B;  Contents: Not executable in PROGRAM mode" },
  41.     {new List<byte> { 0x31, 0x33 },"EndCode: 13;  Contents: FCS error" },
  42.     {new List<byte> { 0x31, 0x34 },"EndCode: 14;  Contents: Format error" },
  43.     {new List<byte> { 0x31, 0x35 },"EndCode: 15;  Contents: Entry number data error" },
  44.     {new List<byte> { 0x31, 0x36 },"EndCode: 16;  Contents: Command not supported" },
  45.     {new List<byte> { 0x31, 0x38 },"EndCode: 18;  Contents: Frame length error" },
  46.     {new List<byte> { 0x31, 0x39 },"EndCode: 19;  Contents: Not executable" },
  47.     {new List<byte> { 0x32, 0x30 },"EndCode: 20;  Contents: Could not create I/O table" },
  48.     {new List<byte> { 0x32, 0x31 },"EndCode: 21;  Contents: Not executable due to CPU Unit CPU error" },
  49.     {new List<byte> { 0x32, 0x33 },"EndCode: 23;  Contents: User memory protected" },
  50.     {new List<byte> { 0x41, 0x33 },"EndCode: A3;  Contents: Aborted due to FCS error in trans-mission data" },
  51.     {new List<byte> { 0x41, 0x34 },"EndCode: A4;  Contents: Aborted due to format error in transmission data" },
  52.     {new List<byte> { 0x41, 0x35 },"EndCode: A5;  Contents: Aborted due to entry number data error in transmission data" },
  53.     {new List<byte> { 0x41, 0x38 },"EndCode: A8;  Contents: Aborted due to frame length error in transmission data" }
  54. };
复制代码
CmodeHeaderCode.cs
  1. internal class CmodeHeaderCode
  2. {
  3.     public static readonly byte[] HeaderCode_RR = { 0x52, 0x52 };
  4.     public static readonly byte[] HeaderCode_RD = { 0x52, 0x44 };
  5.     public static readonly byte[] HeaderCode_WR = { 0x57, 0x52 };
  6.     public static readonly byte[] HeaderCode_WD = { 0x57, 0x44 };
  7.     public static readonly byte[] HeaderCode_TS = { 0x54, 0x53 };
  8.     public static readonly byte[] HeaderCode_MS = { 0x4D, 0x53 };
  9.     public static readonly byte[] HeaderCode_SC = { 0x53, 0x43 };
  10. }
复制代码
功能实现的代码过长,请自行到通讯库项目Gitee 仓库查看吧
FINS-Mode实现

定义一个FinsResult的类用来接收所需要的信息
(目前通信库反馈的大部分数据都是Bool与String列表,所以里面分开成两个Datas)
FinsResult.cs
  1. /// <summary>
  2. /// Fins通信结果类
  3. /// </summary>
  4. public class FinsResult
  5. {
  6.     /// <summary>
  7.     /// FINS通信状态
  8.     /// </summary>
  9.     public bool IsSuccessed { get; set; }
  10.     /// <summary>
  11.     /// FINS通信结果信息
  12.     /// </summary>
  13.     public string ResultMessage { get; set; }
  14.     /// <summary>
  15.     /// 通信命令帧
  16.     /// </summary>
  17.     public string CommandFrame { get; set; }
  18.     /// <summary>
  19.     /// 通信回复帧
  20.     /// </summary>
  21.     public string ResponseFrame { get; set; }
  22.     /// <summary>
  23.     /// 数据列表(bool类型)
  24.     /// </summary>
  25.     public List<bool> Datas_BoolList { get; set; }
  26.     /// <summary>
  27.     /// 数据列表(string类型)
  28.     /// </summary>
  29.     public string Datas_String { get; set; }
  30.     /// <summary>
  31.     /// 完整构造函数
  32.     /// </summary>
  33.     /// <param name="isSuccessed">FINS通信状态</param>
  34.     /// <param name="resultMessage">FINS通信结果信息</param>
  35.     /// <param name="commandFrame">通信命令帧</param>
  36.     /// <param name="responseFrame">通信回复帧</param>
  37.     /// <param name="datas">数据列表</param>
  38.     public FinsResult(bool isSuccessed, string resultMessage, string commandFrame, string responseFrame, List<bool> datas1, string datas2)
  39.     {
  40.         IsSuccessed = isSuccessed;
  41.         ResultMessage = resultMessage;
  42.         CommandFrame = commandFrame;
  43.         ResponseFrame = responseFrame;
  44.         Datas_BoolList = datas1;
  45.         Datas_String = datas2;
  46.     }
  47.     //五参数构造函数(带bool数据列表)
  48.     public FinsResult(bool isSuccessed, string resultMessage, string commandFrame, string responseFrame, List<bool> datas) :
  49.         this(isSuccessed, resultMessage, commandFrame, responseFrame, datas, null)
  50.     { }
  51.     //五参数构造函数(带string数据列表)
  52.     public FinsResult(bool isSuccessed, string resultMessage, string commandFrame, string responseFrame, string datas) :
  53.         this(isSuccessed, resultMessage, commandFrame, responseFrame, null, datas)
  54.     { }
  55.     //四参数构造函数(无数据反馈)
  56.     public FinsResult(bool isSuccessed, string resultMessage, string commandFrame, string responseFrame) :
  57.         this(isSuccessed, resultMessage, commandFrame, responseFrame, null, null)
  58.     { }
  59.     //两参数构造函数(出错时返回)
  60.     public FinsResult(bool isSuccessed, string resultMessage) : this(isSuccessed, resultMessage, null, null, null, null) { }
  61. }
复制代码
通讯库定义了一些常用的内存区域枚举类,使用时可以提前设定好
FinsIOMemoryAreaAddress.cs
  1. /// <summary>
  2. /// FinsIO内存区域地址类
  3. /// </summary>
  4. public class FinsIOMemoryAreaAddress
  5. {
  6.     /// <summary>
  7.     /// 内存区域代码
  8.     /// </summary>
  9.     public FinsMemoryAreaTypeEnum AreaType { get; set; }
  10.     /// <summary>
  11.     /// Word起始地址
  12.     /// </summary>
  13.     public ushort WordAddress { get; set; }
  14.     /// <summary>
  15.     /// Bit起始地址
  16.     /// </summary>
  17.     public ushort BitAddress { get; set; }
  18. }
复制代码
FinsMemoryAreaTypeEnum.cs
  1. /// <summary>
  2. /// Fins内存区域类型
  3. /// </summary>
  4. public enum FinsMemoryAreaTypeEnum
  5. {
  6.     CIOBit,
  7.     CIOWord,
  8.     WRBit,
  9.     WRWord,
  10.     HRBit,
  11.     HRWord,
  12.     DMBit,
  13.     DMWord
  14. }
复制代码
FINS指令配置的代码如下
FinsFrameConfig.cs
  1. public class FinsFrameConfig
  2. {
  3.     public string ICF { get; set; }
  4.     public string RSV { get; set; }
  5.     public string GCT { get; set; }
  6.     public string DNA { get; set; }
  7.     public string DA1 { get; set; }
  8.     public string DA2 { get; set; }
  9.     public string SNA { get; set; }
  10.     public string SA1 { get; set; }
  11.     public string SA2 { get; set; }
  12.     public string SID { get; set; }
  13. }
复制代码
功能实现的代码过长,请自行到通讯库项目Gitee 仓库查看吧
C#控制台测试功能

HostLinkDevice.cs
  1. public class HostLinkDevice
  2. {
  3.     public HostLinkDevice(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
  4.     {
  5.         PLC = new HostLinkFinsDevice(portName, baudRate, parity, dataBits, stopBits);
  6.     }
  7.     //HostLinkFins设备
  8.     private HostLinkFinsDevice PLC;
  9.     //Fins帧参数设置
  10.     private static FinsFrameConfig finsFrameConfig = new FinsFrameConfig()
  11.     {
  12.         ICF = "00",
  13.         DA2 = "00",
  14.         SA2 = "00",
  15.         SID = "00"
  16.     };
  17.     /// <summary>
  18.     /// 串口打开
  19.     /// </summary>
  20.     public void Connect()
  21.     {
  22.         try
  23.         {
  24.             PLC.Connect();
  25.         }
  26.         catch (Exception)
  27.         {
  28.             throw;
  29.         }
  30.     }
  31.     /// <summary>
  32.     /// 串口关闭
  33.     /// </summary>
  34.     public void Disconnect()
  35.     {
  36.         try
  37.         {
  38.             PLC.DisConnect();
  39.         }
  40.         catch (Exception)
  41.         {
  42.             throw;
  43.         }
  44.     }
  45.     /// <summary>
  46.     /// 读取CIO区的连续Bit位方法(异步方法)
  47.     /// </summary>
  48.     /// <param name="WordAdr">读取起始Word地址</param>
  49.     /// <param name="BitAdr">读取起始Bit地址</param>
  50.     /// <param name="ReadCount">读取Bit位数量</param>
  51.     /// <returns>返回通信结果的信息</returns>
  52.     public async Task<List<bool>> ReadCIOBitAsync(ushort WordAdr, ushort BitAdr, ushort ReadCount)
  53.     {
  54.         try
  55.         {
  56.             FinsResult finsResult;
  57.             //IO内存区域设置
  58.             FinsIOMemoryAreaAddress IOMemoryAreaAdr = new FinsIOMemoryAreaAddress()
  59.             {
  60.                 AreaType = FinsMemoryAreaTypeEnum.CIOBit,
  61.                 WordAddress = WordAdr,
  62.                 BitAddress = BitAdr
  63.             };
  64.             //获取FINS通信结果
  65.             finsResult = await PLC.Read_MemoryAreaAsync(IOMemoryAreaAdr, finsFrameConfig, ReadCount);
  66.             if (finsResult.IsSuccessed)
  67.             {
  68.                 if (finsResult.ResultMessage.Equals("OK"))
  69.                 {
  70.                     return finsResult.Datas_BoolList;
  71.                 }
  72.                 else
  73.                 {
  74.                     throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
  75.                 }
  76.             }
  77.             else
  78.             {
  79.                 throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
  80.             }
  81.         }
  82.         catch (Exception)
  83.         {
  84.             throw;
  85.         }
  86.     }
  87.     /// <summary>
  88.     /// 读取W区的连续Bit位方法(异步方法)
  89.     /// </summary>
  90.     /// <param name="WordAdr">读取起始Word地址</param>
  91.     /// <param name="BitAdr">读取起始Bit地址</param>
  92.     /// <param name="ReadCount">读取Bit位数量</param>
  93.     /// <returns>返回通信结果的信息</returns>
  94.     public async Task<List<bool>> ReadWRBitAsync(ushort WordAdr, ushort BitAdr, ushort ReadCount)
  95.     {
  96.         try
  97.         {
  98.             FinsResult finsResult;
  99.             //IO内存区域设置
  100.             FinsIOMemoryAreaAddress IOMemoryAreaAdr = new FinsIOMemoryAreaAddress()
  101.             {
  102.                 AreaType = FinsMemoryAreaTypeEnum.WRBit,
  103.                 WordAddress = WordAdr,
  104.                 BitAddress = BitAdr
  105.             };
  106.             //获取FINS通信结果
  107.             finsResult = await PLC.Read_MemoryAreaAsync(IOMemoryAreaAdr, finsFrameConfig, ReadCount);
  108.             if (finsResult.IsSuccessed)
  109.             {
  110.                 if (finsResult.ResultMessage.Equals("OK"))
  111.                 {
  112.                     return finsResult.Datas_BoolList;
  113.                 }
  114.                 else
  115.                 {
  116.                     throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
  117.                 }
  118.             }
  119.             else
  120.             {
  121.                 throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
  122.             }
  123.         }
  124.         catch (Exception)
  125.         {
  126.             throw;
  127.         }
  128.     }
  129.     /// <summary>
  130.     /// 写入W区的连续Bit位方法(异步方法)
  131.     /// </summary>
  132.     /// <param name="WordAdr">写入起始Word地址</param>
  133.     /// <param name="BitAdr">写入起始Bit地址</param>
  134.     /// <param name="WriteCount">写入Bit位数量</param>
  135.     /// <param name="WriteData">写入数据</param>
  136.     /// <returns>返回通信结果的信息</returns>
  137.     public async Task<string> WriteWRBitAsync(ushort WordAdr, ushort BitAdr, ushort WriteCount, string WriteData)
  138.     {
  139.         try
  140.         {
  141.             FinsResult finsResult;
  142.             //IO内存区域设置
  143.             FinsIOMemoryAreaAddress IOMemoryAreaAdr = new FinsIOMemoryAreaAddress()
  144.             {
  145.                 AreaType = FinsMemoryAreaTypeEnum.WRBit,
  146.                 WordAddress = WordAdr,
  147.                 BitAddress = BitAdr
  148.             };
  149.             //获取FINS通信结果
  150.             finsResult = await PLC.Write_MemoryAreaAsync(IOMemoryAreaAdr, finsFrameConfig, WriteCount, WriteData);
  151.             if (finsResult.IsSuccessed)
  152.             {
  153.                 return finsResult.ResultMessage;
  154.             }
  155.             else
  156.             {
  157.                 throw new Exception($"{finsResult.ResultMessage}{Environment.NewLine}{Environment.NewLine}发送命令帧:{finsResult.CommandFrame}{Environment.NewLine}接收回复帧:{finsResult.ResponseFrame}");
  158.             }
  159.         }
  160.         catch (Exception)
  161.         {
  162.             throw;
  163.         }
  164.     }
  165. }
复制代码
Program.cs
  1. internal class Program
  2. {
  3.     static async Task Main(string[] args)
  4.     {
  5.         #region C-Mode方式
  6.         HostLinkCmodeDevice plc1 = new HostLinkCmodeDevice("COM5", 115200, Parity.None, 8, StopBits.One);
  7.         SemaphoreSlim semaphoreSlim_Comm1 = new SemaphoreSlim(1, 1);
  8.         plc1.Connect();
  9.         var Task1 = Task.Run(async () =>
  10.         {
  11.             await semaphoreSlim_Comm1.WaitAsync();
  12.             Stopwatch stopwatch1 = new Stopwatch();
  13.             stopwatch1.Start();
  14.             string str1 = await plc1.TestCommandAsync("123123");
  15.             stopwatch1.Stop();
  16.             Console.WriteLine("TestCommand:");
  17.             Console.WriteLine(str1);
  18.             Console.WriteLine($"花费时间:{stopwatch1.ElapsedMilliseconds}ms");
  19.             semaphoreSlim_Comm1.Release();
  20.         });
  21.         var Task2 = Task.Run(async () =>
  22.         {
  23.             await semaphoreSlim_Comm1.WaitAsync();
  24.             Stopwatch stopwatch1 = new Stopwatch();
  25.             stopwatch1.Start();
  26.             string str1 = await plc1.Read_DMAreaAsync(0, 3);
  27.             stopwatch1.Stop();
  28.             Console.WriteLine("ReadDM:");
  29.             Console.WriteLine(str1);
  30.             Console.WriteLine($"花费时间:{stopwatch1.ElapsedMilliseconds}ms");
  31.             semaphoreSlim_Comm1.Release();
  32.         });
  33.         await Task.WhenAll(Task1, Task2);
  34.         plc1.DisConnect();
  35.         semaphoreSlim_Comm1.Dispose();
  36.         #endregion
  37.         #region FINS-Mode方式
  38.         //HostLinkDevice plc2 = new HostLinkDevice("COM5", 115200, Parity.None, 8, StopBits.One);
  39.         //SemaphoreSlim semaphoreSlim_Comm2 = new SemaphoreSlim(1, 1);
  40.         //plc2.Connect();
  41.         //var Task3 = Task.Run(async () =>
  42.         //{
  43.         //    await semaphoreSlim_Comm2.WaitAsync();
  44.         //    Stopwatch stopwatch2 = new Stopwatch();
  45.         //    stopwatch2.Start();
  46.         //    var list1 = await plc2.ReadCIOBitAsync(100, 0, 3);
  47.         //    stopwatch2.Stop();
  48.         //    Console.WriteLine("Read CIOBit:");
  49.         //    foreach (var item in list1)
  50.         //    {
  51.         //        Console.WriteLine(item);
  52.         //    }
  53.         //    Console.WriteLine($"花费时间:{stopwatch2.ElapsedMilliseconds}ms");
  54.         //    semaphoreSlim_Comm2.Release();
  55.         //});
  56.         //var Task4 = Task.Run(async () =>
  57.         //{
  58.         //    await semaphoreSlim_Comm2.WaitAsync();
  59.         //    Stopwatch stopwatch2 = new Stopwatch();
  60.         //    stopwatch2.Start();
  61.         //    var list1 = await plc2.ReadWRBitAsync(0, 0, 3);
  62.         //    stopwatch2.Stop();
  63.         //    Console.WriteLine("Read WRBit:");
  64.         //    foreach (var item in list1)
  65.         //    {
  66.         //        Console.WriteLine(item);
  67.         //    }
  68.         //    Console.WriteLine($"花费时间:{stopwatch2.ElapsedMilliseconds}ms");
  69.         //    semaphoreSlim_Comm2.Release();
  70.         //});
  71.         //var Task5 = Task.Run(async () =>
  72.         //{
  73.         //    await semaphoreSlim_Comm2.WaitAsync();
  74.         //    Stopwatch stopwatch2 = new Stopwatch();
  75.         //    stopwatch2.Start();
  76.         //    var list1 = await plc2.WriteWRBitAsync(0, 0, 3, "000100");
  77.         //    stopwatch2.Stop();
  78.         //    Console.WriteLine("Write WRBit:");
  79.         //    Console.WriteLine(list1);
  80.         //    Console.WriteLine($"花费时间:{stopwatch2.ElapsedMilliseconds}ms");
  81.         //    semaphoreSlim_Comm2.Release();
  82.         //});
  83.         //await Task.WhenAll(Task3, Task4, Task5);
  84.         //plc2.Disconnect();
  85.         //semaphoreSlim_Comm2.Dispose();
  86.         #endregion
  87.         Console.ReadKey();
  88.     }
  89. }
复制代码
具体项目请自行到控制台测试项目Gitee 仓库查看吧
测试结果

控制台输出图如下:
C-Mode方式
12.png

FINS-Mode方式
13.png


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册