RS485
Hardware
One RS485/RS422 bus is integrated into AutomatePro with a max data rate of 500 kbps.
Connector Pinout
- Connector
- Development Breakout Board


RS485 Specifications
| Parameter | Value |
|---|---|
| Transceiver | THVD1400DR |
| Data Rate | 500 kbps |
| RS485 Standard | TIA/EIA-485A |
| Duplex | Half |
| Integrated 120 Ω termination resistor | Yes |
Software
Serial Port
/dev/ttyTHS1 is the serial port used for RS485 communication.
Example
This example sends a two-byte counter every second with rs485_sender and prints what rs485_receiver reads, on /dev/ttyTHS1 at 9600 baud, 8 data bits, no parity, 1 stop bit, and no flow control.
The programs are in the misc folder of the AutomatePro tutorials repository, and its README explains how to build and run them.
Run the receiver and the sender in separate terminals, one at each end of the bus.
On a PC with a USB-RS485 adapter, pass the adapter's device as the only argument, for example python3 rs485_sender.py /dev/ttyUSB0; on AutomatePro, the /dev/ttyUSB* ports belong to the 5G modem.
The Python programs need pyserial, and the user needs to be a member of the dialout group.
- Python
- C++
Sender: rs485_sender.py
import serial
import time
import signal
import sys
running = True
def signal_handler(sig, frame):
global running
print("\n[Sender] Stopping...")
running = False
signal.signal(signal.SIGINT, signal_handler)
def main():
port = sys.argv[1] if len(sys.argv) > 1 else '/dev/ttyTHS1'
baudrate = 9600
print(f"[Sender] Opening serial port: {port}")
try:
ser = serial.Serial(port, baudrate=baudrate, bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,
timeout=1)
except serial.SerialException as e:
print(f"[Sender] Failed to open serial port: {e}")
sys.exit(1)
print("[Sender] Serial port ready. Press Ctrl+C to stop.")
counter = 0
while running:
data = bytearray([counter & 0xFF, (counter >> 8) & 0xFF])
ser.write(data)
print(f"[Sender] Sent Data: {data[0]} {data[1]}")
counter += 1
time.sleep(1)
ser.close()
print("[Sender] Closed.")
if __name__ == "__main__":
main()
python3 rs485_sender.py
Receiver: rs485_receiver.py
import serial
import time
import signal
import sys
running = True
def signal_handler(sig, frame):
global running
print("\n[Receiver] Stopping...")
running = False
signal.signal(signal.SIGINT, signal_handler)
def main():
port = sys.argv[1] if len(sys.argv) > 1 else '/dev/ttyTHS1'
baudrate = 9600
print(f"[Receiver] Opening serial port: {port}")
try:
ser = serial.Serial(port, baudrate=baudrate, bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,
timeout=2)
except serial.SerialException as e:
print(f"[Receiver] Failed to open serial port: {e}")
sys.exit(1)
print("[Receiver] Serial port ready. Press Ctrl+C to stop.")
while running:
data = ser.read(2)
if len(data) == 2:
print(f"[Receiver] Received Data: {data[0]} {data[1]}")
elif len(data) > 0:
print(f"[Receiver] Partial Data: {list(data)}")
else:
print("[Receiver] Timeout - no data")
time.sleep(0.5)
ser.close()
print("[Receiver] Closed.")
if __name__ == "__main__":
main()
python3 rs485_receiver.py
Sender: rs485_sender.cpp
#include <iostream>
#include <cstring>
#include <thread>
#include <chrono>
#include <csignal>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
volatile std::sig_atomic_t running = 1;
void signal_handler(int) {
running = 0;
}
bool configure_serial_port(int fd) {
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
perror("[Sender] tcgetattr");
return false;
}
cfsetospeed(&tty, B9600);
cfsetispeed(&tty, B9600);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag &= ~IGNBRK;
tty.c_lflag = 0;
tty.c_oflag = 0;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 10;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_cflag |= (CLOCAL | CREAD);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("[Sender] tcsetattr");
return false;
}
return true;
}
int main(int argc, char** argv) {
signal(SIGINT, signal_handler);
const char* device = argc > 1 ? argv[1] : "/dev/ttyTHS1";
std::cout << "[Sender] Opening serial port: " << device << std::endl;
int fd = open(device, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
perror("[Sender] open");
return 1;
}
if (!configure_serial_port(fd)) {
close(fd);
return 1;
}
std::cout << "[Sender] Serial port ready. Press Ctrl+C to stop.\n";
int counter = 0;
while (running) {
uint8_t data[2];
data[0] = counter & 0xFF;
data[1] = (counter >> 8) & 0xFF;
ssize_t bytes_written = write(fd, data, 2);
if (bytes_written == 2) {
std::cout << "[Sender] Sent Data: " << static_cast<int>(data[0]) << " " << static_cast<int>(data[1]) << std::endl;
} else {
perror("[Sender] Write failed");
}
counter++;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "\n[Sender] Stopping...\n";
close(fd);
std::cout << "[Sender] Closed.\n";
return 0;
}
g++ -o rs485_sender rs485_sender.cpp
./rs485_sender
Receiver: rs485_receiver.cpp
#include <iostream>
#include <cstring>
#include <thread>
#include <chrono>
#include <csignal>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
volatile std::sig_atomic_t running = 1;
void signal_handler(int) {
running = 0;
}
bool configure_serial_port(int fd) {
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
perror("[Receiver] tcgetattr");
return false;
}
cfsetospeed(&tty, B9600);
cfsetispeed(&tty, B9600);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag &= ~IGNBRK;
tty.c_lflag = 0;
tty.c_oflag = 0;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 10;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_cflag |= (CLOCAL | CREAD);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("[Receiver] tcsetattr");
return false;
}
return true;
}
int main(int argc, char** argv) {
signal(SIGINT, signal_handler);
const char* device = argc > 1 ? argv[1] : "/dev/ttyTHS1";
std::cout << "[Receiver] Opening serial port: " << device << std::endl;
int fd = open(device, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
perror("[Receiver] open");
return 1;
}
if (!configure_serial_port(fd)) {
close(fd);
return 1;
}
std::cout << "[Receiver] Serial port ready. Press Ctrl+C to stop.\n";
uint8_t buffer[2];
while (running) {
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read > 0) {
std::cout << "[Receiver] Received: ";
for (ssize_t i = 0; i < bytes_read; ++i) {
std::cout << static_cast<int>(buffer[i]) << " ";
}
std::cout << std::endl;
} else {
std::cout << "[Receiver] No data received.\n";
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "\n[Receiver] Stopping...\n";
close(fd);
std::cout << "[Receiver] Closed.\n";
return 0;
}
g++ -o rs485_receiver rs485_receiver.cpp
./rs485_receiver
Troubleshooting
- No data is being sent or received: Check the wiring and termination resistors. Check the user permissions and serial port parameters such as baud rate, etc.