如何使用python串口写PLC?

how to use python serial write to PLC?

我有2个带串口的PLC。一个是mitsubishi Q00Jcpu mc协议,一个是omron hostlink协议

我尝试使用 python pyserial lib 写入 PLC 并读取响应。 但是失败了,我尝试使用串口工具进行测试并得到了很好的回应, serial tool success communicate with PLC,我读到CIO地址开始100和大小2,它得到12345678,这是一个真实的结果。

我的代码:

import serial

omr = serial.Serial(port='COM4', baudrate=9600, timeout=0.5)
omr.parity=serial.PARITY_EVEN
omr.bytesize = 7
omr.stopbits =2

resp = omr.write(b'\x40\x30\x30\x46\x41\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x31\x30\x31\x42\x30\x30\x30\x36\x34\x30\x30\x30\x30\x30\x32\x30\x35\x2a\x0d')
print(resp) # print 34
resp = omr.write(b'@00FA0000000000101B0006400000205*\CR')
print(resp) # print 36 

好像是return写入数据的长度,hex和ascii都试过了,都失败了。

我怎么算出来的,serial.write的return不是结果。如果需要设备的响应,应该使用 read_until() ,不确定天气这是一个好方法,如果您有任何建议,请告诉我。 无论如何,我做的class,可以通过给不同的参数来读取omron PLC,希望它可以帮助别人。

演示:

import serial

# cmd = '0101B00064000001'

class OMR_SERIAL_TOOL:
    def __init__(self,port,baudrate):
        self.omr = serial.Serial(port=port, baudrate=baudrate, timeout=0.5)
        self.omr.parity=serial.PARITY_EVEN
        self.omr.bytesize = 7
        self.omr.stopbits =2
        self.head ='@00FA000000000'
    
    @staticmethod
    def get_xor(frame):
        res = ord(frame[0])
        for i in frame[1:]:
            res ^= ord(i)
        res = str(res)
        if len(res) == 1:
            res = '0'+res
        return res


    def omr_read(self,head,cmd):
        xor = OMR_SERIAL_TOOL.get_xor(head+cmd)
        self.omr.write('{}{}{}*\r'.format(head,cmd,xor).encode())
        resp = self.omr.read_until("\r".encode())

        return str(resp[23:-4],encoding='utf-8')


test = OMR_SERIAL_TOOL('COM4',9600)
res = test.omr_read(test.head,cmd='0101B00064000002')
print(res) # 12345678 , which is the correct response

砰!版本 1.0

import serial

class OMR_SERIAL_TOOL:
    def __init__(self,port,baudrate,mode):
        self.omr = serial.Serial(port=port, baudrate=baudrate, timeout=0.5)
        self.omr.parity=serial.PARITY_EVEN
        self.omr.bytesize = 7
        self.omr.stopbits =2
        # fins mdoe
        if mode == 'fins':
            self.head ='@00FA000000000'
        self.cmd_map = {
            "MEMORY_AREA_READ":"0101",
            "MEMORY_AREA_WRITE":"0102",
            "MEMORY_AREA_FILL":"0103",
            "MULTI_MEMORY_AREA_READ":"0104",
            "MEMORY_AREA_TRANSFER":"0105"
        }
        # cs/cj mode
        self.io_memory_area_code_map={
            "CIO_bit":"30",
            "WR_bit":"31",
            "HR_bit":"32",
            "AR_bit":"33",
            "CIO_word":"B0",
            "WR_word":"B1",
            "HR_word":"B2",
            "AR_word":"B3"
        }
    
    @staticmethod
    def get_xor(frame):
        res = ord(frame[0])
        for i in frame[1:]:
            res ^= ord(i)
        res = str(res)
        if len(res) == 1:
            res = '0'+res
        res = str(hex(int(res)))[2:]
        upcase_res = ''
        for i in res:
            if i.isdigit():
                upcase_res += i
            elif i.isalpha():
                upcase_res += i.upper()
        if len(upcase_res) == 1:
            upcase_res = '0'+upcase_res
        return upcase_res


    def omr_read(self,cmd,code,address,size):
        address = str(hex(address))[2:]
        size = str(hex(size))[2:]

        while len(address) < 4:
            address = '0' + address
        while len(size) < 4:
            size = '0' + size

        frame = self.head+cmd+code+address+'00'+size
        xor = OMR_SERIAL_TOOL.get_xor(frame)
        #print(frame+xor)
        self.omr.write('{}{}*\r'.format(frame,xor).encode())
        resp = self.omr.read_until("\r".encode())

        return str(resp[23:-4],encoding='utf-8')


omr_client = OMR_SERIAL_TOOL('COM4',9600,'fins')
cmd = omr_client.cmd_map['MEMORY_AREA_READ']
code = omr_client.io_memory_area_code_map['CIO_word']

res = omr_client.omr_read(cmd,code,address=500,size=1)

我在 CIO read 上测试它很好,如果您发现任何错误,请告诉我。