Python Exemplary - RPi Tutorial
deutsch     english    

SERIAL PORT, GPS

The source code of all examples can be downloaded from here.

 

What is the RS-232C protocol?

 

Although Bluetooth, Ethernet, or USB interfaces are commonly used for communication between a computer and peripherals (and I2C, SPI and 1-Wire for microcontroller systems), the communication over the serial interface (RS-232C) is still widespread. Traditionally the serial interface is still used to connect measurement devices (voltmeters, oscilloscopes, etc.) and to communicate with roboters, modems and microprocessor systems (e.g. downloading programs to the Arduino). Modern computers no longer have serial ports, however this problem can be easily solved with low cost USB-to-serial adapters.

The format of the transmitted data is simple. It consists of chronologically transmitted data bytes. The transfer begins with a start bit, where the receiver calls attention to the pending data transfer. Then the data itself follows, including 5, 6, 7 or (usually) 8 bits. In order to facilitate an error correction, a parity bit may be sent which indicates whether an odd or an even number of bits were set, but the parity bit may also be omitted. The transfer is completed with one or two stop bits. In the idle state the sending and receiving devices are not synchronized with each other, i.e. the data transfer can begin at any time (asynchronous protocol). However, it is necessary that both devices agree upon the same time duration of a single bit. This is specified by the baud rate (in baud, bits/s) and can usually only be any of the standardized values 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 baud. In addition, both devices can agree on a handshake (flow control), with which they inform each other whether they are ready for the data transfer. You can distinguish between a hardware and a software handshake depending on whether the handshake uses specific handshake pathways or whether it occurs using special ASCII characters (XON/XOFF) embedded in the data stream.

A typical RS232 port configuration therefore comprises: Baud rate, the number of data bits (5, 6, 7, 8), the number of stop bits (1 or 2) , parity (none, odd, or even), handshake (none, hardware or software).

Example: The flow of voltage during the transmission of the letter 'B', with the configuration 7 databit/no parity/1 stopbit looks as follows.

gps4

 

 

Serial ports on the Raspberry Pi

 

You have two choices to add a serial port to the Raspberry Pi, either over the GPIO connector or using an external USB-Serial converter. Since the Raspbian operation system supports the most common USB-Serial converters like the U232-P9 that you find on eBay and computer shops, it is recommended to connect external RS232-devices via USB. But sometimes you have breakout-modules with a serial interface that are directly connected to the GPIO header such as most GPS modules specially designed for the Raspberry Pi. In this case GPIO pins #8 and #10 are used as UART-TXD0 and UART-RXD0 data transfer ports.

By default, the Raspberry Pi uses the GPIO serial ports to connect an external RS232 terminal as an alternative Linux shell. In early days of the Raspberry Pi this was a interesting alternative that remembers the good old days when terminals (and teleprinter) where the standard input-output devices for minicomputers and mainframes. Today, there are no more specially terminal monitors, but still virtual terminals (terminal emulators) for all common platforms. One of the most popular is PuTTY that can be easily installed even on the Raspberry Pi.

If you want to use the GPIO port for serial communication other than a console, you must disable the console by the Raspi configuration dialog as follows:

Use a attached keyboard/screen or a VNC connection and type in a console:
sudo raspi-config. Select Advanced Options:

gps5

Serial:

gps6

and say No for a login shell:

gps7

 

 

 

GPIO serial communication with the Raspberry Pi 3

 

Unfortunately things changed a bit with the current version of the Jessie operating system for the Raspberry Pi 3. First the serial port name ttyAMA0 reserved until now for the GPIO serial communication was stolen by the Bluetooth driver. The GPIO serial port name is ttyS0 now. Second and more annoying is the fact that the serial port is not functioning because of the higher CPU core clock frequency. Proceed as follows if the GPIO serial port is used:

In a console, open the file /boot/config.txt as sudo in the nano editor

sudo nano /boot/config.txt

and add the line

core_freq=250

Then reboot:

sudo reboot

To access the serial port in your programs, you must use the port name ttyS0 instead of ttyAMA0 and everything should work as with the older Raspberry Pi models. It is not well documented whether the decreased core frequency influences the general behavior of the system.

You can get information about the names of all serial ports with the command

dmesg | grep tty

If you find the text:

console [ttyS0] enabled
(for Raspberry Pi 3)

console [ttyAMA0] enabled
(for older Raspberry Pi)

