本文将使用一个Github开源的组件库技术来读写三菱 FX PLC,使用的是基于串口的实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作

github地址:https://github.com/dathlin/HslCommunication 如果喜欢可以star或是fork,还可以打赏支持,打赏请认准源代码项目。

从NUGET安装

Install-Package HslCommunication

准备

本文将展示如何配置网络参数及怎样使用代码来访问PLC数据,希望给有需要的人解决一些实际问题。主要对三菱Fx系列PLC的X,Y,M,S,C,T,D区域的数据读写

此处使用了串口直接的方式

此处使用到了2个命名空间:

using HslCommunication.Profinet.Melsec;

using HslCommunication;

随便聊聊

当我们一个上位机需要读取100台西门子PLC设备(此处只是举个例子,凡是都是使用Modbus tcp的都是一样的)的时候,你采用服务器主动去请求100台设备的机制对性能来说是个极大的考验,如果开100个线程去轮询100台设备,那么性能损失将是非常大的,更不用说再增加设备,如果搭建Modbus tcp服务器,就可以完美的解决性能问题,因为连接的压力将会平均分摊给每一台PLC,服务器端只要新增一个时间戳就可以知道客户端有没有连接上。

我们在100台PLC里都增加发送Modbus tcp方法,将数据发送到服务器的ip和端口上去,服务器根据站号来区分设备。这样就可以搭建一个高性能总站。 本组件支持快速搭建一个高性能的Modbus tcp总站。

关于两种模式

在PLC端,包括三菱,西门子,欧姆龙以及Modbus Tcp客户端的访问器上,都支持两种模式,短连接模式和长连接模式,现在就来解释下什么原理。

短连接:每次读写都是一个单独的请求,请求完毕也就关闭了,如果服务器的端口仅仅支持单连接,那么关闭后这个端口可以被其他连接复用,但是在频繁的网络请求下,容易发生异常,会有其他的请求不成功,尤其是多线程的情况下。

长连接:创建一个公用的连接通道,所有的读写请求都利用这个通道来完成,这样的话,读写性能更快速,即时多线程调用也不会影响,内部有同步机制。如果服务器的端口仅仅支持单连接,那么这个端口就被占用了,比如三菱的端口机制,西门子的Modbus tcp端口机制也是这样的。以下代码默认使用长连接,性能更高,还支持多线程同步。

在短连接的模式下,每次请求都是单独的访问,所以没有重连的困扰,在长连接的模式下,如果本次请求失败了,在下次请求的时候,会自动重新连接服务器,直到请求成功为止。另外,尽量所有的读写都对结果的成功进行判断。

关于日志记录

不管是三菱的数据访问类,还是西门子的,还是Modbus tcp访问类,都有一个LogNet属性用来记录日志,该属性是一个接口类,ILogNet,凡事继承该接口的都可以用来记录日志,该日志会在访问失败时,尤其是因为网络的原因导致访问失败时会进行日志记录(如果你为这个 LogNet属性配置了真实的日志记录器的话):如果你想使用该记录日志的功能,请参照如下的博客进行实例化:

访问测试项目

下面的一个项目是这个组件的访问测试项目,您可以进行初步的访问的测试,免去了您写测试程序的麻烦,三菱的界面和西门子的界面几乎是一致的。可以同时参考。该项目位于本篇文章开始处的Gitbub源代码里面的

演示项目,和本串口的信息无关

下面的演示了具体如何去访问PLC的数据,我们在访问完成后,通常需要进行处理,以下的示例项目就演示了后台从PLC读取数据后,前台显示并推送给所有在线客户端的功能,客户端并进行图形化显示,具有一定的参考意义,并且推送给网页前端,项目地址为:

它应该和PLC直接连接并接入局域网,然后把数据推送给客户端显示。注意:一个复杂高级的程序就应该把处理逻辑程序和界面程序分开,比如这里的服务器程序实现数据采集,推送,存储。让客户端程序去实现数据的整理,分析,显示,这样即使客户端程序因为BUG奔溃,服务器端仍然可以正常的工作。

