본문으로 건너뛰기
안드로이드 메인보드 · 터치 디스플레이 · 펌웨어 — 2013년부터

Talk to Modbus devices over RS485

Many industrial peripherals — power meters, PLCs, sensors, HVAC controllers — speak Modbus RTU over RS485. This guide covers reaching them from a KTM board that has an RS485 or UART serial port.

This is app-level serial, not ItempApiPub

The device API covers power, display, GPIO, network and kiosk control — not UART I/O. Serial communication uses the standard Android serial interface against the device node listed on your board page. This guide is about that path, not ItempApiPub.

First: find your serial port​

Each board page lists its serial connectors and the device node for each — for example, KTM-S68 maps RS485 to a specific node, and its RS232 ports to /dev/ttyS0, /dev/ttyS6, /dev/ttyS9. Open the node that matches the physical RS485 connector you wired.

If a board's datasheet did not specify the node for a given port, confirm it on the device:

ls /dev/ttyS*

RS485 basics that bite​

RS485 is half duplex — one pair of wires carries both directions, so only one device transmits at a time. Two things follow:

  • Direction control. The transceiver must be switched between transmit and receive around each frame. On KTM boards with a dedicated RS485 port this is handled by the port hardware — you do not toggle a GPIO by hand. (Manually toggling a line from Android userspace is too slow at 115200 baud and truncates the end of the frame — a classic intermittent fault.)
  • Termination. Only the two physical ends of the bus get a 120 Ω terminator, set by jumper/DIP on the board — not by software. Terminating in the middle, or at every node, corrupts the bus.

Modbus RTU frame shape​

A Modbus RTU request is compact and CRC-checked:

[ slave addr ][ function ][ data ... ][ CRC lo ][ CRC hi ]

Example — read 2 holding registers starting at 0 from slave 1 (function 0x03):

01 03 00 00 00 02 C4 0B
└reg─┘ └cnt┘ └CRC┘

The last two bytes are a CRC-16 (Modbus polynomial) over everything before them, sent low byte first.

The read/response cycle​

  1. Build the request bytes, append the CRC.
  2. Write to the serial port; flush.
  3. Read the reply within a timeout (Modbus slaves answer in tens of ms).
  4. Validate the CRC on the reply before trusting it.
  5. If it times out or the CRC fails, retry — noisy buses drop frames.
// Pseudocode against the standard Android serial interface.
// Open the RS485 device node for your board, 8N1 at the device's baud.
SerialPort port = openSerial("/dev/ttyS3", 9600); // node + baud per your device
port.setReadTimeout(300);

byte[] req = withModbusCrc(new byte[]{0x01, 0x03, 0x00, 0x00, 0x00, 0x02});
port.write(req);
port.flush();

byte[] reply = new byte[256];
int n = port.read(reply);
if (n > 0 && modbusCrcOk(reply, n)) {
int[] regs = parseHoldingRegisters(reply, n);
// use regs...
} else {
// timeout or bad CRC — retry with backoff
}

Use a library, don't hand-roll the stack​

CRC, framing, exception responses and retry logic are easy to get subtly wrong. For a real product, use an established Java/Kotlin Modbus RTU library over your serial stream rather than writing the protocol from scratch — hand-rolled Modbus is a reliable source of field bugs. Reserve the byte-level view above for understanding what the library is doing and for debugging on a scope.

Debugging a silent bus​

SymptomLikely cause
No reply at allWrong node, wrong baud, or A/B swapped
Garbage bytesBaud/parity mismatch, or missing termination
Intermittent, worse under loadTermination wrong, or manual direction toggling
First byte lostDirection turnaround timing

Swapping A/B and re-checking baud fixes the majority of "it just won't talk" cases. Confirm the wiring against the RS485 pinout on your board page.

  • Board pages — serial connectors and device nodes per board
  • GPIO API — for non-Modbus digital I/O on the expansion header