0% found this document useful (0 votes)
86 views

Hallberg Gary - Arduino Special Functions (Arduino Short Reads. Book 6) - 2021

6. Hallberg Gary - Arduino Special Functions (Arduino Short Reads. Book 6) - 2021

Uploaded by

Tihomir Mihaylov
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
86 views

Hallberg Gary - Arduino Special Functions (Arduino Short Reads. Book 6) - 2021

6. Hallberg Gary - Arduino Special Functions (Arduino Short Reads. Book 6) - 2021

Uploaded by

Tihomir Mihaylov
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 67

Arduino Special Functions

Book 6 of the Arduino Short Reads Series

Gary Hallberg

North Border Tech Training


First Edition
Copyright © 2021 Gary Hallberg and North Border Tech Training
All reserved. This book or any portion thereof may not be reproduced or used in any manner whatsoever
without the express written permission of the publisher except for the use of brief quotations in a book
review.
First Published, 2021
Contents
About the Arduino Short Reads Series ..................................................................................................... 5
Foreword.................................................................................................................................................... 6
Prerequisites for this Book ........................................................................................................................ 7
Download the Code ................................................................................................................................... 8
Chapter 1: Serial Data Communications ................................................................................................... 9
Parts needed for this Chapter ................................................................................................................ 9
Serial Communications ......................................................................................................................... 9
Experiment 1: Controlling an LED via the Serial Monitor .................................................................. 11
Experiment 2: Reading Strings ............................................................................................................13
Sending Characters from the Arduino to a PC .................................................................................... 14
Arduino Serial Communications Outside of the USB ..........................................................................15
What is Bluetooth? .............................................................................................................................. 16
The HC-05 Bluetooth Module ............................................................................................................. 16
Wiring the HC-05 ................................................................................................................................ 18
Experiment 3: Using the Bluetooth adapter in place of the Serial USB ............................................. 19
Summary .............................................................................................................................................. 24
Chapter 2: Interrupts .............................................................................................................................. 25
Parts needed for this Chapter .............................................................................................................. 25
Debouncing a Switch in Hardware ...................................................................................................... 25
Pseudo Multitasking ............................................................................................................................ 28
Writing Sketches to Process Interrupts............................................................................................... 28
Experiment 4: Hardware based Interrupts ......................................................................................... 29
Timed Interrupts ................................................................................................................................. 32
The DHT11 Temperature and Humidity Sensor ................................................................................. 32
Experiment 5: Timed Interrupts ......................................................................................................... 33
Summary .............................................................................................................................................. 37
Chapter 3: The I2C Bus ............................................................................................................................ 38
Parts needed for this Chapter .............................................................................................................. 38
The I2C Bus .......................................................................................................................................... 38
I2C and Arduino ................................................................................................................................... 40
The DS3231 Real Time Clock Module ................................................................................................. 41
The 12864 0.96 Inch Display Module ................................................................................................. 42
Experiment 6: A I2C Based Digital Real Time Clock ........................................................................... 43
Summary ...............................................................................................................................................51
Chapter 4: The Serial Peripheral Interface Bus ...................................................................................... 52
Parts needed for this Chapter .............................................................................................................. 52
The SPI Bus .......................................................................................................................................... 52
Comparing the SPI Bus to I2C and Serial UART ................................................................................. 54
The SPI Bus and the Arduino Uno ...................................................................................................... 54
The MCP4131-103E/P 10KΩ Digital Potentiometer ........................................................................... 55
Experiment 7: Using the SPI Bus to Control Digital Potentiometers ................................................. 56
Summary .............................................................................................................................................. 60
Chapter 5: The AREF and IOREF Pins ................................................................................................... 61
Parts needed for this Chapter .............................................................................................................. 61
Experiment 8: Using the AREF Pin .................................................................................................... 61
Summary .............................................................................................................................................. 64
Epilogue ................................................................................................................................................... 65
About the Author ..................................................................................................................................... 66
About the Arduino Short Reads Series

The idea underpinning the Arduino short reads series is to provide a comprehensive, easy to follow
tutorial set and reference guide for anybody wanting to learn about Arduino and basic electronics.
Having a short reads series means that students and hobbyists can select key topics of interest in the
field with minimal outlay. The series aims to provide an easy introduction to all topics of interest and
expand on these topics to provide a broader and deeper understanding of that focus area. The books
are currently only available in Kindle format to provide a very inexpensive package backed up by video
content and interactive social media.
The series is aimed at youngsters and adults interested in getting into electronics and it takes a modern
approach, combining the use of the inexpensive software driven Arduino controller board, with a
multitude of sensors and discreet electronic components. The experiments in this series of books are
easy to follow, inexpensive to implement and compelling for all interested in STEM education. I hope
to inspire anybody looking for a future career in technology or to simply to have fun.
The first book of this series looks at the Arduino microcontroller and explains its operation and purpose.
Experiments look to show you how to set up the programming environment and drive LEDs as well as
read input from switches, thermistors and photocells. Book 1 will give you a solid foundation of how
some basic electronic components work and how to use them to make simple designs.
Books 7 and 8 in this Arduino Short Reads Series are still being written but the series focuses on the
following:
• Book 1 – First Steps with Arduino (published)
• Book 2 – Working with Displays (published)
• Book 3 – Controlling Motors (published)
• Book 4 – Range Finding, Object Detection and Object Avoidance (published)
• Book 5 – Building a Simple Rover (published)
• Book 7 – Communications with Arduino and the ESP32
• Book 8 – The Arduino Leonardo

If you find this series of books useful then please leave your review and rating on
Amazon.
Follow North Border Tech Training on Facebook and Twitter for the latest news and
insights as to how this series will develop.
Foreword

Book 1 of this series sets out to provide a basic understanding of the Arduino platform, how to program
it and how to interface simple electronics. This book builds on that basic knowledge and rounds out the
capabilities of the platform by looking at the special functions that the Arduino Uno supports. This book
is a great complimentary text for Book 1.
You may have noticed that some of the I/O pins of the Arduino Uno have a second function. It is these
we will explore. They include serial data transmission, the SPI bus and the I2C interface. We will also
look at hardware and timed interrupts. Mastering these skills will open a world of much more
sophisticated sensors and devices to enhance your current and future project work.
I have no doubt the skills learnt here will allow you to develop more engaging and useful projects.
Without further delay let us get into the content.
Prerequisites for this Book

This book assumes you have read Book 1 of the series (‘First Steps with Arduino’) or you already have
some experience of the Arduino platform, how to set up the IDE and undertake some basic Arduino
programming tasks. Basic functions such as ‘digitalRead’ and ‘digitalWrite’ are not covered here
but are explained in Book 1.
Download the Code

You can download the Arduino Code for the experiments in this book from GitHub using the link below.

https://github.com/ghallberg-nbtt/sturdy-octo-goggles
I recommend that you do this as I have removed some of the comments from the code in the book
listings to aid readability in print form. I strongly recommend that you comment your code heavily to
facilitate understanding and to become familiar with best engineering practice.
Chapter 1: Serial Data Communications

In this chapter we will explore serial communications to and from the Arduino Uno. In Book 5 we used
a Bluetooth module to allow remote control of the autonomous vehicle. We will use the same module
here, but first we will take a close look at how serial communications work and explore in more detail
the Serial Monitor using the USB port.

Parts needed for this Chapter


• Arduino Uno or clone board
• Half or full-size breadboard
• 1 x HC-05 Bluetooth module
• 1 x 1KΩ resistor
• 1 x 2KΩ resistor
• Jumper wires

Serial Communications
Serial communications form part of the earliest form of electronic communications. The Telegraph is
one such example of a system that uses serial communications. They are still important in today’s
electronic systems. You will most likely encounter this form of communication with the Universal Serial
Bus or USB that is pretty much ubiquitous in modern electronic equipment including the Arduino
range.
Efficient serial communications buses require a transmit path, a receive path and a voltage reference to
act as ground. These systems are referred to as 3-wire or full duplex, as data can be transferred in the
transmit and receive directions at the same time. Such a system is depicted in Figure 1-1. There are also
systems that share a single transmit and receive path. These 2-wire systems are also referred to as half
duplex as it is not possible to transmit and receive data at the same time.

Figure 1-1: A Full Duplex Serial Data System


Image source: The author
This type of system is referred to as a serial system as the data is transmitted and received in the form
of a bit stream one at a time. Parallel data systems can transfer every bit in the data at once by having a
transmit wire for every bit as shown in Figure 1-2. Figure 1-2 represents a 4-bit parallel system.

Figure 1-2: A 4-Bit Parallel Data Transfer System


Image source: The author
Throughout the years there has been some terminology that has evolved to describe serial
communications. For us, the key parameter is the data transfer rate. This is called the baud rate and is
expressed in bits per second.
There are other considerations too. To make sense of the data, the devices at each end of the link must
talk the same protocol. The key parameters will be the number of data bits in the stream, the number
of stop bits and the number of parity bits. The parity bit is used to detect errors in the frame.
There are 2 forms of parity. These are termed even and odd. Since the data stream is made up of zeros
and ones, to detect an error we only need to identify whether there should be an odd or even number of
ones in the data stream. Table 1-1 illustrates an example.
Databits Number of ones Parity
Odd parity bit Even parity bit
00000000 0 000000001 000000000
01010100 3 010101000 010101001
11001001 4 110010011 110010010
11111110 7 111111100 111111101

Table 1-1: Parity Bit Calculation


