采集PLC数据,plc能否主动通知采集端

采集PLC数据,plc能否主动通知采集端
最近接到一个任务调查关于采集PLC设备内的数据写入数据库的课题,第一次接触PLC。
自已写的采集数据demo,不知道地址位和数据长度,采集时会出现半包和粘包的现象。

目前的解决方案:往plc写完一条完整数据后,跳过一个地址位写第二条数据,采集端通过地址位是否为空来判断一条完整的数据。

疑问:PLC程序将工厂设备的数据成功写入PLC设备时,是否能通知采集端并告知写入的地址位和数据长度
plc设备是三菱L系列,MC协议。

img

你用的什么协议,485+modbus rtu吗

  • 你看下这篇博客吧, 应该有用👉 :工业4.0时代,您需要的是高性价工业物联网智能网关(超高性价比),PLC远程监控,PLC远程维护,系统数据采集,一个都不能少。
  • 除此之外, 这篇博客: 威纶通触摸屏的配方功能具体使用方法介绍(宏指令写入PLC)中的 威纶通触摸屏的配方功能具体使用方法介绍(宏指令写入PLC) 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 0.1

    1. 如下图所示,新建一个测试项目,在系统参数中添加所需的设备,这里以MT8071iE和三菱FX系列PLC为例进行说明,(旧版本的触摸屏可能不支持本文演示的方法,请注意)
      1
    2. 在“系统参数”—“配方数据库”中点击添加按钮图标,如下图所示,设置名称为Recipe,在右侧的窗口中点击“新增”添加所需的项目,第一行为参数名称,下面依次为各个参数,参数的名称和数据类型可根据自己需要进行设置,这里以32位浮点型数据进行举例
      2
    3. 如下图所示,在工程文件—配方数据记录中点击“新增”,
      3
    4. 如下图所示,点击“新增”按钮即可添加空白的配方
      4
    5. 点击确定后,系统会提示如下所示内容,点击“是”确认,
      5
    6. 如下图所示,点击“元件”—“配方检视”,新增配方检视元件,在配方目录中选择配方名称为“Recipe”
      6
    7. 添加完成后,如下图所示,
      7
    8. 点击“元件”—“字符”添加一个字符元件,用于创建新增配方的名称,如下图所示,读取/写入地址选择Local HMI—RECIPE—ParaName,
      8
    9. 添加完成后,如下图所示,
      9
    10. 点击“元件”—“数值元件”,添加我们所需的数值元件,读取/写入地址设置为我们配方中设置好的变量,如下图所示,
      10
    11. 添加3个,如下图所示,连接的变量分别为Para1、Para2、Para3
      11
    12. 同样地操作,再添加所需的数值元件,读取/写入的地址连接PLC的寄存器地址,如下图所示,
      12
    13. 添加3个,如下图所示,连接的变量分别为D200、D204、D208
      13
    14. 在“工程文件”—宏指令中添加一段宏程序,用于将HMI配方数据库设置的数据写入到PLC中(当然也可以从PLC上传到HMI,这里仅以写入到PLC举例说明)
      14
    15. 添加一个位状态设置元件,如下图所示,该元件的地址采用HMI的LB0,开关类型为复归型,当点击时触发宏指令transfer,即我们刚才创建的宏指令,
      15
    16. 添加完成后如下图所示,
      16
    17. 如下图所示,添加多状态设置元件,用于新增配方和删除配方,写入地址为RECIPE—Command,写入常数1为新增配方;
      17
      写入常数3为删除配方,
      18
    18. 添加完成后如下图所示,
      19
    19. 我们开启离线模拟查看仿真效果,如下图所示,我们输入配方名称BS,并设置 3个参数的值分别为20.0、15.0、23.0,
      20
      此时点击“新增配方”,如下图所示,可以看到已经成功添加了一个名为BS的配方数据,
      21
    20. 此时点击“写入PLC”按钮,如下图所示,可以看到配方中的数据已经成功被写入到PLC的数据寄存器D200、D204、D208中。
      22
  • 以下回答由chatgpt基于相关博客总结生成:

    作为一名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)
    

    当然,以上只是一些示例代码和思路,具体实现时需要根据实际情况进行调整、优化。