Skip to content

RS-485 Usage

The RS-485 transceiver on the RS485 CAN HAT (SP3485) connects to the Pi’s UART and supports half-duplex communication at up to 10 Mbps. By default, the board ships with hardware auto TX/RX switching, so you can send and receive without toggling any GPIO pins in software.

  1. Enable UART. In /boot/config.txt (or /boot/firmware/config.txt), make sure the UART overlay is enabled:

    enable_uart=1
  2. Disable the serial console. The Pi’s default login shell on the serial port will interfere with RS-485 data. Use raspi-config to disable it:

    Terminal window
    sudo raspi-config

    Navigate to Interface Options > Serial Port. Answer No to “login shell accessible over serial” and Yes to “serial port hardware enabled.”

  3. Reboot.

    Terminal window
    sudo reboot

RS-485 uses a differential pair. Connect your two devices as follows:

HAT TerminalRemote Device
AA
BB
GNDGND (recommended)

Connecting GND between devices is not strictly required by the RS-485 standard, but it is strongly recommended to establish a common reference and prevent ground-potential differences from corrupting data.

Install pyserial and make sure RPi.GPIO is available (it ships with Raspberry Pi OS by default):

Terminal window
pip3 install pyserial
import RPi.GPIO as GPIO
import serial
EN_485 = 4
GPIO.setmode(GPIO.BCM)
GPIO.setup(EN_485, GPIO.OUT)
GPIO.output(EN_485, GPIO.HIGH) # HIGH = transmit mode
t = serial.Serial("/dev/ttyS0", 115200)
print(t.portstr)
strInput = input('Enter some words: ')
n = t.write(strInput.encode())
print(f"Wrote {n} bytes")
# Read back echo (if loopback or remote device echoes)
response = t.read(n)
print(response)
#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#define EN_485_PIN 7 /* wiringPi pin 7 = BCM GPIO 4 */
int main(void)
{
int fd;
if (wiringPiSetup() < 0) {
fprintf(stderr, "wiringPi setup failed\n");
return 1;
}
pinMode(EN_485_PIN, OUTPUT);
digitalWrite(EN_485_PIN, HIGH); /* Transmit mode */
fd = serialOpen("/dev/ttyS0", 115200);
if (fd < 0) {
fprintf(stderr, "Unable to open serial device\n");
return 1;
}
serialPuts(fd, "Hello from RS-485!\n");
printf("Data sent.\n");
serialClose(fd);
return 0;
}

Compile with:

Terminal window
gcc -o rs485_send rs485_send.c -lwiringPi
gcc -o rs485_recv rs485_recv.c -lwiringPi

In its default factory configuration, the RS485 CAN HAT provides automatic transmit/receive switching. The RSE (RS-485 Enable) pin is connected through a circuit that detects UART activity and toggles the SP3485 direction pin automatically. This means:

  • You do not need to control GPIO 4 in software.
  • The transceiver switches to transmit when the UART sends data and returns to receive when the line goes idle.

This is the simplest mode of operation and works well for most applications.

If your application requires explicit control over transmit/receive timing (for example, to implement a custom protocol with tight turnaround requirements), you can switch to manual control:

  1. Modify the board. Move the 0-ohm resistor from the “AUTO” position to the “MANUAL” position on the RSE selector pads. Refer to the board silkscreen for pad locations.

  2. Control GPIO 4 (BCM) in software. The RSE pin directly drives the SP3485 enable lines:

    • HIGH = transmit mode (driver enabled, receiver disabled)
    • LOW = receive mode (driver disabled, receiver enabled)
  3. Toggle before send/receive.

    import RPi.GPIO as GPIO
    EN_485 = 4
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(EN_485, GPIO.OUT)
    # To transmit:
    GPIO.output(EN_485, GPIO.HIGH)
    # ... write to serial ...
    # To receive:
    GPIO.output(EN_485, GPIO.LOW)
    # ... read from serial ...