Advanced Serial Programming - Appendixes - Arduino: A Quick-Start Guide, Second Edition (2015)

Arduino: A Quick-Start Guide, Second Edition (2015)

Part III. Appendixes

Appendix 3. Advanced Serial Programming

In nearly all of the book’s projects, we’ve used the Arduino’s serial port. Sometimes we only emitted debug messages to monitor the current state of our sketches, but often we needed it to actually output information or to send commands. And the fact is, we’ve used the Serial class without explaining how serial communication actually works. We’ll catch up on that in this appendix.

To communicate with an Arduino, we mainly used JavaScript, and in some cases we used Processing. But many developers prefer other languages, and in this appendix, you’ll also learn how to use C/C++, Java, Ruby, Python, and Perl to talk to an Arduino.

Learning More About Serial Communication

In Chapter 2, Creating Bigger Projects with the Arduino, you saw that you need only three wires for serial communication: a common ground, a line for transmitting data (TX), and one for receiving data (RX). (See the diagram here.)

Data is transmitted as electrical pulses, so both communication partners need a reference for the voltage level, and that’s what the common ground is for. The transmission line is used to send data to the recipient and has to be connected to the recipient’s receiving line. This enables full-duplex communication where both partners can send and receive data simultaneously. (Wouldn’t it be great if people could also communicate full-duplex?)

We now know how to connect two devices, but we still have to transmit some data. Therefore, both communication partners have to agree on a protocol, and here, you can see what a typical serial communication looks like. The different states of a bit are represented by different voltage levels. Usually, a 0 bit is represented by 0 volts, while 5 volts stands for a 1 bit. (Some protocols use -12V and 12V, respectively.)

The following parameters control a serial communication:

images/serial_communication

· A start bit indicates the beginning of a data word and is used to synchronize the transmitter and receiver. It is always 0.

· A stop bit tells us when the last data bit has been sent and separates two consecutive data words. Depending on the particular protocol agreement, there can be more than one stop bit, but that happens rarely.

· Information is transferred as binary data bits; that is, if you’d like to transmit the letter M, you have to turn it into a number first. Several character set encodings are available, but when working with the Arduino, the ASCII encoding fits best. In ASCII, an uppercase M is encoded as the decimal number 77, which is 01001101 in binary. This is the bit sequence that eventually gets transmitted.

· The parity bit indicates whether the number of 1s in the data has been odd or even. This is a simple error-checking algorithm that is rarely used and that stems from a time when network connections were less reliable than they are today. Parity control can be “none” (no parity bit is sent), “odd” (the parity bit is set if the amount of 1s in the data bits is odd; otherwise, it is 0), or “even” (the parity bit is set if the amount of 1s in the data bits is even; otherwise, it is 0). We chose odd parity for our data, and because there are 4 bits set to 1 in 01001101, the parity bit is 0.

· The baud rate defines the transmission speed and is measured in transmission steps per second. When working with the Arduino, typical baud rates are 9600, 14400, 19200, or even 115200. Note that the baud rate doesn’t define how much data is actually transferred per second, because you have to take the control bits into account. If your connection settings are 1 start bit, 1 stop bit, no parity, and 8 bits per byte, then you have to transfer 1 + 1 + 8 = 10 bits to transfer a single byte. With a baud rate set to 9600, you can then theoretically send 9600 / 10 = 960 bytes per second—at least if every bit gets transferred in exactly one transmission step.

Serial Communication Using Various Languages

When working with the Arduino, you often have to talk to it using a serial port. In this section, you’ll learn how to do that in various programming languages. For demonstration purposes, we’ll use the same Arduino sketch for all of them:

SerialProgramming/AnalogReader/AnalogReader.ino

const unsigned int BAUD_RATE = 9600;

const unsigned int NUM_PINS = 6;

String pin_name = "";

boolean input_available = false;

void setup() {

Serial.begin(BAUD_RATE);

}

