ljean / modbus-tk

Create Modbus app easily with Python
Other
557 stars 211 forks source link

When "data_format='f'",Invalid CRC in response #176

Open waCoding opened 1 year ago

waCoding commented 1 year ago

My board surport float point number transmission. When excute" data = master.execute(address, cst.READ_HOLDING_REGISTERS, regAddress, quantity, data_format='f')", "modbus_tk.exceptions.ModbusInvalidResponseError: Invalid CRC in response" is display. Please, help.

jacksonmatheson commented 1 year ago

Can you please sniff the packets between the 2 devices and paste the raw transmission details for me to review please. Can't really help with so little info.

waCoding commented 1 year ago

Can you please sniff the packets between the 2 devices and paste the raw transmission details for me to review please. Can't really help with so little info.

Thanks for answer. The device for Modbus Slave is STM32F407 with UCOSIII and uCModBus ported. uCModbus Slave support float point transmission, if the register address is higher than "MODBUS_CFG_FP_START_IX"(here is 100) , and the device will send 4 Bytes with format of IEEE 754.

The data transmitted by modbus_tk excute is : 01 03 00 64 00 01 C5 D5 The reply is below. 01 03 04 3E B0 F1 AF F3 D0 01 03 04 3E B2 AC C9 EA AA 01 03 04 3E B3 7C 2F 67 20 01 03 04 3E B6 BF 70 67 E9 01 03 04 3E B5 0C 8A 62 9A 01 03 04 3E B3 DF 3A DE 1F 01 03 04 3E B0 64 E6 5D 76 01 03 04 3E B0 87 73 D4 29 01 03 04 3E B1 E0 F4 EF BB 01 03 04 3E B6 10 34 1A 2A

And when the register address is low than MODBUS_CFG_FP_START_IX, excute data = master.execute(address, functioncode, regAddress, quantity), it works well.

Here is my code:

import serial
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
from PySide6.QtCore import QTimer

master = modbus_rtu.RtuMaster(serial.Serial("Com7", baudrate=115200, bytesize=8, parity='N', stopbits=1, xonxoff=0))
master.set_timeout(5.0)
# master.set_verbose(True)

getDataTimer = QTimer()
data = [100]

def getdata(address=1, fuctioncode=3, regAddress=0, quantity=1):
    global data   
    data = master.execute(address, functioncode, regAddress, quantity, data_format='f')
    print(data)

getDataTimer.timeout.connect(lambda: getdata(1, cst.READ_HOLDING_REGISTERS, 65000, 1))

Thank you again

jacksonmatheson commented 1 year ago

Can you please copy and paste your code. There are typo's in that and i beleive it's not correct.

Firstly:

Also, you state that your execute command sends 01 03 00 64 00 01 C5 D5 , but your actual master.execute (line: 22) is:
1, cst.READ_HOLDING_REGISTERS, 65000, 1 which is sending a request to slave_id=1, holding registers, starting from register 65,000, which would make the actual packet modbus_tk send be 01 03 FD E8 00 01 [CRC_HERE]

One quick thing to check though, i know you're talking about the register addresses above 100, but double check you're not trying to get more than 100 registers at one, I do know of a few slave devices that will fail when more than 100 are requested, although you should be able to poll address over 65,000.

Can you also repeat your poll at 65000 but request len=2 and let me know.

waCoding commented 1 year ago

Sorry about this mistake,the actual code is correct, I didn't type it correctlly. Here is the copy of code.

uCModbus support 65535 holding registers. And these registers are divided in two parts by defining MODBUS_CFG_FP_START_IX, one part is for 16 bit, and another part is for float point. When the request address is equal or bigger than MODBUS_CFG_FP_START_IX, uCModbus Slave will feedback a float point number with format of IEEE 754.

import serial
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
from PySide6.QtCore import QTimer

master = modbus_rtu.RtuMaster(serial.Serial("Com7", baudrate=115200, bytesize=8, parity='N', stopbits=1, xonxoff=0))
master.set_timeout(5.0)
# master.set_verbose(True)

getDataTimer = QTimer()
data = [100]

def getdata(address=1, functioncode=3, regAddress=0, quantity=1):
    global data
    data = master.execute(address, functioncode, regAddress, quantity, data_format='f')
    print(data)

getDataTimer.timeout.connect(lambda: getdata(1, cst.READ_HOLDING_REGISTERS, 100, 1))
waCoding commented 1 year ago

Can you please copy and paste your code. There are typo's in that and i beleive it's not correct.

Firstly:

  • Line 16: def getdata(address=1, fuctioncode=3, regAddress=0, quantity=1):
  • Line 18: data = master.execute(address, functioncode, regAddress, quantity, data_format='f')
  • fuctioncode vs functioncode

Also, you state that your execute command sends 01 03 00 64 00 01 C5 D5 , but your actual master.execute (line: 22) is: 1, cst.READ_HOLDING_REGISTERS, 65000, 1 which is sending a request to slave_id=1, holding registers, starting from register 65,000, which would make the actual packet modbus_tk send be 01 03 FD E8 00 01 [CRC_HERE]

One quick thing to check though, i know you're talking about the register addresses above 100, but double check you're not trying to get more than 100 registers at one, I do know of a few slave devices that will fail when more than 100 are requested, although you should be able to poll address over 65,000.

Can you also repeat your poll at 65000 but request len=2 and let me know.

I have repeat my test of polling at 65000 and length =2. The result is : If the slave is a simulation machine by modbus slave, modbus_tk works well, but if the slave is the STM32F407, the CRC Error emerged. For the simulation machine I set the data format as 32bit float little-endian. And actually, in the STM32F407 I use the same data format. Thank you!

waCoding commented 1 year ago

I have tracked the received response from the STM32F407 Slave machine, I got this. image image

And I use another poll tool to get the raw data, I got like this. Response image Request image

Thank you again.

enev13 commented 1 year ago

Maybe you should investigate the parse_response method of the RtuQuery class in modbus_rtu.py