0

我正在使用 PySerial 库从 modbus rtu 从站读取保持寄存器值。我有一个带有 Unix 操作系统的嵌入式网关设备(所以 /dev/tty 端口)。和一个 modbus 从站,它可以给我一些指标,例如频率、温度等。我尝试使用 pymodbus 库建立连接并读取寄存器内容,在其设备上使用制造商的 modbus 连接规范,但它不起作用。我收到了这个错误,需要进一步的低级分析:

AttributeError:“ExceptionResponse”对象没有属性“registers”

第一步 - 连接

我得到了easymodbus库,因为它更容易确定如何建立连接以及将哪些片段传递给从站。说到这一点,我注意到在 RS485 上需要在 pyserial 上配置进一步的设置。我用下面的代码做到了

self.__ser.rs485_mode = serial.rs485.RS485Settings(rts_level_for_tx=self.rts_level_for_tx,rts_level_for_rx = self.rts_level_for_rx, delay_before_tx=self.delay_before_tx, delay_before_rx=self.delay_before_tx)

它读取以下值:

[RS485]
rts_level_for_tx = true
rts_level_for_rx = true
delay_before_tx = 2
delay_before_rx = 2

第二步 - 读取保持寄存器

制造商参数报告如下:

[ReadHoldingRegister]
deviceAddress = 1
memoryAddress = 7136
byteCount = 1
timeout = None
Multiply = 0
Divide = 0

整体执行流程报告如下。如您所见,发送者 modbus 消息已正确构建。右侧有 CRC 字节,但端口上的响应引发了超时错误。当按预期接收到较少的字节数据时会引发它。

2020-04-13 21:16:51,397 - ModbusClient - INFO - configuration ended
2020-04-13 21:16:51,403 - ModbusClient - INFO - connection on serial port with the following parameters established: {'dsrdtr': False, 'baudrate': 9600, 'parity': 'N', 'bytesize': 8, 'write_timeout': 10, 'timeout': 10.0, 'rtscts': False, 'stopbits': 1, 'inter_byte_timeout': None, 'xonxoff': False}
2020-04-13 21:16:51,404 - ModbusSerialReader - INFO - connection established
2020-04-13 21:16:51,406 - ModbusClient - INFO - data before Cyclic Redundancy Check
2020-04-13 21:16:51,408 - ModbusClient - INFO - data sent for read holding register function bytearray(b'\x01\x03\x1b\xdf\x00\x01\xb3\x14')
2020-04-13 21:17:01,416 - ModbusClient - INFO - data read from serial port bytearray(b'\x01\x83\x02\xc0\xf1')
2020-04-13 21:17:01,420 - ModbusSerialReader - ERROR - Exception Reading holding registers: 'TimeoutError'

下面的代码显示了有关此行为的更多详细信息。

def read_holdingregisters(self, starting_address, quantity):
        """
        Read Holding Registers from Master device (Function code 3)
        starting_address: First holding register to be read
        quantity:  Number of holding registers to be read
        returns:  Int Array [0..quantity-1] which contains the holding registers
        """
        self.__transactionIdentifier+=1
        if (self.__ser.closed):
            raise Exception.SerialPortNotOpenedException("serial port not opened")
        if ((starting_address > 65535) | (quantity >125)):
            raise ValueError("Starting address must be 0 - 65535; quantity must be 0 - 125");
        function_code = 3
        length = 6;
        transaction_identifier_lsb = self.__transactionIdentifier&0xFF
        transaction_identifier_msb = ((self.__transactionIdentifier&0xFF00) >> 8)
        length_lsb = length&0xFF
        length_msb = (length&0xFF00) >> 8
        starting_address_lsb = starting_address&0xFF
        starting_address_msb = (starting_address&0xFF00) >> 8
        quantity_lsb = quantity&0xFF
        quantity_msb = (quantity&0xFF00) >> 8

        data = bytearray([self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb, quantity_lsb, 0, 0])

        self.logger.info('data before Cyclic Redundancy Check'.format(bytearray(data)))

        crc = self.__calculateCRC(data, len(data)-2, 0)
        crcLSB = crc&0xFF
        crcMSB = (crc&0xFF00) >> 8
        data[6] = crcLSB
        data[7] = crcMSB

        self.logger.info('data sent for read holding register function {0}'.format(bytearray(data)))

        self.__ser.write(data)
        bytes_to_read = 5+int(quantity*2)
        data = self.__ser.read(size=bytes_to_read)
        b=bytearray(data)
        data = b

        self.logger.info("data read from serial port", data)

        if (len(data) < bytes_to_read):
           self.logger.exception('Exception Reading holding registers: TimeoutError')
        ...

如果您需要任何进一步的详细信息,请不要犹豫对这个问题发表评论。谢谢

4

0 回答 0