the console is not disabled (see above how to disable it).

 

 

Serial communication using a Serial-USB converter

 

As stated before, most models are supported by the current version of the Jessie operating system. After you insert the adapter, you can check if it is recognized by typing

dmesg | grep tty

You should see a line with USB like

pl2303 converter now attached to ttyUSB0

Note the name ttyUSB0 of the serial port, because you will need it in your programs.

gps8

 

 

RS232 level converter for the serial GPIO port

 

Since GPIO ports use 0/3.3V logic, you must insert a TTL to RS232 level converter if you want to use the GPIO for external RS232 devices. Most of them are built around the MAX3232 chip. Connect the 4 pins as shown to the right. (Search on eBay for “RS232 Serial Port To TTL Converter Module MAX3232”).

gps10
(Red arrows show data flow direction)

The female DB9 connector uses the following pinout:

gps12

Caution: Never connect an external RS232 device directly to the GPIO, because the high voltage level may destroy the Raspberry Pi. If you connect a serial device with a R232-converter, make sure that it uses the 3.3V supply (pin # 1).

There are also serial devices/adapters working with TTL levels. If you want to use such a device directly with the GPIO port, make sure that you can power it with 3.3V since the standard TTL signal 0V/5V can destroy your Raspberry Pi.

 

 

Experiment 1: Simulating a device connected via RS232

 

Sometimes you want to use the Raspberry Pi as controller or interface to a measurement device or a sensor that communicates via a serial connection.

Aim:
For this demonstration we simulate the measurement device by a computer running a terminal emulator (like PuTTY) over a serial port (e.g. a USB-to-RS232 adapter). For the Raspberry Pi we use the GPIO with a level converter. DB9 male and female plug pins correspond.

gps13

Program:[►]

# Serial1.py

import serial
import time

port = "/dev/ttyAMA0"  # Raspberry Pi 2
#port = "/dev/ttyS0"    # Raspberry Pi 3

def readLine(port):
    s = ""
    while True:
        ch = port.read()
        s += ch
        if ch == '\r':
            return s

ser = serial.Serial(port, baudrate = 1200)
print "starting"
while True:
    time.sleep(1)
    print "sending synch"
    ser.write("A")
    rcv = readLine(ser)
    print "received:", rcv
Highlight program code (Ctrl+C copy, Ctrl+V paste)

Remarks:
The Raspberry Pi controller sends a synchronizing character 'A' to the device to request data. Then it accumulates incoming characters in the blocking function readLine() until a <CR> is received.

To avoid blocking the main loop may request data every second and accumulate any number of received characters by checking the number of characters nbChars in the input buffer and use read(nbChars) to get them altogether.

Program:[►]

# Serial2.py

import serial
import time

port = "/dev/ttyAMA0"  # Raspberry Pi 2
#port = "/dev/ttyS0"    # Raspberry Pi 3

ser = serial.Serial(port, baudrate = 1200)
print "starting"
while True:
    time.sleep(1)
    ser.write("A")
    nbChars = ser.inWaiting()
    if nbChars > 0:
        data = ser.read(nbChars)
        print data

Highlight program code (Ctrl+C copy, Ctrl+V paste)

Remarks:
For testing purposes of a RS-232 device attached to the Raspberry Pi, it is sometime convenient to use a terminal emulator in order to communicate manually instead of using a program. To do so, install PuTTY on the Raspberry Pi with the command

sudo apt-get install putty

and open PuTTY in an VNC session by clicking the icon in Menu | Internet. In the Basic options dialog check the button Serial and select /dev/ttyS0 for the Raspberry Pi 3 or /dev/ttyAMA0 for older versions.

serial1

 

 

Experiment 2: Use a GPS module and show current GPS information

 

Commercial GPS modules are typical devices that use the serial protocol to transmit data to an external device. Most of them do not require any special setup nor commands to function. When powered up, they send lines of ASCII text in a special format, called NMEA messages, that can be received as string with with a simple readline() call. Normally the baud rate is 9600 baud by default, but you should consult the data sheet to check this.

Aim:

Attach a GPS module to the Raspberry Pi and capture data lines in the console.

The Cirocomm module mounted on a Raspberry Pi breakout board with a 40 pin header. It is more sophisticated and contains a real-time clock with battery backup and a 3 axis digital compass using I2C communication. It is available from different distributors (see also on eBay).
gps15

Connecting the Microstack module is extremely simple, just use 3 wires as shown in the picture here. If you are operating the module outdoor, there is no need for an external antenna. To test the module, you can start a PuTTY terminal (baud rate: 9600 baud) in a VNC session or write a simple Python program that just reads and displays the incoming data. Be aware that for the Raspberry Pi 3 the serial port name is different and you must set the core_freq parameter as stated above.

Do not power the module with 5V!

gps14

The Grove-GPS module armed with the SIMCOM SIM28 chip is connected the same way, just use 3 wires as shown in the picture here. To test the module, you can start a PuTTY terminal (baud rate: 9600 baud) in a VNC session or write a simple Python program that just reads and displays the incoming data. Again for the Raspberry Pi 3 the serial port name is different and you must set the core_freq parameter as stated above.

Do not power the module with 5 V!

gps17

Program:[►]

# Serial3.py

import serial

port = "/dev/ttyAMA0"  # Raspberry Pi 2
#port = "/dev/ttyS0"    # Raspberry Pi 3

ser = serial.Serial(port, baudrate = 9600, timeout = 0.5)
while True:
    data = ser.readline()
    print "Data:--", data,
Highlight program code (Ctrl+C copy, Ctrl+V paste)

 

Remarks:
The NMEA protocol is somewhat knotty. All NMEA messages start with the $ character, and each data field is separated by a comma. The line containing the latitude and longitude of the current location can be extracted in the $GPGGA line that contains 14 fields. Follows an example:

$GPGGA,181908.00,3404.7041778,N,07044.3966270,W,4,13,1.00,495.144,M,29.200,M,0.10,0000*40

GP represent that it is a GPS position (GL would denote GLONASS).
181908.00 is the time stamp: UTC time in hours, minutes and seconds.
3404.7041778 is the latitude in the DDMM.MMMMM format. Decimal places are variable.
N denotes north latitude.
07044.3966270 is the longitude in the DDDMM.MMMMM format. Decimal places are variable.
W denotes west longitude.
4 denotes the Quality Indicator:
0 = No GPS data
1 = Uncorrected coordinate
2 = Differentially correct coordinate (e.g., WAAS, DGPS)
4 = RTK Fix coordinate (centimeter precision)
5 = RTK Float (decimeter precision.
13 denotes number of satellites used in the coordinate.
1.0 denotes the HDOP (horizontal dilution of precision).
495.144 denotes altitude of the antenna.
M denotes units of altitude (eg. Meters or Feet)
29.200 denotes the geoidal separation (subtract this from the altitude of the antenna to arrive at the Height Above Ellipsoid (HAE).
M denotes the units used by the geoidal separation.
1.0 denotes the age of the correction (if any).
0000 denotes the correction station ID (if any).
*40 denotes the checksum.

Here a proposal how to parse the line "hand-knitted":

Program:[►]

# Serial4.py

import serial

port = "/dev/ttyAMA0"  # Raspberry Pi 2
#port = "/dev/ttyS0"    # Raspberry Pi 3

def parseGPS(data):
#    print "raw:", data
    if data[0:6] == "$GPGGA":
        s = data.split(",")
        if s[7] == '0':
            print "no satellite data available"
            return        
        time = s[1][0:2] + ":" + s[1][2:4] + ":" + s[1][4:6]
        lat = decode(s[2])
        dirLat = s[3]
        lon = decode(s[4])
        dirLon = s[5]
        alt = s[9] + " m"
        sat = s[7]
        print "Time(UTC): %s-- Latitude: %s(%s)-- Longitude:%s(%s)\
-- Altitute:%s--(%s satellites)" %(time, lat, dirLat, lon, dirLon, alt, sat) 

def decode(coord):
    # DDDMM.MMMMM -> DD deg MM.MMMMM min
    v = coord.split(".")
    head = v[0]
    tail =  v[1]
    deg = head[0:-2]
    min = head[-2:]
    return deg + " deg " + min + "." + tail + " min"

ser = serial.Serial(port, baudrate = 9600, timeout = 0.5)
while True:
    data = ser.readline()
    parseGPS(data)
Highlight program code (Ctrl+C copy, Ctrl+V paste)

Remarks:
You can also use a Python NMEA parser module from here.

It is interesting to know the principles of GPS: The GPS receiver determines the distances to at least 3 GPS satellites and calculates the location with triangulation:

gps16