[咕咕李大哥的A面]通过MODBUS协议修改三菱PLC继电器Y开合状态失败的问题及解决办法/电脑通过MODBUS协议控制三菱PLC的简单办法

一、三菱PLC继电器说明

图1. 三菱FX3s继电器一览

       三菱PLC主要有两种继电器,分别是输入输出继电器X/Y、以及辅助继电器M;其中,输出继电器Y及一般用的辅助继电器M可以通过GX WORKS的'修改当前值'功能来改变继电器的开合状态。

注意:PLC会实时监测输入继电器X的状态,因此无法使用修改当前值的方式来修改输入继电器X的开合状态。

       因此我们可以使用GX WORKS或MODBUS协议的写线圈功能来修改输出继电器或辅助继电器的开合状态,这给电脑控制PLC带来了可能。

二、三菱PLC通过MODBUS修改继电器线圈

2.1 MODBUS功能代码

图2. PLC可用功能代码

       根据MODBUS功能代码及三菱PLCmodbus手册,我们可以根据05功能代码对内部线圈进行读写。

2.2 请求文本格式

       请求文本格式如下图所示:

图3. 线圈写入请求文本格式

       根据请求文本的格式,我们只需要知道线圈编号即可通过MODBUS来修改继电器Y或M的开合状态。

2.3 三菱PLC继电器线圈编号/位软元件

       三菱的各个线圈编号见下图(以FX3s为例):

图3. 软元件地址

2.4 使用串口工具修改继电器

       我们可以通过串口调试工具如:modscan32等对线圈进行读写测试:

图4. 使用modscan32闭合继电器Y14

       其中,01是设备从站号,05是功能码(写线圈功能),33 0B通过查图2表格可以知道是Y13线圈,FF 00是线圈闭合,F2 BC为前面数据的CRC校验码

       因此 01 05 33 0B FF 00 F2 BC 的功能为闭合Y13输出线圈。如果执行成功,我们将在响应缓冲区中收到PLC的响应:01 05 33 0B FF 00 F2 BC

       此时我们通过GX WORKS软元件/缓冲储存器批量监视可以看到Y13的值变为1(闭合)

图5. 使用GX WORKS查询继电器状态

       同理我们也可以通过修改33 0B为00 00等来修改内置M线圈的状态。

2.5 使用Python串口模块修改继电器

       在Python编程中,我们可以通过以下代码来对PLC线圈进行读写:

import serial
import time


# raw_data 十进制格式列表:[站号,功能码,软元件地址,读写位数/数据]
def calculate_crc(raw_data):
    # 将 raw_data 转换为 hex_data
    hex_data = [format(x, 'X').zfill(4) for x in raw_data]
    string = hex_data[0]
    hex_data[0] = string[-2:]
    string = hex_data[1]
    hex_data[1] = string[-2:]
    try:
        hex_data[4]   # 确认是否有第五位→多寄存器读写
    except:
        print("no hex 4")
    else:
        string = hex_data[4]
        hex_data[4] = string[-2:]   # 多寄存器位数信息
        string = hex_data[5]
        hex_data[5] = string.zfill(8)   # 写入2个寄存器/补充至8位16进制数
        string = hex_data[5]
        string1 = string[-4:]     # 串口写入高低位与PLC高低位逻辑不一致,需要高低4位互换
        string2 = string[:4]
        hex_data[5] = ''.join([string1, string2])
    # 将 hex_data 转换为 str_data
    str_data = ' '.join([x[i:i + 2] for x in hex_data for i in range(0, len(x), 2)])
    # 将字符串转换为十六进制数组
    data_array = [int(x, 16) for x in str_data.split(' ')]

    # 计算CRC校验码
    crc = 0xFFFF
    for i in range(len(data_array)):
        crc ^= data_array[i]
        for j in range(8):
            if crc & 1:
                crc >>= 1
                crc ^= 0xA001
            else:
                crc >>= 1
    # 将CRC校验码添加到原始数据后面
    crc_code = str_data + ' ' + format(crc & 0xFF, '02X') + ' ' + format((crc >> 8) & 0xFF, '02X')
    return crc_code  # return str  crc_data: 01 06 00 0A 00 6F E9 E4