初始化访问PLC对象

如果想使用本组件的数据读取功能,必须先初始化数据访问对象,根据实际情况进行数据的填入。 下面仅仅是测试中的数据:

MelsecFxSerial melsecFx = new MelsecFxSerial( );

melsecFx.SerialPortInni( sp =>

{

sp.PortName = "COM1";

sp.BaudRate = 9600;

sp.DataBits = 7;

sp.StopBits = System.IO.Ports.StopBits.One;

sp.Parity = System.IO.Ports.Parity.Even;

} );

melsecFx.Open( );

串口的初始化操作一定要正确

关于地址的表示方式

使用字符串表示,这个组件里所有的读写操作提供字符串表示的重载方法,所有的支持访问的类型对应如下,字符串的表示方式存在十进制和八进制的区别:

输入继电器:"X10", "X17"               // 字符串为八进制机制

输出继电器:"Y10" , "Y17"              // 字符串为八进制机制

内部继电器:"M100", "M200"          // 字符串为十进制

步进继电器:"S100" , "S200"          // 字符串为十进制

数据寄存器:"D100", "D200"           // 字符串为十进制

计数寄存器:"C100" , "C200"          // 字符串为十进制

定时寄存器:"T100" , "T200"           // 字符串为十进制

展示一些简单实用基础数据读写,这些数据的读写没有进行严格的是否成功判断(判断方法参照后面的代码),一般网络良好的情况下都会成功,但不排除失败,以下代码仅作测试,所有没有严格判断是否成功:

// 此处以D寄存器作为示例

short short_D1000 = melsecFx.ReadInt16( "D100" ).Content; // 读取D1000的short值

ushort ushort_D1000 = melsecFx.ReadUInt16( "D100" ).Content; // 读取D1000的ushort值

int int_D1000 = melsecFx.ReadInt32( "D100" ).Content; // 读取D1000-D1001组成的int数据

uint uint_D1000 = melsecFx.ReadUInt32( "D100" ).Content; // 读取D1000-D1001组成的uint数据

float float_D1000 = melsecFx.ReadFloat( "D100" ).Content; // 读取D1000-D1001组成的float数据

long long_D1000 = melsecFx.ReadInt64( "D100" ).Content; // 读取D1000-D1003组成的long数据

ulong ulong_D1000 = melsecFx.ReadUInt64( "D100" ).Content; // 读取D1000-D1003组成的long数据

double double_D1000 = melsecFx.ReadDouble( "D100" ).Content; // 读取D1000-D1003组成的double数据

string str_D1000 = melsecFx.ReadString( "D100", 10 ).Content; // 读取D1000-D1009组成的条码数据

// 读取数组

short[] short_D1000_array = melsecFx.ReadInt16( "D100", 10 ).Content; // 读取D1000的short值

ushort[] ushort_D1000_array = melsecFx.ReadUInt16( "D100", 10 ).Content; // 读取D1000的ushort值

int[] int_D1000_array = melsecFx.ReadInt32( "D100", 10 ).Content; // 读取D1000-D1001组成的int数据

uint[] uint_D1000_array = melsecFx.ReadUInt32( "D100", 10 ).Content; // 读取D1000-D1001组成的uint数据

float[] float_D1000_array = melsecFx.ReadFloat( "D100", 10 ).Content; // 读取D1000-D1001组成的float数据

long[] long_D1000_array = melsecFx.ReadInt64( "D100", 10 ).Content; // 读取D1000-D1003组成的long数据

ulong[] ulong_D1000_array = melsecFx.ReadUInt64( "D100", 10 ).Content; // 读取D1000-D1003组成的long数据

double[] double_D1000_array = melsecFx.ReadDouble( "D100", 10 ).Content; // 读取D1000-D1003组成的double数据

写入操作

// 此处以D寄存器作为示例

melsecFx.Write( "D100", (short)1234 ); // 写入D1000 short值 ,W3C0,R3C0 效果是一样的

