Я использую библиотеку PySerial для чтения значения регистра удержания из ведомого устройства Modbus rtu. У меня есть встроенное устройство шлюза с ОС Unix (поэтому порты / dev / tty). и ведомый Modbus, который может дать мне некоторые показатели, такие как частота, температура и т. д. c. Я попытался установить sh соединение и прочитать содержимое регистров с помощью библиотеки pymodbus, используя спецификацию производителя на соединение Modbus на своем устройстве, но это не сработало. Я получил эту ошибку, которая требует дальнейшего анализа низкого уровня:
AttributeError: у объекта 'ExceptionResponse' нет атрибута 'registers'
1-й шаг - подключение
Я получил библиотеку 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
2-й шаг - чтение регистра удержания
Производитель параметры представлены ниже:
[ReadHoldingRegister]
deviceAddress = 1
memoryAddress = 7136
byteCount = 1
timeout = None
Multiply = 0
Divide = 0
Общий поток выполнения представлен ниже. Как видите, сообщение отправителя modbus было правильно построено. с CR C байт справа, но ответ на порт вызвал ошибку тайм-аута. Он вызывается, когда ожидается меньшее количество байтов данных.
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')
...
Пожалуйста, если вам нужна дополнительная информация, Не стесняйтесь комментировать этот вопрос. Спасибо