void loop() {

if (input_available) {

if (pin_name.length() > 1 &&

(pin_name[0] == 'a' || pin_name[0] == 'A'))

{

const unsigned int pin = pin_name.substring(1).toInt();

if (pin < NUM_PINS) {

Serial.print(pin_name);

Serial.print(": ");

Serial.println(analogRead(pin));

} else {

Serial.print("Unknown pin: ");

Serial.println(pin);

}

} else {

Serial.print("Unknown pin name: ");

Serial.println(pin_name);

}

pin_name = "";

input_available = false;

}

}

void serialEvent() {

while (Serial.available()) {

const char c = Serial.read();

if (c == '\n')

input_available = true;

else

pin_name += c;

}

}

This program waits for the name of an analog pin (a0, a1,…a5) and returns its current value. So, all of our clients have to send data to the Arduino (the name of the pin), and they have to receive the result. In the following figure, you can see it working with the IDE’s serial monitor.

images/analog_reader

Although you have already seen a few Arduino programs using the serial port, you should pay special attention to the sketch above, because it uses one of the new features in Arduino 1.0: the serialEvent function. The Arduino calls this function automatically at the end of the loop function, and you can use it to process data arriving at the serial port. This nicely decouples your application’s logic from the more or less mechanical task of performing serial communication.

Programs using serialEvent often follow the same pattern. They define a global variable for aggregating incoming data (pin_name in our case), and they define a global Boolean variable that indicates whether new data is available (input_available, in our case). Whenever we read a newline character from the serial port, we set input_available to true. So, when the Arduino calls loop the next time, we know that new data has arrived, and we also know that we can find it in pin_name. After we have processed the data, we set the input string to an empty string and setinput_available to false.

Back to the clients we’re going to implement. Although we use different programming languages to implement them, they all look similar: they expect the name of the serial port to connect to as a command-line argument; they constantly send the string “a0” to the Arduino to get back the current value of analog pin 0; they print the result to the console; they use a constant baud rate of 9600; and they wait for two seconds after opening the serial port, because many Arduinos reboot upon opening a serial connection.

Some Arduinos—for example, the Leonardo or the Micro—do not reboot upon opening a serial connection. If you’re using one of these boards, your program should wait until the serial stream is open:

Serial.begin(9600);

while (!Serial) ;

For some of the clients, you need to install additional libraries. In some cases, you have to do that as an admin user on your machine. I won’t mention that explicitly in the following sections. Also, you should make sure you don’t have any serial monitor windows open when running one of the examples in the following sections.

Finally, you should keep in mind that all sample programs show the bare mechanics of serial port programming. In production code you’d at least check whether the data you read back from the Arduino has the right format.

C/C++

Although you program the Arduino in C++, you don’t need to write clients talking to the Arduino in C++ or C. Still, you can, and it’s easy if you use Tod E. Kurt’s excellent arduino_serial[147] as a basis.

The project implements a complete command-line tool offering a lot of useful options. For our purposes, that’s not necessary. It’s sufficient to download the files arduino-serial-lib.h and arduino-serial-lib.c.

The arduino-serial library exports the following functions:

· serialport_init opens a serial port connection. It expects the name of the serial port to be opened and the baud rate to be used. It returns a file descriptor if everything went fine, and it returns -1 otherwise.

· When you no longer need the serial port connection, you should close it using serialport_close.

· With serialport_writebyte, you can send a single byte to an Arduino connected to your computer’s serial port. Simply pass it the file descriptor returned by serialport_init and the byte to be written. It returns -1 if an error occurred. Otherwise, it returns 0.

· serialport_write writes an entire string to the serial port. It expects a file descriptor and the string to be written. It returns -1 if an error occurred. Otherwise, it returns 0.