melsecFx.Write( "D100", (ushort)45678 ); // 写入D1000 ushort值

melsecFx.Write( "D100", 1234566 ); // 写入D1000 int值

melsecFx.Write( "D100", (uint)1234566 ); // 写入D1000 uint值

melsecFx.Write( "D100", 123.456f ); // 写入D1000 float值

melsecFx.Write( "D100", 123.456d ); // 写入D1000 double值

melsecFx.Write( "D100", 123456661235123534L ); // 写入D1000 long值

melsecFx.Write( "D100", 523456661235123534UL ); // 写入D1000 ulong值

melsecFx.Write( "D100", "K123456789" ); // 写入D1000 string值

// 读取数组

melsecFx.Write( "D100", new short[] { 123, 3566, -123 } ); // 写入D1000 short值 ,W3C0,R3C0 效果是一样的

melsecFx.Write( "D100", new ushort[] { 12242, 42321, 12323 } ); // 写入D1000 ushort值

melsecFx.Write( "D100", new int[] { 1234312312, 12312312, -1237213 } ); // 写入D1000 int值

melsecFx.Write( "D100", new uint[] { 523123212, 213, 13123 } ); // 写入D1000 uint值

melsecFx.Write( "D100", new float[] { 123.456f, 35.3f, -675.2f } ); // 写入D1000 float值

melsecFx.Write( "D100", new double[] { 12343.542312d, 213123.123d, -231232.53432d } ); // 写入D1000 double值

melsecFx.Write( "D100", new long[] { 1231231242312, 34312312323214, -1283862312631823 } ); // 写入D1000 long值

melsecFx.Write( "D100", new ulong[] { 1231231242312, 34312312323214, 9731283862312631823 } ); // 写入D1000 ulong值

读取Bool示例:

// 以下是简单的读取,没有仔细校验的方式

bool X1 = melsecFx.ReadBool( "X1" ).Content;

bool[] X1_10 = melsecFx.ReadBool( "X1", 10 ).Content;

// 如果需要判断是否读取成功

OperateResult R_X1 = melsecFx.ReadBool( "X1" );

if (R_X1.IsSuccess)

{

// success

bool value = R_X1.Content;

}

else

{

// failed

}

OperateResult R_X1_10 = melsecFx.ReadBool( "X1", 10 );

if (R_X1_10.IsSuccess)

{

// success

bool x1 = R_X1_10.Content[0];

bool x2 = R_X1_10.Content[1];

bool x3 = R_X1_10.Content[2];

bool x4 = R_X1_10.Content[3];

bool x5 = R_X1_10.Content[4];

bool x6 = R_X1_10.Content[5];

bool x7 = R_X1_10.Content[6];

bool x8 = R_X1_10.Content[7];

bool x9 = R_X1_10.Content[8];

bool xa = R_X1_10.Content[9];

}

else

{

// failed

}

写入单个的bool,不支持批量写入

// 以下是简单的写入,没有仔细校验的方式

melsecFx.Write( "M100", true );

// 如果需要判断是否读取成功

OperateResult write1 = melsecFx.Write( "M100", true );

if (write1.IsSuccess)

{

// success

}

else

{

// failed

}

更多的操作和细节可以参照DEMO项目和源代码项目。

