ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

汇川EASY系列PLC以太网Socket主站通讯实现思路与实战详解

汇川EASY系列PLC以太网Socket主站通讯实现思路与实战详解 把汇川EASY系列PLC的以太网通讯做成socket主站这件事值得好好聊一聊。我当年第一次在EASY系列上跑通socket客户端时最大的感受是原来汇川小PLC也能干这么“上位机”的活儿。现在不少现场项目里设备数据要进MES、要传给数据库、要跟第三方视觉或扫码枪对接如果只有Modbus TCP一条路很多时候会被对方的数据格式或主动交互需求卡住。而socket主站方案可以直接按对方的协议发包、收包、解析自由度完全在你自己手里。这篇文章会把EASY系列做socket主站的完整思路写清楚包括为什么用主站而不是从站、网络规划要注意什么、程序结构怎么搭、代码怎么写、参数怎么算以及我实际踩过的坑。适合正在搞汇川小型PLC以太网通讯、需要和设备/上位机做自定义协议对接的工程师参考也适合刚接触socket通讯、对TCP/UDP还没完全建立概念的人先通一遍底层的逻辑。1. 为什么EASY系列通讯要选socket主站方案很多人在汇川EASY系列上做以太网通讯第一反应是走Modbus TCP。Modbus TCP确实简单从站和主站都有现成功能块数据映射也方便。但实际项目里你会发现一个很现实的问题不是所有设备都愿意做Modbus TCP从站。比如你对接一套相机视觉系统供应商只提供了基于TCP的JSON或XML字符串协议比如对接一个MES的OPC UA网关对方要求你用固定端口主动建立连接然后周期性上传JSON文本再比如对接WCS调度系统它要求上位机作为服务端你来连它。这些场景下Modbus TCP根本不够用你需要的是通用的、能自定义报文内容的TCP客户端或服务端能力。所谓socket主站通俗地讲就是PLC主动创建socket、主动连接远端服务器、主动发包收包。对应到汇川EASY系列上就是把传统上位机里的socket网络编程搬到PLC里做。EASY系列基于Codesys平台本身支持标准库函数所以TCP client/UDP send这些操作在指令层面都可以实现。选主站方案的另一个逻辑是主动性。做主站意味着通讯节奏由你控制什么时候发、多久发一次、断线后多久重新连、重连多少次都写在PLC的状态机里。而做从站的话主动权在对方手里对方不连接你的话你连排查都只能干等。对一个需要稳定运行的设备来说把主动权握在自己手上比什么都重要。此外EASY系列做socket主站还有一个隐形的优势可以实现多目标交互。PLC可以作为TCP客户端同时连接多个服务器比如一个给数据库网关发数据一个接收视觉结果完全靠本地端口区分通讯链路。这种结构如果靠Modbus TCP叠加配置会非常绕。一句话总结如果对方的设备只支持自定义TCP/UDP报文或者你想主动发起通讯并控制重连节奏就一定要用socket主站方案。EASY系列完全具备这个能力而且实现起来没有想象中那么复杂。2. 搞定EASY系列socket主站的软件与硬件基础2.1 硬件选型与端口确认汇川EASY系列目前主流的几个型号比如EASY521、EASY321、EASY322等本体都带有以太网口大部分支持socket通讯。但要注意不同型号的固件和库支持程度有差异。比如有些早期固件版本socket相关的扩展指令不完整或者对并发连接数有限制。选型时优先选固件版本较新、带以太网口且确认支持网络通讯指令的型号。另外一个很关键的点EASY系列支持几个socket连接以汇川官方常见规格来看一般支持4到8个连接取决于型号和库版本。实际项目里别把连接数用满因为TCP异常断线时连接不会立刻释放如果连接数耗尽其他设备就再也连不上了。我自己的习惯是一个PLC最多规划2到3个socket连接留出冗余。2.2 软件环境InoProShop与库文件EASY系列的编程软件是InoProShop这个软件基于Codesys内核开发整体操作逻辑跟Codesys V3系列很像。新建工程时选择对应的EASY系列CPU型号编程语言用ST或FBD都可以socket通讯的逻辑建议用ST编写因为状态机、字节处理和异常分支用ST代码更顺手。关键的一步是添加与socket相关的库文件。在InoProShop里EASY系列默认的库可能不包含直接可拖拽的TCP Client指令块需要从库管理器添加。常见的库包括CAA Socket库Codesys的通用socket实现汇川封装的NetClient库或TCP通讯库不同软件版本库里名称略有差别SysCom或SysLibSocket等系统级通讯库库的添加路径一般是工程树里的“库管理器” - 右键“添加库” - 搜索“Socket”或“Net”关键词 - 选择与固件版本匹配的库文件。这里有个容易踩的坑库版本选太高或太低编译时会报一堆函数找不到的错误。我的建议是优先选择随软件版本自动匹配的默认库不要手动下载最新库强行加进老工程。2.3 网络规划里的常见雷区EASY系列通过网线直连或交换机连接上位机/服务器这块听起来简单但在现场经常出问题。首先是IP段的规划。如果PLC、上位机、服务器不在同一个网段socket通讯直接失败。我的建议是在项目设计阶段就统一规划IP地址PLC用固定IP比如192.168.1.10上位机服务器用192.168.1.100不要用DHCPPLC里设固定IP最稳妥。其次是防火墙。如果上位机或服务器有Windows防火墙并拦截了未授权的入站连接PLC发出去的connect请求就是石沉大海。所以调试时第一件事就是把两端防火墙全部关掉测试通了之后再把必要端口加白名单。第三是网关。如果PLC要跨网段访问服务器需要配置默认网关如果只是同一交换机下的局域网通讯不配网关也没问题。EASY系列的IP配置在系统参数里的“以太网”页面注意改IP后要重启PLC才会生效。我自己调试时习惯准备一根网线直连PLC和电脑先把最简单的通讯跑通再接交换机、接服务器层层递进出了问题也好定位。3. 从0开始搭建一套PLC socket主站通讯框架3.1 通讯指令的基本结构与调用关系EASY系列做socket主站常用的指令块大致分几类连接类用于创建socket、设置IP和端口、发起连接请求。一般包括SocketCreate、SocketConnect或TCP_Client、TCPConnect等。数据收发类用于发送缓冲区和接收缓冲区数据比如SocketSend、SocketReceive、TCP_Send、TCP_Receive。状态检测与关闭类用于检测连接状态、获取错误码、关闭socket比如SocketClose、TCP_Close、SocketError等。不同厂商封装的指令名字可能不同但逻辑是相同的。重点不是记住具体指令名而是理解整个动作序列创建socket - 绑定/设置远端地址 - 发起连接 - 等待连接成功 - 进入周期性的收发流程 - 断线重连或主动关闭。从时序上看socket主站通讯不是像Modbus轮询那样简单调一个功能块就能完成它往往需要一个状态机的调度。原因是connect是非阻塞或半阻塞的过程你调用连接指令后不可能原地等它连接成功必须让PLC程序周期扫描在后续扫描周期里去查询连接状态。3.2 状态机设计思路我在EASY系列上实现socket主站状态机大致分成这么几个状态空闲IDLE状态初始化参数置位创建请求跳转到创建状态。创建状态SOCKET_CREATE调用创建socket指令创建成功后跳转到连接状态失败则记录错误并回到空闲。连接状态CONNECTING调用连接指令之后不要反复调用连接指令而是在每个周期检查连接状态变量。连接成功跳转到在线通讯状态失败或者超时则跳转到关闭状态然后延时后重新发起连接。在线通讯状态ONLINE周期性执行数据发送、接收、解析。同时监控连接状态如果检测到连接断开跳转到关闭状态。关闭状态CLOSE调用关闭指令关闭socket清空连接句柄延时后回到空闲状态准备下一次重连。这个状态机看似简单但实际价值极大。它保证了一点socket生命周期的每个动作都有明确的入口和出口不会出现在连接未建立时去收发数据、或者在socket未释放时反复创建新socket的问题。3.3 代码结构示例ST语言实现下面用ST语言写一个最简可用的socket主站框架。假设库里的插入方式是通过功能块调用代码里用的函数名参考汇川常见NetClient库格式实际使用时以你工程中的库定义为准。程序变量区VAR byState : BYTE : 0; (* 0-空闲/1-创建/2-连接/3-在线/4-关闭 *) hSocket : DWORD : 0; (* socket句柄 *) bConnectStart : BOOL : FALSE; (* 发起连接触发位 *) bManualClose : BOOL : FALSE; (* 手动关闭触发位 *) bOnline : BOOL : FALSE; (* 在线状态标志 *) wSendBuffer : ARRAY[0..99] OF BYTE; (* 发送缓冲区 *) wRecvBuffer : ARRAY[0..255] OF BYTE; (* 接收缓冲区 *) wRecvNum : WORD : 0; (* 实际接收字节数 *) wSendLen : WORD : 0; (* 待发送字节数 *) sServerIP : STRING : 192.168.1.100; dwServerPort : DWORD : 5020; stClient_Connect : Client_Connect; stClient_Send : Client_Send; stClient_Receive : Client_Receive; stClient_Close : Client_Close; stConnResult : INT; stTimer : TON; bTimeOut : BOOL : FALSE; END_VAR主程序框架CASE byState OF 0: (* 空闲状态 *) IF bConnectStart THEN byState : 1; END_IF 1: (* 创建socket *) stClient_Connect.bExecute : FALSE; IF hSocket 0 THEN (* 调用创建函数假设CreateSocket在内部完成仅在函数返回成功时给句柄 *) stClient_Connect.sIP : sServerIP; stClient_Connect.dwPort : dwServerPort; stClient_Connect.bExecute : TRUE; END_IF IF stClient_Connect.bActive THEN byState : 2; END_IF 2: (* 连接状态 *) stClient_Connect.bExecute : TRUE; IF stClient_Connect.bError THEN byState : 4; END_IF IF stClient_Connect.bConnected THEN hSocket : stClient_Connect.hSocket; bOnline : TRUE; byState : 3; END_IF 3: (* 在线通讯状态 *) IF bManualClose OR stClient_Connect.bDisconnected THEN bOnline : FALSE; byState : 4; END_IF (* 周期性发送 *) IF bHaveDataToSend THEN stClient_Send.hSocket : hSocket; stClient_Send.pData : ADR(wSendBuffer); stClient_Send.dwLen : wSendLen; stClient_Send.bExecute : TRUE; END_IF (* 接收数据 *) stClient_Receive.hSocket : hSocket; stClient_Receive.pData : ADR(wRecvBuffer); stClient_Receive.dwMaxLen : SIZEOF(wRecvBuffer); stClient_Receive.bExecute : TRUE; IF stClient_Receive.bActive THEN wRecvNum : stClient_Receive.dwRecv; (* 实际收到的字节数 *) (* 解析数据 *) END_IF 4: (* 关闭状态 *) stClient_Close.hSocket : hSocket; stClient_Close.bExecute : TRUE; hSocket : 0; bOnline : FALSE; stTimer(IN:TRUE, PT:T#3S); IF stTimer.Q THEN stTimer(IN:FALSE); byState : 0; END_IF END_CASE这段代码不是照抄某个现成工程而是提炼出一个通用的框架。核心思想就是每个状态做且只做该状态该做的事情。连接成功后在线状态里每次扫描都去调接收功能块发送则按你自己的节拍控制。3.4 数据缓冲区与字节顺序处理socket通讯的底层是字节流所以PLC内部的数据发出去之前必须转换成字节数组收到的字节数组也要按双方约定的格式解析回变量。这里往往是新手最容易翻车的地方。比如PLC内部一个REAL类型变量你要发到上位机。REAL在内存中占4字节直接发送的话上位机收到的可能是“大端”或“小端”排列取决于PLC的字节序以及你组包的方式。多数情况下汇川PLC内部按小端存放即低字节在前。而很多上位机协议尤其是Modbus、MQTT、JSON序列化之后则是大端传输。所以你需要做字节交换。我的经验是不要依赖PLC底层字节序而是自己写一组打包/拆包函数。例如把REAL转4个BYTE再按协议顺序放入发送缓冲区收到4个BYTE再合成REAL。这样无论两端字节序如何上层逻辑都清清楚楚。一个简单的REAL转四字节并反序的例子STPROGRAM PackReal VAR_INPUT Value : REAL; END_VAR VAR_OUTPUT ByteOut : ARRAY[0..3] OF BYTE; END_VAR VAR pData : POINTER TO BYTE; i : INT; END_VAR pData : ADR(Value); FOR i : 0 TO 3 DO ByteOut[i] : pData[i]; END_FOR (* 如果需要大端则反序输出 ByteOut[0]..ByteOut[3] *)反过来收到四字节后拼REAL用MEMCPY或者指针复制都可以。另一个容易忽略的是字符串。上位机协议里很多字段是ASCII字符串或十六进制字符串PLC里STRING变量直接发送时会带上长度字节或结尾的0x00。对方如果按固定长度解析就会错位。最好的方式是先根据协议确认为定长字符串还是变长字符串再决定要不要裁剪或补空格。4. 参数计算与报文设计以及实用技巧4.1 通讯周期怎么定socket主站的通讯周期不像Modbus轮询那样由硬件定时器决定而是由你的程序扫描周期和定时发送逻辑共同决定。如果PLC扫描周期是5ms而你每周期都发送一次数据那每秒200包的发送频率其实已经很高了。但TCP的带宽和服务器处理能力未必需要这么高而且高频发送会把CPU时间片大量耗在组包和拷贝上。我通常的做法是高速实时类数据如伺服位置、IO状态建议10ms到20ms发一次中速过程类数据如温度、压力、报警状态100ms或500ms发一次低频配置文件或诊断信息1秒到5秒发一次。设计中建议把心跳报文与数据报文分开。心跳报文只包含设备ID和状态位数据报文才带实际过程数据。这样服务器能很方便地区分“设备在线但没新数据”和“设备下线”的区别。4.2 报文帧格式推荐自定义socket通讯报文最怕的是边界不明。TCP是流式传输接收方不知道一帧数据从哪里开始、在哪里结束所以必须定义好帧格式。我推荐一种经典结构起始符比如0xAA55 报文长度2字节 设备ID2字节 数据类型1字节 数据区N字节 校验2字节CRC16 结束符0x0D 0x0A这个结构的好处是上位机和PLC都能靠起始符找头、靠长度字段跳帧、靠校验过滤脏数据。即使网络里混入干扰包或粘包也能自恢复。长度字段很重要建议只计算“长度字段之后、结束符之前”的字节数这样解析时容易统一处理。CRC16可以选择Modbus CRC16算法它非常成熟PLC里实现起来也不复杂。4.3 心跳机制与断线重连参数TCP连接本身并不能实时感知物理链路的中断比如网线被拔掉或者对端断电本端可能要几分钟后才会在发送数据时感知到。所以socket主站通讯一定要设计心跳和断线检测。心跳有两种方式一种是PLC主动周期发心跳另一种是设定接收超时时间即如果超过N秒没收到任何数据就认为链路异常主动关闭socket并重连。我强烈建议两种同时用。超时时间设置一般设3到5秒。太短会因为瞬时网络延迟造成误判太长又会导致故障发现太慢。心跳周期一般是1到2秒。如果上位机本来就周期性下发数据心跳可以直接合并到数据接收里不需要单独再发。重连延时我习惯设3秒。断开后延时3秒再重新发起连接避免高频重连打爆服务器和PLC自身的socket资源。同时要加一个重连次数上限比如连续重连10次失败后置一个通讯故障报警提醒现场人员检查网络或服务器。4.4 双端故障判断服务器死机了怎么办如果服务器端程序崩溃或者设备掉电PLC端的socket连接不会立刻消失。这时PLC发送数据可能成功因为数据进了系统缓冲区但服务器没有任何反应。所以单靠TCP连接状态无法准确判断业务是否健康。我的做法是业务层再加一层应答机制。每条数据报文带唯一序列号服务器处理并返回相同序列号的ACK。PLC连续发送N次都没收到对应ACK就判定服务器业务异常执行断线重连或报警。这一套机制在对接MES、WCS等第三方系统时非常管用。应答超时时间要根据最长的业务处理时间设定比如服务器处理一条数据可能要几百毫秒到1秒那ACK超时设2秒比较合理。4.5 与触摸屏/上位机同时通讯的方案用EASY系列做socket主站不代表以太网口只能干这一件事。汇川的Ethernet口可以同时支持HMI连接、编程调试、Modbus TCP从站以及socket主站。但要注意多任务共用同一个网口时通讯性能会相互影响。比如有人在InoProShop里在线监控程序时数据量会增大socket的通讯延迟会变高。实际项目中我通常把HMI放在一个独立网段的口上如果PLC有多网口或者让HMI直接跟PLC的编程口通讯把以太网口专门留给socket主站。如果只有一个网口且必须同时承担HMI和socket主站建议把socket的发送周期调大一点避免以太网带宽被频繁占满。5. 常见问题、实测经验与排查技巧5.1 连接不上服务器报错怎么排查socket主站通讯中最常见的就是“连接失败”或“连接超时”。遇到这类问题我建议按下面的顺序排查不要上来就改代码。先确认物理链路。网线是否完好、交换机的指示灯是否亮、IP是否冲突。一个很笨但很有效的办法用电脑替代PLC测试服务器是否正常监听端口。如果电脑上用一个TCP调试工具都能连上那问题大概率在PLC侧如果电脑也连不上就别折腾PLC了去查服务器和网络。再确认PLC侧指令执行状态。连接失败后读取功能块的错误代码或状态位把错误码转换成文本打印在HMI上或通过调试监视。常见错误包括目标服务器不存在、端口未开放、连接超时、请求被丢弃。最后确认防火墙和安全策略。服务器如果是Windows系统检查入站规则是否放行了目标端口服务器上的杀毒软件也可能误拦截PLC的IP。还有一类比较隐蔽的情况是服务器上只有一个网卡但配置了多个IPPLC连了其中一个之间路由不通。5.2 连接正常但收不到数据连接是通的而且PLC的发送指令也执行成功但PLC就是收不到任何数据。这种问题大多是协议层面而非网络底层的故障。首先检查服务器是否真的收到了PLC发的数据。在服务器端用抓包工具或日志观察。如果服务器收到了但没有回数据说明问题在对方的业务逻辑或报文解析上。其次是报文格式问题。对方按长度或固定偏移解析你的报文长度对不上服务器可能直接丢弃了连错误都不返回。检查报文长度字段是否包含了所有应含的字节结束符是否正确CRC校验是否通过。还有一种玄学情况PLC接收功能块每周期都调用但返回的接收字节数一直是0。这种情况要考虑是否socket接收缓冲区没有及时处理或者接收区被填满后溢出。解决方法是每次接收完成后清空接收标志并对接收缓冲区设置合理上限避免长年累月不读取导致缓冲溢出。5.3 断线之后重连不上很多项目调试时第一个坑是“重连不上”。前面连接正常中间人为拔网线或重启服务器等网络恢复后PLC再也不主动重连了。这里面十有八九是socket句柄没有正确释放。TCP连接在断开后系统不会立刻释放句柄和端口资源操作系统一般要等待一段时间2到4分钟确保网络上残留的数据包被清空。如果你在重连时没有走“关闭并销毁socket句柄”这一步而是直接再次调用创建连接功能块那么底层的创建socket函数可能返回错误或者绑定同一个本地端口时报“端口被占用”之类的异常。正确做法是检测到连接断开后首先调用关闭功能块等关闭指令完成、socket句柄归零再等待一个延时1到3秒重新发起创建。不要在关闭动作还没完成时就直接重新连接。另外重连间隔建议使用随机或抖动延时。比如固定3秒延时加上0到1秒的随机抖动可以避免多个PLC同时重启后在同一时刻一起涌向服务器造成瞬时压力。5.4 bind报错only one usage of each socket address如果你在调试过程中碰到类似“bind: only one usage of each socket address (protocol/network address/port)”这样的错误信息恭喜你socket通讯中很经典的端口占用问题被你遇到了。这个错误并不是EASY系列特有的在C/C、Java、Python上位机、以及PLC内部Socket库中都会出现。原因是同一个IP地址和端口组合已经被另一个socket占用了。比如你的PLC作为客户端每次连接使用一个本地端口如果上次断开后端口未被释放再次创建socket绑定该端口时系统就会拒绝。应对方案有两个层面。第一层是代码层确保关闭socket时真正完成了close动作等待系统回收。第二层是设计层在创建socket时设置SO_REUSEADDR地址重用选项这样即使前一个socket还未完全释放也能绑定同一端口。但注意PLC的socket库不一定开放这个选项所以更稳妥的还是不要频繁创建socket而是尽量复用同一个连接只有断开后才重建。如果错误出现在上位机或第三方通信库的日志里那大概率是那个程序的socket没有释放或没有设置SO_REUSEADDR。这种情况下要么修改上位机代码要么重启上位机程序释放端口要么在操作系统层查看哪些端口被占用用命令找到进程后排查。我自己的经验是PLC侧尽量避免使用固定本地端口让系统自动分配更省心。如果一定要固定端口则必须在断开后加入足够长的重连延时给系统留出端口回收时间。5.5 实测100ms周期连接300台设备的经验最后分享一个验证过的小经验。我之前一个项目里EASY系列PLC作为socket主站同时规划了最多4个连接一个接MES数据网关一个接视觉检测系统一个作为心跳上报一个作为远程固件或参数下载通道。实际稳定运行下来每个连接的通讯周期设100msCPU占用率和扫描周期几乎没受到太大影响。但是前提是组包的效率要高不要在ST里用大量字符串拼接类操作尽量用字节数组指针操作。扫描周期保持在5ms左右网络波动时偶发的重连也能在3秒内自动恢复。所以EASY系列做socket主站绝不是“小马拉大车”只要协议设计和状态机逻辑清晰它完全可以承担现场设备与信息化系统之间的关键通讯任务。5.6 常见问题速查表下面这张表汇总了我在汇川EASY系列socket主站通讯中遇到的高频问题附带处理方向方便你现场快速定位。现象常见原因处理方向连接失败/超时网段不通、IP错误、服务器未启动、防火墙拦截先电脑测试端口通断再查PLC侧错误码连接成功但收不到数据报文格式不符、服务器未回包、校验错、接收缓冲溢出抓包对比报文长度和字段检查CRC确认接收缓冲上限收发数据乱码字节序不一致、字符串定长/变长不匹配、浮点解析方式不一致统一大小端规则编写独立的打包/拆包函数断线后不重连socket句柄未释放、本地端口未回收、重连延时太短确保关socket完成后延时3秒再重建重建前句柄归零连接数不足模型限制连接数为4~8异常断线占用句柄定期巡检连接数主动清理无效连接留出冗余系统卡顿/扫描周期变长收发频率过高、组包代码低效、在线监控抢资源降低发送频率避免每周期大量字符串操作组包用字节指针这些问题的排查思路其实和上位机socket编程非常相似。PLC里的socket无非是把socket函数封装成了功能块但底层机制依然是TCP四次握手、TIME_WAIT、SO_REUSEADDR这些细节。懂通讯原理的人换到PLC平台照样能快速定位问题这就是我为什么建议做自动化的人一定要学一点socket网络编程的原因。6. 一个可以“抄作业”的最小工程结构和执行清单如果你现在就要在EASY系列上开发socket主站建议按照下面的清单一步步落地。第一步确认型号和固件。进入InoProShop的PLC信息页面确认型号支持socket扩展库固件版本太老就先升级。如果你不确定可以先随便写一个库函数调用编译能过基本就说明支持。第二步建立库清单。在库管理器里确认存在socket或tcp相关库编译一个空的ST程序提前暴露缺库的问题。第三步固定IP和网络参数。PLC设置固定IP和服务器同一网段。调试期先不配网关直连测试。第四步写状态机。把空闲、创建、连接、在线、关闭五态代码抄进去不通的就先不用收发数据把连接这一条线跑通。第五步连接成功后再加收发逻辑。先发送一个固定字符串服务器回复一个固定字符串验证全链路。然后再逐步叠加数据解析、心跳、重连逻辑。第六步压力测试和异常注入。人为拔网线、重启服务器、切换交换机观察PLC能否在预期时间内自动恢复确认报警和重连参数是否合理。这套流程我每次做新项目都会走一遍即便协议不同框架都是通用的。顺着走基本不会出现那种“代码写完了但完全跑不通”的绝望局面。7. 上手EASY系列socket主站后的几点真实体会做了几个项目之后再回头看EASY系列的socket主站通讯给我最大的感受是小PLC也能干“大活”但前提是程序结构必须严谨。socket通讯不像Modbus轮询那样错了顶多通讯超时socket一旦管理不善会出现socket泄漏、端口占用、缓冲区错乱等一连串麻烦排查起来非常磨人。我的建议是不要在程序里到处直接调用socket指令所有socket相关操作统一封装成功能块集中管理状态、错误码和句柄。这样如果出了问题你只需要看一个功能块内部的执行情况而不是满工程找发送接收调用点。毕竟PLC程序写完半年后你再打开看自己代码的时候良好结构带来的维护便利会远远超过当初“简单粗暴写进去”省下的半小时。通讯周期、心跳间隔、重连延时这些参数每个项目都要根据对方的服务器性能和网络状况重新调。不要迷信某个“万金油”参数数值合理即可关键是有参数化设计上位机配置表或HMI里能直接改免得每次调整都要重新下载PLC程序。最后说一个细节接到服务器的数据不要只解包完就扔到一边建议为每帧报文打上时间戳。时间戳可以是PLC系统时间也可以是上位机下发的时钟基准。这样后续查数据延迟、查历史报警、做数据补传都有据可依。很多项目后期扯皮都是因为缺了这一个小小的“时间标记”。
返回列表