RS485
The Pi-Tron has an RS485 interface connected to uart0. In order to use uart0 the following adjustments have to be made.
Baud rate: 115200
1. Update Raspberry Pi OS
pi@raspberry:~ $ sudo apt-get udpate
pi@raspberry:~ $ sudo apt-get dist-upgrade
2. Edit the config.txt
pi@raspberry:~ $ sudo nano /boot/config.txt
Enter the following at the end of the file:
### Serial interface
dtoverlay=uart0,txd0_pin=32,rxd0_pin=33,pin_func=7 ## RS485 on UART0
3. UART and Serial device assignments
The following table shows the relation between the UART, tty and serial devices on the Pi-Tron.
Pi-Tron | Used as | Accessible via | Connector |
---|---|---|---|
uart0 | Console; TTL; RS485 | /dev/ttyAMA0, /dev/serial0 | X800 |
uart1 | Console; TTL; RS485; RS232 | /dev/ttyS0, /dev/serial1 | X900 |
Send and Receive mode: The send and receive direction of the RS485 chip can be controlled through GPIO 30
. The GPIO has to be configured as output and setting it to 0
or Low
switches the chip to receive
mode, whereas setting it to 1
or High
switches the chip to send
mode.
After the activation of a UART on the Pi-Tron, the relation between serial device and tty device can be looked up in the /dev
folder of the OS.
The following command shows which serial device points to which tty device.
pi@pitron:~ $ ls -la /dev/ser*
lrwxrwxrwx 1 root root 7 Feb 14 2019 /dev/serial0 -> ttyAMA0
lrwxrwxrwx 1 root root 5 Feb 14 2019 /dev/serial1 -> ttyS0
In the above listing both Pi-Tron serial devices have been activated. If only one UART device is on then this command will only produce one line as a result or if no UARTs are active, an error will be shown.
Note: After activating a serial device on the Pi-Tron, there could still be an operating system console active on the serial device. To make sure the serial device can be used exclusively by the user, the cmdline.txt
file in the /boot
folder has to be checked.
pi@pitron:~ $ sudo nano /boot/cmdline.txt
Look for the part which reads console=serial0,115200
or console=serial1,115200
and delete it from the cmdline.txt file if it is present. Make sure to not insert any line breaks, all the information in the cmdline.txt has to be on one single line.
Example:
Before, the system console is active on serial0:
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=43c1e3bb-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
After, the console is now deactivated on all serial devices:
dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=43c1e3bb-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
4. Further reading
For more information about the Raspberry Pi serial devices, visit the Raspberry Pi website here: https://www.raspberrypi.org/documentation/computers/configuration.html#configuring-uarts
5. Examples
The following example shows how to write and read data from the RS485 interface using ttyAMA0
(other names: serial0 or uart0). We use the GPIO 30 to switch between send and receive mode of the RS485 chip. The example was made for Python 3 using pySerial 3.4 (sudo pip3 install pyserial==3.4).
#!/usr/bin/python3
import serial, time
import RPi.GPIO as GPIO
# Set GPIO configuration for GPIO 30, we need output
# GPIO 30 switches between send and receive mode of the
# RS485 chip. HIGH = send, LOW = recieve
GPIO.setmode(GPIO.BCM)
GPIO.setup(30, GPIO.OUT)
GPIO.output(30, GPIO.HIGH)
# Create serial object and set configuration
ser = serial.Serial()
ser.port = "/dev/ttyAMA0"
ser.baudrate = 115200
ser.bytesize = serial.EIGHTBITS
ser.parity = serial.PARITY_NONE
ser.stopbits = serial.STOPBITS_ONE
#Set timeout to None, blocking read
ser.timeout = None
ser.writeTimeout = 2
# Open serial device....
try:
ser.open()
except Exception as e:
print ("Error while opening the serial port: " + str(e))
exit()
# When the serial port is open, we can communicate
if ser.isOpen():
try:
# Empty input buffer on start
ser.flushInput()
# Empty and delete out going data
ser.flushOutput()
# Wait
time.sleep(0.1)
# Variable to hold how many lines of data we wrote and received
numOfLines = 0
while True:
# Write a "Hello World!" to the serial device
ser.write("Hellow World!\n".encode())
# Flush out the data in the buffer
ser.flush()
# Print something to the consle...
print("Write data! " + str(numOfLines))
# Count lines written .. and received...
numOfLines = numOfLines + 1
# Set GPIO 30 to low, meaning receive data on RS485
GPIO.output(30, GPIO.LOW)
# Sleep
time.sleep(0.01)
# Try to read from the serial port until LF ir \n is received
try:
# Wait for data, blocking call, as timeout is set to None
myvar = ser.read_until() # Wait for LF
except:
# If wrong data is received or status of serial port not ready...
myvar = b'Error receiving!'
# Print recieved data to console...
print("Read data! " + myvar.decode('ascii'))
# If we have written 50 time the line "Hello World!" to the
# serial port and also received something, leave the program
if (numOfLines >= 50):
break
# Change the GPIO 30 back to high, write data
GPIO.output(30, GPIO.HIGH)
# Wait some time...
time.sleep(0.05)
# When we are done, close the serial port and leave the program...
ser.close()
except Exception as e1:
# If there is a problem while communicating...
print ("Error while communicating....:" + str(e1))
else:
#Something went wrong while opening the serial port.
print ("Cannot open serial port!")
The following two examples are written in C and use the WiringPi library to facilitate the communication over a serial device, which is in this case /dev/ttyAMA0
. The first program just writes one string to the RS485 and then quits. The second program just receives characters and prints them to the console.
First we have to install the WiringPi library:
sudo apt-get update
sudo apt-get install git-core
cd ~
git clone https://github.com/WiringPi/WiringPi.git
cd WiringPi
./build
gpio -v
Executing "gpio -v" prints the current WiringPi version to the console as well as the Raspberry Pi model. The WiringPi library should report version 2.52 or later.
The programs below can be compiled like this:
gcc -o rs485_receive rs485_receive.c -lwiringPi
In this case the source code file is named "rs485_receive.c", but you can simply substitute that with your filename. The parameter "-o" for output allows you to name the compiled program which can be different from the name of the source code file if you choose so.
Send data via RS485:
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/types.h>
#include <inttypes.h>
#include <wiringPi.h>
#include <softPwm.h>
#include <wiringPiSPI.h>
#include <wiringSerial.h>
int fd;
int pin_rs485_dir = 30;
char strDevice[256] = "/dev/ttyAMA0";
char strToSend[256] = "Hello World!";
// We are using a baud rate of 19200
int baudRate = 19200;
int main (void)
{
int chr;
int nRet;
//Setup
wiringPiSetup();
//Set GPIO 30 as output
pinMode(pin_rs485_dir, OUTPUT);
//Switch RS485 to send
digitalWrite(pin_rs485_dir,1);
// Opening the serial device, we just supply the baud rate,
// WiringPi does the rest for us and sets 8 databits and no parity
fd = serialOpen(strDevice,baudRate);
if(fd==-1)
{
printf("Error: Couldn't open serial device\n");
}
else
{
printf("Opened serial device [fd=%d]\n",fd);
// Write our string to the serial device and thus to the RS485 chip
serialPuts(fd, strToSend);
printf("put string %s\n",strToSend);
serialClose(fd);
printf("Closed serial device\n");
}
}
Receive data via RS485:
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/types.h>
#include <inttypes.h>
#include <wiringPi.h>
#include <softPwm.h>
#include <wiringPiSPI.h>
#include <wiringSerial.h>
int fd;
int pin_rs485_dir = 30;
char strDevice[256] = "/dev/ttyAMA0";
// We are using a baud rate of 19200
int baudRate = 19200;
int main (void)
{
int chr;
int nRet;
// Setup
wiringPiSetup();
// Set GPIO 30 as output
pinMode(pin_rs485_dir, OUTPUT);
// Switch RS485 to receive
digitalWrite(pin_rs485_dir,0);
// Opening the serial device, we just supply the baud rate,
// WiringPi does the rest for us and sets 8 databits and no parity
fd = serialOpen(strDevice,baudRate);
if(fd==-1)
{
printf("Error: Couldn't open serial device\n");
}
else
{
printf("Opened serial device [fd=%d]\n",fd);
printf("Recv: ");
fflush(stdout);
while(1)
{
// Check to see if we received data
nRet = serialDataAvail(fd);
if (nRet>=0)
{
// Get data from the buffer
chr = serialGetchar(fd);
if(chr!=-1)
{
// Print it to the console
printf("%c",chr);
fflush(stdout);
}
}
else
{
printf("Error: serialDataAvail=-1\n");
serialFlush(fd);
printf("Flushed serial device\n");
serialClose(fd);
printf("Closed serial device\n");
return 0;
}
}
}
}