协议说明

HostLink C-mode可以直接通过PC连接欧姆龙PLC,可以直接读取/写入欧姆龙PLC寄存器的协议。

其中分为1对1,以及1对N模式,1对1表示1台PC只能连接一个PLC,1对N表示1台PC可以通过协议连接多个PLC。而1:1与1:N在数据帧上也有所不同,其中1:1不需要带有PLC站号,这点比较好理解,毕竟只有一个PLC就无所谓区别是哪一个PLC了。连接图示如下所示:

命令发送和响应帧描述

数据帧一般包含:

1、起始符 '@'    1byte

2、站号  BCD格式 0-31的数  2byte

3、头部 一般为命令的类型 2byte

4、内容   命令的参数

5、FCS  校验码  对FCS之前的字节数组进行异或  2byte

6、结束码  PLC回复时带有,表示是否有异常

7、结束符  "*/r" 2byte  注意'/r'是回车符,与'/n'是不同的

Command Frame Format

Response Frame Format

C-MODE协议关于分帧的规定

当发送或接受的数据帧超过131字节时,将会对发送和结束的数据帧进行分割,会分割多个不同的帧来进行发送。最后如果不是最后一帧,每个帧的最后一个字符为'\r',用于分割不同的帧。结束的帧与正常的帧一样结尾"*\r"。因为1:1和1:N发送的帧有所不同,故在分帧上发送的字数也不尽相同。我们可以知道1:1有可能会多发一个数。

未发送完成的,即没有Terminator,只有'\r',那么回应方需要先发一个'\r'才会继续发送下一个帧。直到发送了Terminator或接收到Terminator。

PC发送数据时产生分帧时的规定,如下图所示:

PC发送数据时产生分帧时的规定,如下图所示:

C-MODE可以读写的寄存器

C-MODE读取寄存器时的具体协议

读取规则除了RG和RE之外,其他的Memory读取协议都是一样的。这两个的读取可查阅官方文档。

 C-MODE寄存器写  -Monitor模式下才能正确写入

常用的寄存器除了WE之外其他都差不多的帧内容

C#实现协议

读取寄存器部分代码

目前不支持RE,RG。方法主体使用泛型来编写,返回值设计了一个泛型类型表示通讯是否成功、通讯时间、以及读取到的寄存器内容。返回的类型设计为:

    public class HostLinkResult<T> where T : unmanaged{public bool IsSuccessful { get; set; }public IList<T> Results { get; set; }public long CommunicationTime { get; set; }}