A key point to remember is that the parity bit is calculated with the parity bit included with the data
bits. In Table 1-1, The first example is all zeros in the data stream and if odd parity is used, the parity
bit is set to 1 since there would be an odd number of ones including the parity bit. The parity bit is set
to 0 if even parity is used. In row 2, there are 3 ones in the data stream and if odd parity is used the
parity bit will be set to 0 and 1 if even parity is used.
You will often see serial transmission expressed as the baud rate, the number of data bits, the number
of parity bits and the number of stop bits. ‘9600 8 N 1’ is common shorthand for 9600bps, 8 data bits,
no parity bits and 1 stop bit.
It is often a case that data is received faster that it can be processed. In this situation, the receiving
station stores the unprocessed data in a buffer (an area of memory space). The buffer is finite and so it
can become full. Serial data protocols support flow control mechanisms. If the transmission system
uses just 3 wires (transmit, receive and ground), the flow control functionality is encoded, and the
receiving station instructs the sending station to halt transmission until such time as the buffer has free
space. The receiving station will then instruct the sending station to re-start transmission of the data.
One such encoding mechanism is called X-ON/X-OFF. There are hardware-based flow control
mechanisms that use extra wires to initiate flow control. RS-232 is a popular and mature standard that
can use hardware flow control. I recommend that you take some time to study RS-232.
The device that takes care of serial communications in most electronic devices is the UART (Universal
Asynchronous Receiver-Transmitter).
In book 1, we took a close look at the Serial Monitor within the Arduino IDE that can be used to display
data from the Arduino. To date, we have not looked at how we send data from the Serial Monitor to the
Arduino board and so this is a good place to start with the first experiment.

Experiment 1: Controlling an LED via the Serial Monitor


Although a simple experiment, it does introduce 2 functions that we have not reviewed so far in all the
previous books. The first function checks to see if serial data is available to read and the other reads the
data. We will control the built in LED that is assigned to pin 13 on genuine Arduino boards and most
clone boards. Consequently, there is no breadboard layout, but simply connect the Arduino to your PC
using the USB port and type in or copy the Sketch as in Listing 1-1.
/*
Serial Monitor
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/sturdy-octo-
goggles/blob/master/LICENSE
*/

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW); //Ensure LED is off
Serial.begin (38400); //initiate serial monitor at 38400bps
}

void loop() {
// put your main code here, to run repeatedly:
if (Serial.available() > 0) {
byte incomingByte = Serial.read();
//1 = on and 0 = off
if (incomingByte == 49) {
digitalWrite(LED_BUILTIN, HIGH); //Turn on LED
Serial.println ("LED on");
} else if (incomingByte == 48) {
digitalWrite(LED_BUILTIN, LOW);
Serial.println ("LED off");
} else {
Serial.println ("invalid input");
}
}
}

Listing 1-1: The Sketch to Explore the Serial Monitor


Listing source: The author
After you load the Sketch open the Serial Monitor. You will need to make some adjustments. The baud
rate will be set to 38400bps and you must select ‘No line ending’. If you do not do this the serial monitor
will add a line feed character after the input. Try the Sketch out by entering various characters in the
input box and press send or carriage return. Your output should be like that in Figure 1-3.

Figure 1-3: The Serial Monitor for Experiment 1


Image source: The author
The Sketch enables the built in LED and ensures it is turned off. The code then loops until there is data
to read in the serial buffer. The check is done by code below. Greater than 0 means at least 1 character
is in the receive buffer.
if (Serial.available() > 0) {
//Code here to process data
}