· Use serialport_read_until to read data from a serial port. Pass it a file descriptor and a buffer to be filled with the data read. The method also expects a delimiter character, the maximum length of the buffer, and a timeout value measured in milliseconds. serial_port_read_until stops reading when it finds the delimiter character, when the buffer is full, or when it times out. If it cannot read any more data before one of these conditions is met, it returns -1. Otherwise, it returns 0.

· To make sure that all data you’ve written gets actually transferred, call serialport_flush and pass it the file descriptor of your serial port connection.

Here’s how to use the code for communicating with our analog reader sketch (note that the following code will run on your PC and not on your Arduino):

SerialProgramming/C/analog_reader.c

Line 1

#include <stdio.h>

-

#include <unistd.h>

-

#include <termios.h>

-

#include "arduino-serial-lib.h"

5

#define MAX_LINE 256

-

-

int main(int argc, char* argv[]) {

-

int timeout = 1000;

-

10

if (argc == 1) {

-

printf("You have to pass the name of a serial port.\n");

-

return -1;

-

}

-

int baudrate = B9600;

15

int arduino = serialport_init(argv[1], baudrate);

-

if (arduino == -1) {

-

printf("Could not open serial port %s.\n", argv[1]);

-

return -1;

-

}

20

sleep(2);

-

char line[MAX_LINE];

-

while (1) {

-

int rc = serialport_write(arduino, "a0\n");

-

if (rc == -1) {

25

printf("Could not write to serial port.\n");

-

} else {

-

serialport_read_until(arduino, line, '\n', MAX_LINE, timeout);

-

printf("%s", line);

-

}

30

}

-

serialport_close(arduino);

-

return 0;

-

}

First we import all the libraries we need, and we define a constant for the maximum length of the lines we are going to read from the Arduino. Then we define a main function.

After we’ve made sure that the name of a serial port was passed on the command line, we initialize a serial port in line 15. Then we sleep for two seconds to give the Arduino some time to get ready. After that, we start a loop in line 23 where we constantly send the string “a0” to the Arduino. We check the result of serialport_write, and if it was successful, we read the result sent by the Arduino in line 27. Let’s compile our little program:

maik> gcc arduino-serial-lib.c analog_reader.c -o analog_reader

Determine what serial port your Arduino is connected to (mine is connected to /dev/tty.usbmodem24321) and run the program like this:

maik> ./analog_reader /dev/tty.usbmodem24321

a0: 495

a0: 376

^C

Everything works as expected, and accessing a serial port using C isn’t that difficult. To embed this code into a C++ program, you should wrap it in a class named SerialPort or something similar.

Note that the arduino-serial library works on any POSIX-compatible system—in other words, it won’t work on Windows.

Java

The Java platform standardizes a lot, and it also defines how to access a serial port in the Java Communications API.[148] But the API is only a specification that still has to be implemented. Unfortunately, there is no complete or even perfect implementation available at the time of this writing.

For many years the RXTX project[149] provided a good implementation, but it hasn’t been updated for a while now.

Oracle’s own implementation runs only on a few platforms, and the remaining solutions are commercial products you have to pay for.

Fortunately, the jSSC (java-simple-serial-connector) project[150] comes to the rescue. It doesn’t implement the Java Communications API, but it follows a rather pragmatic approach. (Guess why we’re using it?) Also, it doesn’t have a lot of bells and whistles yet, but it runs on many platforms and works perfectly with the Arduino.

jSSC is completely self-contained—that is, you only need the jssc.jar file to get started with your first project. Download the most current release and make sure that jssc.jar is on your class path. Then enter the following code in your favorite IDE or text editor:

SerialProgramming/Java/AnalogReader.java

import jssc.SerialPort;

import jssc.SerialPortList;

import jssc.SerialPortException;

