forked from sfera-labs/exo-sense-py-modbus
-
Notifications
You must be signed in to change notification settings - Fork 54
Open
Description
Description
I am using Esp32, MAX485 AND Sensor
while trying to read slave(Sensor) from read_holding_registers function
sending the frame correctly
b'\x08\x03\x00\x00\x00\x02\xc4\x92'
but the response receive is wrong
b'\xc2\xb0\xdc\xa4\xe6X\x7f'
Error reading Modbus registers: invalid response CRC
i had played with some of the delay but does not able to resolve the issue.
kindly help me to resolve the issue. Thanks in advance. In code I will attach what are the modification I tried
Reproduction steps
1.In issue#50,73, 75 i have read but doesn't get an idea how to fix my issue
2.
3.
...
MicroPython version
v1.23.0
MicroPython board
ESP32
MicroPython Modbus version
# e.g. v2.3.7
# use the following command to get the used version
import os
from umodbus import version
print('MicroPython infos:', os.uname())
print('Used micropthon-modbus version:', version.__version__)Relevant log output
MPY: soft reboot
Used micropthon-modbus version: 2.3.7User code
main.py
from umodbus.serial import Serial
from machine import Pin
from machine import UART
import time
# Define the pins for Modbus communication
rtu_pins = (Pin(17), Pin(18))
# Initialize the Modbus object
m = Serial(baudrate=9600, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=Pin(15), uart_id=2)
# Increase timeout for Modbus response
m._uart.init(timeout=2000) # Set UART timeout to 2000 ms (2 seconds)
# Function to read current die height
def readCurrentDieHeight():
slave_addr = const(0x08) # Modbus slave address (updated to 8)
starting_address = const(0x00) # Start reading from address 0x0000
register_quantity = const(2) # Read two registers (32-bit value)
# Try reading the holding registers
try:
time.sleep(0.2) # Small delay to give slave time to respond
register_values = m.read_holding_registers(slave_addr, starting_address, register_quantity, signed=False)
except Exception as e:
print(f"Error reading Modbus registers: {e}")
return False, 0.0
while True:
print("start")
success, die_height = readCurrentDieHeight()
In serial.py
# using _send function I had varied time.sleep_us(85) also eliminate +100 from sleep_time_us because my slave baud rate is 9600
def _send(self, modbus_pdu: bytes, slave_addr: int) -> None:
print("................trace send frame...................")
"""
Send Modbus frame via UART
If a flow control pin has been setup, it will be controlled accordingly
:param modbus_pdu: The modbus Protocol Data Unit
:type modbus_pdu: bytes
:param slave_addr: The slave address
:type slave_addr: int
"""
# modbus_adu: Modbus Application Data Unit
# consists of the Modbus PDU, with slave address prepended and checksum appended
modbus_adu = bytearray()
modbus_adu.append(slave_addr)
modbus_adu.extend(modbus_pdu)
modbus_adu.extend(self._calculate_crc16(modbus_adu))
print(modbus_adu)
if self._ctrlPin:
self._ctrlPin.on()
#print('on')
# wait until the control pin really changed
# 85-95us (ESP32 @ 160/240MHz)
#time.sleep_us(200)
time.sleep_us(85)
# the timing of this part is critical:
# - if we disable output too early,
# the command will not be received in full
# - if we disable output too late,
# the incoming response will lose some data at the beginning
# easiest to just wait for the bytes to be sent out on the wire
send_start_time = time.ticks_us()
#print(f"Send start time: {send_start_time}")
# 360-400us @ 9600-115200 baud (measured) (ESP32 @ 160/240MHz)
#print(f"control pin condition befor write: {self._ctrlPin.value()}")
self._uart.write(modbus_adu)
send_finish_time = time.ticks_us()
#print(f"Send finish time: {send_finish_time}")
if self._has_uart_flush:
self._uart.flush()
time.sleep_us(self._t1char)
else:
sleep_time_us = (
self._t1char * len(modbus_adu) - # total frame time in us
time.ticks_diff(send_finish_time, send_start_time)+
100 # only required at baudrates above 57600, but hey 100us
)
time.sleep_us(sleep_time_us)
if self._ctrlPin:
self._ctrlPin.off()
#print('off')
in _uart_read I didn't change anything and try to print the response which is wrong
def _uart_read(self) -> bytearray:
"""
Read incoming slave response from UART
:returns: Read content
:rtype: bytearray
"""
response = bytearray()
print("...........trace response frame inside _uart_read..........")
# TODO: use some kind of hint or user-configurable delay
# to determine this loop counter
for x in range(1, 120):
if self._uart.any():
# WiPy only
#response.extend(self._uart.readall())
response.extend(self._uart.read())
# variable length function codes may require multiple reads
if self._exit_read(response):
break
# wait for the maximum time between two frames
time.sleep_us(self._inter_frame_delay)
print(response)
return responseAdditional informations
No response
Metadata
Metadata
Assignees
Labels
No labels