采集PLC数据,plc能否主动通知采集端
最近接到一个任务调查关于采集PLC设备内的数据写入数据库的课题,第一次接触PLC。
自已写的采集数据demo,不知道地址位和数据长度,采集时会出现半包和粘包的现象。
目前的解决方案:往plc写完一条完整数据后,跳过一个地址位写第二条数据,采集端通过地址位是否为空来判断一条完整的数据。
疑问:PLC程序将工厂设备的数据成功写入PLC设备时,是否能通知采集端并告知写入的地址位和数据长度
plc设备是三菱L系列,MC协议。
你用的什么协议,485+modbus rtu吗
作为一名IT专家,我可以告诉你,PLC设备是可以主动通知采集端写入的地址位和数据长度的。PLC设备一般有多种通信协议,这里提到的三菱L系列的PLC设备使用的是MC协议。MC协议支持二进制和ASCII方式进行通信,其中二进制方式是更常用的方式。
在使用MC协议读写数据时,需要按照格式进行数据包的组装和解析。MC协议的数据包格式为:
| 前导码(2Byte) | 网络编号(1Byte) | PC编号(1Byte) | 目标CPU模块I/O编号(3Byte) | 请求服务编号(2Byte) | 子服务标志(1Byte) | 请求数据长度(2Byte) | 请求数据 | 后续码(1Byte) |
其中,请求服务编号和子服务标志用于指定需要进行的操作,请求数据长度指定请求数据的长度。因此,在数据包中,PLC设备可以主动通知采集端请求数据的长度。
关于半包和粘包问题,建议可以使用TCP协议或UDP协议进行通信,使用一定的数据分隔符进行数据包的组装和解析。具体实现方法可以使用Python的socket模块实现,示例如下:
# 采集端示例代码
import socket
HOST = '192.168.1.1' # PLC设备的IP地址
PORT = 1024 # PLC设备的端口号
BUFSIZ = 1024 # 缓冲区大小
SEPARATOR = b'\x01\x02\x03\x04' # 数据分隔符
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
data = b''
while True:
buffer = sock.recv(BUFSIZ)
if not buffer:
break
data += buffer
while data:
index = data.find(SEPARATOR)
if index == -1:
break
packet = data[:index]
data = data[index + len(SEPARATOR):]
# 处理数据包
# ...
sock.close()
其中,数据分隔符使用了不常见的'\x01\x02\x03\x04',可以根据实际需求选择合适的数据分隔符。
在PLC设备端,需要实现采集端发来的请求,并返回相应的数据。示例代码如下:
# PLC设备示例代码
import socket
HOST = '0.0.0.0' # 绑定任意IP地址
PORT = 1024 # 端口号
BUFSIZ = 1024 # 缓冲区大小
SEPARATOR = b'\x01\x02\x03\x04' # 数据分隔符
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
while True:
conn, addr = sock.accept()
data = b''
while True:
buffer = conn.recv(BUFSIZ)
if not buffer:
break
data += buffer
while data:
index = data.find(SEPARATOR)
if index == -1:
break
packet = data[:index]
data = data[index + len(SEPARATOR):]
# 处理数据包
# ...
# 组装响应数据包,并发送
response_data = b'...'
conn.send(response_data)
conn.close()
在处理数据包时,可以使用struct模块来解析和打包数据。示例代码如下:
import struct
# 解析数据包
packet = b'\x50\x00\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00\x04\x00\x01\x00\x00\x00\x00\x00'
header = struct.unpack('<HHBBI', packet[:12])
sub_header = struct.unpack('<BBI', packet[12:])
# 打包响应数据包
response_data = struct.pack('<HHBBI', 0x5000, 0x10, header[2], header[3], 0)
response_data += struct.pack('<BBI', sub_header[0], sub_header[1], 0)
当然,以上只是一些示例代码和思路,具体实现时需要根据实际情况进行调整、优化。