public class AnalogReader {

public static void main(String[] args) throws Exception {

if (args.length != 1) {

System.out.println(

"You have to pass the name of a serial port."

);

System.exit(1);

}

try {

SerialPort serialPort = new SerialPort(args[0]);

serialPort.openPort();

Thread.sleep(2000);

serialPort.setParams(

SerialPort.BAUDRATE_9600,

SerialPort.DATABITS_8,

SerialPort.STOPBITS_1,

SerialPort.PARITY_NONE

);

while (true) {

serialPort.writeString("a0\n");

System.out.println(readLine(serialPort));

}

}

catch (SerialPortException ex) {

System.out.println(ex);

}

}

private static String readLine(SerialPort serialPort) throws Exception {

final int MAX_LINE = 10;

final byte NEWLINE = 10;

byte[] line = new byte[MAX_LINE];

int i = 0;

byte currentByte = serialPort.readBytes(1)[0];

while (currentByte != NEWLINE) {

line[i++] = currentByte;

currentByte = serialPort.readBytes(1)[0];

}

return new String(line);

}

}

Although this program defines a class named AnalogReader, it’s not very object-oriented. We only define it because everything in Java has to live in a class context.

The main function implements the protocol for our Arduino sketch. First, we make sure that the name of a serial port was set on the command line. Then we use this name to initialize a new SerialPort object. To open the serial port, we call the openPort method. After a two-second pause, we configure the serial port’s parameters.

In the loop that follows, we send the string “a0” to the serial port using SerialPort’s writeString method. Afterward, we read the result by invoking the readLine function and print it to the console.

Currently, jSSC doesn’t offer a readLine function, so we have to write our own. The function reads the Arduino’s response byte by byte using the readBytes method, because jSSC doesn’t offer a method for reading a single byte. readLine appends all bytes read to the byte array named lineuntil it detects a newline character (ASCII code 10). Finally, it converts the byte array into a String object and returns it.

Here’s how to compile and use the program:

maik> javac -cp jssc.jar AnalogReader.java

maik> java -cp jssc.jar:. AnalogReader /dev/tty.usbmodem24321

a0: 496

a0: 433

a0: 328

a0: 328

^C

AnalogReader does exactly what it’s intended to do: it permanently prints the values of the analog pin 0. Accessing a serial port in Java is a piece of cake if you use the right libraries.

Note that jSSC also allows you to write object-oriented code. It has a SerialPortEventListener interface that makes it easy to decouple the handling of serial communication from your application’s logic. Have a look at the project’s examples to learn more about these features.

Ruby

Even dynamic languages such as Ruby give you instant access to your computer’s serial port and to an Arduino connected to it. But before that, you need to install the serialport gem:

maik> gem install serialport

Using it, you can connect to the Arduino in just 30 lines of code.

SerialProgramming/Ruby/analog_reader.rb

Line 1

require 'rubygems'

-

require 'serialport'

-

-

if ARGV.size != 1

5

puts "You have to pass the name of a serial port."

-

exit 1

-

end

-

-

port_name = ARGV[0]

10

baud_rate = 9600

-

data_bits = 8

-

stop_bits = 1

-

parity = SerialPort::NONE

-

15

arduino = SerialPort.new(

-

port_name,

-

baud_rate,

-

data_bits,

-

stop_bits,

20

parity

-

)

-

-

sleep 2

-

while true

25

arduino.write "a0\n"

-

sleep 0.01

-

line = arduino.gets.chomp

-

puts line

-

end

We create a new SerialPort object in line 15, passing it all the usual parameters. After we sleep for two seconds, we start a loop and call write on the SerialPort object. To get the result back from the Arduino, we call gets, and then we print the result to the console. Here you can see the program in action:

maik> ruby analog_reader.rb /dev/tty.usbmodem24321

a0: 496

a0: 456

a0: 382

