8

Interfacing with Arduino

As well as using straightforward digital inputs and outputs to connect electronics to an Arduino, the Arduino also supports three common standards for serial interfaces. These are I2C (pronounced “I squared C”), SPI, and UART (or TTL Serial).

Whereas digital and outputs are fine for connecting switches or LEDs with no intelligence, the serial interfaces to Arduino are often used to connect ICs or modules that might have their own microcontroller built-in. Serial communication is the norm when you need to send and receive more information than a single high or low. This includes some sensor chips that might send their readings as a stream of binary digits, or display modules that expect to be sent a stream of binary digits telling them what to display.

Each of the three serial interfaces is covered in separate chapters that follow this one, but all have certain basic principles in common. These common principles are described in this chapter.

Binary

You may remember that back in Chapter 5, you learned a little about bits and bytes. Let’s now look at this in more detail.

Computers communicate with each other and with smart peripherals using binary. A bit is a single “binary digit” that can only have a value of 0 (low) or 1 (high). If you only need to communicate a single bit, then you can do that with a digital output that is either high or low. However, if you need to communicate more information than that at a time, then you need to combine a number of bits together. Most often you combine eight bits into what is called a byte.

In our familiar decimal system of numbers (also called base 10), if you have a number like 123, each digit (1, 2, and 3) has one of a possible 10 values (0 to 9). The rightmost digit represents the units, the next digit to the left is the tens, and the leftmost digit (in this example) is the hundreds. So, in actual fact, the decimal number 123 is made up of 1 × 100 + 2 × 10 + 3 × 1.

Computers use binary (base 2) rather than decimal, and in binary, each digit can only have one of two possible values (0 or 1). Rather than each digit position (from right to left) being 10 times the previous digit, it’s just 2 times the previous digit position. So, the binary number 110 must not be confused with decimal one hundred and ten, but is, when converted to decimal, just 1 × 4 + 1 × 2 + 0 = 6.

A byte of eight bits can therefore be used to represent any number between 0 and 255. So binary 11111111 is 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255.

Let’s go back to our decimal number 123. That would in binary be: 0 × 128 + 1 × 64 + 1 × 32 + 1 × 16 + 1 × 8 + 0 × 4 + 1 × 2 + 1 × 1. Collecting together the bits, that gives us a binary number of 01111011. Don’t worry, you are unlikely to ever need to convert between binary and decimal by hand; your pocket calculator or one of many online number-base converters can do that for you.

Arduino Types and Binary

Just as you can declare a variable to be of type int, Arduino C also has two types that are commonly used to represent bytes (byte and char).

A byte represents a number between decimal 0 and decimal 255.

The char data type also represents eight bits, but rather than being concerned with numbers between decimal 0 and decimal 255, the built-in Arduino char type represents numbers between –128 and +127. It is most often used with just its first 7 digits (counting from right to left) to represent characters in the roman alphabet using the encoding of text characters into binary called ASCII (American Standard Code for Information Interchange).

You can read more about Arduino C’s data types in the section “Arduino Data Types” in Chapter 1.

You can try out a bit of binary arithmetic on your Arduino if you like. Download sketch_08_01_binary from www.simonmonk.org/nextsteps2 and upload it onto your Arduino.

Images

When you open the Serial Monitor, you should see trace that looks something like this:

101010

2A

42

Note the use of the B prefix to the numbers to specify that they are in binary. I have included leading zeros so that all eight bits of the byte are shown, but this is not mandatory.

The first result (101010) is the result of the addition printed as binary. Notice the optional number base as the second parameter to println. The next line (2A) is the result in hexadecimal (more on that in the next section) and the final line shows the result in decimal (42).

Hexadecimal

Hexadecimal (more commonly just called hex) is number base 16. This means that each digit of a hex number can have one of 16 possible values. These are represented by the numerical digits 0 to 9 followed by the letters A to F. Table 8-1 shows the numbers between 0 and 15 in decimal, binary, and finally hex.

Images

Table 8-1   Binary and Hexadecimal Numbers

Because a hex digit represents four bits, two hex digits can be used to represent a byte. When dealing with binary communications, you will often find that hex is used rather than binary or decimal.

If you need to define hex values in your Arduino code, you can do so like this:

byte a = 0x2A

The 0x indicates that the digits that follow the x are to be treated as hex, in this case, assigning the decimal value of 42 to a (2 × 16 + 10).

Masking Bits

A common problem when you receive data from a peripheral using any kind of connection is that the data arrives packed into bytes. Peripheral designers often fit as much information as they can into as few bits as possible, speeding up communication, but often at the expense of making the devices more difficult to program.

The process of “masking” bits allows you to disregard some of the data in a byte or larger data structure. Figure 8-1 shows how a byte containing multiple data can be masked to produce a number from the least significant three bits of the byte.

Images

Figure 8-1   Masking bits.

You’ll come across the phrases “least significant” and “most significant” to describe binary numbers. In binary written in the normal mathematical way, the most significant bit is the leftmost bit and the least significant bit is the rightmost. After all, the rightmost is only worth 1. You’ll also see the terms most significant bit (MSB) and least significant bit (LSB).

The least significant bit is also sometimes referred to as bit 0, bit 1 being the next most significant bit, and so on.

In the example shown in Figure 8-1, the data byte has some values at the most significant end that we are not interested in and only three bits at the least significant end that we want to extract as a number.