When data is available to read, we initiate a byte variable to hold that data. The ‘Serial.read()’
function actually reads the data a byte at a time and returns a byte and not a ‘char’ variable. The
program works by turning the LED on when the character ‘1’ is pressed and off when ‘0’ is pressed. All
other input is ignored. The Sketch also writes to the Serial Monitor window to confirm the state of the
LED.
So why do we look for ‘49’ to represent the character ‘1’ and ‘48’ for ‘0’? The answer lies in the fact that
‘Serial.read()’ function returns a byte and only reads one character at a time. For serial
communications, the characters are encoded as series of 8-bit binary numbers. These can be
represented in binary, decimal and hexadecimal format. This code is standard as is called the ASCII
(American Standard Code for Information Interchange) code.
Table 1-2 shows the ACSII code, and you can see that the character ‘1’ is represented by the number ‘49’
and ‘0’ by ‘48’.
CHAR DEC HEX CHAR DEC HEX CHAR DEC HEX CHAR DEC HEX CHAR DEC HEX CHAR DEC HEX CHAR DEC HEX CHAR DEC HEX
[NUL] 0 00 32 20 @ 64 40 ` 96 60 € 128 80 160 A0 À 192 C0 à 224 E0
[SOH] 1 01 ! 33 21 A 65 41 a 97 61 (n/a) 129 81 ¡ 161 A1 Á 193 C1 á 225 E1
[STX] 2 02 " 34 22 B 66 42 b 98 62 ‚ 130 82 ¢ 162 A2 Â 194 C2 â 226 E2
[ETX] 3 03 # 35 23 C 67 43 c 99 63 ƒ 131 83 £ 163 A3 Ã 195 C3 ã 227 E3
[EOT] 4 04 $ 36 24 D 68 44 d 100 64 „ 132 84 ¤ 164 A4 Ä 196 C4 ä 228 E4
[ENQ] 5 05 % 37 25 E 69 45 e 101 65 … 133 85 ¥ 165 A5 Å 197 C5 å 229 E5
[ACK] 6 06 & 38 26 F 70 46 f 102 66 † 134 86 ¦ 166 A6 Æ 198 C6 æ 230 E6
[BEL] 7 07 ' 39 27 G 71 47 g 103 67 ‡ 135 87 § 167 A7 Ç 199 C7 ç 231 E7
[BS] 8 08 ( 40 28 H 72 48 h 104 68 ˆ 136 88 ¨ 168 A8 È 200 C8 è 232 E8
[HT] 9 09 ) 41 29 I 73 49 i 105 69 ‰ 137 89 © 169 A9 É 201 C9 é 233 E9
[LF] 10 0A * 42 2A J 74 4A j 106 6A Š 138 8A ª 170 AA Ê 202 CA ê 234 EA
[VT] 11 0B + 43 2B K 75 4B k 107 6B ‹ 139 8B « 171 AB Ë 203 CB ë 235 EB
[FF] 12 0C , 44 2C L 76 4C l 108 6C Œ 140 8C ¬ 172 AC Ì 204 CC ì 236 EC
[CR] 13 0D - 45 2D M 77 4D m 109 6D (n/a) 141 8D 173 AD Í 205 CD í 237 ED
[SO] 14 0E . 46 2E N 78 4E n 110 6E Ž 142 8E ® 174 AE Î 206 CE î 238 EE
[SI] 15 0F / 47 2F O 79 4F o 111 6F (n/a) 143 8F ¯ 175 AF Ï 207 CF ï 239 EF
[DLE] 16 10 0 48 30 P 80 50 p 112 70 (n/a) 144 90 ° 176 B0 Ð 208 D0 ð 240 F0
[DC1] 17 11 1 49 31 Q 81 51 q 113 71 ‘ 145 91 ± 177 B1 Ñ 209 D1 ñ 241 F1
[DC2] 18 12 2 50 32 R 82 52 r 114 72 ’ 146 92 ² 178 B2 Ò 210 D2 ò 242 F2
[DC3] 19 13 3 51 33 S 83 53 s 115 73 “ 147 93 ³ 179 B3 Ó 211 D3 ó 243 F3
[DC4] 20 14 4 52 34 T 84 54 t 116 74 ” 148 94 ´ 180 B4 Ô 212 D4 ô 244 F4
[NAK] 21 15 5 53 35 U 85 55 u 117 75 • 149 95 µ 181 B5 Õ 213 D5 õ 245 F5
[SYN] 22 16 6 54 36 V 86 56 v 118 76 – 150 96 ¶ 182 B6 Ö 214 D6 ö 246 F6
[ETB] 23 17 7 55 37 W 87 57 w 119 77 — 151 97 · 183 B7 × 215 D7 ÷ 247 F7
[CAN] 24 18 8 56 38 X 88 58 x 120 78 ˜ 152 98 ¸ 184 B8 Ø 216 D8 ø 248 F8
[EM] 25 19 9 57 39 Y 89 59 y 121 79 ™ 153 99 ¹ 185 B9 Ù 217 D9 ù 249 F9
[SUB] 26 1A : 58 3A Z 90 5A z 122 7A š 154 9A º 186 BA Ú 218 DA ú 250 FA
[ESC] 27 1B ; 59 3B [ 91 5B { 123 7B › 155 9B » 187 BB Û 219 DB û 251 FB
[FS] 28 1C < 60 3C \ 92 5C | 124 7C œ 156 9C ¼ 188 BC Ü 220 DC ü 252 FC
[GS] 29 1D = 61 3D ] 93 5D } 125 7D (n/a) 157 9D ½ 189 BD Ý 221 DD ý 253 FD
[RS] 30 1E > 62 3E ^ 94 5E ~ 126 7E ž 158 9E ¾ 190 BE Þ 222 DE þ 254 FE
[US] 31 1F ? 63 3F _ 95 5F [DEL] 127 7F Ÿ 159 9F ¿ 191 BF ß 223 DF ÿ 255 FF

Table 1-2: The ASCII Code


You can see that the table contains a mix of printable and control characters such a line feed and
backspace.

Experiment 2: Reading Strings


Reading a single character in the form of a byte may be fine for your application but reading entire
strings of data in text form and processing that may be better for human interaction. In this experiment,
we will explore the use of the ‘Serial.readString()’ function.
The hardware layout will be as for Experiment 1 with the Arduino board connected to the USB and the
internal LED will be used. Type in or copy the Sketch as in Listing 1-2.
/*
Reading Strings
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/sturdy-octo-
goggles/blob/master/LICENSE
*/

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW); //Ensure LED is off
Serial.begin (38400); //initiate serial monitor at 38400bps
}

void loop() {
// put your main code here, to run repeatedly:
if (Serial.available() > 0) {
String incomingString = Serial.readString();
//1 = on and 0 = off
if (incomingString == "on") {
digitalWrite(LED_BUILTIN, HIGH); //Turn on LED
Serial.println ("LED on");
} else if (incomingString == "off") {
digitalWrite(LED_BUILTIN, LOW);
Serial.println ("LED off");
} else {
Serial.println ("invalid input");
}
}
}

Listing 1-2: Reading Strings via the Serial Monitor


Listing source: The author
The only differences between this Sketch and the one for Experiment 1 is that we now set the variable
to type ‘String’ and use the ‘Serial.readString’ function in place of ‘Serial.read’. Now we can
type a word, and the only accepted input are the words ‘on’ and ‘off’. Furthermore, we do not have to be
concerned with ASCII encoding. The function takes care of that.

Sending Characters from the Arduino to a PC


2 functions exist that act in the opposite way to ‘Serial.read()’ and ‘Serial.readString()’.
The ‘Serial.write’ function can send a single byte value that would equate to an ASCII character,
and it is also can send a string. The usage follows:
• Serial.write(val)
• Serial.write(str)
• Serial.write(buf, len)

An explanation of what each argument does is below:


• ‘val’: a value to send as a single byte.
• ‘str’: a string to send as a series of bytes.
• ‘buf’: an array to send as a series of bytes.
• ‘len’: the number of bytes to be sent from the array
Examples of usage are:
Serial.write(49); // send a byte with the value 49 i.e. the char ‘1’

If we want to send a string, we will pass the string to the ‘write’ function and it will send it. The function
also returns the length of the string, and we would use this variation as below:
int bytesSent = Serial.write("hello"); //send “hello” and return 5

You may want to check if there is space in the buffer before transmitting the data and you can do this
with the ‘Serial.availableForWrite()’ function.
We have used ‘Serial.print’ and ‘Serial.println’ regularly in previous books of this series. The
difference between ‘Serial.print’ and ‘Serial.println’ compared to ‘Serial.write’ is that the
‘print’ and ‘println’ functions transmit data in human readable format. This need not be true of
‘Serial.write’.

Arduino Serial Communications Outside of the USB


You will have seen that the Arduino I/O pins 0 and 1 have special functions. They can also be used for
serial communications should you not wish to use the USB port. Figure 1-4 is an image of these pins on
the Arduino Uno.
Figure 1-4: Arduino Uno Serial Data Pins
Image source: The author
I/O pin 0 can be used to receive serial data and I/O pin 1 to transmit data. The third wire would be the
ground on the Arduino board. We will explore the use of these pins by experimenting with a Bluetooth
adapter that is designed to use them. We used a Bluetooth adapter in Book 5 of this series, and we will
use the same adapter here.

What is Bluetooth?
Bluetooth is a short-range wireless technology that was designed to do away with the computer’s jungle
of wires. The technology is highly commoditized, meaning it is extremely cheap and you can find
Bluetooth functionality in all sorts of devices such as headsets, speakers, keyboards, and the like.
Bluetooth components can be used as master and slave pairs to provide 2-way serial connections in
place of cables, and this is how we will use the technology. We should be able to achieve a maximum
range of 20m.

The HC-05 Bluetooth Module


We will use the HC-05 Bluetooth module. This is an extremely common component since it can be used
both as a master and a slave. It is capable of 2-way (full duplex) communications. The default baud rate
is 9600bps and so draws on a lot of parallels with our Serial Monitor on the Arduino IDE. Be sure to
purchase the version of the module with the breakout pins so that it can easily be connected to the
breadboard. Figure 1-5 shows a picture of the HC-05.
Figure 1-5: The HC-05 Bluetooth Module
Image source: The Web (public domain)
Let us take a closer look at the pinouts. The VCC supply is between +4VDC and +6VDC (typically
+5VDC). GND is ground. There are 2 serial data pins, TXD and RXD, these will connect to I/O pins 0
and 1 of the Arduino Uno that are set aside for serial communications. The STATE pin is connected to
the on board LED, it can be used as a feedback indicator to show if Bluetooth is working properly. The
EN pin is used to toggle between Data mode (set ‘LOW’) and AT command mode (set ‘HIGH’). By default,
it is in Data mode. Here is a more detailed summary the HC-05 specification.
• Serial Bluetooth module for Arduino and other microcontrollers
• Operating Voltage: 4V to 6V (Typically +5V)
• Operating Current: 30mA
• Range: <100m
• Works with Serial communication (USART) and TTL compatible
• Follows IEEE 802.15.1 standardized protocol
• Uses Frequency-Hopping Spread spectrum (FHSS)
• Can operate in Master, Slave or Master/Slave mode
• Can be easily interfaced with Laptop or Mobile phones with Bluetooth
• Supported baud rate: 9600,19200,38400,57600,115200,230400,460800
• Default Bluetooth Name: “HC-05”
• Default Password: 1234 or 0000
• Default Communication: Slave
• Default Mode: Data Mode
• Data Mode Baud Rate: 9600, 8, N, 1
• Command Mode Baud Rate: 38400, 8, N, 1

Wiring the HC-05


Figure 1-6 shows how to wire the HC-05 to the Arduino board.
Figure 1-6: Connecting the HC-05 and the Arduino
Image source: The author
What we want to achieve is for the HC-05 to pair with the Bluetooth on your PC and act as a COM port
that can be used in place of the USB cable. We need to connect the HC-05 ‘TXD’ pin to the ‘RX’ pin of
the Arduino and the ‘RXD’ pin of the HC-05 to the ‘TX’ pin of the Arduino.
You will see that we have added a potential divider to the ‘RXD’ pin of the HC-05. Although the HC-05
takes a 5VDC supply, it uses 3.3VDC logic for the ‘TXD’ and ‘RXD’ pins. Since pin 1 of the Arduino will
drive the ‘RXD’ pin of the HC-05 at 5VDC for logic ‘HIGH’, we should add a potential divider to bring
this down to 3.3VDC. The ‘TXD’ pin of the HC-05 will drive pin 0 of the Arduino at 3.3VDC, but this is
high enough for the Arduino to register this as logic ‘HIGH’, so no extra components are needed. We do
not need to connect the ‘EN’ and ‘STATE’ pins of the HC-05.

Experiment 3: Using the Bluetooth adapter in place of the Serial USB


We will reuse the Sketch from Experiment 2 to control the Built in LED via Bluetooth. There is one
important change that is needed and that is to set the Serial baud rate to 9600bps as below:
Serial.begin (9600);

We will connect the HC-05 to the Arduino board using the layout in Figure 1-7.
Figure 1-7: The Breadboard Layout to Connect the HC-05 to the Arduino
Image source: Created with Fritzing
We will power the Arduino with a battery connected to the Power input barrel as we want the system to
be remote from our PC. You will see LED indicators on the HC-05. The next task will be to pair the HC-
05 to your PC. What follows are the steps for Bluetooth pairing on a Windows 10 PC. If you do not have
built in Bluetooth, then the same process applies to a Bluetooth USB adapter.
In Windows 10 you will need to add a new Bluetooth device. Select Settings > Bluetooth & other
devices as in Figure 1-8.
Figure 1-8: Windows 10 Setting Screen
Image source: Microsoft Windows
Select Add Bluetooth or other device. You will be presented with the screen as in Figure 1-9. Select
the Bluetooth option.

Figure 1-9: Selecting a Bluetooth Device


Image source: Microsoft Windows
All being well, the HC-05 will be detected by your PC. You will need to enter the default passcode of
1234 to complete pairing as in Figure 1-10.
Figure 1-10: Pairing with the HC-05
Image source: Microsoft Windows
You will be presented with the screen as in Figure 1-11 on successful completion of the pairing process.

Figure 1-11: Successful Pairing


Image source: Microsoft Windows
The next process is to setup the HC-05 for serial communications. If you look at Figure 1-12, you will
see a menu item called ‘More Bluetooth options’. You need to select this. When the Bluetooth
Settings dialog box opens, select the COM Ports tab.
Figure 1-12: The Bluetooth Settings Dialog
Image source: Microsoft Windows
You should see entries in there against the HC-05. If not, you may need to select Add.. and select an
incoming port and outcoming port from the drop-down options provided. You need to note the COM
port number of the Outgoing HC-05 port. For me this is COM10.
Upload the Sketch to your Arduino Uno ensuring that the baud rate in the Sketch is 9600bps. Use the
USB to do this. We are doing this as the default baud rate in the HC-05 is 9600bps. We can change the
baud rate of the HC-05 to another value with what are called ‘AT’ commands, but really the objective
here is to see how we can use I/O pins 0 and 1 for serial communications so we will leave it at the default
value.
Once you have done that, disconnect the USB. Change the serial port setting in the Arduino IDE to that
of the outgoing port of the HC-05. Open the Serial Monitor and you should be able to control the LED
the same way as in Experiment 2.
A photograph of my setup is shown in Figure 1-13.
Figure 1-13: My Serial Bluetooth Setup
Image source: The author
I am conscious that these experiments are not the most interesting, but the purpose of this chapter was
to explore serial communications with Arduino. In Book 7 we will revisit serial communications with
Bluetooth and create a much more engaging project.

Summary
In this chapter we took deeper look at the Serial Monitor and how to input data from an external source
in the form of a byte stream and standard text. You were introduced to the ASCII coding and asked to
look closer at the RS-232 specification. You learnt how to use I/O pins 0 and 1 on the Arduino Uno for
serial communications and use a Bluetooth module to pair with a PC to invoke wireless serial
communications.
Chapter 2: Interrupts

In this chapter we will look a processor interrupts. The ability to handle interrupts is a fundamental
feature of all microcontrollers and microprocessors. Understanding what an interrupt is and how it
works is an essential skill for the electronic engineer. Essentially, an interrupt is a signal from a source
external to the processor that stops the processor executing its current task to start work on a specific
block of code associated with that interrupt. When that code is finished, the processor will resume its
original task.
You can appreciate the uses this has for emergency action, the change direction of a vehicle, an
emergency stop or trigger for an environmental alarm.

Parts needed for this Chapter


• Arduino Uno or clone board
• Half or full-size breadboard
• 74AHCT14 Schmitt Trigger
• 1 x DHT11 temperature and humidity sensor
• 1 x Common Cathode RGB LED
• 1 x LED
• 3 x 220Ω resistor
• 1 x 10KΩ resistor
• 1 x 100Ω resistor
• 1 x 10uF 16V electrolytic capacitor
• 1 x pushbutton switch
• Jumper wires

Debouncing a Switch in Hardware


In this chapter we want to explore hardware-based interrupts. We will trigger the interrupts by looking
for a change in state of an Arduino I/O pin. We know from previous books that a switch is a mechanical
device, and its metal contacts will bounce momentarily, making and breaking the connection, until such
time they settle. We know our Arduino ‘loop’ function is so fast that it can see and react to these state
changes. We used software to add a small delay such that the switch bounce is mitigated. If we used a
switch to trigger an interrupt, then debouncing in software will not be possible. We would restart the
interrupt subroutine on each bounce of the switch contact. Using a hardware solution to debounce a
switch is useful in many scenarios and an essential skill for the electronic engineer.
Figure 2-1 is an illustration of a bouncing switch with state against time. When the switch is pressed,
the voltage state will oscillate between high and low levels for a few milliseconds.
Figure 2-1: The Behavior of Bouncing Switch Contacts
Image source: The author
The first part of the hardware solution will be to filter out the bounce using what is called an RC filter.
RC filter means Resistor-Capacitor filter. This is illustrated in Figure 2-2.

Figure 2-2: The RC Filter Circuit


Image source: The author
If you place a resistor between the switch and the Arduino digital input and a capacitor between the
input and ground. The capacitor will charge up to the supply voltage. The rate of charge is defined by
the value of R1, R2 and the Capacitor. When the switch is pressed, the capacitor will discharge through
the path to ground. The value of R2 will limit the rate of discharge. The charge rate will be much slower
than the discharge rate given that R1 + R2 will be 10100Ω when charging and 100Ω when discharging.
When the switch is pressed, we would now be presented with the behavior shown in Figure 2-3 where
the voltage state drops in a slow curve. At some point the voltage level will be such that the Arduino
input state will switch from ‘HIGH’ to ‘LOW’.
Figure 2-3: The RC Filter Behavior
Image source: The author
The slow rate of voltage dip will work with the Arduino digital input, but it would be nice to create a
sharp edge and clean state change using external hardware. We can do this with a Schmitt Trigger. A
Schmitt Trigger is a digital inverting device that provides a clean and sharp state change in response to
the state of the input. Figure 2-4 shows how a Schmitt trigger should be connected to our RC filter
circuit and Figure 2-5 shows the resultant behavior when a Schmitt trigger is added. The switch is now
debounced although we do have to invert the logic in any Sketch.

Figure 2-4: The RC Filter with Schmitt Trigger added


Image source: The author
Figure 2-5: The Schmitt Trigger Behavior
Image source: The author
In our experiment we will be using a 74AHCT14 Schmitt Trigger. This device has 6 Schmitt Triggers
although we will only be using 1. Figure 2-6 show the pinouts of this device.

Figure 2-6: The Pinouts for the 74AHCT14 Schmitt Trigger


Image source: The author

Pseudo Multitasking
The use of interrupts can give your Sketches the feeling of being able to multitask. You cannot achieve
full multitasking with the Arduino as it has a single processing core. Having the Sketch suspend a task
to process an interrupt will give that you a multitasking feel. The same is also true of timed interrupts
that we will look at later in this chapter.

Writing Sketches to Process Interrupts


A variable that may change in the code associated with an interrupt must be declared as ‘volatile’.
The qualifier ‘volatile’ tells the compiler, that the value may change at any time as would be the case
with an interrupt. An example of the declaration is below:
volatile int rgbLedColor = 9;
You need to instruct the Arduino to listen for interrupts and you do this by attaching an interrupt in the
‘setup’ function. You need to call the function ‘attachInterrupt()’ to do this. You need to pass a
few arguments within this function. The first is the identity of the I/O pin that will be used for the
interrupt. This in turn is passed to the function ‘digitalPinToInterrupt()’ which returns the
value needed. Let us assume we will use pin 2. Next, we need to specify the name of the function we will
call when the interrupt is triggered. In our example we will call the function ‘changeColor’. Finally,
we need to specify whether the interrupt will be triggered off a rising or falling edge. Putting it all
together, the line of code below will call the interrupt from a rising edge (that is on the button press).
attachInterrupt(digitalPinToInterrupt(2),changeColor, RISING);

Another factor to bear in mind is that the Arduino Uno can support 2 hardware interrupts. INT0 and
INT1 are mapped to I/O pins 2 and 3 respectively.

Experiment 4: Hardware based Interrupts


Our Sketches to date have been executed synchronously. This means that each line of code is executed
in turn. Our Sketches have made use of the ‘delay’ function to time tasks, but the delays have been
short so that button presses can be detected. In this experiment, we will set an RGB LED to a specific
color and then adjust the brightness using a ‘for’ loop. We want to change the color on each button
press, but if we did not use an interrupt, we would need to wait until the loop had finished and the code
would most certainly miss a brief button press. We can address this by using an interrupt. The RGB
LED and Pulse Width Modulation are covered in Book 1 of this series. That said, I will be using a
Common Cathode RGB LED with the pin configuration shown in Figure 2-7. Be sure to check your pin
configuration and if you use a Common Anode RGB LED, you will need to invert the logic in the Sketch.

Figure 2-7: The Common Cathode RGB LED


Image source: The Web (public domain) with annotations by the author
First build the breadboard layout as shown in Figure 2-8.
Figure 2-8: The Breadboard Layout to Trigger an External Interrupt
Image source: Created with Fritzing
Next type in or copy the Sketch as shown in Listing 2-1.
/*
Hardware Interrupts
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/sturdy-octo-
goggles/blob/master/LICENSE
*/

//Define colors
const int RED = 11;
const int GREEN = 10;
const int BLUE = 9;

//Define button switch pin


const int SWITCH = 2;

//Volatile variables can be changed within the interrupt routine


volatile int color = RED; //initial color red
void setup() {
pinMode (RED, OUTPUT);
pinMode (GREEN, OUTPUT);
pinMode (BLUE, OUTPUT);

//Turn LED off


digitalWrite (RED, LOW);
digitalWrite (GREEN, LOW);
digitalWrite (BLUE, LOW);

//Attach interrupt
//Switch press will be rising edge due to Schmitt Trigger inversion
attachInterrupt(digitalPinToInterrupt(2), changeColor, RISING);
}

void loop() {
//Brighten LED
for (int i = 0; i <= 255; i++) {
analogWrite (color, i);
delay (10);
}
//Dim the LED
for (int i = 255; i >= 0; i--) {
analogWrite (color, i);
delay (10);
}
delay (500);
}

void changeColor () {
//Turn off current LED
digitalWrite (color, LOW);
//Select a new color
if (color == RED) {
color = GREEN;
} else if (color == GREEN) {
color = BLUE;
} else {
color = RED;
}
}

Listing 2-1: The Sketch to Process an External Interrupt


Listing source: The author
You can watch a video demonstration of this experiment here (https://youtu.be/ClbJl5A5xyk).

Timed Interrupts
Timed interrupts are simply tasks that execute periodically. The Arduino Uno has 3 timers built into
the system and we use one of these timers to control timed interrupts. In fact, we have used these timers
for many experiments in previous books. The PWM capable pins are controlled by timers when used
for PWM actions. The ‘delay’ function also uses a timer.
The 3 timers on board the Arduino Uno are referred to as Timer 0, Timer 1 and Timer 2. Timed
interrupts use Timer 1. However, the PWM pins 9 and 10 also use this timer so these pins cannot be
used for PWM tasks when using Timer 1. The following PWM pins are associated with the following
timers:
• Timer 0 - 6 and 5
• Timer 1 - 9 and 10
• Timer 2 - 11 and 3
Timer 1 is 16-bit and so can count from 0 to 65535. When 65535 is reached, the counter resets to 0. The
system uses a clock divider to control the rate of count. Without the clock divider, the counter would
clock at 16 million cycles per second. Timer 0 and Timer 2 are 8-bit and so the count is 0 to 255.
We can use a 3rd party library called ‘TimerOne’ that deals with all the complexity of using the timer
such that we can simply set the trigger period for the interrupt routine. To load the library, select
Sketch > Include Library > Manage Libraries. From the resultant window, search for ‘TimerOne’
and then click install.
In Experiment 5, we will use a timed interrupt to flash an LED every second while the main ‘loop’
measures temperature and humidity using a DT-11 sensor. We can also use a hardware interrupt to
toggle between Fahrenheit and Celsius.

The DHT11 Temperature and Humidity Sensor


Before we move on to the experiment, let us look at the DHT11 Temperature and Humidity sensor.
An image of the DHT11 is shown in Figure 2-9 with its associated pinouts.

Figure 2-9: The DHT11 Temperature and Humidity Sensor


Image source: The author
The package may come with 4 pins, but only 3 pins have connections. Check your device, it is usually
pin 3 that has no connection on a 4-pin device. It requires just a supply, ground, and a single Arduino
I/O pin for connectivity. The unit can measure temperature in the range of 0-50C with 1 degree
resolution. It has an accuracy of about +/-2C. It can measure humidity from 20% ~ 90% with 1%
resolution and +/-5% accuracy. There is a selection of libraries available in the Arduino IDE and we will
use the ‘simpleDHT’ library written by Winlin.

Experiment 5: Timed Interrupts


For this experiment, start by building the breadboard layout shown in Figure 2-10.

Figure 2-10: The Breadboard Layout to Demonstrate Timed Interrupts


Image source: Created with Fritzing
Next type in or copy the Sketch as in Listing 2-2.
/*
Timed Interrupts
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/sturdy-octo-
goggles/blob/master/LICENSE
*/

#include <TimerOne.h>

/*
This Sketch was written with SimpleDHT version 1.0.14
The code may need to be modified if other versions are used
*/
#include <SimpleDHT.h>

// assign I/O pins


const int SWITCH = 2;
const int LED = 12;

// variables that will change value

volatile int units = 1; // Celsius or Fahrenheit selected

// for DHT11,
// VCC: 5V or 3V
// GND: GND
// DATA: 8
int pinDHT11 = 8;
SimpleDHT11 dht11(pinDHT11);

void setup() {
// set I/O pins
pinMode (LED, OUTPUT);
//Attach interrupt
//Switch press will be rising edge due to Schmitt Trigger inversion
attachInterrupt(digitalPinToInterrupt(2), changeUnit, RISING);
//Initialize Serial monoitor for display
Serial.begin (9600);
//Set up timed interrupt
Timer1.initialize (1000000); //set to 1 second in microseconds
Timer1.attachInterrupt(flashLED); //runs flashLED on timed interrupt
}

void loop() {
// read temperature and humidity
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht11.read(&temperature, &humidity, NULL)) !=
SimpleDHTErrSuccess) {
Serial.print("DHT11 read fail");
Serial.println ("err="); Serial.print(err); delay(1000);
return;
}

// display the results


int tempC = temperature;
if (units == 1) {
Serial.print ("Temperature: ");
Serial.print((int)temperature);
Serial.print("C ");
Serial.print ("Humidity: ");
Serial.print((int)humidity);
Serial.println("%");
Serial.println("");
} else {
// convert to Fahrenheit
temperature = ((temperature / 5) * 9) + 32;
Serial.print ("Temperature: ");
Serial.print((int)temperature);
Serial.print("F ");
Serial.print ("Humidity: ");
Serial.print((int)humidity);
Serial.println("%");
Serial.println("");
}
delay (1500);
}

void changeUnit () {

//Toggle C and F
if (units == 1) {
units = 0;
} else {
units = 1;
}
}

void flashLED () {
digitalWrite(LED, !digitalRead(LED)); //Toggle LED
}

Listing 2-2: The Sketch to Demonstrate Timed Interrupts


Listing source: The author with library contribution by Winlin and Paul Stoffregen
Let us review the code. It starts by importing the libraries that we need.
#include <TimerOne.h>
#include <SimpleDHT.h>

With respect to the DHT11, we need to pass the ID of the pin that the data lead is connected to.
int pinDHT11 = 8;
SimpleDHT11 dht11(pinDHT11);

Since the focus of this experiment is to investigate timed interrupts, we will focus on that code first. We
need to initialize the timer by calling the function below and attach the name of the function that will
be executed. Here, we set the timer to 1000000 microseconds which is 1 second and the ‘flashLED’
function will be executed each second.
Timer1.initialize (1000000);
Timer1.attachInterrupt(flashLED);

The function ‘flashLED’ simply inverts the current state of the pin to which the LED is connected.
A hardware interrupt is used to change the units from Celsius to Fahrenheit and vice versa. We do not
need to review this code.
The remining code is focused within the main ‘loop’ function and controls the DHT11 sensor.
First, I need to point out that I used version 1.0.14 of the ‘SimpleDHT’ library, and the Sketch was
written around this. There are differences in the code associated with some library versions so check
the documentation using the ‘more info’ link if things do not work. If in doubt, use version 1.0.14.
The code reads the temperature and humidity from the DHT11 sensor. The code for this comes directly
from the library examples. In version 1.0.14 of the library, the code checks to see if there is an error
when reading the sensor and displays the error code if one occurs. If there is no error, the temperature
and humidity values are inserted in the respective byte variables. The ‘&’ symbol in front of the
temperature and humanity values means we are passing a reference to those variables so they can be
used in the ‘dht11.read’ function. The ‘return’ statement means that the current function (which is
the main ‘loop’) will terminate at that point and start over.
The code only then needs to print the results to the serial monitor. The resultant output from the Sketch
is shown in Figure 2-11.
Figure 2-11: The Serial Monitor Output for Experiment 5
Image source: The author

Summary
In this chapter you learnt how to debounce a switch with hardware using a Schmitt Trigger and RC filter
circuit. You explored reasons why software debouncing is not appropriate for debouncing a switch for
interrupts. You learnt how to control the I/O pin and timed interrupts supported by the Arduino Uno.
You learnt about the 3 timers on the Arduino Uno and how they have multiple purposes such controlling
PWM and how this can constrain the use of PWM pins or the timers for interrupts. You also looked at
how to load external libraries and how they make easy the programming of sophisticated sensors such
the DHT11 and Arduino features such as timers.
Chapter 3: The I2C Bus

In this series of books, we have looked at how to interface sensors using serial communications,
Bluetooth and with dedicated libraries. What we have not yet explored is how the Arduino can utilize a
standard protocol designed for interworking between electronics devices. The I2C protocol (pronounced
‘eye two see’ or ‘eye squared see’) was designed for this task and is the heart of many sophisticated
modules.

Parts needed for this Chapter


• Arduino Uno or clone board
• Half or full-size breadboard
• 1 x DS3231 Real Time Clock
• 1 x 12864 0.96 Inch Display Module
• 2 x 4.7KΩ or 5.1KΩ resistors
• Jumper wires

The I2C Bus


The I2C protocol was developed by Philips Semiconductors in the early 1980s. It was design for
relatively low speed communications between various Integrated Circuits. By the 1990’s the protocol
was standardized and adopted by other chip manufacturers who came out with their own I2C capable
devices.
I2C is a 2-wire protocol since it only needs 2 wires. These are a data line and a clock. Not all
manufacturers use the term I2C to describe the communication bus on their devices. However, if they
use the term 2-wire, then you can be fairly sure it complies with the I2C standard.
A derivative of the I2C protocol is the System Management Bus or SMBus. This enhanced version of the
I2C protocol was developed by Intel and Duracell. The electrical limits of the SMBus are slightly
different and it also introduces an error checking protocol. It also has an interrupt feature that allows a
slave to notify the master of certain events. It is possible to mix I2C and SMBus devices on the same bus
if you carefully follow the design information in the device datasheet.
Figure 3-1 shows the reference setup for the I2C bus. Multiple devices share the same communication
lines. These lines are a Serial Clock Line (SCL) and a bi-directional data line (SDA). The I2C bus requires
the use of pull-up resistors on both the SCL and SDA lines.
Figure 3-1: The Reference I2C Setup
Image source: The author
The I2C protocol needs a single master device on the bus. However, the bus supports multiple slave
devices. In our experiment, the Arduino Uno will act as the master. The master is responsible for
initiating all communications. The slave devices cannot initiate communications and can only respond
to requests from the master. Without this approach multiple devices may try to ‘talk’ at the same time
leading to garbles messaging.
All slave devices receive communications from the master. However, each slave device has a unique 7-
bit address. The master attaches this address or ID to the message and only that recipient will process
the message. It is essential that each slave device has a unique address. Some I2C devices have selectable
addresses, and some have addresses hardcoded by the manufacturer. This means you need to refer to
the datasheet to ensure that each device on the bus has a unique address. It is often the case that a
manufacturer of the device will allocate a range of addresses, and these will be identified in the part
number. Devices with selectable addresses may have pins dedicated to address selection.
The I2C bus needs pull up resistors as the I/O pins are configured as open collector. Choosing the right
value of pull-up resistor is important. You can refer to the datasheet to recommend a resistor value.
However, if you choose a high value, say 10KΩ, it will probably work, but the performance may be slow
as the resistance value may be deemed to be ‘weak’ and slow to pull up. A lower resistance value will
mean the system will work faster but will draw more much current. This is a consideration for battery
operated devices. You may want to consider using one of the many I2C pull up resistor calculators on
the Web, but values of 4.7KΩ to 10KΩ are generally fine when working with Arduino.

I2C and Arduino


Figure 3-2 shows the location of the I2C pins on the Arduino Uno Rev 3.

Figure 3-2: I2C pins on the Arduino Uno


Image source: Arduino.cc with annotations by the author
You will see that the A4 and A5 pins have dual uses. A4 is SDA and A5 is SCL. On the Uno Rev 3 there
are 2 dedicated I2C pins above the AREF pin. These are hard wired to the A4 and A5 pins. If you use the
A4 and A5 pins in I2C mode, then you cannot use those pins for analog inputs.
The other point to bear in mind is that your Sketches will need to load the ‘Wire.h’ library for I2C
communications using the code below:
#include <Wire.h>
For the experiment, we will use 2 I2C devices to create a simple clock. The Arduino board does not have
a real-time clock that holds time of day and so we will use a DS3231 I2C real-time module and an I2C
display.

The DS3231 Real Time Clock Module


Although you can create a clock using just a display and an Arduino controller, you will soon find out
that the Arduino will the lose time of day each time the Arduino is powered down. The DS3231 Real-
Time Clock (RTC) module provides the year, month, day, hours, minutes, seconds and has a battery to
back up the settings such that any project can be powered down and the time of day maintained.
Figure 3-3 shows the DS3231 real time clock module.

Figure 3-3: The DS3231 Real Time Clock Module


Image source: The Web (public domain)
At the heart of the RTC module is the DS3231 RTC chip from Maxim. This is a capable chip and can
adjust for the days in the month and allow for leap years up until 2100. The clock operates in either the
24-hour or 12-hour format with an AM/PM indicator. It also provides two programmable time-of-day
alarms. The module also can output a square wave at either 1Hz, 4kHz, 8kHz or 32kHz. This is handled
programmatically and can be used as an interrupt for alarm conditions in time-based applications.
The DS3231 is extremely accurate due to having a Temperature Compensated Crystal Oscillator
(TCXO). The frequency of crystal oscillator without temperature control can vary at extreme
temperatures so compromising accuracy. The DS3231 is immune to this characteristic as the oscillator
has temperature compensation hardware and firmware onboard. A temperature sensor next the
oscillator is used by the processor to adjust the frequency by adding or removing ‘ticks’ from the clock.
On the reverse side of the module, you will find a CR2032 battery that is used to maintain the time after
power is removed.
The I2C address of the DS3231 is factory set to 0x68 Hex and cannot be changed. The DS3231 RTC
module also comes with a 32 byte 24C32 EEPROM chip from Atmel having unlimited read-write cycles.
It can be used to save settings or any other data. The I2C address of the EEPROM can be changed easily
with the three A0, A1 and A2 solder jumpers highlighted in Figure 3-3. Each one of these is used to
hardcode the address. If a jumper is shorted with solder that sets the address bit to 0.
The 24C32 EEPROM uses 7-bit I2C addressing. An 8th bit, which is the least significant bit, is used as a
read/write flag. Figure 3-4 shows how the addressing is arranged for the EEPROM.
Figure 3-4: The 24C32 EEPROM Addressing Scheme
Image source: The author
The first 4 bits are always set to 1010. If a jumper is left open the associated address selector will be
pulled into a ‘HIGH’ state and so the address bit will be 1. Therefore, by default the I2C address of the
24C32 EEPROM is binary 1010111 or HEX 0x57.
As with all complex modules, we will use a library to pick up the heavy work. We will use the ‘RTClib.h’
written by Adafruit.

The 12864 0.96 Inch Display Module


The 12864 display module is a 0.96 inch OLED (Organic Light-Emitting Diode) display. It uses the
SSD1306 displays driver that has an I2C interface. It is a high quality, 128 x 64 pixel, self-illuminating
display. Examples of these display modules are pictured in Figure 3-5. Be sure to acquire one with the
PCB header for location into the breadboard.

Figure 3-5; The 12864 0.96 Inch Display Module


Image source: The Web (public domain)
The 12864 OLED display has some advantages to other common displays. First, the I2C interface means
that only 2 pins are needed and it can share the bus with other devices. Second, it can display both text
and graphics.
The I2C address for the display’s driver chip, the SSD1306 is hardcoded. You should use a prewritten
Sketch to scan for the address after it is connected to your Arduino. The Sketch can be downloaded here
(https://playground.arduino.cc/Main/I2cScanner/) and we will use this at the start of Experiment 6.
As with most sophisticated modules, there is an Arduino library that makes our programming task
much easier, and we will use the ‘Adafruit_SSD1306.h’ library. This library has several functions
that can write directly to the pixels, draw shapes, and write text. There are even websites that offer tools
for you to create bitmap images for this display. When writing to display you need to specify the
coordinates of the pixel, shape, or text you are writing. Top left is [0, 0], bottom left is [0, 63], top right
is [127, 0] and bottom right is [127, 63] as illustrated in Figure 3-6.

Figure 3-6: The Coordinate Arrangement of the 12864 OLED Display


Image source: The author

Experiment 6: A I2C Based Digital Real Time Clock


Time now to put together our project and look at the I2C bus in operation. We know the default I2C
address of the DS3231 Realtime Clock. This is 0x68 Hex. We need to verify the I2C address of the 12864
OLED Display. We do this my running the ‘i2c_scanner’ Sketch. But first, build the breadboard layout
as in Figure 3-7.
Figure 3-7: The Breadboard Layout to Connect the 12864 OLED Display to the I2C Bus
Image source: Created with Fritzing
The ‘Wire.h’ library will use the internal pullup resistors of the Arduino for the I2C bus. These resistors
may be between 10KΩ and 30KΩ depending on the manufacturer. 10KΩ should be OK for this lab, but
the bus speed will be relatively slow. I used a pair of 5.1KΩ resistors on the SCL and SDA lines as
external pullups to speed up the bus (not that we would notice in this case).
Next, copy the ‘i2c_scanner’ Sketch from the Website. Open the Serial Monitor and upload the Sketch
to the Arduino. After running the Sketch, you should see an output like that in Figure 3-8 giving you
the I2C address of the display.
Figure 3-8: The Serial Monitor showing the I2C Address of the 12864 OLED Display
Image source: The author
You can see that the I2C address of my display is HEX 0x3C.
Moving onto the complete clock. We will set the time of the DS3231 automatically by using the date and
time the Sketch is compiled and uploaded to the Arduino. This only needs to be done once and so we
will set an I/O pin low with a jumper. When the Sketch is first uploaded the jumper should be connected
to the ground (GND) rail. This will pull the input ‘LOW’. Code placed in the ‘setup’ function of the
Sketch will detect the state of this pin and update the clock. The jumper can then be removed. An
internal pullup resistor will then send the state of this pin ‘HIGH’. The code to update the clock will be
skipped for all future restarts and you will see that the date and time are retained after each power cycle
by means of the battery on the DS3231 module. You now need to build the breadboard layout as shown
in Figure 3-9.
Figure 3-9: The Breadboard Layout for the I2C Clock
Image source: Created with Fritzing
The Sketch for the I2C Clock is shown in Listing 3-1.
/*
I2C Clock
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/sturdy-octo-
goggles/blob/master/LICENSE
*/

#include <Wire.h>
#include <RTClib.h>
#include <Adafruit_SSD1306.h>

char daysOfTheWeek[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri",


"Sat"};
const int SETCLOCKPIN = 2;
const int SCREEN_WIDTH = 128;
const int SCREEN_HEIGHT = 64;
const int OLED_RESET = -1; //uses Arduino reset button
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RTC_DS3231 rtc;

void setup() {
Serial.begin(9600);
delay(3000); // wait for console opening
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 allocation failed");
for (;;); // Don't proceed, loop forever
}
pinMode (SETCLOCKPIN, INPUT_PULLUP);
if (! rtc.begin()) {
Serial.println("RTC not found");
while (1);
}
if (digitalRead(SETCLOCKPIN) == LOW) {
Serial.println("setting");
if (rtc.lostPower()) {
//Set time to that when program was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// Following line sets the RTC with an explicit date & time
// for example to set January 27 2017 at 12:56 you would call:
// rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0));
}
}

void loop() {

display.clearDisplay(); //clear display


DateTime now = rtc.now(); //get date and time from DS3231
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(65, 50); //moves curser
char buf_date[6];
//formats date with leading zeros where needed
sprintf(buf_date, "%02d/%02d", now.day(), now.month());
display.print(buf_date);
display.setCursor(0, 50);
//displays day of the week
display.print(daysOfTheWeek[now.dayOfTheWeek()]);
display.setCursor(0, 0);
//format the time
char buf_time[6];
display.setTextSize(3);
sprintf(buf_time, "%02d:%02d", now.hour(), now.minute());
display.print(buf_time);
display.setCursor(88, 7);
display.setTextSize(2);
display.print (":");
char buf_second[3];
sprintf(buf_seconds, "%02d", now.second());
display.print(buf_seconds);
display.display();
delay(1000);
}

Listing 3-1: The Sketch for the I2C Clock


Listing source: The author with library contributions from Adafruit
Let us review the code. The first thing you should notice is that there is little code needed with respect
to the I2C bus. The ‘Wire.h’ library takes care of most of this, and we only need to pass the I2C address
of the display.
First, the necessary libraries are included.
#include <Wire.h>
#include <RTClib.h>
#include <Adafruit_SSD1306.h>

Next, we define a constant ‘char’ array to hold the days of the week. This is a 2-dimensional array to
hold the seven days, each expressed in 3-character format. This necessitates an array of size of 7 x 4.
The Arduino programming language is based on c++ and when we define each day, 3 spaces in the array
are needed for the day of the week and c++ adds the null termination character ‘\0’. A space is needed
for this character or the compiler will throw an error.
char daysOfTheWeek[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
"Sat"};

The other constants are self-explanatory. We will use I/O pin 2 to set the clock after the Sketch is first
uploaded. We define the screen width and height and state that we will use the Arduino’s reset button
to reset the display.
const int SETCLOCKPIN = 2;
const int SCREEN_WIDTH = 128;
const int SCREEN_HEIGHT = 64;
const int OLED_RESET = -1; //uses Arduino reset button

We then create objects for the DS3231 and 12864 display.


Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RTC_DS3231 rtc;

A block of code is placed in the ‘setup()’ function to check for the presence of the display on the I2C
bus and we pass the I2C address as an argument. If the display is not found we effectivity stop the code
there with a loop that runs forever (‘for (;;)’)
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 allocation failed");
for (;;); // Don't proceed, loop forever
}

We also want to check for the presence of the DS3231 RTC. If the DS3231 is not found, then the code
will also stop at this point with another way of implementing a forever loop with a ‘while’ loop.
if (! rtc.begin()) {
Serial.println("RTC not found");
while (1);
}

If the DS3231 is found, we check to see if pin 2 of the Arduino is ‘LOW’, and if it is, we set the time. The
function ‘rtc.lostPower()’ returns ‘TRUE’ if the DS3231 as lost track of time. We can then execute
a special set of arguments to apply the date and time that the Sketch was compiled (‘F(__DATE__),
F(__TIME__)’). This may still be a few seconds away from the real time, but close enough for our
experiment.
if (digitalRead(SETCLOCKPIN) == LOW) {
Serial.println("setting");
if (rtc.lostPower()) {
//Set time to that when program was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// Following line sets the RTC with an explicit date & time
// for example to set January 27 2017 at 12:56 you would call:
// rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0));
}
}

The main ‘loop’ function focuses on getting the current time and displaying the result. We create an
object of the ‘DateTime’ class and get the current time from the DS3231.
DateTime now = rtc.now();

We then set the text size for the screen. The smallest is 1 and the largest 3. We move the cursor to where
we want to place the text and set the color to a redefined value that turns on the pixel. The constant
‘SSD1306_WHITE’ does this. It implies the color white, but the screen will illuminate with whatever
color the LEDs are. The constant ‘SSD1306_BLACK’ turns off the LEDs.
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE); // Turns on pixel
display.setCursor(65, 50);

We want to print the date and time in a recognizable format. We could print the returned values from
‘now.day()’ and ‘now.month()’, but this would not print leading zeros if they are needed. We can
used the ‘sprint()’ function to do that formatting using the precursor ‘%02’ to print 2 figures with a
leading zero if the value is less than 10. Within the ‘sprintf’ function, will create a string called ‘date’
with the day and month separated with the ‘/’ symbol. We send this string to the SSD1306 display using
the ‘display.print’ function.
sprintf(buf_date, "%02d/%02d", now.day(), now.month());
display.print(buf_date);

Note that ‘display.print’ does not actually display the text. It prepares the display to show this text
and a trigger is needed later.
The time is treated in a similar way to the date to position the text, size the text and format the text.
Finally, we trigger the display to show the date and time using the function below:
display.display();

An image of my setup is shown in Figure 3-10 and a video of this project can be seen here
(https://youtu.be/Yh-CEspwd6Y).
Figure 3-10: The I2C Digital Clock
Image source: The author

Summary
In this chapter you learnt about the I2C bus, its history and how it works. You learnt what pins on the
Arduino Uno can be used for I2C communications. You were made aware to use manufacturers
datasheets to understand the I2C addresses for electronic components and modules as well as choosing
the best pullup resistor values. You learnt about the DS3231 Real Time Clock and the 12864 OLED
display that uses the SSD1306 driver chip. You learnt how the ‘Wire.h’ library and other libraries make
programming I2C modules much easier.
Chapter 4: The Serial Peripheral Interface Bus

This is a third communications method that can be used between peripheral devices and the Arduino
board. The other 2 being serial UART and I2C. The Serial Peripheral Interface, or SPI (often pronounced
‘spy’) Bus for short is covered in this chapter.

Parts needed for this Chapter


• Arduino Uno or clone board
• Half or full-size breadboard
• 2 x MCP4131-103E/P 10KΩ Digital Potentiometer
• Jumper wires

The SPI Bus


The SPI bus was originally developed by Motorola. It is a ‘full duplex’ serial communications
technology. ‘Full duplex’ means it has separate transmit and receive channels so that data can be
transmitted and received simultaneously in each direction between master and slave devices. The SPI
protocol is not a formal standard and so there may be differences between devices from different
manufacturers, but there is a common implementation that fortunately is supported by Arduino, the
associated libraries and many of the peripheral modules. Just like the I2C bus, it is important to read
the datasheet for a device to understand how the SPI bus is implemented and to understand any
potential incompatibilities.
SPI buses have different modes of operation depending on the needs of the device. SPI devices are often
referred to as slaves. SPI devices are ‘synchronous’ meaning that data is clocked by a Serial Clock Line
(SCLK). Data can be shifted into the slave device either on the rising or falling edge of the clock. This is
called the clock phase. You can also set the polarity of the clock by making the default state ‘HIGH’ or
‘LOW’. So, there are 2 options for clock phase and 2 options for clock polarity. This means there are 4
ways to configure the SPI bus as summarized in Table 4-1.
SPI Mode Clock Polarity Clock Phase
Mode 0 Low at Idle Data Capture on Clock Rising Edge
Mode 1 Low at Idle Data Capture on Clock Falling Edge
Mode 2 High at Idle Data Capture on Clock Falling Edge
Mode 3 High at Idle Data Capture on Clock Rising Edge

Table 4-1: SPI Bus Communication Modes


Understanding these modes of operational is useful, but an Arduino library designed to work with a
specific device will generally automatically select the correct mode of operation for that device.
There are 3 pins used between master and all slave devices.
• Shared Serial Clock (SCLK)
• Master Out/Slave In (MOSI)
• Master In/Slave Out (MISO)
Each slave device also needs a Slave Select (SS) pin. This means that the I/O pins needed on the Arduino
board will number 3+n where n is the number of slaves.
Figure 4-1 shows the reference SPI architecture with 2 slave devices.

Figure 4-1: The SPI Reference Architecture


Image source: The author
Table 4-2 describes the function of each SPI Bus communications line.
SPI Communication Line Description
MOSI Used for sending serial data from the master to the slave
MISO Used for sending serial data from the slave to the master
SCLK The synchronization clock
SS The Slave Select line. By pulling this line low you select that slave. Only 1 SS
line should be low at any time

Table 4-2: The Function of the SPI Bus Communications Lines


All slave devices on the SPI Bus share the SCLK, MOSI and MISO lines as all messages are send to every
slave device. You need to ensure that only 1 slave is selected by sending the SS line low for the device.
The sequence of actions for communicating with a slave on the SPI Bus is as follows:
1. Send the SS pin for the desired slave ‘LOW’.
2. Toggle the SCLK line up and down at a speed less than or equal to the transmission speed
supported by that device.
3. For each clock cycle, send 1 bit to the slave on the MOSI line and receive 1 bit on the MISO line.
4. Continue until all bits are send, then stop toggling to clock.
5. Return the SS pin for that slave device ‘HIGH’.

Comparing the SPI Bus to I2C and Serial UART


Many of the modern devices have both I2C and SPI functionality on the same device. So, what do you
choose to use? There are advantages and disadvantages to each technology and what you choose
depends on your specific requirements for your project. Table 4-3 highlights some of differences
between these technologies.
SPI Bus I2C UART
Highest speed Speed dependent on Requires baud rate to be agreed
characteristics of the bus (length by both ends before transmission
of bus pullup resistor values, can start
number of devices)
Is generally easier to work with Requires only 2 communications No real overhead and simple to
compared to the I2C Bus lines implement
No pullup resistors needed Can support communications No predefined master or slave
between devices operating from
different voltage rails
Number of slave devices limited Number of slaves limited by the Cannot easily support multiple
only by the number of available SS number of available slave slave devices
pins addresses
Has built in Arduino hardware and Has built in Arduino hardware and Has built in Arduino hardware and
software support software support software support

Table 4-3: Some Differences between the SPI Bus, I2C and Serial UART

The SPI Bus and the Arduino Uno


The Arduino Uno has dual use pins that act as I/O pins and SPI Bus pins. These are listed below:
• Default SS: pin 10
• MOSI: pin 11
• MISO: pin 12
• SCK: pin 13
You can use other Arduino I/O pins for the Slave Select if more slaves are required, but pin 10 tends to
be the default, or first pin used, as it sits next to the other SPI Bus pins.
There is an Arduino ‘SPI.h’ library that can be used to interface to SPI compatible devices. There is a
little work needed to set up the SPI bus using this library and we will explore this in Experiment 7.

The MCP4131-103E/P 10KΩ Digital Potentiometer


The MCP4131 is controlled by an SPI compatible interface and is a digital potentiometer. Rather than
a central manually controlled wiper. The resistance is set by software commands. Digital
potentiometers can be used in place of the standard wiper versions and are useful devices. They can be
used for volume and tone controls in audio circuit so that an Arduino, or other microcontrollers, can be
used to interface with and control analog electronics.
Figure 4-2 shows the pinouts of the MCP4131-103E/P. This is a 10KΩ device and other resistance values
are available.

Figure 4-2: The Pinouts of the MCP4131-103E/P


Image source: The author
You will see that the naming convention for the SPI Bus pins differs to the accepted norm. This reflects
the fact that the SPI Bus is not a defined standard. However, in this case the manufacturer clearly states
that the device is SPI Bus compatible. The pins we have are:

• CS is Chip Select, Active Low


• SCK is the clock
• SDI/SDO are multiplexed MOSI and MISO pins
• VSS is the ground or 0V
• VDD is the supply that will be set to +5VDC
• P0A and P0B are the 2 ends of the Potentiometer and P0W is the wiper
Here are some key features of the MCP4131 series:
• 7-bit, 128 resistor (128 Steps) network
• Resistance options: 5kΩ, 10kΩ, 50kΩ and 100kΩ
• SPI Serial Interface (10 MHz, modes 0,0 & 1,1)
The resistance of any device is identified in the part number. The ‘103’ represents 10 followed 3 zeros.
So how do we write data to the MCP4131-103E/P? Once the SPI Bus is configured, we need to access
what is termed a ‘register’ in the device and then write data to that specific register. The register we will
write to relates to the pot’s wiper. Registers generally have an address and then some attributes that
need to be set before writing data. You can consider registers in electronics to be a form of memory.
The register for the wiper in the MCP4131-103E/P is structured as follows:
The first 4 bits are called AD3, AD2, AD1 and AD0. These hold an address for the entity we want to
program and the address for the pot’s wiper is 0000.
Next there are 2 bits referred to as C1 and C0. These bits identify the kind of command we want to
execute for the address. We can either read data from the address, write data to the address, increment
the data of the wiper by a value of 1, or decrement the data by a value of 1. The command for writing
data to the address is 00 and we want to write data.
Next there are 2 bits referred to as D9 and D8. D9 is undefined and is always 0. D8 can be set for
variants of the MCP413X/415X/423X/425X family of digital potentiometers that support 8-bit and 7-
bit resolution. The MCP4131-103E/P only supports 7-bit resolution and so D9 should be set to 0.
So, we first set the register to all zeros (00000000), send the command, and then send the data next
before setting the Chip Select ‘HIGH’. The summary of the wiper’s register is shown in Table 4-4.

AD3 AD2 AD1 AD0 C1 C0 D9 D8


0 0 0 0 0 0 0 0

Table 4-4: The MCP4131-103E/P Register Value for the Pot’s Wiper

Experiment 7: Using the SPI Bus to Control Digital Potentiometers


This is a simple experiment designed to explore the operation of the SPI Bus and the ‘SPI.h’ library.
We will write a Sketch to increase the resistance of 1 potentiometer whilst reduced the resistance of the
other. We will connect P0A of each potentiometer to +5V and PoB to 0V. The wiper of each
potentiometer will be connected to an analog input on the Arduino, and we will measure the voltage
obtained to check that the system is working.
First build the breadboard layout as shown in Figure 4-3:
Figure 4-3: The Breadboard Layout for Experiment 7
Image source: Created with Fritzing
Next type in or copy the Sketch shown in Listing 4-1.
/*
SPI Bus
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/sturdy-octo-
goggles/blob/master/LICENSE
*/

#include <SPI.h>

const int CS1 = 10; //cs pot 1


const int CS2 = 9; //cs pot 2
const int POT1 = A1; //wiper pot 1
const int POT2 = A2; //wiper pot 2
const byte address = 0x00;

float voltage1; //volts for pot 1


float voltage2; //volts for pot 2

void setup() {
pinMode (CS1, OUTPUT);
pinMode (CS2, OUTPUT);
pinMode (POT1, INPUT);
pinMode (POT2, INPUT);
SPI.begin();
Serial.begin (115200);
}

void loop() {
for (int i = 0; i <= 128; i++) //7 bits addressing for the pot wiper
{
//increase resistance of pot 1
digitalWrite(CS1, LOW);
SPI.transfer(address);
SPI.transfer(i);
digitalWrite(CS1, HIGH);
voltage1 = analogRead (POT1) / 1023.0 * 5.0;
//decrease resistance of pot 2
digitalWrite(CS2, LOW);
SPI.transfer(address);
SPI.transfer(128 - i);
digitalWrite(CS2, HIGH);
voltage2 = analogRead (POT2) / 1023.0 * 5.0;
Serial.print ("Pot 1: ");
Serial.print (voltage1);
Serial.print ("V ");
Serial.print ("Pot 2: ");
Serial.print (voltage2);
Serial.println ("V ");
delay(200);
}
delay(500);
for (int i = 0; i <= 128; i++)
{
//decrease resistance of pot 1
digitalWrite(CS1, LOW);
SPI.transfer(address);
SPI.transfer(128 - i);
digitalWrite(CS1, HIGH);
voltage1 = analogRead (POT1) / 1023.0 * 5.0;
//increase resistance of pot 2
digitalWrite(CS2, LOW);
SPI.transfer(address);
SPI.transfer(i);
digitalWrite(CS2, HIGH);
voltage2 = analogRead (POT2) / 1023.0 * 5.0;
Serial.print ("Pot 1: ");
Serial.print (voltage1);
Serial.print ("V ");
Serial.print ("Pot 2: ");
Serial.print (voltage2);
Serial.println ("V ");
delay(200);
}
}

Listing 4-1: The Sketch to Control the Digital Potentiometers


Listing source: The author
Let us look at the code. First, we load the ‘SPI.h’ library.
#include <SPI.h>

From the list of constant declarations, the register value for the pot’s wiper is the most significant and
we discussed why the value is 0.
const byte address = 0x00;

We want to convert the analog input value for each pot back into a voltage, so we need 2 floating point
variables.
float voltage1; //volts for pot 1
float voltage2; //volts for pot 2

In the ‘setup’ function we assign the Arduino I/O pins and start the Serial Monitor to display the wiper
voltages. A fast baud rate is selected to empty the buffer quickly. We also initialize the SPI Bus with the
line of code below.
SPI.begin();
In general, you can use the basic ‘begin’ function that has no arguments. This will load the default SPI
Bus values. For an Arduino Uno this will be a bus data rate of 5Mbps, Mode 0 and the Most Significant
Bit (MSB) first. Since most SPI device support bus speeds of more than 5Mbps, this command will be
fine. Mode 0 and MSB first are also common then there is no need for any other command. If, however,
you wanted more control you can substitute the line ‘SPI.begin()’ with the following:
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));

This will run the bus at 10Mbps, the maximum speed of the MCP4131-103E/P.
In the main ‘loop’ function, we step through each resistance value with a ‘for’ loop until the maximum
is reached and then step down again to 0. The MCP4131-103E/P supports 7-bit resolution so there are
128 steps.
With each step, we transfer a new value to the MCP4131-103E/P by first sending the register value and
then the data.
digitalWrite(CS1, LOW);
SPI.transfer(address);
SPI.transfer(i);
digitalWrite(CS1, HIGH);

Reading the value from the wiper, we then convert this back to a voltage value. We need to use floating
point arithmetic. The value from the Arduino’s ADC is an integer so we must append 1023 and 5 with
‘.0’ to force floating point arithmetic. Otherwise, the resultant value will always be 0.
voltage1 = analogRead (POT1) / 1023.0 * 5.0;

The rest of the code should be self-explanatory.


Figure 4-4 shows some results from my Serial Monitor.

Figure 4-4: The Pot Values on the Serial Monitor


Image source: The author

Summary
In this chapter you learnt about the Serial Peripheral Interface Bus and compared its features with the
I2C and Serial UART technologies. You learnt how to program the SPI bus using the Arduino library
and what Arduino I/O pins are set aside for SPI communications. You learnt about the MCP4131-
103E/P digital potentiometer and how to program it using the SPI bus.
Chapter 5: The AREF and IOREF Pins

You may have noticed two more Arduino pins that we have not yet covered. In this short final chapter,
we will look at the AREF and IOREF pins and conclude the book with a simple experiment.
The IOREF pin is easy to deal with as it provides a reference for a shield of the working voltage of the
board. It is not an I/O pin as such and connecting a voltage to this pin will do nothing. The operating
voltage of an Arduino Uno is 5V and so the IOREF will be 5V. An Arduino Due works at 3.3V and the
IOREF is set to 3.3V. There is nothing more really to say about the IOREF pin.
AREF means Analog Voltage Reference. It allows us to feed a reference voltage into the board which we
can use as an alternative maximum voltage for the Analog to Digital Converter (ADC). By default, the
ADC is set to read 0V as the minimum and 5V as the maximum. It has a 12-bit resolution and so a digital
reading of 0 correlates to 0V and 1023 correlates to 5V. Let us say we are working with 3.3V logic. The
maximum voltage we can present to an analog input will be 3.3V. This means the maximum ADC value
will be ~675. We are losing one third of the ADC’s resolution. The AREF pin allows us to redefine the
resolution of the ADC. By attaching a voltage of 3.3V to the AREF pin, 0V will be represented by 0 and
3.3V by 1023. It is this functionality we will test with a simple experiment.

Parts needed for this Chapter


• Arduino Uno or clone board
• Half or full-size breadboard
• 1 x 10KΩ potentiometer
• Jumper wires

Experiment 8: Using the AREF Pin


In this experiment, we will use a potentiometer as a potential divider and connect the wiper to one of
the Arduino’s analog input pins. We will first connect one terminal of the potentiometer to 5VDC and
monitor the value from the ADC. We will then connect the terminal of the potentiometer to 3.3V and
again measure the ADC values. Finally, we will connect 3.3V to the AREF pin and measure the ADC
values. The Sketch needed for this experiment is shown in Listing 5-1.
/*
The AREF Pin
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/sturdy-octo-
goggles/blob/master/LICENSE
*/
const int pot = A0;

void setup() {
Serial.begin (9600);
}

void loop() {
int val = analogRead(pot);
Serial.println (val);
delay (500);
}

Listing 5-1: The Sketch for the AREF Pin Experiment


Listing source: The author
The breadboard layout for the first part of the experiment is shown in Figure 5-1.

Figure 5-1: The Breadboard Layout for 5V connected to the Pot


Image source: Created with Fritzing
Load the Sketch and open the Serial Monitor. Turn the potentiometer to both extremes. You will see
ADC values of between 0 and 1023.
Figure 5-2 show the next phase where one terminal of the pot is connected to 3.3V.

Figure 5-2: The Pot Connected to 3.3V


Image source: Created with Fritzing
The Serial Monitor output should now show ADC values of between 0 and ~664. You can appreciate
that is quite a lot of resolution is lost.
Figure 5-3 shows the final scenario with 3.3V connected to the AREF pin.
Figure 5-3: 3.3V Connected to the AREF pin
Image source: Created with Fritzing
The serial monitor output should now show ADC values of between 0 and 1023, although the maximum
output may be around 1021 or 1022 due to tolerances.
Warning: Do not connect a voltage greater than +5VDC to the AREF pin!

Summary
In this chapter you learnt about the functions of the AREF and IOREF pins and how the AREF pin can
be used to increase the resolution of the Analog to Digital Converter.
Epilogue

We have come to the end of this part of the journey. I feel this book is a great companion to Book 1 of
this series (First Steps with Arduino) as it builds on the essential basics learnt from that book. The skills
learnt here can be applied to projects for the hobbyist and the most complex professional developments
alike. They are highly relevant for anybody looking for a career in electronics or just looking to have
fun.
In the subsequent books in the series, we will use our knowledge gained to look at other focus areas and
create ever more challenging, creative and interesting projects. Whatever your goals are, I hope to have
inspired you and helped you some way to achieving those goals.
If you like this book and the series of books, please leave a review on the Amazon website. For the latest
news on other books in the series you can following my Facebook page, Twitter or follow me as an
author on Amazon.
About the Author

Gary Hallberg has over 34 years of experience in the telecommunications and data communications
industries. He started his career working with circuit switched voice and data technologies in PDH and
SDH environments and then moved on to work with early packet switched networks using Frame Relay
and ATM. His career shifted focus to IP routing when the Internet started to grow, designing large scale
service provider networks using leading edge equipment from vendors such as Juniper and Cisco. Gary
attained Cisco Certified Professional status during this time. Presently, he is working for a global
equipment vendor with a focus on Ethernet networks and is at the forefront of network evolution,
providing infrastructures for SD-WAN, Network Functions Virtualization, SDN and 5G backhaul. Gary
has a Bachelor of Engineering degree in electronic engineering and a Master of Philosophy degree in
robotics and manufacturing.

You might also like