^Canalog_reader.rb:27:in `gets': Interrupt

from analog_reader.rb:27

Using Ruby to access an Arduino is a good choice because you can fully concentrate on your application. All of the ugly details you have to deal with in other programming languages are well hidden.

Python

Python is another dynamic programming language you can use to quickly create Arduino clients. For programming a serial port, download and install the pyserial library first.[151] There is a special installer for Windows, but usually it’s sufficient to install it like this:

maik> python setup.py install

After you’ve installed pyserial, you can use it to create a client for our analog reader sketch:

/SerialProgramming/Python/analog_reader.py

Line 1

import sys

-

import time

-

import serial

-

5

if len(sys.argv) != 2:

-

print "You have to pass the name of a serial port."

-

sys.exit(1)

-

-

serial_port = sys.argv[1]

10

arduino = serial.Serial(

-

serial_port,

-

9600,

-

serial.EIGHTBITS,

-

serial.PARITY_NONE,

15

serial.STOPBITS_ONE)

-

time.sleep(2)

-

while 1:

-

arduino.write("a0\n")

-

line = arduino.readline().rstrip()

20

print line

We make sure that we have the name of a serial port on the command line. Then we create a new Serial object in line 10, passing it all the parameters we’d like to use for serial communication.

After sleeping for two seconds, we start an infinite loop. In the loop, we send the string “a0” to the serial port calling write. We read the result returned by the Arduino using the readline method and output the result to the console. Here’s what a typical session looks like:

maik> python analog_reader.py /dev/tty.usbmodem24321

a0: 497

a0: 458

a0: 383

^C

Isn’t that code beautiful? With about twenty lines of Python code, you get full control over your Arduino sketch. So, Python is another excellent choice for writing Arduino clients.

Perl

Perl is still one of the most widely used dynamic programming languages, and it has good support for serial communication. Some distributions come with libraries for programming the serial port, but usually you have to install a module first.

Windows users should have a look at Win32::SerialPort.[152] For the rest, Device::SerialPort is a good choice. You can install it as follows:

maik> perl -MCPAN -e 'install Device::SerialPort'

Then use it like this:

SerialProgramming/Perl/analog_reader.pl

Line 1

use strict;

-

use warnings;

-

use Device::SerialPort;

-

5

my $num_args = $#ARGV + 1;

-

if ($num_args != 1) {

-

die "You have to pass the name of a serial port.";

-

}

-

10

my $serial_port = $ARGV[0];

-

my $arduino = Device::SerialPort->new($serial_port);

-

$arduino->baudrate(9600);

-

$arduino->databits(8);

-

$arduino->parity("none");

15

$arduino->stopbits(1);

-

$arduino->read_const_time(1);

-

$arduino->read_char_time(1);

-

-

sleep(2);

20

while (1) {

-

$arduino->write("a0\n");

-

my ($count, $line) = $arduino->read(255);

-

print $line;

-

}

We check whether the name of a serial port was passed on the command line. Then we create a new Device::SerialPort instance in line 11. We configure all serial port parameters, and in line 16, we set a timeout value for read calls. If we did not set it, read would return immediately, giving the Arduino no time to respond. read_char_time sets a timeout for the waiting period between two characters.

Then we sleep for two seconds and start an infinite loop. Here we send the string “a0” to the serial port and read the Arduino’s response using the read method. read expects a maximum number of bytes to be read, and it returns the actual number of bytes read and the data it received. Finally, we output the result to the console. A typical program run looks as follows:

maik> perl analog_reader.pl /dev/tty.usbmodem24321

a0: 496

a0: 366

a0: 320

^C

That’s it! It takes only about twenty lines of Perl code to create a client for the analog reader Arduino sketch. So, Perl is a good choice for programming Arduino clients, too.

Footnotes

[147]

https://github.com/todbot/arduino-serial

[148]

http://www.oracle.com/technetwork/java/index-jsp-141752.html

[149]

http://rxtx.qbang.org/

[150]

https://code.google.com/p/java-simple-serial-connector/

[151]

http://sourceforge.net/projects/pyserial/files/

[152]

http://search.cpan.org/dist/Win32-SerialPort/