def writedata(ser, hexcode):
    send_data = bytes.fromhex(hexcode)    # HEX码 转换 bytes 字节码     发送数据转换为b'\xff\x01\x00U\x00\x00V'
    ser.write(send_data)   # 发送命令
    time.sleep(0.02)        # 延时,否则len_return_data将返回0,此处易忽视!!! 延迟低于 0.01无法接收数据
    len_return_data = ser.inWaiting()  # 获取缓冲数据(接收数据)长度
    return_data = ser.read(len_return_data)  # 读取缓冲数据
    # bytes(2进制)转换为hex(16进制),应注意Python3.7与Python2.7此处转换的不同,并转为字符串后截取所需数据字段,再转为10进制
    str_return_data = str(return_data.hex())   # bytes(2进制)转换为hex(16进制
    # 返回数据
    return str_return_data

# 写两个寄存器,calculate自动高低位切换
print(calculate_crc([1, 16, 10, 2, 4, 888888]))


print(calculate_crc([1, 5, 13067, 0]))

# 打开串口COM4,根据自己的PLC修改COM口及波特率参数
ser2 = serial.Serial('COM4', 38400, 8, 'N', 1, 0.3)

# Y13线圈写入闭合
writedata(ser2, calculate_crc([1, 5, 13067, 65280]))
# 相当于 writedata(ser2, '01 05 33 0B FF 00 F2 BC')

# Y13线圈写入断开
writedata(ser2, calculate_crc([1, 5, 13067, 0]))
# 相当于 writedata(ser2, '01 05 33 0B 00 00 B3 4C')

Python代码说明

calculate_crc()代码作用为将10进制数修改为16进制数,并根据数据的位数,自动补齐modbus代码及计算CRC校验码,同时将超过65535的数值高低位按照三菱的高低位标准进行调换,可实现modbus传入32位数而不发生数据错误。

writedata()代码用为,使用serial模块将modbus代码发送至PLC,使用时需要提交串口信息ser及请求文本,例:writedata(ser2, '01 05 33 0B FF 00 F2 BC'),其中ser2为串口信息、 '01 05 33 0B FF 00 F2 BC'为请求文本。

三、三菱PLC输出继电器Y无法修改的原因

       在我遇见的情况中,继电器Y无法修改的原因多是因为相应的继电器Y被作为梯形图的输出,导致修改失败

       当梯形图中,相应的输出继电器Y作为输出时,无法使用GXWORKS及MODBUS来修改输出继电器Y,原因是梯形图运行过程中会根据条件快速刷新输出继电器的状态,因此通过GXWORKS及MODBUS修改的继电器状态会在一瞬间被新的状态刷新。

       如上图,当Y13继电器作为急停开关X000的输出时,我们通过GXWORKS及MODBUS都无法对Y13继电器的状态进行修改,修改的状态会被梯形图的输出所覆盖导致修改失效。

       因此,我们使用python程序控制PLC的输出继电器Y时,应选用未被编入梯形图中的继电器,或作为输入的继电器进行控制,避免modbus请求文本失效。

四、电脑通过串口使用modbus协议控制PLC的应用

       电脑通过串口连接PLC,在电脑中使用Python应用modbus协议,根据Python程序的控制逻辑来对PLC进行控制,可以实现计算机读取PLC数据、控制连接在PLC上的电机、气缸、继电器等执行机构,实现计算机接入工业控制网络,其次,还可以通过modbus收集PLC数据,通过SQL服务上传至服务器,实现工业Iot监视及控制。

五、结语

      根据后续的测试发现,位于梯形图输出位置的输出继电器Y无法通过modbus修改其开合状态,可通过梯形图控制辅助继电器M,Python程序定时查询相应的辅助继电器M的开合状态,使用if条件对相应的Y进行控制实现相同的功能。

      使用modbus来查询继电器状态和读写D寄存器的相关文章也会在后续发布,欢迎大家一起交流学习,喜欢自动化相关的编程的可以关注我,B站账号与CSDN账号一致,同时也可以关注我的Gitee账号:咕咕李大哥。

       文章写的有点粗糙,有疑问的地方可以关注留言,一起交流学习,共同进步。

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,可以了解到104协议遥测解析遥测可以使用Java实现。根据ICE104Java解析源码中提到的内容,可以自己使用Java编写代码来解析从站发送的遥信、遥测数据。在遥测量的解析中,可以根据101的遥测中定义的三种类型的值(归一化值、标度值和短浮点数)进行解析。具体的解析方法可以参考“电力101/104规约中遥测量类型转换”。在Java中,可以编写相应的代码来解析这三种类型的值。如果遇到一些无法解析的情况,可以尝试在网上寻找源码,或者参考其他语言的源码进行参考。所以,可以使用Java来实现104协议遥测的解析。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [ICE104规约Java解析源码](https://download.csdn.net/download/u013225431/12766373)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [电网101、104规约解析(Java)](https://blog.csdn.net/oshan2012/article/details/90372241)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值