串口调试助手读写三菱fx3u数据_C#读写三菱Fx PLC 使用Fx 串口协议 读写Fx3U设备相关推荐

  1. python读写磁盘扇区数据_C++-如何直接读取Windows磁盘扇区的数据?

    1.通过CreateFile系列来完成 读写扇区可以通过CreateFile打开磁盘逻辑分区,还要通过SetFilePointer以文件操作的方式把指针移到要操作的磁盘扇区开始处,在定位到要访问的扇区 ...

  2. 串口调试助手读写三菱fx3u数据_通过FX3U-485-BD实现PLC和计算机的RS485通信

    在挑残机项目中,主站需要记录PLC(FX3U-128MT)的错误报警信息,故需要在PLC和主站PC间进行通信,且PLC和主站PC间距离较长,考虑到RS232最远通信距离为15m不能达到我们的要求,在本 ...

  3. 计算机串口无法发数,单片机向电脑发送数据,为什么串口调试助手收不到数据 求助...

    试试我这个 #include #define uint unsigned int #define uchar unsigned char #define BAUD 9600 #define XTAL ...

  4. 串口调试助手读写三菱fx3u数据_用电脑通过串口(RS485)给三菱PLC(FX3U)发指令,怎样在梯形图里写接收串口数据的程序?...

    展开全部 在PLC参数中设置串口参数.起始符和停止符.具体设e68a8462616964757a686964616f31333431373334置方法是:定义起始符02H,定义停止符为回车或其他即可. ...

  5. opc读取ab的plc数据_C#读写 AB PLC 直接通过节点来读写数据 读写 AllenBradley PLC

    本文将使用一个Github开源的组件库技术来读写AB PLC,使用的是基于以太网的实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 本类库绝对是ab最 ...

  6. ATECC508A芯片开发笔记(九):加密读写508芯片数据的流程及相应设置

    目录 ATECC508A芯片开发笔记(九):加密读写508芯片数据的流程及相应设置 1.Encrypted Read 1.1 Standard Encrypted Read Flow 1.2 Simp ...

  7. pandas读写结构化数据(read_csv,read_table, read_excel, read_html, read_sql)

    pandas读写结构化数据(read_csv,read_table, read_excel, read_html, read_sql) 如果你不知道pandas目前提供的读取数据的API或者自己在当前 ...

  8. python里读写excel等数据文件的6种常用方式

    下面整理下python有哪些方式可以读取数据文件. 1. python内置方法(read.readline.readlines) read() : 一次性读取整个文件内容.推荐使用read(size) ...

  9. python读excel 包含格式_python里读写excel等数据文件的几种常用方式

    python处理数据文件第一步是要读取数据,文件类型主要包括文本文件(csv.txt等).excel文件.数据库文件.api等. 下面整理下python有哪些方式可以读取数据文件. 1. python ...

最新文章

  1. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用原型链和EventTrigger
  2. python 获取当前ip
  3. 如何开发auto complete 智能提示功能
  4. 怎么修改_论文查重之后怎么修改?
  5. 计算机与在勘察地质中的应用,地质勘察中计算机信息技术的应用
  6. 还在头痛被黑客劫持? 五步帮你摆脱烦恼!
  7. C语言——知识点汇总
  8. Arduino驱动MAX30102踩坑记
  9. class CText{}; CText t; int const CText::*p; 什么意思?
  10. 使用Java生成思维导图
  11. ZBrush中的法线贴图你知道吗?
  12. windows不是正版_你的电脑win10系统是正版吗?教你四步测试
  13. linux同步webdav,基于 WebDAV 的 安卓 与 Linux 之间的写作同步
  14. C语言----隐藏代码文件
  15. 苹果发布2019款iPad mini/Air:配A12芯片支持手写笔
  16. 【python】牛顿迭代法求解多元函数的最小值--以二元函数为例
  17. odoo小程序商城概览(睿鸥商城)
  18. 关于超级计算机的英语作文,关于无人驾驶的英文作文
  19. 如何将图片批量重命名001开始?
  20. Blender 人物模型多边形建模

热门文章

  1. 人力成本是如何蚕食企业利润的?如何破解高成本和改善盈利能力?
  2. WordPress主题美食餐厅主题
  3. day24_雷神_django项目部署
  4. 易语言操作数据库之EDB数据库
  5. fix协议的服务器,FIX 协议开发(3):QuickFIX/J 实战经验小结
  6. quartz定时任务(数据库需要的表)
  7. 云服务器部署安全组开放端口小结
  8. 【grpc】项目启动缺少grpc架包引用
  9. 本地ISO文件作为YUM源
  10. STC89C52:快速搭建与IO