方法主体,分为发送命令和解析返回帧。返回帧为16进制的多段字,可以先将及写入Ilist<short>中,在全部写入IList<T>中。

        public HostLinkResult<T> Read<T>(int begin, int length, RegisterType readType) where T : unmanaged{Stopwatch sw = new Stopwatch();sw.Restart();HostLinkResult<T> result = new HostLinkResult<T>();var size = Marshal.SizeOf(default(T));string commandStr = "";commandStr += _firstChar;if (_unitNumber >= 0){commandStr += _unitNumber.ToString("X2");}commandStr += $"{GetReadHeaderCode(readType)}";commandStr += $"{begin:0000}";var registerNumber = (size / 16 * length);  if (registerNumber < 1) registerNumber = 1; //寄存器数量必须大于1commandStr += $"{registerNumber:0000}";Tuple<bool, List<short>> r = SendReadCommand(commandStr, readType);result.IsSuccessful = r.Item1;result.CommunicationTime = sw.ElapsedMilliseconds;if (!r.Item1) return result;byte[] bytes = BytesHelper.StructsToBytes(r.Item2);result.Results = BytesHelper.BytesToStructs<T>(bytes);result.CommunicationTime = sw.ElapsedMilliseconds;return result;}

读取寄存器帧的命令,发送字符串的生成方法SendReadCommand如下:

        /// <summary>/// 处理读取命令  /// </summary>/// <param name="commandStr"></param>/// <returns></returns>private Tuple<bool, List<short>> SendReadCommand(string commandStr, RegisterType readType){commandStr += $"{GetChecksum(commandStr)}";commandStr += "*\r";string resultStr = "";List<short> result = new List<short>();
#if DEBUGWriteToLog($"PC=>PLC\t:{commandStr}");
#endif_serialPort.Write(commandStr);try{string curFrame = "";while (true){curFrame = _serialPort.ReadTo("\r");    //接收到一帧    读后就没有\r了
#if DEBUGWriteToLog($"PLC=>PC\t:{curFrame}");
#endifvar checksum = GetChecksum(curFrame.Substring(0, curFrame.Length - 3));var fcs = curFrame.Substring(curFrame.Length - 3, 2);if (checksum != fcs)//检测校验码{_lastErrorMessage = "The received data FCS error";
#if DEBUGWriteToLog($"Error\t:{_lastErrorMessage}");
#endifreturn new Tuple<bool, List<short>>(false, result);}if (curFrame.IndexOf("*") == -1)  //判断是否是结束符  当前不是结束符{
#if DEBUGWriteToLog($"Info\t:Current frame isn't end.");
#endifresultStr += curFrame.Substring(0, curFrame.Length - 3); //去掉FCS和Terminator fcs效验过留着没用了}else{WriteToLog($"Info\t:Current frame is end.");resultStr += curFrame.Substring(0, curFrame.Length - 3);break;  //这里退出}_serialPort.Write("\r");  //发送一个回车}string errCode = "";if (_unitNumber >= 0){errCode = resultStr.Substring(5, 2);if (!CheckErrorCode(errCode)) return new Tuple<bool, List<short>>(false, result);resultStr = resultStr.Remove(0, 7);  //已经验证过ErrCode 可以把头部去掉}else{errCode = resultStr.Substring(3, 2);if (!CheckErrorCode(errCode)) return new Tuple<bool, List<short>>(false, result);resultStr = resultStr.Remove(0, 5);  //已经验证过ErrCode 可以把都去掉}
#if DEBUGWriteToLog($"resultStr is\t:{resultStr}");
#endifif (readType == RegisterType.TC_Status){foreach (var c in resultStr){result.Add(c == '0' ? (short)0 : (short)1);}}else{for (int i = 0; i <= resultStr.Length - 4; i += 4){result.Add(short.Parse(resultStr.Substring(i, 4), System.Globalization.NumberStyles.HexNumber));}}return new Tuple<bool, List<short>>(true, result);}catch (Exception exp)   //一般是超时的异常{_lastErrorMessage = exp.StackTrace;
#if DEBUGWriteToLog($"Error\t:{_lastErrorMessage}");
#endifreturn new Tuple<bool, List<short>>(false, result);}}

C-MODE写入寄存器的具体代码

写入代码返回比较简单,主要是验证是否正确的写入。具体代码如下

      public bool Write<T>(int begin, IList<T> datas, RegisterType writeType) where T : unmanaged{Stopwatch sw = new Stopwatch();sw.Restart();string commandStr = "";commandStr += _firstChar;if (_unitNumber >= 0){commandStr += _unitNumber.ToString("X2");}commandStr += $"{GetWriteHeaderCode(writeType)}";commandStr += $"{begin:0000}";var bytes = BytesHelper.StructsToBytes(datas);var words = BytesHelper.BytesToStructs<short>(bytes);foreach (var word in words){commandStr += $"{word:X4}";}if (!SendWriteCommand(commandStr, writeType)) return false;else return true;}

读取寄存器帧的命令,发送字符串的生成方法SendWriteCommand如下:

   private bool SendWriteCommand(string commandStr, RegisterType writeType){commandStr += GetChecksum(commandStr);  //添加验证码string reply = "";  //欧姆龙回复的字符串string replyCheckSum = "";string errorCode = "";if (commandStr.Length <= 129){commandStr += "*\r";    //所有要发送的数据_serialPort.Write(commandStr);
#if DEBUGWriteToLog($"PC=>PLC\t:{commandStr}");
#endifreply = _serialPort.ReadTo("\r");
#if DEBUGWriteToLog($"PLC=>PC\t:{reply}");
#endifreplyCheckSum = reply.Substring(reply.Length - 3, 2);if (replyCheckSum != GetChecksum(reply.Substring(0, reply.Length - 3))){_lastErrorMessage = "The received data FCS error";
#if DEBUGWriteToLog($"Error\t:{_lastErrorMessage}");
#endifreturn false;}errorCode = "";if (_unitNumber >= 0)errorCode = reply.Substring(5, 2);else errorCode = reply.Substring(3, 2);
#if DEBUGWriteToLog($"Error code\t:{errorCode}\r");
#endifif (!CheckErrorCode(errorCode)) return false;return true;}else{string firstFrame = "";string residueStr = "";if (_unitNumber > 0){firstFrame = commandStr.Substring(0, 127);  //写入头部和前30个字residueStr = commandStr.Remove(0, 127);}else{firstFrame = commandStr.Substring(0, 125);  //写入头部和前30个字residueStr = commandStr.Remove(0, 125);}firstFrame += GetChecksum(firstFrame + "\r");_serialPort.Write(firstFrame);
#if DEBUGWriteToLog($"PC=>PLC\t:{firstFrame}\r");
#endifwhile (true){reply = _serialPort.ReadTo("\r");if (reply.IndexOf("*") != -1)    //已经是结束帧  其他的帧只是回车符{replyCheckSum = reply.Substring(reply.Length - 3, 2);if (replyCheckSum != GetChecksum(reply.Substring(0, reply.Length - 3))){_lastErrorMessage = "The received data FCS error";
#if DEBUGWriteToLog($"Error\t:{_lastErrorMessage}\r");
#endifreturn false;}errorCode = "";if (_unitNumber >= 0)errorCode = reply.Substring(5, 2);else errorCode = reply.Substring(3, 2);
#if DEBUGWriteToLog($"Error code\t:{errorCode}\r");
#endifif (!CheckErrorCode(errorCode)) return false;return true;}else   //不是结束帧  只回复回车。  没有FCS{string sendCurFrame = "";//需要发送的当前帧if (residueStr.Length / 4 <= 31)   //需要发送的最后一帧  31 * 4 = 124{sendCurFrame = residueStr;  //全部发送sendCurFrame += GetChecksum(sendCurFrame);_serialPort.Write(sendCurFrame + "*\r");WriteToLog($"PC=>PLC\t:{sendCurFrame}");}else{sendCurFrame = residueStr.Substring(0, 124);  //发送31字residueStr.Remove(0, 124);sendCurFrame += GetChecksum(sendCurFrame);_serialPort.Write(sendCurFrame + "\r");WriteToLog($"PC=>PLC\t:{sendCurFrame}");}}}}}

NOTE

由于本人没有欧姆龙PLC做验证,只是在朋友的帮助下验证了几个命令。所以C#代码仅供参考。

欧姆龙PLC HostLink通讯 C-MODE格式相关推荐

  1. MatrikonOPC与欧姆龙PLC以太网通讯

    摘要 MatrikonOPC通过以太网连接欧姆龙CP系列和CJ系列PLC,NET30-CS通讯桥接器为PLC提供以太网通讯接口, 同时支持hostlink.NTLINK.Finstcp和ModbusT ...

  2. 西门子PLC协议转换CIP协议,实现与罗克韦尔/AB、欧姆龙PLC之间通讯

    IGT-DSER智能网关模块支持西门子.三菱.欧姆龙.AB等各种品牌的PLC之间通讯,同时也支持PLC与Modbus协议的工业机器人.智能仪表等设备通讯.网关有多个网口.串口,也可选择WIFI,4G无 ...

  3. 研华webaccess与欧姆龙PLC以太网通讯配置

    摘要 通过研华WebAccess软件实现以太网采集现场设备的实时生产数据和设备状态数据.现场控制器采用欧姆龙CP和CJ系列PLC,以太网通讯模块采用第三方外置即插安装式工业通讯桥接器NET30-CS, ...

  4. 欧姆龙PLC modbusRTU通讯解析(CP1E)

    一 ModbusRTU说明 1.采用ModbusRTU通讯协议,进行读写操作: 2.19200;8,1,N;modubs-rtu简易主站 3.A640.0上升沿启动命令:ON-执行中,OFF-未执行或 ...

  5. 昆仑通态屏与欧姆龙PLC和台达变频器联合控制通讯

    昆仑通态屏与欧姆龙PLC和台达变频器联合控制通讯功能:用触摸屏与欧姆龙PLC进行通讯,同时与变频器直接进行通讯控制,触摸屏做为上位机 配件:昆仑通态触摸屏,欧姆龙CP1H PLC,台达VFD M变频器 ...

  6. 欧姆龙OMRON PLC之HostLink通讯协议(五)- CP1H以太网FINS/TCP通讯实例

    //写在前面: 自2010年起,本人陆续在新浪博客上面发了几篇OMRON PLC的应用笔记,曾经很疑惑阅读量异常增加,后来发现原来是这里有人转载.现将原文照发在这里,希望能帮到做工控的同行朋友们. C ...

  7. OMRON欧姆龙PLC与VB、C#通过以太网(FinsTCP/FinsUDP)、串口(FinsCom/HostLink)、DTU通讯的DLL

    http://blog.sina.com.cn/s/blog_16d7d3ecb0102x3qi.html 1.0 通讯组件概述 通讯组件用于PC与可编程控制器(PLC).智能仪表等进行数据通讯,适用 ...

  8. 欧姆龙CP/CJ系列PLC以太网通讯方案

    欧姆龙CPCJ系列PLC以太网通讯方案 描述: NET30-CS用于欧姆龙CP1E/CP1H/CP1L/CJ1M/CJ2M等系列PLC. NET30-CS 桥接器采用三通设计,不占用PLC通讯口,不对 ...

  9. PLC无线通讯方案,支持西门子,三菱,欧姆龙,台达等各品牌PLC

    在实际项目中,经常有多台PLC之间需要通讯,距离可能从几十米到几千米,也有的客户需要通过互联网来远距离监控PLC的状态. 在这里介绍一种PLC无线通讯的实现方法,采用巨控GRM200系列PLC专用无线 ...

最新文章

  1. Android中获取手机的IMEI
  2. Mysql修复损坏表并写脚本自动修复
  3. MySQL—【加餐1】高效查询方法
  4. E - 数据结构实验之排序五:归并求逆序数
  5. 【PP生产订单】入门介绍(三)
  6. JZOJ 1322. 硬币游戏
  7. SQL Server Compact的DLL文件介绍
  8. 2016-04-25-信息系统实践手记5-CACHE设计一例
  9. 北航计算机组成原理ppt,北航计算机组成原理课件.ppt
  10. 计算机python语言_计算机语言Python解释器
  11. 在线英文翻译中文比较
  12. JS获取本地文件的内容
  13. c# 通过查看注册表的方式来判断电脑安装office的版本
  14. ctf中压缩包隐写经验总结
  15. 厦大C语言上机1382
  16. 《微观经济学》第八章 博弈论与寡头市场初步笔记
  17. C#大文件上传支持切片上传
  18. 基于STM32CubeMX的stm32f103c6t6液晶0.96OLED显示字母数字汉字图片显示
  19. 04.TFT_RGB接口时序分析
  20. ML之VC维:VC维(Vapnik-Chervonenkis Dimension)理论的概述(衡量模型复杂度和预测能力的指标)的简介、案例理解之详细攻略

热门文章

  1. 3、★☛基于STM32的手机通过wifi控LED灯√♠★
  2. 项目开发中之如何对接
  3. 计算机无法显示移动硬盘,电脑不显示移动硬盘怎么办 检测不到移动硬盘的原因...
  4. 从电路交换到分组交换——TDM、ATM
  5. java 算出下一个工作日_如何计算JAVA中两个不同日期之间的工作日(不包括周末)?...
  6. 流密码(一)同步流密码、自同步流密码以及线性反馈移位寄存器
  7. 知网CAJ转PDF(硕博论文带书签)
  8. 如何快速制作微信旅游相册?简单操作,效果精美!
  9. 头歌Python,7号的,作业,
  10. python少儿编程讲师笔试题_小码王教育儿童编程教师面试:做笔试题(填空题和编程题,填空题 - 职朋职业圈...