About this article
These are problems I actually ran into while working with industrial devices over RS-485 and COM ports. No theory — concrete situations, symptoms and fixes.
COM port disappears after a reboot
Symptom: The USB-RS485 converter was on COM8; after a reboot Windows reassigned it to COM12.
Cause: Windows assigns COM numbers dynamically. With each connection to a different USB port, or after certain updates, the number can change.
Fix:
- Device Manager → Ports (COM and LPT) → right-click the device → Properties → Port Settings → Advanced
- Change "COM Port Number" to a fixed value (e.g. COM8) and tick "Use this COM port even if it's in use"
- Alternatively: don't hardcode the port number in code — give the user a list of available ports to choose from
Device doesn't respond — but it's definitely connected
Symptom: Port opens, request goes out, timeout — no response.
Order of checks:
-
Baud rate — check the device documentation. The default 9600 is not a rule. Try 19200, 38400, 115200.
-
Parity and stop bits — some devices use
8E1(8 data bits, Even parity, 1 stop bit) or8N2. Wrong setting = no response. -
Slave address — check the sticker or documentation. If unknown, scan (1–32 is a typical range).
-
Termination — a missing 120 Ω terminator often shows up as no response on a longer cable but works on a short one.
-
A/B swapped — swap the A and B wires.
-
Converter without auto-DE — some USB-RS485 converters require manual control of the DE (Driver Enable) pin via RTS. In Python:
rtscts=Trueordsrdtr=True.
Response is cut off — only part of the frame arrives
Symptom: Modbus returns a CRC error or too few bytes.
Causes and fixes:
Too short a read timeout:
# Too little — slow devices may not finish in time
client = ModbusSerialClient(port="COM8", baudrate=9600, timeout=0.5)
# Safer
client = ModbusSerialClient(port="COM8", baudrate=9600, timeout=2)
Garbage at the start of the buffer (converter echo):
# Clear the buffer before sending the request
serial_port.reset_input_buffer()
serial_port.reset_output_buffer()
Frame fragmentation on Windows: Windows groups bytes in the buffer, which can cause read() to return only part of the frame. Fix: read in a loop until the expected number of bytes is collected, or implement an inter-byte timeout.
Works on one machine, doesn't work on another
Symptom: Same code, same device — works on one PC, fails on another.
Causes:
-
Converter drivers — CH340 requires a driver on older Windows 10. Check Device Manager for a yellow exclamation mark.
-
Different library version — pymodbus 2.x and 3.x have different APIs.
pip show pymodbuson both machines. -
Antivirus blocks the port — some AV software (especially corporate) can block access to COM ports. Check AV logs or disable temporarily.
-
Permissions — on Linux:
sudo usermod -a -G dialout $USER— without this a normal user can't access/dev/ttyUSB*.
Communication works, but the values are wrong
Symptom: Connection is fine, registers read, but values make no sense (e.g. temperature -32768°C or flow 99999).
Causes:
-
Float endianness — a 32-bit float assembled from two Modbus registers can be in various orders:
- Big-endian: register 0 = MSW, register 1 = LSW
- Little-endian: register 0 = LSW, register 1 = MSW
- Byte-swap: bytes within each register swapped
import struct r = result.registers # Try all combinations if the value is nonsensical: struct.unpack(">f", struct.pack(">HH", r[0], r[1]))[0] # BE struct.unpack(">f", struct.pack(">HH", r[1], r[0]))[0] # LE words -
Address offset — the documentation lists address
40001, but in FC03 you have to pass0. Always subtract 40001 (or 30001 for Input Registers). -
Scaling — a value of
1234may mean12.34(× 100) or123.4(× 10). Check the register documentation.
Port held by another process
Symptom: Serial Exception: [Errno 16] Device or resource busy (Linux) or Access is denied (Windows).
Windows — find which process took the port:
Windows has no built-in way to show which process holds a COM port. Quickest fix — handle.exe from Sysinternals:
# Device number = COM number minus 1
handle.exe \Device\Serial0 # COM1
handle.exe \Device\Serial7 # COM8
# Or all serial devices at once:
handle.exe -a Serial
The usual suspects: Modbus Poll, other Python instances, LOGO! Soft Comfort, printer drivers with a built-in COM port.
Linux:
fuser /dev/ttyUSB0 # shows the PID
lsof /dev/ttyUSB0 # more detail