To do this kind of manipulation use &. The symbol “&” “ands” the corresponding bits of two bytes together. That is, the resulting bit will only be “1” if both the bits at that position are both “1.”

This masking is done by “anding” the data with a mask value that has the three bits you’re interested in set to 1. Then you “and” together two bytes; each of the bits is, in turn, “anded” with each other to build a result. The result of “anding” two bits is only 1, if both the bits are 1.

Here’s how the example looks in Arduino C using the & operator. Note that bitwise “and” uses the single & character rather than the && often found in the conditions of “if” statements.

byte data = 0b01100101;
byte result = (data & 0b00000111);

At the end, the variable “result” contains the value 5 (decimal).

Shifting Bits

Another thing you will find with received data is that having masked the bits you want, those bits are not all at the least significant end of the byte.

For example, if the value of interest in the data used in Figure 8-1 was between bits 5 and 3 (see Figure 8-2), you need to first mask the bits of interest, as you did in the previous example, and then sift the bits three places to the right.

Images

Figure 8-2   Masking and shifting bits.

You use the C operator >> to shift bits to the right and the number following the >> is the number of bit positions to shift the bits. This may result in some bits being shifted off the end of the byte. Here’s this example written in C:

byte data = 0b01101001;
byte result = (data & 0b00111000) >> 3;

At the end of this operation, “result” will contain the value 0b101. Figure 8-2 illustrates this process. What if you need to take two 8-bit bytes and assemble them into a single 16-bit int? You can accomplish this by first shifting the bits of one byte (the most significant byte) to one end of the int and then adding in the second byte. Figure 8-3 illustrates this process and here is how it looks in code:

Images

Figure 8-3   Combining bytes.

byte highByte = 0b01101010;
byte lowByte = 0b00001111;
int result = highByte << 8 + lowByte;

Serial Data

While you will occasionally find parallel interfaces used for communicating between microcontrollers and modules, these suffer from the disadvantage that they require one GPIO line for each bit being transferred. It is therefore much more common to use a serial interface where one GPIO pin is used to send or receive data one bit at a time. This is slower than a parallel interface but has the advantage that it uses less GPIO pins.

The sending of serial data is time dependent. For example, how do you know whether a GPIO pin being high for 10 milliseconds constitutes a single 1 bit or 10 successive 1 bits? This depends on the speed of transmission, something that can either be agreed on in advance by both the sender and receiver, or more commonly is specified by one side providing a clock signal. Figure 8-4 shows how you might connect two Arduinos together so that they can communicate by a serial connection using two GPIO pins on each Arduino. One pin (pin 5) is used for data, the second pin (pin 6) is used to provide a clock signal to synchronize the two Arduinos.

Images

Figure 8-4   Two Arduinos communicating serially.

We will see the code in a minute, but in this setup, the sending Arduino is going to start counting and every second it will send the new count to the receiving Arduino. The receiving Arduino needs the Serial Monitor to display the count, so it should be connected to your computer and it can then provide 5V power to the sending Arduino, without the need for USB power.

Figure 8-5 shows what happens on the GPIO pins of the sending Arduino as it sends a byte 00101010 (decimal 42 again).

Images

Figure 8-5   Clocking serial data from one Arduino to another.

The sequence for sending data is as follows:

1.   Set the GPIO pin according to the first bit of the byte to be sent.

2.   Wait for the GPIO pin to be stable.

3.   Pulse the clock pin.

4.   Repeat from step 1 for the next bit until all 8 bits are sent.

Download sketch_08_02_serial_tx from www.simonmonk.org/nextsteps2 and upload it onto one Arduino.

WARNING   Do not upload this transmitting sketch (sketch_08_02_serial_tx) to a pair of Arduinos connected as shown in Figure 8-4, or you will be connecting one digital output pin directly to another. If one is high and the other low, this could damage your Arduino.

On your second Arduino (the receiving Arduino) upload sketch_08_03_serial_rx and open the Serial Monitor. You should then see a series of numbers sent from the transmitting Arduino. Note that this is not a very reliable method of serial communication because there is nothing to mark the start or end of a byte and you may have to press the Reset button on the receiver to get the two Arduinos in step.

Here is the code for the transmitter:

Images

Most of the action for the transmitter takes place in the sendByte function. The sendByte function contains a loop that sends each bit in turn. This first of all sets the data pin high or low depending on the current bit (bitRead(b, 7-i)). Note that the index position is “7-i” not just “i” because we are starting with the leftmost digit. A pulse is then applied to the clock pin and then the next bit is sent.

Here is the corresponding receiver code:

Images

This code uses pins 5 and 6 to communicate with the other Arduino, but also uses the serial interface to display the numbers it receives in the Serial Monitor.

The loop function contains a for loop that expects to receive each of the eight bits of the byte, counting from 0 to 7 with a variable “i.”

The transmitting Arduino will send a pulse on the clock pin when it wants to send a bit, so, for each bit, the receiving code needs to wait until the clock pin goes high and then read the data pin to see if that bit is a 1 or a 0. This new bit gets added to the byte (“x”) by first shifting all the bits in the byte one position to the left (“x = x << 1”) and then adding the new bit.

When all eight bits have been collected, the value of “x” will be displayed.

Summary

In this chapter you have experienced the basic principles of most serial communication between microcontrollers or between a microcontroller and a peripheral. In the chapters that follow, you will delve a bit deeper into different types of serial interfaces that allow things such as two-way communication, communication to more than one device at a time (busses), and communication without a shared clock signal.