Vous êtes sur la page 1sur 303

Sold to

sadikdelioglu@gmail.com

Peter Dalmaris

Lecture 2

Arduino Step by Step

Section 1 Lecture 2
The Arduino ecosystem

Before setting up the "hello world" demo app of the electronics world (the blinking LED),
let's have a really quick look at the Arduino ecosystem. The members of this ecosystem are
the bits and pieces that come together when you build an Arduino project.

The Arduino ecosystem is made up of these parts:

1.

The Arduino board

2.

The Arduino IDE

3.

The Arduino core software library ("Arduino language")

4.

Third party software libraries

5.

Shields

6.

Components

The Arduino board

In the beginning, way back in 2005, there was only one board. Rumour has it that it was
called the "Arduino" in honour of the place where the idea for an open-source hardware
prototyping platform was conceived. Today there are numerous boards, with a wide range
of capabilities. Processing, input/output, power consumption, size, and price are various
metrics in which modern Arduino boards dier from each other.

The very popular Arduino Uno Rev 3

!Arduino-ocial boards are made by companies that work in collaboration with the Arduino
team to ensure compatibility. They are the only ones licensed to use the name "Arduino". In
return, makers of ocial Arduino boards pay a fee to the Arduino project. There are also

Peter Dalmaris

Lecture 2

Arduino Step by Step

The very small Arduino Micro

many clones, derivatives and counterfeit boards that while using the open-sourced Arduino
software and schematics do not contribute to the project financially. They also are not
providing any guarantee of compatibility and quality. I recommend you only purchase an
ocial Arduino board for both peace of mind and for the nice feeling of contribution to the
project.

The Arduino IDE

The Arduino IDE, or Integrated Development Environment, is the tool you use to create an
Arduino program and upload it to your board. An Arduino program is called a sketch, a
reminder that what you are actually doing is prototyping, which in turn means that anything
you do is subject to trial, testing, and change.

Here is an example of the Arduino IDE.


2

Peter Dalmaris

Lecture 2

Arduino Step by Step

The Arduino IDE can be downloaded from the Arduino website and it works on Mac, Linux
and Windows computers. Its only requirement is the Java Runtime Environment (JRE).
Simply download the IDE installer for your computer, and run it. The installer will let you
know if you need to download the JRE. Get it from http://arduino.cc/en/Main/Software.

With the IDE installed, you will be able to type, upload to the board, and debug (ie. fix) your
sketches. You also use the IDE to communicate both ways with the board: to upload your
sketches to the Arduino, and to receive messages from the Arduino.

The Arduino language

When you download the Arduino IDE, you also get the Arduino core library. This library is a
collection of functions or methods that allow you to control the various aspects of your
board's functionality. For example, if you want to read an analogue value from pin 1, you
call the relevant method like this:

analogRead(1);

Awesomely simple! If you want to turn an LED light on, that requires "writing" a digital value
1 to a digital pin. Connect the LED through a resistor to digital pin 13 and use this method:

digitalWrite(13, HIGH);

Apart from methods like these, meant to interact with the environment, the Arduino core
library gives you many others. There are control structures, arithmetic operators,
mathematics functions and many others. All of them are listed and documented in the
references page of the Arduino project's web site.

I will be explaining the use of many of these methods as we use them throughout this
course.

Third party software libraries

Lot's of people have contributed to the Arduino ecosystem by writing their own libraries
and making them available to others. These third-party libraries often address gaps in
functionality that the Core library perhaps does not oer, or it does not oer well. In other
cases, these libraries oer alternative ways of doing things.

For example, this library allows you to add infra-red remote control capability to your
project. This one implements a web server that can run on your board, which is very useful
for remote sensing or remote control applications.

Shields

Very often, certain hardware components are used so widely that eventually a company
assembles them together on a printed circuit board so that it is easy to plug into an Arduino
board without any wires. These extension boards are known as "shields".

Peter Dalmaris

Lecture 2

Arduino Step by Step

The Ethernet shield is very common. It makes it very easy to add Ethernet and Internet
communications to your project. You could just buy the WizNet controller, connector and
other parts and create your own Ethernet adaptor, but it would be silly to do that.
Remember that our mission is to build prototypes so that we can implement our ideas, not
to fiddle around with problems already solved well by others!

Another popular shield is the Arduino Motor Shield through which you can control all sorts
of motors, very useful if you want to build a robot, a racing car, or a remote control lawn
mower.

In section 4 we will be playing with the Ethernet shield.

Components

Finally, there are the individual components. These are typically small devices that you plug
into your board by using jumper cables and breadboards.

For example, if you want to take temperature and humidity readings, you could use the
DHT11 sensor.

If you need to measure distance, then you could use an ultrasonic distance sensor.

In sections 2 and 3 of this course we will be experimenting with many useful components.

Conclusion

Ok, that concludes a brief dive into the Arduino ecosystem. Please take a few minutes to
answer a few quiz questions before continuing with Lecture 3 where we examine the
Arduino tools and the prototyping process.

Peter Dalmaris

Lecture 3

Arduino Step by Step

Section 1 Lecture 3
Tools and the prototyping process

In this lecture I will show you the tools and process involved in prototyping with the
Arduino.

There is nothing Arduino-specific about either these tools or process. The Arduino is an
incredibly eective creative tool because it accelerates prototyping dramatically.

The prototyping process

Prototyping is an iterative process whereby each iteration's objective is the refinement of a


prototype.

It looks like this:

!
It all begins with an idea, a problem or a thing that you would like to build. Usually you will
have some prior knowledge of the problem area, or some informed assumptions that can
help you get started. But at the very beginning, you will not have the details or at least
some of the knowledge necessary to help you in actually building whatever you are trying to
build.

So, you go ahead and use what you know to build a prototype, version 1. This prototype
may barely work at all, but it should be doing something that you can test and learn from.
Testing yields information that you can use to adjust your original assumptions. This
adjustment is called refinement.

Peter Dalmaris

Lecture 3

Arduino Step by Step

Iteration after iteration will yield more and more information and result to more and more
refinements until at some point your prototype, be it version 100 or version 1000, is the
product or solution you aimed for.

Of course, the Arduino is not necessary in the prototyping process. You could do
prototyping using bare-bones electronic components down to the transistor. However with
the Arduino, you can prototype much faster because (1) you will be using general purpose
and already tested components which allow you to focus on your actual objective and (2)
you will be using high-level tools to do so.

Tools

Yet another really nice thing about prototyping with the Arduino is that you only need few
and very basic tools.

Not including the board itself, shields and other components mentioned in Lecture 2, you
can build great projects with just these items:

1.

Multimeter (not strictly needed)

2.

Solderless Breadboards

3.

Jump wires

4.

Power supply (not strictly needed)

A multimeter

A multimeter is not required for the majority of the projects you will be building as a
beginner. However having one and getting to know how to use it will help you a lot later on.

Multimeters vary in capabilities and prices, but for


$20 or $30 you can get a really nice digital one that
will show you things like:

1. Voltage AC and DC

2. Resistance

3. Continuity between two parts of a circuit

With these basic capabilities, you will be able to


check that there is voltage dierential between two
pins, or that a battery is charged, check the
resistance of a resistor, and confirm that two parts of
a circuit are electrically connected.

This is what a typical digital multimeter looks like.

!
2

Peter Dalmaris

Lecture 3

Arduino Step by Step

Solderless Breaboards

A solderless breadboard is a convenient way


to connect components together without a
need to use solder and a soldering iron.

With a breadboard, you will just connect your


components into electrically connected
sockets. When you are done, you can clear the
breadboard and use it for another project.

In a breadboard you get a couple of rows


containing sockets that carry ground and
positive voltages along one or both sides of
the board, and multiple columns containing
sockets that are electrically connected.

Here's a medium-sized breadboard.

If you could x-ray a breadboard, you would


see something like this:

An "x-ray" photo of a breadboard

You can see here how sockets are electrically


connected vertically or horizontally.

And here is a picture of a simple Arduino


project where an LED that is connected to the
Arduino pin 9 (digital out) and ground via a
resistor. Instead of making the connections
directly into the Arduino connectors, which
would result in a messy bungle of wires, I
plugged the LED, resistor and jumper cables
into a mini-breadboard. Much cleaner setup!

!
!

Jumper wires

A jumper wire is a thin cable with pins at either end. Use them to
make connections on a breadboard and on the Arduino headers.
They come in many colours and lengths. One thing to remember:
you don't want to run out of jumper cables during your
prototyping so make sure you have plenty available!

My only "rules" when it comes to jumper cables are these:

Peter Dalmaris

1.

Use red for positive voltages

2.

Use black for ground

Lecture 3

Arduino Step by Step

Any other colours can be used to signify the connection of dierent kind of components or
functions that each one serves. For example, you could use light coloured wires for sensors
and dark for buttons or displays. Up to you.

Power supply

The Arduino can provide power for itself and for the circuit you are building from the USB
cable that is used to connect it to your computer.

However, there are three obvious cases where you will need an external power supply:

1. If you want your sketch and gadget to continue its operation after your computer is
turned o.

2. If your circuit becomes large enough so that the Arduino can't provide enough
power

3.

If your computer's USB port can't provide enough power.

Here are three things you can do to deal with such situations:

An external power supply

This provides DC power from an electrical outlet. Anything


rated at 9V to 12V and 250mA or more will work with the
Arduino. Just make sure it outputs DC power, not AC! I got
mine from an old cordless phone.

A breadboard power supply

Very useful if you want to drive devices that need more


power than what the Arduino can provide, such as a motor.
I have one of these which uses the same kind of power
brick as the Arduino and provides both 5V and 3.3V of
selectable output.

A battery pack

If you want to go o-grid, then you need battery power.


You can buy plastic battery cases specifically designed for
the Arduino on ebay, or just find an old broken battery
operated toy and recycle its battery pack. Here's one that
I use. You just need this pack to produce voltage that falls
within the Arduino's operating range.

!
4

Peter Dalmaris

Lecture 3

Arduino Step by Step

Ok, with all the logistics out of the way, time to get into our first project: let's go to Lecture 4
and make an LED blink!

Peter Dalmaris

Lecture 4

Arduino Step by Step

Section 1 Lecture 4
The blinking LED

The basics

A Light Emitting Diode is a special kind of a


diode in that it can emit light. Although all
diodes do emit light, in most cases this light is
not bright enough so we can't see it. LEDs
are specially constructed to allow the light
produced to escape outwards so we can see
it instead of just being absorbed by the
semiconductor.

A diode is a polarised device. In a polarised


device, there is a correct way and an incorrect
way of connecting it to your circuit.
Connecting a polarised device to your circuit
incorrectly will, at least, result in your device not working. In some cases the device can
burn out.

This is what an LED device looks like. Notice that there is a short and a long "leg". The
short leg is called "the cathode", often noted with a "k" and should be connected to
the negative ("-") voltage. The longer leg is called "the anode", often noted with an "a"
and should be connected to the positive ("+") voltage. Other devices of note that are
polarised and use similar or same terminology are transistors and certain types of
capacitors.

Symbolically, i.e. in diagrams depicting electronic circuits, an LED is depicted like this:

!
The basic characteristic of a diode is that it is a semiconducting device that allows the flow
of electricity (electrons) only towards one direction. Think of it as the equivalent of a
plumbing valve that allows water to flow only in one direction. Therefore, diodes are used in
situations where we want to restrict the directionality of electricity. Diodes are used

Peter Dalmaris

Lecture 4

Arduino Step by Step

extensively in applications like the conversion of current from alternating to direct, in radio
transmitters for the modulation of signals, and many others.

The symbol of a diode is almost the same as the one for an LED. The only dierence is the
presence of three little arrows which show that light is emitted from an LED:

!
Let's experiment with an LED

With the background and theory behind us, lets implement our first Arduino circuit. The aim
is to become familiar with plugging components into the breadboard, uploading and
running a sketch.

In our first sketch we will simply make an LED


blink on and o.

Here's a diagram of the circuit you need to


build now.

Use a red jumper cable to connect the Arduino


digital socket 9 to any socket in an empty
column on the breadboard. Let's name this
column "1". Take a 220 Ohm resistor (or close),
and connect one pin in one of the sockets of
column "2" in the breadboard (which is the first
column on the left of column 1), and the other
in a socket in an empty column (make this
column "3").

Connecting a resistor in series with an LED is


important. Because the LED does not oer
much resistance to electricity, connecting an
LED directly to power will cause a high current
to flow through it and quickly burn it. This
situation is described mathematically by Ohm's
Law, which states that R=V/I, where R is the
resistance of a device, V is the voltage at its
two connectors, and I the current that flows through it. If you solve this equation for I, you

Peter Dalmaris

Lecture 4

Arduino Step by Step

get that I=V/R. For an LED, R is almost zero, so no matter what the V is, the I will be a very
large number.

Now here is the tricky part that has to


do with connecting the LED in
accordance with its polarity: Take an
LED, find the long leg and plug it into an
empty socket in column "1". This
socket conveys the positive ("+")
voltage. Plug the other leg into an
empty socket in column 2. An easy
mnemonic rule to help you remember
the polarity of the LED pins is that the
long leg must be connected to a higher
voltage.

Finally, use a black jumper wire to


connect the Arduino's ground (GND)
socket to an empty socket in column 3.

To finish up with the wiring, plug the


Arduino USB cable into an available
USB port in your computer. What you
should have now is something like this:

!
Sketch

The LED isn't doing anything at the moment. To get it to light up and blink, we need to
upload a sketch to the Arduino with the appropriate instructions.

Here's the program we'll use. I'll explain how it works. You can either type it into a new
Arduino IDE editor window, or load it by selecting File > Examples > 01. Basics > Blink from
the Arduino IDE menu. If you do this, remember to change the number "13" to "9" for
variable "led". I also made it available as a text file download from the materials tab.

!
!
!
!
!
!
!
!
!
!
3

Peter Dalmaris

Lecture 4

Arduino Step by Step

// give a name to the pin to which the LED is connected:


int led = 9;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off
delay(1000); // wait for a second

Because this is your first ever Arduino program, I will explain a few things before continuing:

Comments
Any text following "//" or in-between "/*" and "*/" is a comment, and the Arduino will ignore
it. People use these symbols to type comments, like in this example.

Functions
An Arduino program can be broken down in parts by using functions. Functions make it
easy to create little programs within a large program, and to call each of these little
programs by name. In this example, we used 2 functions with names setup() and loop().
These are special functions that the Arduino will call itself. When the Arduino starts, it will
first call the setup() method and execute any commands it finds inside. Then, it will call
loop() again and again until you turn o the power, every time executing whatever
commands it finds inside. You can create your own functions and name them whatever you
like, as long as you don't use a reserved name (like "loop" or "setup"). Function names
can't have white spaces or other "special" characters inside them.

A function may or may not return a value when it finishes its execution. Notice that loop is
declared as void loop()? The void means that loop does not return anything when it
finishes its execution. Same thing happens with setup().

Local and global variables


If you want to store and retrieve values in your sketch, you need to use variables. Variables
can store numbers, text, booleans (true/false values) and other data types. In the very
beginning of this example, we have this statement:

Peter Dalmaris

Lecture 4

Arduino Step by Step

int led = 9;
This creates a global variable named led, and stores the value 9 in it, which is of type int
(integer). A global variable is accessible from anywhere in your sketch. In this example, you
can see that inside the setup() function, there is a reference to "led", and similarly there is a
reference to "led" from inside the loop() function. On the other hand, a local variable is one
that is only accessible from within it's own context. If we had declared the led variable
inside the setup() function, then it would only be accessible by other statements inside the
setup() function and would not be accessible from the loop() function.

Arduino functions
Arduino's magic is in the functions that are build-in to the language. These functions make
it easy to control many aspects of our hardware.

Notice that in the setup() function, there is a call to the function pinMode. This function
takes in two parameters: first the number of the pin we want to configure, and second the
mode that we want to assign to this pin.

In our example, we have pinMode(led, OUTPUT);. Remember that we have a global


variable called led in which we stored the number "9". So we can re-write the pinMode
instruction as pinMode(9, OUTPUT);. This means that we configure pin 9, which is a
digital pin with possible states HIGH (5V) and LOW (GND) to be an output. Being an output,
this pin can be used to send a value to a connected device, in our case the LED.

With the setup() function complete, the Arduino then starts calling the loop() function. The
first thing that happens there is calling the digitalWrite function:

digitalWrite(led, HIGH);
With digitalWrite, we assign a new state to a pin. We can rewrite this statement as
digitalWrite(9, HIGH);, and, as you can probably guess, we are changing the state
of pin 9 to HIGH, which is 5V. As soon as this happens, your LED will light up!

We want to keep this LED lit for a little while, so we use the instruction delay to keep
things as they are. delay accepts one parameter, that is the number of milliseconds to wait
for. So in our case:

delay(1000);
means: "wait for 1000 milliseconds", which is 1 second.

Then we call digitalWrite again, but this time we change the state of pin 9 to LOW,
which is 0 Volts.

digitalWrite(9, LOW);

Peter Dalmaris

Lecture 4

Arduino Step by Step

We wait at this state for another second, then the loop starts all over again.

So there you have it, your first Arduino circuit, and a blinking LED!

In the next Lecture, we will make the same LED, using the exact same circuit, fade on and
o, giving us a much nicer visual eect to look at. Before that, please complete the Lecture
4 quiz.

Peter Dalmaris

Lecture 5

Arduino Step by Step

Section 1 Lecture 5
The fading LED

Tweaking the software

In Lecture 4, we created a simple circuit in


which an LED blinks on and o. The
Arduino sketch that drove the circuit
simply wrote a HIGH or LOW value to the
digital output pin 9, and the LED was turn
on or o accordingly.

What we want to do now, is to make the


LED not blink but fade on and o. We will
be keeping the exact same circuit, and
we'll only change the sketch to make this
happen.

Here's the new sketch (slightly modified


from the sample in the Arduino IDE which
you can load by going to File > Examples
> 01.Basics > Fade) (see next page):

!
!
!
!
!
!
!
!
!

Peter Dalmaris

Lecture 5

Arduino Step by Step

int led = 9; // the pin that the LED is attached to


int brightness = 0; // the bigger this number, the brighter the LED is
int fadeAmount = 5; // the bigger this number, the faster the the LED will fade on or off
// the setup routine runs once when you press reset:
void setup() {
pinMode(led, OUTPUT); // declare pin 9 to be an output:
}

// the loop routine runs over and over again forever:


void loop() {
analogWrite(led, brightness); // set the brightness of pin 9:
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends
// of the fade:
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
}
// wait for 10 milliseconds to see the dimming effect
delay(10);
}

The most important dierence between this sketch and the one in Lecture 4, is that we now
use analogWrite instead of digitalWrite. While digitalWrite can only output a HIGH
or LOW value, analogWrite allows us to output any value from 0 to 255, or, to be more
precise, any of 256 voltage levels from 0V to 5V. The higher the voltage on the pin to which
the LED is connected, the brighter the LED will be lit.

In the loop() function, we first set the brightness of the LED, using the analogWrite
function, by selecting the pin to which the LED is connected, and the 'brightness'.
Brightness is a global variable of type integer that was initialised to be 0 when the program
starts. So, the first time that the program runs in the Arduino, this instruction will look like
this:

analogWrite(9, 0);
In the next instruction, after the comment, we calculate a new value for the brightness. The
new brightness is equal to the old brightness plus the fadeAmount, the value stored in
another global variable that we set to be 5 in the very start of the program. So, the first time
the program runs, this instruction will look like this:

brightness = 0 + 5;
Therefore, brightness will now become 5.

Peter Dalmaris

Lecture 5

Arduino Step by Step

Next, we use a control structure to determine if we have reached a limit for the brightness,
either the lower limit (0) or the upper limit (255). If we have, then we switch the sign of the
fadeAmount variable. The eect is that if the LED was becoming brighter because the
fadeAmount was positive, then once it reaches it brightest setting (when brightness equals
255), then fadeAmount will be changed its negative (-5) and brightness will start moving
towards zero.

In the statement:

if (brightness == 0 || brightness == 255)


...the part within the parentheses is called a "condition". The "==" tests for equality. You
could test for "greater" with ">" or "less" with "<", as well as for a variety of other
conditions.

In the same statement, the "||" is the boolean operator "OR". You can join two conditions
together, and the result will be true if one of them is true. So, in our example, whatever is
between the curly brackets will be executed if either brightness is zero OR brightness is
255.

Section 1 complete

This concludes the lectures in Section 1 of our course! In Section 2 we will look into various
sensors that allow your Arduino project to take measurements from the world around it.

Peter Dalmaris

Lecture 6

Arduino Step by Step

Lecture 6
About sensors

With the basics right behind us, we can now move on to the next set of lectures where you
get to learn about how to connect and use various kinds of sensors with your Arduino.

Sensors are the eyes and ears of machines: they provide environmental data. There are all
sorts of sensors, some more exotic than others. Here's a shortlist from Wikipedia:

Light

Motion

Temperature

Magnetic fields

Gravity

Humidity and moisture

Vibration

Pressure

Electrical fields

Sound

Stretch and stress

Clever gadgets combine multiple sensors in order to capture a more complete snapshot of
their environment. This is similar to our human perception of the environment that is based
on multiple senses, like sight and hearing.

Each sensor that is attached to a machine requires processing power. The more sensors
attached, the greater the processing requirements on the machine. In the Arduino Uno, the
ATMega328 micro-controller is a simple computer running at a clock speed of 16MhZ
(mega-hertz). This means that this Arduino can process roughly 16 million instructions every
second. This processing resource has to be shared between all the things that your Arduino
is supposed to do, like reading values from its sensors, doing calculations, updating a
screen or other outputs, communicating with other devices, and interacting with the user.

The Arduino is fast, but it has a limit, and your design must take that into consideration.

Peter Dalmaris

Lecture 6

Arduino Step by Step

In the lectures in this section, we will play with the following sensors:

A photo-resistor for measuring light

Combined temperature and humidity

Infrared line sensor

Barometric sensor for measuring air pressure

Ultrasonic sensor for measuring distance to other objects

Tilting, so you know if your gadget has fallen over

Orientation

Simple sensors, like the photo-resistor for measuring light, work by measuring the voltage
they provide to one of the analog sockets in the Arduino. You can do this by using the
analogRead function (the opposite of the analogWrite function that we saw in the last
lecture, Lecture 5). Other sensors are a bit more involved, and they require special software
libraries to work with the hardware. More often than not, however, these libraries are very
easy to learn and they provide useful extra features at no additional cost.

Let's get right into it, and have a look at the photo-resistor.

Peter Dalmaris

Lecture 7

Arduino Step by Step

Lecture 7
Measuring light

Measuring light is really easy. There are many sensors capable of detecting or measuring
light, but the photo-resistor is one of the easiest to use. A photo-resistor is simply a resistor
in which the resistance changes in accordance to its exposure to light.

You can find these devices on eBay for less that $3 for a
pack of ten. Think about what you can do with a device that
can detect light. Of course, your gadget will be able to know
if its day or night, or if the lights are on. So you could build a
gadget that that turns on a small light at the entrance of you
home when it darkens, so you don't have to walk in the dark.
You could also use a photo-sensitive device to allow two
gadgets to communicate with light; this is the principle
behind the typical television remote control where the
remote control and the television communicate using
infrared light. You could also build a simple robot that follows
a bright or dark line on the floor. Can you think of anything else you could do with a light
sensor?

Let's create a light-sensing circuit

We'll now create a circuit that contains a photo-resistor, and we'll use an Arduino sketch to
take light intensity readings from it.

Look at the circuit in the image below, and try to copy it. Here are a few things to be extra
careful about:

Counting from the right, the photo-resistor is connected to a socket in column 1. Its
second leg is connected to a socket in column 4.

We use a 220 Ohm resistor (or close, the exact rating is not important in this exercise) in
series with the photo-resistor in order to create a "voltage divider". More about this in a
minute.

Connect the resistor's second leg to a socket in column 8.

Connect the black jumper wire to the GND socket on the Arduino, and the red to 5V. Even
if you switch these connections, this circuit would still work because we are not using any
polarised components.

Lastly, connect a green jumper wire from a socket in column 4 to A0, which is the Arduino
analog port 0.

Peter Dalmaris

Lecture 7

Arduino Step by Step

Notice how you connected the green cable in column 4, where the resistor and the photoresistor meet? This type of wiring is called a "voltage divider" or "impedance divider", and
its purpose is to create an output voltage that is a fraction
of the input voltage to the divider. Look at the diagram
(right):

Vin is represented by the red jumper wire in our Arduino


diagram, the earth symbol is represented by the black
jumper wire. The Vout is represented by the green jumper
wire. Vout depends on the impedance (resistance) of Z1
and Z2, which in the case of our Arduino circuit are the
resistor and the photo-resistor. Since the resistor's
resistance is fixed, and the resistance of the photoresistor varies depending on the ambient light situation,
Vout will also vary. By taking a measurement of Vout, we
gain information about the light intensity in our lab.

The higher the measurement in socket A0, the more intense the light is. The closer to zero it
gets, the darker our lab is.

That's enough for now with the hardware. Let's look at the software.

Peter Dalmaris

Lecture 7

Arduino Step by Step

The sketch

Here's our program for this exercise:

// the setup routine runs once when you press reset:


void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
delay(10);
}

!
Much of this sketch should be familiar to you now. There's
setup(), loop(), and delay(), which we have seen before.

There's a couple of new things here. First, look in the


setup() function. There is this statement:

Serial.begin(9600);
This creates a serial connection which the Arduino can
use to send text output to our terminal. This way the
Arduino can "talk" to us. This terminal can be opened by
clicking on Tools > Serial Monitor, and it looks like this:

!
3

Peter Dalmaris

Lecture 7

Arduino Step by Step

!
We will be printing the light intensity value to the serial monitor in a moment.

Next, have a look in the loop() function. In the first actual statement after the comment, we
use the analogRead(A0) function to get a reading from socket A0 ("Analog 0") and store it to
the local integer variable sensorValue. Easy, right?

We now have a value captured from the photo-resistor's voltage divider circuit, let's print it
to the monitor so we can actually see it. Also easy, just do this:

Serial.println(sensorValue);
This statement, says: "Go to the serial port, print line with content 'sensorValue'". The "ln"
part of the println function means that this particular function will create a new line after
it prints out the text that is contained within the parentheses. You could use just
Serial.print(sensorValue), but then the output would look like this:

9469459469459459469459469469469459469
... not very useful, very hard to read.

When you send this program to the Arduino, wait for it to upload, and then open up the
monitor. You will see something like this:

946

946

946

946

946

946

946

945

946

946

!
4

Peter Dalmaris

Lecture 7

Arduino Step by Step

The actual values will vary because of the dierences in the components you used in your
circuit compared to mine, and of course the lighting conditions in our two labs are probably
dierent. But as long as you see similar values (above 0 and below 1024), then it worked!

Questions

That was easy, right? Please try out these questions before moving on to the next Lecture,
where you will learn about measuring temperature and humidity.

Peter Dalmaris

Lecture 8

Arduino Step by Step

Lecture 8
Measuring temperature and humidity

In this lecture you will learn how to measure temperature and humidity. To do this, we will
use a sensor from the DHT family of temperature and humidity sensors.

The most common DHT sensors are the DHT11 and


DHT22. The DHT22 is double the price of the DHT11,
while still only around $10 on eBay, but has better
accuracy. Electrically, they are exactly the same, so you
could swap them in and out of your circuits at any time.
You can find DHT11's on eBay for less than $2.

In our example in a minute, I will be using the DHT22, like


the one in this picture (right).

There are 4 pins in the sensor's package, but only 3 are


actually used. Looking at the device from the front, going from left to right, pin 1 is for 5V
power, pin 2 is for data, pin 3 is not used, and pin 4 is GND.

Inside, this sensor is fairly sophisticated and contains hardware that does a lot of the work
that otherwise we would have to do in our Arduino sketch. As a result, as you'll see in a
minute, all we have to do is take a reading, there is no need for any conversion calculations
or any other hardware at all.

The DHT11 and DHT22 sensors, within their plastic case, contain:

A capacitive humidity sensor

A thermistor

A chip that does analog to digital conversion

Capacitive humidity sensors

Capacitive humidity sensors are robust solutions for measuring humidity if our application is
ok with the relatively low accuracy of this device. Both DHT11 and DHT22 have a humidity
accuracy of around 5%, and are calibrated in the factory. In a capacitive humidity sensor, a
polymer or metal-oxide material is exposed to the environment and its dielectric properties
change as the humidity changes.

A thermistor is a resistor in which the resistance changes as the temperature changes. In


the DHT11 and DHT22, the readings in temperature are fairly accurate, at around 0.5%
accuracy.

Peter Dalmaris

Lecture 8

Arduino Step by Step

Assembly

Time to put the demo circuit together. We will need:

The Arduino

Three jumper wires

A DHT11 or DHT22

A 10kOhm resistor

Here is the circuit we are going to build:

The resistor is used to as a "pull-up" and it


protects the Arduino (or whatever logic
device the resistor is connected to) in case
we either remove the sensor, or the sensor
malfunctions. The Arduino's input sockets
have build-in pull-up resistors, but they are
much smaller and it is a good idea to
provide our own.

Peter Dalmaris

Lecture 8

Arduino Step by Step

Sketch

With the demo circuit assembled, lets now turn to the Arduino sketch that will drive it.

Here is the sketch, with comments:

// Example testing sketch for various DHT humidity/temperature sensors


// Written by ladyada, slightly modified, public domain
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

//
//
//
//

includes and external library


what pin we're connected to
* The device type DHT22, DHT11, DHT21*
Initialize the device

void setup() {
Serial.begin(9600);
Serial.println("DHT test");
dht.begin();

// Start the serial port, set speed


//*Print a message to monitor*
// Start the device

}
void loop() {
float h = dht.readHumidity(); //*Set local float variable for humidity*
float t = dht.readTemperature();//Set local float variable for temperature
// *check if returns are valid, if they are *
// NaN (not a number) then something went wrong!
if (isnan(t) || isnan(h)) {
Serial.println("Failed to read from DHT");
} else {
Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperature: ");
Serial.print(t);
Serial.println(" *C);

//*problem*

//*Print humidity reading*


//*This outputs a tab*
//*Print temperature reading*

}
delay(500); //*Introduce a delay because these sensors are* //*slow*
}
Notice that there is an inclusion of the DHT.h library in the first line.

Peter Dalmaris

Lecture 8

Arduino Step by Step

This library makes it easy to communicate with the DHT device. We will need to download it
and make it available to our sketch.

Get it from Adafruit's Github account at https://github.com/adafruit/DHT-sensor-library.


Setup instructions are included in that page. Don't forget to restart the Arduino IDE once
you are finished.

Now we'll run that sketch and look at the monitor output:

And that is how you connect and use the DHT22 or DHT11 sensor to the Arduino!

Questions
Please attempt the lecture questions before moving on to
lecture 9.

Peter Dalmaris

Lecture 9

Arduino Step by Step

Lecture 9
Barometric pressure

Measuring the atmospheric pressure has several applications. Obviously, if you are a
meteorologist, knowing the pressure at a geographical location helps forecasting the
weather. But there's more.

Atmospheric pressure is defined as the weight of a column of air above an object. As the
height of a column of air above an object changes depending on its altitude, so does the
weight of that column. Atmospheric pressure at the surface of the sea is higher than that on
the top of a tall mountain because the column of air above it is higher. Therefore, measuring
the atmospheric pressure is also a simple way of figuring out your altitude, or the altitude of
one of your flying gadgets.

The standard unit for measuring atmospheric pressure is "Pa", or "Pascals". At sea level,
the standard pressure is defined to be 101.325 kPa, or 101,325 Pa.

We will be measuring atmospheric pressure by using the BMP085 sensor. This sensor costs
around $8 on eBay. It can measure pressure from 300hPa to 1100hPa, which converts to
around 500 meters below sea level to 9,000 meters above sea level. It's accuracy is also
excellent, around 0.03hPa. "hPa" is pronounced "hectoPascal".

Another nice thing about this sensor is that it also measures the temperature.

The BMP085 talks to other devices via the I2C interface, a digital serial communications
interface that only needs two wires for communication, and two for power. One
communication wire is called SDA, and it transmits
data, while the second, SCL, is for the clock signal.
A clock signal is needed because I2C is a
synchronous interface.

The sensor uses 3.3V (not 5V!), which the Arduino


conveniently provides. Here's what this sensor looks
like (right).

!
The BPM085 measures pressure by taking
advantage of the piezo-resistive property that silicon and germanium have. This property
involves the change in resistance in those materials depending on the amount of
mechanical load that is put on them.

!
1

Peter Dalmaris

Lecture 9

Arduino Step by Step

Assembly

Let's puts together this circuit and try out the sensor.

We will need:

The Arduino

Four jumper wires

A BMP085 sensor device

Here's what we are going to build (right).

This is very simple wiring. In Lecture 8


we connected a humidity and
temperature sensor, and we included a
pull-up resistor. We don't need this
resistor now because it is included
within the sensor's package. That's one
less thing for us to do.

If you are unsure of the connections,


double check the markings of each pin
on the sensor.

Peter Dalmaris

Lecture 9

Arduino Step by Step

Sketch

Done with the assembly, lets work on the sketch now.

Just like in Lecture 10, to use the barometric sensor we include an external library in our
sketch. This comes from Adafruit, and you can find it on Github. Follow the instructions in
the README.txt file for setting it up, and don't forget to restart your Arduino IDE!

Here's the sketch, it comes straight of the examples that are included with the Arduino IDE.
I have added some comments to help you understand what is going on:

#include <Wire.h> //*Include the Wire library which allows *


//*To use the I2C interface*

#include <Adafruit_BMP085.h>

//*Include the Adafruit_BMP085


//*library to easily take*
//*readings from the sensor*

Adafruit_BMP085 bmp;

//*Declare the bpm variable,


//*an easy to remember reference for the
//*device

void setup() {
Serial.begin(9600); //*Setup serial communication and speed*
if (!bmp.begin()) { //*Try to start the device*
//*If it is not starting, print message*
Serial.println("Could not find a valid BMP085 sensor, check
wiring!);
while (1) {}

//* Go in an endless loop. This prevents the*


//*Arduino from calling the loop function*

}
void loop() {
Serial.print("Temperature = ");
Serial.print(bmp.readTemperature()); //*Read and *
//*print temperature*
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bmp.readPressure()); //*Read and print*
//*pressure*
Serial.println(" Pa");
// Calculate altitude assuming 'standard' barometric
// pressure of 1013.25 millibar = 101325 Pascal
Serial.print("Altitude = ");
Serial.print(bmp.readAltitude()); //*Read and print*
//*altitude*
Serial.println(" meters");
3

Peter Dalmaris

//
//
//
//

Lecture 9

Arduino Step by Step

you can get a more precise measurement of altitude


if you know the current sea level pressure which will
vary with weather and such. If it is 1015 millibars
that is equal to 101500 Pascals.

Serial.print("Real altitude = ");


Serial.print(bmp.readAltitude(101500)); //*Read and print*
//*calibrated altitude*
Serial.println(" meters");
Serial.println();
delay(500);
}
Now we'll run this sketch and look at the monitor output:

And that is how you connect and use the BMP085 barometric sensor with the Arduino!

Questions

Please attempt the lecture questions before moving on to lecture 10.

Peter Dalmaris

Lecture 10

Arduino Step by Step

Lecture 10
Motion

!
Knowing if something is moving is useful in many applications. The classic example is
security, where an alarm system can detect an intruder moving inside a room, so that it can
notify the police. Another common use is in home and oce automation, where you could
get the lights to turn on and o automatically depending on whether someone is still in the
room or turning on the flood light in your driveway as
your car approaches.

There are several technologies used in motion sensors,


each with their own capabilities and price points.

Passive infrared (PIR) sensors are very common and


typically found in home electronics. They detect the heat
that is emitted by the body of a person in a room as it
contrasts against the background heat. A PIR sensor
does not emit any energy, it just sits there and waits for a
heat source to enter its field of vision. They look like this
(an example of a home security system motion sensor right).

!
An ultrasonic motion sensor uses ultrasounds
to detect moving objects. Just like bats, an
ultrasonic sensor emits ultrasounds at
frequencies from 30khz to 50kHz and then
picks up their echo. These sensors can often
measure the time a signal takes to return, and
from that it can calculate the distance to the
object. Therefore, ultrasonic sensors can
calculate both distance from an object as well
as whether the object is moving. We will be
looking at ultrasonic sensors in the following
Lecture.

!
A microwave motion sensor works on the same principle as the ultrasonic sensor, except
that instead of ultrasounds it emits microwaves. They are still relatively cheap, and because
microwaves are much higher in terms of frequency than ultrasounds, motion can be
1

Peter Dalmaris

Lecture 10

Arduino Step by Step

detected with a lot more detail. Many microwave


motion sensors can determine not only the
motion itself, but also distance and speed using
the Doppler eect.

Here is what a microwave sensor module looks


like (of course the module is covered by a plastic
cover when installed - right).

!
!
In this lecture, we will connect a passive infrared sensor to our Arduino, calibrate it, and
turn an LED on every time motion is detected.

Assembly

Let's puts together this circuit and test out the motion sensor.

We will need:

The Arduino

Four jumper wires

A PIR sensor, like the HC-SR501

One resistor, 1k

One LED

Here's what we are going to build (right).

While you are connecting the motion


sensor, it's a good idea to remove the
sensor cover so you can see the pin
markings, ensuring that power is
connected the right way.

This circuit will detect motion through


the sensor, and send a signal to the
Arduino via digital pin 2. The Arduino will
receive the signal and in turn activate
the LED via digital PIN 13. Notice that
the Arduino UNO board already has an
small LED connected to digital port 13, so you could choose to not connect yours.

Peter Dalmaris

Lecture 10

Arduino Step by Step

!
Sketch

Done with the assembly, let work on the sketch now.

/*
* PIR sensor tester
*/
int
int
int
int

ledPin = 13;
inputPin = 2;
pirState = LOW;
val = 0;

// choose the pin for the LED


// choose the input pin (for PIR sensor)
// we start, assuming no motion detected
// variable for reading the pin status

void setup() {
pinMode(ledPin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input
Serial.begin(9600);
}
void loop(){
val = digitalRead(inputPin); // read input value
if (val == HIGH) { // check if the input is HIGH
digitalWrite(ledPin, HIGH); // turn LED ON
if (pirState == LOW) { // we have just turned on
Serial.println("Motion detected!);
// We only want to print
// on the output change, not state
pirState = HIGH;
}
} else {
digitalWrite(ledPin, LOW); // turn LED OFF
if (pirState == HIGH){
// we have just turned off
Serial.println("Motion ended!");
// We only want to print on
// the output change, not state
pirState = LOW;
}
}

Peter Dalmaris

Lecture 10

Arduino Step by Step

By now, this sketch should be easy to read and understand. We start by setting constants
for the pins and values. The LED is connected to digital pin 13, and the sensor's output to
digital pin 2. We also assume that when the Arduino starts, there is no motion, so variable
pirState is set to LOW, and val, the variable to which the output state of the PIR sensor is
stored, is 0 (LOW).

In the setup() function, we set pin 13 to be output, and pin 2 to be input. We also initialise
the serial port so that we can see text output in the monitor window.

In the loop() function, we constantly read the value of the PIR sensor by using the
digitalRead(inputPin) function. This function reads voltage in the range of 0V to 3.3V (at
least for the sensor I am using), and the Arduino translates that to LOW and HIGH
respectively.

If HIGH is detected, the Arduino will set pin 13 to HIGH and this will activate the LED. If the
previous state of the sensor was LOW, then the Arduino detects this as new motion, so it
will print a message to the monitor, and set pirState to HIGH. This will prevent the Arduino
from continuously printing out that new motion was detected while the actual motion is still
continuing.

Upload it to see it working, don't forget to open up the monitor window (Tools > Serial
Monitor). You should see something like this:

!
If you are not sure what the pirState variable is actually doing, do this little experiment:

Peter Dalmaris

Lecture 10

Arduino Step by Step

Modify the sketch by replacing the lines:

if (pirState == LOW) {
Serial.println("Motion detected!");
pirState = HIGH;
}
with only:

Serial.println("Motion detected!");

... and the lines:

if (pirState == HIGH){
Serial.println("Motion ended!");
pirState = LOW;
}

... with only:

Serial.println("Motion ended!");

Upload the edited sketch. Open the monitor and activate the sensor by waving your hand
above it. What can you see in the monitor?

You can calibrate the sensitivity and amount of time that the sensor stays activated by
turning the two small orange knobs. Experiment with them to see the eect they have on
the sensor's output.

That's it with the PIR sensor for now. Please attempt the quiz questions before continuing
with the next lecture, were you'll learn about the ultrasonic distance sensor.

Peter Dalmaris

Lecture 11

Arduino Step by Step

Lecture 11
Distance

There are lots of applications where we not only need to know that an object, or a person,
in nearby, but also how far they are. Imagine a robot moving around in a room. The robot
can use a distance (or proximity) sensor to detect that it is approaching a wall or another
object. Or, you could use a proximity sensor to automatically open a door if a person is
within a meter of the sensor. You find
such sensors in cars (to help with
parking and to avoid small accidents),
and in smart phones where the
smartphone can detect, for example,
that the phone is held against the
user's head, useful so that the screen
is turned o to avoid accidental
touchscreen input.

There are many types of technologies


that can be used to make a proximity
sensor. In this lecture we will focus on
the ultrasonic sensor, which is
essentially a "land sonar": it emits a
high frequency sound, far beyond
what the human ear can hear, and
waits for the echo. Once it captures
the echo, it counts the time that
elapsed between the emission of the
ultrasound signal and the capture of
its echo, and based on that it
calculates the approximate distance
of the object that produced the echo.

Ultrasonic sensors are solid-state devices, very reliable and cheap. Especially in indoor
environments, and for small spaces (or measuring small distances), these sensors represent
a good choice. Anything that is solid enough to allow sounds to bounce will work with
these sensors. If you want to measure or detect things like smoke and clouds, you will need
to use something else, perhaps a microwave doppler radar.

For the Arduino, a commonly used proximity sensor is the HC-SR04. You can find them on
Ebay for less than $2 each.

They are very easy to use, let's have a look.

!
1

Peter Dalmaris

Lecture 11

Arduino Step by Step

Assembly

Let's puts together this circuit and test


out the motion sensor.

We will need:

The Arduino

Six jumper wires



An ultrasonic sensor, like
the HC-SR04.

Here's what we are going to build:

[show image of "S2 L12 - distance.png"]

The sensor will constantly take distance


measurements of whatever happens to
be in front of it: your hand, books etc. The
Arduino will receive these readings and
print them to the monitor. Very simple.

!
Sketch

Done with the assembly, let work on the sketch now.

#define trigPin 13
#define echoPin 12
void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
long duration, distance;
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration/2) / 29.1;
2

Peter Dalmaris

Lecture 11

Arduino Step by Step

if (distance >= 200 || distance <= 0)


{
Serial.println("Out of range);
}
else {
Serial.print(distance);
Serial.println(" cm");
}

delay(500);
}

!
There's quite a lot happening in this small amount of code.

We define the sensor's trigger and echo pins to be 13 and 12 respectively. In the setup
function, we initialise the monitor, and set pin 13 to be the output and pin 12 to be the
input.

Through pin 13, the Arduino will ask the sensor to trigger a ping, similar to the "boing" noise
that submarines emit when they use their sonar. This ping, assuming it bounces of an
object in range, will come back and will be picked up by the sensor's receiver. The Arduino
will know when that happens because it is monitoring pin 12, which is connected to the
sensor's echo pin.

In the loop() function, we first setup two variables of type long. Long numbers are 4 bytes in
size, a total of 32 bits, and can hold very large numbers: -2,147,483,648 to 2,147,483,647.
The variable duration will hold the total number of microseconds that it took for the ping to
reach the object and return to the sensor. The variable distance will contain the distance to
that object in centimetres.

0.5

The Arduino is triggering a ping by writing to the trigger pin three pulses: first, a digital LOW
for 2 microseconds, then a digital HIGH for 10 microseconds, and finally a digital LOW
which stays low until the next iteration of the loop.

Ping 1

Ping 2

Ping 2

!
It then uses the function pulseIn to get the number of microseconds in takes of the ping to
come back. PulseIn accepts two parameters: a pin number (in our case it is 12, stored in
variable echoPin), and the pulse level we want to detect, in our case it is HIGH because we
3

Peter Dalmaris

Lecture 11

Arduino Step by Step

want to detect the 10 microsecond ping we just emitted. As soon as the Arduino calls the
pulseIn function, it starts timing. It returns the number of microseconds from the time the
function was called until it detects the ping echo.

The distance is calculated by the Arduino. It divides by two the duration that the pulseIn
function returned, since the ping travels a total of twice the distance to the object (going
there and its echo coming back). It then divides again by the "magic number" 29.1. This
number derives from this calculation:

The speed of sound at 0 degrees celsius is measured to be 331.5 meters per second. At
dierent temperatures, the speed of sound is calculated by adjusting 331.5m/s for the
temperature by multiplying by 0.6:

SpeedOfSound(Temperature) = 331.5 + 0.6 * Temperature


At 20 degrees, this works out to be 343.5 m/s.

We need to convert the seconds to microseconds and the length from meters to
centimetres:

SpeedOfSound = 343.5 * 100 / 1,000,000 = 0.03435 cm/


microseconds
This means that sound, at 20 degrees, can travel a distance of 0.03435 centimetres in one
microsecond. If a signal and its echo take X microseconds to do the round trip, then the
total distance covered is:

Total_distance = X * 0.03435 = X / 29.1


We adjust this so that we only include the duration of the one-way trip to the target (instead
of the return trip), and the formula becomes:

distance = ( X / 2) * 0.03435 = ( X / 2 ) / 29.1


Wikipedia has a very good article on how to calculate the speed of sound, for the curious.

Limitations

If the distance to a target is over 200 centimetres, the Arduino reports that the target is out
of range, since at that distance measurements are not reliable. The same happens if the
distance is negative (question to consider, why do we need to test for negative
distance???). Any other distance condition is valid, so the monitor will print out the distance
in centimetres.

Peter Dalmaris

Lecture 12

Arduino Step by Step

Lecture 12
Measuring acceleration

Acceleration is defined as the rate by which the velocity of an object changes. The velocity
of an object changes when a force is applied to it. Acceleration is quantified by a direction
and a magnitude. Direction is the way to which a force is directing the object, and
magnitude relates to the strength of the applied force. Acceleration is described by
Newton's Second Law.

Having the ability to measure acceleration is very useful. For this purpose, we use an
accelerometer. An accelerometer measures the force that is applied to a small test mass.
This test mass is placed inside the device and is held in place by one or more springs (or
something equivalent). As gravity, or other forces, are applied on the test mass, they make
it move towards a particular direction. The device measures the distance this mass travels
from its resting position. The longer the distance, the stronger the force.

Imagine the accelerometer (or your self) in free fall, the test mass, as it is falling, is "feeling"
no force being applied upon it. In a free-fall situation, the accelerometer would report no
acceleration at all.

We use accelerometers in cars to detect collisions (and deploy airbags), or to gather


performance statistics. Accelerometers are embedded in smart phones to provide
orientation information, and for making games that are played by moving a controller
device. You could use one in a toy car so that the car's wheels stop spinning if it has turned
over, or to make toys that react to the movement of a controller in 3-D space.
Accelerometers are also part of Inertial Navigation
Systems (INS) that help vehicles (ships, planes,
cars, submarines etc.) maintain knowledge of their
location when other positioning systems, like GPS,
are not available.

In our experiment, we will use a common 3-axis


accelerometer, the ADXL335. It is very cheap at
around $7 on eBay, and very easy to connect to the
Arduino through any of the analog pins. It reports
acceleration in 3 dimensions, X, Y and Z. It is very
robust as it can detect forces of up to 10,000 Gs (1
G is equivalent to the Earth's gravity at the surface).

!
!
1

Peter Dalmaris

Lecture 12

Arduino Step by Step

Assembly

Let's puts together this circuit and test out the


motion sensor.

We will need:

The Arduino

Five jumper wires



An ADXL335 3-axis
accelerometer.

The sensor takes three acceleration


measurements, X, Y, and Z. The Arduino reads
the analog outputs 0, 1, and 2, acquires the
measurements, and prints them to the monitor.

Also, be very mindful of the power limits of this


device. It needs 3.3V input, not 5V! If you
provide 5V you may actually damage it!

Sketch

Done with the assembly, let work on the sketch now.

!
int x, y, z;
void setup()
{
Serial.begin(9600); // sets the serial port to 9600
}
void loop()
{
x = analogRead(0); // read analog input pin 0
y = analogRead(1); // read analog input pin 1
z = analogRead(2); // read analog input pin 1
Serial.print("accelerations are x, y, z: ");
Serial.print(x, DEC); // print acceleration in the X axis
Serial.print(" "); // prints a space between the numbers
Serial.print(y, DEC); // print acceleration in the Y axis
Serial.print(" "); // prints a space between the numbers
Serial.println(z, DEC); // print acceleration in the Z axis
delay(100); // wait 100ms for next reading }
2

Peter Dalmaris

Lecture 12

Arduino Step by Step

!
We have not seen the analogRead() function before, but I am sure you can guess what it
does: it reads the voltage present at one of the analog pins. The accelerometer outputs
voltage to its three outputs relevant to the forces applied to it.

For example, at rest, the reading on the Z axis is around 410. If I push the device upwards, I
apply force along the Z axis which makes the test weight inside the accelerometer "feel"
heavier, and the voltage on the Z pin increases, causing the reading to increase (i.e. to
~470, in my experiment). If I push the device downwards, the opposite happens.

By taking and evaluating measurements in all three axis, you could make it possible for your
device to know the precise direction of its movement and the force applied to it.

Peter Dalmaris

Lecture 13

Arduino Step by Step

Lecture 13
Infrared line sensor

An infrared line sensor is a simple device made up of an infrared emitting LED and an
infrared sensitive photo-resistor.

You could use one of these sensors to build a robot that follows a dark line on the floor, or
your own heart rate monitor.

The principle of operation is very simple: The transmitter produces infrared light which
bounces of a surface and comes back to be captured by the photo-resistor. The more
infrared light is reflected back into the photo-resistor, the
higher the output of the sensor gets.

In our experiment we will use a QRE1113 line sensor from


Sparkfun. You can get something like this on eBay for
less than $2.

Assembly

Let's puts together this circuit and test out the motion
sensor.

We will need:

The Arduino

Three jumper wires

An QRE1113 line sensor or equivalent


(like this ywRobot device).

Here's what we are going to build (right).

For power, you can plug this sensor into


either the 3V or 5V sockets on the Arduino.

!
!

Peter Dalmaris

Lecture 13

Arduino Step by Step

Sketch

This one is very simple, just read the analog output at pin A0 and print it to the monitor:

// Line Sensor Breakout - Analog


int out;
void setup()
{
Serial.begin(9600); // sets the serial port to 9600
}
void loop()
{
out = analogRead(0); // read analog input pin 0
Serial.println(out, DEC); // print acceleration in X axis
delay(100); // wait 100ms for next reading
}

Peter Dalmaris

Lecture 14

Arduino Step by Step

Lecture 14
Tilt and impact sensor

In many cases, knowing the exact force and direction applied to our gadgets is an overkill;
just knowing that a bottle has been tipped over is enough to know that the lid should close
automatically. For simple cases like that, a 3-axis accelerometer is an overkill. We could use
a simple sensor that can detect the shock of an impact or for being upside down.

The tilt and impact sensor is a simple switch which closes a


circuit when positioned in a particular way. They are very cheap,
around $5 on eBay for a pack of 10. They come in a variety of
shapes, but usually they are made of a tiny metallic cylinder with a
thin copper wire coming out of one end. The cylinder contains
wires or a metal ball. When the device is hit or when its orientation
changes, the wires or the ball come in contact with the wall of the
cylinder and closes a circuit between the cylinder and the external
wire. They can be very sensitive, so care must be given to
compensating for this sensitivity, otherwise we would be getting readings
that look chaotic. We are going to ignore this sensitivity for now.

Here is what a tilt sensor looks like from the outside (right - top)

... and on the inside (right - bottom).

!
!

Peter Dalmaris

Lecture 14

Arduino Step by Step

Assembly

To put this circuit together, we'll just


use the Arduino, no breadboard is
required.

We need to do a bit of soldering in


order to connect the sensor to wires
which we can connect to the
Arduino. If you have never done
soldering before, follow this tutorial
for some instructions. Be careful not
to get burned!

Here's what we are going to build


(right)

!
!
Sketch

This is another very simple sketch. We'll just use the analog port to determine if the switch
inside the sensor is closed or open. You could just as easily have used a digital pin since
there are only two states to detect, open or close, which nicely translate to HIGH or LOW.

!
int out;
void setup()
{
Serial.begin(9600); // sets the serial port to 9600
}
void loop()
{
out = analogRead(0); // read analog input pin 0
Serial.println(out, DEC);
delay(100); // wait 100ms for next reading
}

!
2

Peter Dalmaris

Lecture 14

Arduino Step by Step

Try out by connecting the sensor to the Arduino and moving the sensor in dierent
directions. This is easier if you use some electrical tape to keep the sensor wires tidy. You
could even stick the sensor onto the Arduino, and move the whole assembly instead of only
the sensor. This will help in keeping the connections firm.

Peter Dalmaris

Lecture 15

Arduino Step by Step

Lecture 15:
Button

A button is a simple on-o switch. There are many kinds of buttons, distinguished by the
mechanism used to close or open a circuit, but essentially all buttons belong to one of two
families: those that keep the connection in either an open or a closed state, and those that
return to their original (default) state.

Here are some examples of switches.

Clock-wise from the top:

A toggle switch. It stays open or closed after pushing it.

An on/o switch that also remains open or


closed.

A momentary button that remains closed


while pressure is applied to it, then returns to
the open position.

A keyboard key or a door bell button are both momentary buttons. Momentary buttons are
also known as "biased" because they have a tendency to return to their original position. A
light switch, on the other hand, stays at the position it was pushed to, so it is often called
"un-biased".

Peter Dalmaris

Lecture 15

Arduino Step by Step

Experiment

Let's create a simple circuit to demonstrate a


button.

We don't really need the Arduino for this. A


battery, an LED, a resistor and the button itself
would suce.

But, using the Arduino is simple enough, and


it's already got an LED in pin 13 we can use
anyway, and no need to worry about a battery
pack.

Plus, we can use the monitor to actually see a


message when the button is pressed.

So, we'll setup this circuit (at right).

!
Once assembled, the project will look like this
(below):

Peter Dalmaris

Lecture 15

Arduino Step by Step

Sketch

The sketch is simply taking a reading from digital pin 2, where one of the pins of the button
is connected, and writing a value to digital pin 13, where the LED is connected.

I could have written this script to be even smaller, but I will leave that for you to do as an
exercise.

/*
Pushbutton sketch a switch connected to pin 2 lights the LED
on pin 13
*/
const int ledPin = 13;
const int inputPin = 2;
void setup() {
pinMode(ledPin, OUTPUT); //
//
//
//
//
pinMode(inputPin, INPUT);
}

choose the pin for the LED


choose the input pin (for a
pushbutton)
declare LED as output
declare pushbutton as input

void loop(){
int val = digitalRead(inputPin); // read input value
if (val == HIGH)
{
digitalWrite(ledPin,HIGH);
} else
{
digitalWrite(ledPin,LOW);
}
}
And that's how you can use a momentary button with the Arduino!

Peter Dalmaris

Lecture 16

Arduino Step by Step

Lecture 16
Potentiometer

In this lecture I'll show you how to use a potentiometer. A


potentiometer is a device that allows you to change the value of a
resistance by turning a knob.

Let's put this circuit together, and then we'll discuss how it works. In
particular, we'll see what is happening
inside the potentiometer.

Assembly

Let's assemble the circuit. You will need:

The Arduino

A potentiometer

An LED

A resistor to protect the LED (I used a


1k resistor)

As you turn the knob of the potentiometer,


the resistance connected to its output pin
changes. This in turn changes the voltage
on that pin. This output voltage is read by
the Arduino at analog pin 0 (A0).

The Arduino will then use digital pin 11 to


drive the LED. Although pin 11 is digital, we
are using its Pulse Width Modulation (PWD)
feature, like we did back in Lecture 5. We
just glossed over this feature back then: we
used the analogWrite instruction which
makes use of this feature. Later in this
lecture I will explain how PWD works.

Heres a photo of the assembled circuit:

!
!
1

Peter Dalmaris

Lecture 16

Arduino Step by Step

How it works

Potentiometer

Remember back in Lecture 7 where you learned


about the voltage or impedance divider? Back then,
the divider was fixed as we used two fixed resistors.

In a potentiometer, we still have these two resistors


inside the package, but at least one of them is
variable, that is, the resistor changes as we turn the
knob.

In the diagram on the right, the pin in the middle is


connected to a dial that is made of conductive
material, like copper. They gray-coloured circle
represents a resistor, with its two ends connected to V+ and Ground. As the dial comes in
contact with dierent parts of the resistor, it samples a voltage between V+ and ground,
and we can read this voltage from the middle pin.

So there you have it, a potentiometer is nothing more than a variable voltage divider.

Pulse Width Modulation

Arduino's digital pins can output HIGH and LOW, as we have already seen. Some of these
digital pins, however, are special: although they can still only output HIGH and LOW, their
output can be modulated is a way that this output can behave as if it was analog.

Have a look at this diagram, taken


from the Arduino web site. A
"normal" digital pin outputs 0V or
5V, like in the top and bottom
waveform examples. But, in a pin
that supports PWM, we can output
5V for only part of the period. In the
second waveform, for example, we
output 5V for 25% of the period,
and 0V for the rest. In the third
example, its 50% and 50%
respectively.

On the LED, this kind of modulation


on the output signal has an eect
similar to using an analog pin and
outputting voltage in the range of
0V to 5V. In eect, we simulate
analog output using a digital pin!

Peter Dalmaris

Lecture 16

Arduino Step by Step

Sketch

Here's the sketch that drives this circuit:

int potentiometerPin = 0;
int ledPin = 11;
int potentiometerVal = 0;
void setup()
{
Serial.begin(9600); // setup serial
}
void loop()
{
potentiometerVal = analogRead(potentiometerPin);
//I use the map function because PWM pins can only accept
//values from 0 to 255. Analog pins can output values from
//0 to 1023. With the map function, the range 0-1023 is
//converted to appropriate values from 0 to 255.
int mappedVal = map(potentiometerVal,0,1023,0,255);
Serial.print(potentiometerVal);
Serial.print(" - ");
Serial.println(mappedVal);
analogWrite(ledPin,mappedVal);
delay(10);
}
There is nothing new here. We have seen the "map" function in an earlier lecture, so you
know that this function is used when we want to make a range of values fit within another
range of values. In this case, we read values in the range of 0 to 1023 from analog pin 0,
and we want to make this fit in the range 0 to 255, which is what the pulse width
modulation-capable pin 11 can output.

Other than that, we simply use the "analogRead" function to read a value from analog pin 0,
and the "analogWrite" function to create a PWM pulse on digital pin 11.

Simple!

Peter Dalmaris

Lecture 16

Arduino Step by Step

Here's an experiment: Take a small speaker and connect it to the breadboard so that it
replaces the LED. Fire up the circuit. Can you hear the sound coming out of it? Can you
notice how its pitch changes as you turn the knob?

Peter Dalmaris

Lecture 17

Arduino Step by Step

Lecture 17
Flex sensor

A flex sensor is a device made of a thin, flexible


material of which the resistance changes (it increases)
as it flexes. Hence, its name.

You can use these sensors to detect stress in machines


or structures, but also in things like this "power glove":

There's lots of other uses, like in biometrics, in fitness products, and in gaming devices.

Let's have a look at the flex sensor in action.

Peter Dalmaris

Lecture 17

Arduino Step by Step

Assembly

This is what we are going to build:

You will need:

The Arduino

A flex sensor (you can get one from Sparkfun


for around $12)

A 1k resistor (to build a voltage divider)

Three jumper wires.

!
Heres the completed circuit:

!
2

Peter Dalmaris

Lecture 17

Arduino Step by Step

Sketch

And, here's the script. All we need to do is to read the voltage at analog pin 0 and print it in
the monitor.

void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023)
//to a voltage (0 - 5V):
float voltage = sensorValue * (5.0 / 1023.0);
// print out the value you read:
Serial.println(voltage);
}
Upload it to your Arduino and open up the monitor. Bend the sensor back and forth. See
how the output fluctuates as the sensor's shape changes?

What's inside a flex sensor?

A flex sensor is made of carbon resistive elements surrounded by a plastic flexible


protective cover. As the elements are bend, their resistance increases as a function of its
radius because the resistive material becomes slightly thinner. In eect, when the material
becomes thinner, there is less carbon to conduct electricity, therefore the resistance
increases.

Peter Dalmaris

Lecture 18

Arduino Step by Step

Lecture 18
Membrane potentiometer

A rather unusual type of potentiometer is the


membrane potentiometer.

A membrane potentiometer is electrically


exactly the same as a typical rotary
potentiometer. The dierence is in the user
interface. Instead of rotating a knob in order
to change the resistance of the middle pin,
you can slide your finger over the sensor's
surface.

Assembly

What we are going to build is exactly


the same circuit as in Lecture 16.
We'll just replace the rotary
potentiometer with the membrane
potentiometer.

Here's the parts we need:

The Arduino

A membrane potentiometer

3 Jumper wires

Here's the circuit:

!
!

Peter Dalmaris

Lecture 18

Arduino Step by Step

And heres the assembled circuit:

The monitor output is essentially the same as with the potentiometer. The only dierence is
that the actual resistance of the voltage divider will be dierent between the two devices so
the actual reading will be dierent in analog pin 0.

Peter Dalmaris

Lecture 18

Arduino Step by Step

Sketch

Here's the sketch, as a reminder since we've seen this before.

void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023)
// to a voltage (0 - 5V):
float voltage = sensorValue * (5.0 / 1023.0);
// print out the value you read:
Serial.println(voltage);
}

What's inside a membrane potentiometer?


The membrane potentiometer works on the same principle as a
regular potentiometer. The dierence is that a rotary potentiometer
has a conductive wire attached to the knob, and as the knob turns, it
makes the conductive wire come in contact with a circular resistor.

!
The membrane
potentiometer,
however, is made by having a conductive
membrane (hence the name) that is
suspended over a resistor material. As one
presses the membrane, it comes in contact
with the resistor under it at dierent lengths
of the resistor, and closes a circuit, thereby
implementing the voltage divider.

Peter Dalmaris

Lecture 19

Arduino Step by Step

Lecture 19
Buzzer

A buzzer is a device that can generate simple


tones, typically used to provide audible feedback
to the user. Buzzers are used in alarm clocks,
keypads, many household appliances and simple
toys.

To show you how a buzzer works with the Arduino,


we will re-purpose the circuit we used back in
Lecture 16, where we controlled the brightness of
an LED using a potentiometer. What we'll do here,
is to control the tone of the sound emitted by a
buzzer using the same potentiometer. We'll just
replace the LED with the buzzer.

Assembly

This is what we'll make:

We will need:

The Arduino,

A buzzer,

7 jumper wires.

The circuit is essentially the same as


in Lecture 16. We use the digital pin
11 to generate PWD pulses that
depend on the voltage measured at
analog pin 0. This is the voltage
controlled by the potentiometer.

As the potentiometer generates a


higher voltage, the pulses in digital
pin 11 have a longer duty cycle and
trigger the buzzer to generate a
louder, higher pitch sound. When the
potentiometer generates a lower
voltage, pin 11 generates a shorter duty cycle pulse which makes the buzzer generate a
softer, lower pitch sound.

!
1

Peter Dalmaris

Lecture 19

Arduino Step by Step

And here's the assembled circuit:

!
!

Peter Dalmaris

Lecture 19

Arduino Step by Step

Sketch

The only dierence between this script and the one from Lecture 16 is the variable name for
the buzzer pin. ledPin is now buzzerPin.

int potentiometerPin = 0;
int buzzerPin = 11;
int potentiometerVal = 0;
void setup()
{
Serial.begin(9600); // setup serial
}
void loop()
{
potentiometerVal = analogRead(potentiometerPin);
//I use the map function because PWM pins can only accept
//values from 0 to 255. Analog pins can output values from
//0 to 1023. With the map function, the range 0-1023 is
//converted to appropriate values from 0 to 255.
int mappedVal = map(potentiometerVal,0,1023,0,255);
Serial.print(potentiometerVal);
Serial.print(" - ");
Serial.println(mappedVal);
analogWrite(buzzerPin,mappedVal);
delay(10);
}
And there you go, making sounds with the Arduino is super easy.

Peter Dalmaris

Lecture 20

Arduino Step by Step

Lecture 20
Direct current motor

Direct current motors represent the easiest way to add movement to your projects. But
easy does not mean less capable. A direct current or DC motor can be a very cost
eective and flexible solution for all sorts of projects: robots, cars, boats, toy helicopters,
home automation, and many more.

In this lecture I will show you how to use a DC motor through a series of demos. All involve
two geared DC motors (why use just one when we can use two?) and a motor break-out
circuit. Ill explain what these are in a minute. Heres what we are going to build in this
lecture:

First, well just hook the motors to the Arduino via the motor break-out board, and make
them spin in a single direction.

Second, well get the motors spinning forwards and backwards using a potentiometer as
a controller.

Third, well use an ultrasonic sensor to get the motors to spin faster or slower depending
on the distance between the sensor and an object in front of it.

Before we get into the demo, I want do a quick introduction to motors, and specifically to
discuss the kinds of motors people can use in their projects.

!
!

Peter Dalmaris

Lecture 20

Arduino Step by Step

Motors

The most common type of motor is the DC motor. These are


low cost devices that work by connecting two wires to
positive and negative voltage. Once you connect them to
power, the shaft will start spinning towards a direction. This
direction depends on the polarity of the connection. To
reverse the direction of the spin, just switch the electrical
connections.

All electrical motors work by taking advantage of the forces


generated by a magnet (permanent or temporary electro-magnet) and the electric field
generated by electrical current as it travels through a coil. (Schematic taken from http://
www.electrical4u.com/working-or-operating-principle-of-dc-motor/).

The DC motor can spin very quickly, which often is not what we want in our applications.
For example, if you are building mechanism that opens the shutters of a window, you would
like the shutter to open slowly to avoid damaging it. A DC motor on its own would try to go
full speed immediately. So, in most cases people attach a gear box to the motor. The gear
box will convert high rotational spin from the shaft of the motor to lower rotational speed,
and often with a higher torque so that large loads can be moved.

In the examples in this lecture, I will show you what a gear box
looks like.

Another common type of motor is the stepper motor. Stepper


motors operate by moving the motor shaft in steps, hence the
name. While the DC motor will move constantly while there is
power, a stepper motor will move by one step when a signal is
send via a wire, and then stop. How big each step is depends on
the construction of the motor. For applications where you need
2

Peter Dalmaris

Lecture 20

Arduino Step by Step

fine control and small movements, a stepper motor is a good choice. For example, they are
used in 3-D printers, where milli-meter accuracy is needed.

Stepper motors tend to be much bulkier and expensive then DC motors. They contain
multiple coils and more complicated mechanical components, and that reflects in the price.
Your circuitry also needs to be more complicated because you need to provide several
signal lines of control to make it work.

A common problem with stepper motors is that in certain situations


(usually under high load), there is a mismatch between the signal
that the motor controller is sending and the actual mechanical
movement that the motor produces. In simple words, the motor
may miss steps and the controller will never know because
usually there is no feedback mechanism to track and confirm
movement.

A servo motor comes in to fix this problem. A servo motor contains a DC


(usually) motor, a gear box, and a position feedback mechanism. This mechanism can make
the humble DC motor as accurate as a stepper motor (for a lower price), with the added
benefit of monitoring and confirming the actual position of the shaft. Servo motors are used
extensively in robotics, manufacturing automation systems, and high-end toys.

!
!
!

Peter Dalmaris

Lecture 20

Arduino Step by Step

Demo 1: Motor quick start guide

Lets build a simple circuit that controls 2 geared DC motors from a toy tank that I stole
from my kids (they originally stole it from me).

Even though you could connect a DC motor directly to the Arduino, that is not a good idea.
The Arduino can only provide very little current
to external devices, and only tiny motors
would be satisfied with that. In virtually all reallife applications, we need to provide external
power to the motor, and only signalling from
the Arduino.

To do this, I am going to use a break-out board


that contains the L298N motor driver bridge.
This IC can provide high current to our motors,
so we can use it in power-hungry applications.
You cant use this IC on its own, you need to
provide supporting capacitors and diodes, so I
find it a lot more convenient to use a break-out
board that contains the L298N, such as the
one in this image.

You can get these devices fully assembled and ready to use on eBay for a couple of dollars.

Heres the schematic of the circuit we are going to build:

Peter Dalmaris

Lecture 20

Arduino Step by Step

!
!

And heres what the assembled


circuit looks like:

!
!
!
!
!
!
!
!
!
!
!
!
!
!
!

BEWARE! I was not able to find an appropriate part in the software I use to create the
circuit diagrams (Fritzing) for the L298N break-out board, so I am approximating it with this
basic black device containing 11 pins. From left to right, the pins on this mockup device
are:

1
Out1

2
Out2

3
Out3

4
Out4

5
In1

6
In2

7
In3

8
In4

9
12V+

10
Gnd

11
5V+

Try to match these pins against the marked connectors in your break-out board and you
should be ok.

Ill explain what the role of each pin is on the break-out board now.

Out1 and Out2 control the speed and direction of motor 1. Out3 and Out4 control motor 2.
As we are using DC motors, the higher the voltage dierential between the pins in those
pairs, the faster the motors will spin. If you want to reverse the motors, you must change
the polarity of these pins. This is something that the L298N will do for you with the
appropriate signal in the input pins.

Peter Dalmaris

Lecture 20

Arduino Step by Step

In1 and In3 control the direction of spin for motor 1 and motor 2 respectively.

In2 and In4 control the speed for each motor.

Pin 9 receives +12V or higher


from an external power source.
In the schematic, I show two 9V
batteries is series, to give us a
total of 18V. Alternatively, you
could use an external power
supply.

Finally, pin 10 is for ground, and


should be connected to one of
Arduinos Gnd pins so that both
the Arduino and the break-out
board are grounded together.

Ok, enough with the preliminary,


lets put this circuit together, and
also look at the sketch!

[VIDEO]

!
!

Peter Dalmaris

Lecture 20

Arduino Step by Step

Sketch for Demo 1


Heres the sketch for Demo 1.

//Arduino PWM Speed Control


int
int
int
int

E1
M1
E2
M2

=
=
=
=

5;
4;
6;
7;

void setup()
{
pinMode(M1, OUTPUT);
pinMode(M2, OUTPUT);
}
void loop()
{
int value;
for(value = 0 ; value <= 255; value+=1)
{
digitalWrite(M1,HIGH);
digitalWrite(M2,HIGH);
analogWrite(E1, value);
//PWM Speed Control
analogWrite(E2, value);
//PWM Speed Control
delay(30);
}
}

We start by setting the digital pins for the motor 1 and motor 2 control. We need two pins to
control each motor. The M pins control the direction of rotation for the motor shafts, and
the E pins control the speed.

In the setup() function we set the mode for pins M1 and M2 to be output (so we can control
the direction of the spin).

In the loop() function, we have a for loop that cycles from 0 to 255, so it covers all the
possible PWM values that can be written to pins E1 and E2 (Arduino pins 5 and 6
respectively).

Every time that the block in this loop runs, we first set the direction of spin for both motors
by writing a HIGH value to pins M1 and M2 (Arduino pins 4 and 7 respectively), and then
we set the spin by using the PWM function analogWrite. The value we write to these pins
is controlled by the for loop.

Once you connect this circuit and run the loop, you will have your motors starting from zero
speed, speeding up gradually until they reach their maximum rotational speed, before they
suddenly stop to a halt and then repeating the same processes again, until power is
switched o.

Peter Dalmaris

Lecture 20

Arduino Step by Step

To change the direction of rotation, just change the value you write to either M1 or M2 pins
to LOW, and upload the sketch. You will see the corresponding motor shaft moving the
opposite way compared to the original sketch.

Easy!

Demo 2: Control speed and direction with a


potentiometer
The circuit for demo 1 is interesting but
not very useful. It would be great if we
could control both the direction and the
speed of rotation of our motors, right?

Thats what well do now. Well use a


potentiometer in two ways:

First, when we turn the knob, the


motors will turn faster or slower.

Second, well modify our sketch so


that with the same potentiometer we
can control both the direction of spin
and the speed of our motors.

Heres the demo 2 circuit (right).

The only dierence to the demo 1 circuit


is the addition of the rotary
potentiometer. It is connected to the 5V and Gnd columns on the breadboard, and to
analog pin 0 on the Arduino.

!
!
!
!
!

Peter Dalmaris

Lecture 20

Arduino Step by Step

Sketch for Demo 2, version 1: control speed with a


potentiometer

Heres the first sketch for Demo 2. This sketch allows the control of only the rotational
speed of the two motors:

//Arduino PWM Speed Control


int
int
int
int

E1
M1
E2
M2

=
=
=
=

5;
4;
6;
7;

void setup()
{
Serial.begin (9600);
pinMode(M1, OUTPUT);
pinMode(M2, OUTPUT);
}

void loop()
{
int potentiometerVal = analogRead(A0);
Serial.println(potentiometerVal);
move_motors(potentiometerVal);
}

void move_motors(int potValue)


{
int mappedVal = map(potValue,0,1023,0,255);
digitalWrite(M1,HIGH);
digitalWrite(M2, HIGH);
analogWrite(E1, mappedVal);
//PWM Speed Control
analogWrite(E2, mappedVal);
//PWM Speed Control
delay(30);
}

I have highlighted the changes and additions from the sketch in Demo 1 in red.

In the loop() function, we take a reading from analog pin 0 where the middle pin of the
potentiometer is connected. We then call the function move_motors and pass the
potentiometer reading to it. Inside move_motors, we simply map the potentiometer reading
(which comes in the range of 0 to 1023) to a value between 0 and 255 (which is the range of
valid values for the PWM pins), set the direction of rotation for the two motors using the
digitalWrite functions, and set the speed using the PWM function analogWrite to be
mappedVal (which in turn is relevant to the value we set by turning the potentiometer).

Upload this sketch and turn the knob of the potentiometer back and forth. See how the
speed of the motors change accordingly?

Peter Dalmaris

Lecture 20

Arduino Step by Step

Sketch for Demo 2, version 2: control speed and


direction with a potentiometer

Theres one more thing to do, and that is to also be able to control the direction of rotation
of the motors, not just the speed. What Id like to do is to be able to accelerate the motor
towards one direction when I turn the knob of the potentiometer towards the left, and to the
opposite direction when I turn the knob towards the right. Schematically, this is what I
would like to achieve: The red circle represents the potentiometer knob, and the black
shows movement of the knob towards the left or the right.

!
!
!
!
!
!
!
!
!
!

Motors move
anti-clickwise

Neutral motors dont


move

Motors move
clickwise

We are only going to make an adjustment to the sketch to make this happen, no need to
modify the circuit at all.

Here is the modified sketch:

//Arduino PWM Speed Control


int
int
int
int

E1
M1
E2
M2

=
=
=
=

5;
4;
6;
7;

void setup()
{
Serial.begin (9600);
pinMode(M1, OUTPUT);
pinMode(M2, OUTPUT);
}

void loop()
{
int potentiometerVal = analogRead(A0);
Serial.println(potentiometerVal);
move_motors(potentiometerVal);
}

void move_motors(int potValue)


10

Peter Dalmaris

Lecture 20

Arduino Step by Step

{
if (potValue < 512)
{
int mappedVal = map(potValue,0,512,0,255);
//Going forward
digitalWrite(M1,HIGH);
digitalWrite(M2, HIGH);
analogWrite(E1, mappedVal);
//PWM Speed Control
analogWrite(E2, mappedVal);
//PWM Speed Control
delay(30);
} else
{
//Going backward
int mappedVal = map(potValue-512,0,512,0,255);
digitalWrite(M1,LOW);
digitalWrite(M2, LOW);
analogWrite(E1, mappedVal);
//PWM Speed Control
analogWrite(E2, mappedVal);
//PWM Speed Control
delay(30);
}

Block 1

Block 2

I have highlighted in red the part of the sketch that has changed from the script in demo 2.
In the move_motors(int pot_value) function, potValue, the value read from analog pin 0
where the potentiometer is connected, is tested using the if function. If potValue is less than
512, then the first block is executed, if not then the second block is executed.

In block 1 and 2, the motor control functionality from demo 2 is repeated with the dierence
that now we now need to recognise that the potentiometers range of outputted values is
divided to two parts. The first part, from 0 to 512, is used for moving the motors towards
one direction, while the second one, 513 to 1023, moves the motors towards the other
direction.

So, we need to adjust the code so that the new range of the potentiometer is taken into
account. In Block 1, the range from 0 to 512 is converted to the PWM range of 0 to 255. In
Block 2, potValue values are from 513 to 1023, still 512 possible values, so the range is
eectively the same as with Block 1, except that we need to make an adjustment to
potValue by subtracting 512 from it so that the value that the map function evaluates nicely
fits within this range.

The only other dierence between these two blocks is that in Block 1, a HIGH is written to
M1 and M2, while in Block 2 we write a LOW, therefore spinning the motors towards the
opposite direction.

Go ahead, try it.

If you are having any diculty understanding what is going on in Blocks 1 and 2,
experiment with the sketch. Try changing the map function values to something dierent.
For example, in Block 2, instead of map(potValue-512,0,512,0,255) try map(potValue,

11

Peter Dalmaris

Lecture 20

Arduino Step by Step

0,512,0,255) and upload the sketch. What happens to the rotational speed of the motors?
Perhaps you could try this too: map(potValue,512,1023,0,255). Upload and compare to the
previous two versions. Any dierence in behaviour? Can you explain any dierences or
similarities?

Demo 3: Control speed with a distance sensor

By now, you have learned how to control a motor through code, and through an external
controlling device like a potentiometer. The sketch would look much the same if you used a
simple joystick instead. You can see how from a humble beginning you can start branching
out and experimenting with dierent types of hardware, gradually reaching more interesting
and capable configurations.

Well do one last experiment for this lecture. We will connect an ultrasonic distance sensor
in the place of the potentiometer, and use that to control the rotational speed of the motors.
The idea is this: The distance sensor will tell the Arduino how close it is to an obstacle. If it
gets too close, it will start slowing down the motors, eectively slowing down our prototype
vehicle. Otherwise, it will forge ahead full speed.

Heres the schematic:

!
!
!
!
!
!
!
!
!
!
!
!
!
!
12

Peter Dalmaris

Lecture 20

Arduino Step by Step

!
Have a look at Lecture 11 if you need a reminder on how to connect the ultrasonic distance
sensor. This sensor uses 4 wires, two for power (5V and Ground), one for the Trigger pin,
and one for Echo. Connect those wires as shown in the schematic, and upload the
following sketch:

//Arduino PWM Speed Control


int
int
int
int

E1
M1
E2
M2

=
=
=
=

5;
4;
6;
7;

#define trigPin 13
#define echoPin 12

void setup()
{
Serial.begin (9600);
pinMode(M1, OUTPUT);
pinMode(M2, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}

void loop()
{
long duration, distance;
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration/2) / 29.1;

move_motors(distance);

void move_motors(int distance)


{
if (distance >= 50 ){
Serial.print(distance);
Serial.println(" cm - 255");
digitalWrite(M1,HIGH);
digitalWrite(M2, HIGH);
analogWrite(E1, 0);
//PWM Speed Control
analogWrite(E2, 0);
delay(30);
}
else {
int mappedVal = map(distance,0,50,0,255);

13

Peter Dalmaris
Serial.print(distance);
Serial.print(" cm - ");
Serial.println(mappedVal);
digitalWrite(M1,HIGH);
digitalWrite(M2, HIGH);
analogWrite(E1, 255-mappedVal);
analogWrite(E2, 255-mappedVal);
delay(30);

Lecture 20

Arduino Step by Step

//PWM Speed Control


//PWM Speed Control

}
}

Much of this code, at least the part in the loop() function, has been taken from the sketch in
Lecture 11. It generates the ping pulse that is emitted by the sensor, and then calculates
the distance of an object from the time it takes for the echo to return.

Once the distance is calculated, the move_motors function is called, and the distance is
passed as an integer parameter. Just like in Demo 2 Version 2, motors are moved in one of
two ways: if distance is 50cm or less, the motor speed is proportional to the distance. The
smaller the distance is, the smaller the speed. Otherwise, if the distance is over 50cm, then
motors will move at their maximum speed.

If these motors were part of a fully assembled vehicle, the eect of this sketch would be
that the vehicle would be capable of avoiding hitting an object by slowing down on
approach, until it came to a full stop.

Upload the sketch and play with it to get a sense of it in real life. Try to imagine how it
would behave in a real situation. Can you foresee any limitations? Can you imagine any
improvements?

Improvements

For example, in the current version of the sketch, the vehicle would come to a complete
stop only when the distance to a wall was 0cm. Is this sucient? Perhaps it should come to
complete stop a bit earlier, maybe at 5cm? Or perhaps, to be even more cautious, the
vehicle should backup slightly away from the obstacle in order to provide room for a turning
manoeuvre?

Can you make changes to the Demo 3 sketch and implement these scenarios (or whatever
other improvement you can think of)?

14

Peter Dalmaris

Lecture 23

Arduino Step by Step

Lecture 23
Servo motors

In Lecture 20, you learned about the DC motor: a versatile yet low-priced solution for
providing motion to your projects. A weakness (or characteristic) of the plain vanilla DC
motor is that it spins like crazy, and while it does we dont know where the shaft is or how
far it has traveled because there is no feedback provided! Once you apply power, it wants
to go as fast as it can for at long as it can!

This is great for applications were continuous movement is needed, like for propelling a
vehicle, but not when we need to be able
to generate precise movement.

But imagine building a robot that


performs surgery on humans. Some of
you may hopefully work on something
like this in the not so distant future. In
such application, precision and control
feedback is paramount. You dont just
want to tell the motor to rotate its shaft
by 90 degrees, you also want
confirmation that it did.

!
In Lecture 20 there was a passing mention of the servo
motor. The servo motor is a spruced up DC motor
that includes circuitry for fine movement control and
feedback. In this Lecture, we will learn about how to
use this kind of motor. We will use both the build-in
servo motor library that comes standard with the Arduino IDE,
and a third party library that adds a bunch of very useful
features.

Lets go straight to the assembly and sketches.

Peter Dalmaris

Lecture 23

Arduino Step by Step

Demo 1a: quick start


guide

We are going to use the servo motor library


that is build-in to the Arduino IDE to start
playing with our servo motor real quickly. First,
lets put the circuit together, then well have a
look at the sketch.

This is what we are going to assemble (right).

There are a couple of things to notice here.

First, there is no motor break-out board like


the one we used in the DC motor lecture. Back
then, I said that because the Arduino cannot
provide much current, it is best to always use
an external power source to power our
motors, and that is what the break-out board
was meant to do. I did not lie back then, but
sometimes we can make an exception. In this
circuit, my servo motor is small enough to not
stress the Arduino too much. So, I decided to
plug it straight into the Arduino in order to keep things simple.

But thats not where this decision ends. Notice the big round tube at the lower part of the
breadboard? That is a capacitor. Even though my servo motor is small, occasionally in may
draw more power than what the Arduino can provide, but only momentarily, like when it
starts a new move. To counteract that, I have plugged in a capacitor between the Ground
and +5V columns. A capacitor is a reservoir of electricity, a bit like a battery that can charge
and discharge very quickly. Plugged into the circuit like this, when the servo motors starts
and draws more power than what the Arduino can provide, the capacitor will start
discharging and providing the motor the additional power it needs. Just plug in a capacitor
that is 300F or more and youll be ok.

The motor itself has three wires coming out of it. Two are for power (+5V and Gnd), and one
for signal. Plug the signal wire to digital pin 9, and the other two to the +5V and Ground
columns on the breadboard.

We could try to control the servo motor through the Arduino digitalWrite functions but that
would require us figuring out the right values to write, and the timing for writing those
values. Thats too much work. We are lucky, though, because with the Arduino IDE we get
the Servo library, which contains functions that allow us to easily work with servo motors.
Well using this library first, and then Ill show you an alternative third-party library that
provides additional functionality.

Peter Dalmaris

Lecture 23

Arduino Step by Step

Demo 1a sketch
Heres the sketch:

#include <Servo.h>
Servo myservo;

// create servo object to control a servo


// a maximum of eight servo objects can be created

int pos = 0;

// variable to store the servo position

void setup()
{
myservo.attach(9);
}

// attaches the servo on pin 9 to the servo object

void loop()
{
for(pos = 0; pos < 180; pos += 1)
{
myservo.write(pos);
delay(15);
}
for(pos = 180; pos>=1; pos-=1)
{
myservo.write(pos);
delay(15);
}
}

//
//
//
//

goes from 0 degrees to 180 degrees


in steps of 1 degree
tell servo to go to position in variable 'pos'
waits 15ms for the servo to reach the position

Block 1

// goes from 180 degrees to 0 degrees


// tell servo to go to position in variable 'pos'
// waits 15ms for the servo to reach the position

Block 2

This is one of the demo sketches that also come with the Arduino IDE. You can find it by
clicking on File > Examples > Servo > Sweep.

We first declare our intention to use a servo motor by including the Servo library (#include
<Servo.h>), and creating the variable myservo that we use as a handle to the Servo
object (Servo myservo;).

In the setup function, we tell the Arduino that the control wire from our servo motor is
attached to digital pin 9 (myservo.attach(9);).

The work is done in the loop() function, where we use the for loop to count from 0 to 180,
and another one to count backwards, from 180 to 0. This has the eect of the shaft of the
servo motor travelling 180 degrees to one side, and 180 degrees to the other side, 1 degree
at a time, constantly.

Inside each for block, we first write a value to the motor using myservo.write(d), where d
is a number representing the degree to which the shaft should turn. If we want to turn it by
15 degrees, we write myservo.write(15). Simple, right?

Peter Dalmaris

Lecture 23

Arduino Step by Step

In Block 1, we get the shaft to turn from 0 to 180 degrees, and in Block 2 to travel all the
way back to 0 degrees.

Finally, notice how we set a delay of 15 milliseconds inside each block, after a movement
has been written? We need this because it takes a bit of time for the motor to move, and we
want to make sure that any previous instruction has been completed before sending
through the next move instruction.

That was easy but not satisfying enough. I want to be able to control the servo motor my
self, instead of the Arduino being in charge. How about we try to connect a potentiometer
and use it as a controller for the motor?

Demo 1b: Control the servo


with a potentiometer
Lets attach a rotary potentiometer, and adjust
our sketch to enable us control of the motor by
turning the knob.

Heres the new circuit (right).

The potentiometer is attached to power, and


middle pin goes to analog pin 0 (A0) on the
Arduino.

The new sketch looks is this:

#include <Servo.h>
Servo myservo;

// create servo object to control a servo

int potpin = 0; // analog pin used to connect the potentiometer


int val;
// variable to read the value from the analog pin
void setup()
{
myservo.attach(9);
}

// attaches the servo on pin 9 to the servo object

void loop()
{
val = analogRead(potpin);
// reads the value of the potentiometer (0 to 1023)
val = map(val, 0, 1023, 0, 179); // scale it to use it with the servo (0 to 180)
myservo.write(val);
// sets servo position according to the scaled value
delay(15);
// waits for the servo to get there
}
4

Peter Dalmaris

Lecture 23

Arduino Step by Step

Just like in Demo 1a, we include the Servo library and set pin 9 as the servo pin. In the
loop() function, we constantly take readings from analog pin 0 (A0) where the potentiometer
is attached. Because the range of values read in A0 is not the same as the values we can
send to the servo, we use the map function to scale appropriately.

Finally, we use the myservo.write(val); function to send the scaled value to the
potentiometer.

Try it out!

Demo 2: Setup and play with VarSpeedServo


The build in Servo library is good
and very simple to use. However,
theres more we can do with the
hardware than it allows us.

For example, how fast should the


motor move from one position to
the next? What about the ability
to define a set of movements for
the motor to perform, and then
send them with a single
instruction?

To achieve functionality like that,


we need to use an external
library. I am going to show you
how to use the VarSpeedServo library, written by Korman and updated by Philip van Allen.
Thank you to both for their work and contribution!

First, you will need to get this library. Go to https://github.com/netlabtoolkit/VarSpeedServo


and look for the Download ZIP button.

Download it somewhere on your computer,


and double-click on it to extract the files
from the archive. You will end up with a new
folder named VarSpeedServo-master.

!
!
!
!
!
5

Peter Dalmaris

Lecture 23

Arduino Step by Step

!
You need to rename this folder, so that its
now called VarSpeedServo (i.e. remove
the -master part.

You now need to copy this folder to the


folder where Arduino keeps its third-party
libraries. Dont know where that is? No
problem, the Arduino IDE luckily
knows.

From the Arduino menu item, click


on Preferences. This dialog box
appears, and at the very top you
can see the Arduino folder. Go to
this folder using your Finder (Mac)
or Windows Explorer (Windows),
and look for a subfolder named
libraries.

Copy the VarSpeedServo folder into


the libraries folder. You are done.

Restart the Arduino IDE by closing


it and opening it up again. To verify
that the VarSpeedServo library was
imported succesfuly, click on
Sketch > Import library, and look
for the new library. It usually goes
to the bottom of the list.

Now that we have the new library


imported, lets use it.

Ill show you two sketches that come


as examples with this libraries that
compare exactly the two examples from
Demo 1.

The first one is the Sweep example.


Assemble the circuit you used in Demo
1a, and load the sketch on the Arduino
IDE by clicking on File > Examples >

Peter Dalmaris

Lecture 23

Arduino Step by Step

VarSpeedServo > Sweep.

Heres the sketch:

#include <VarSpeedServo.h>
VarSpeedServo myservo;

// create servo object to control a servo


// a maximum of eight servo objects can be created

const int servoPin = 9; // the digital pin used for the servo
void setup() {
myservo.attach(servoPin); // attaches the servo on pin 9 to the servo object
myservo.write(0,255,true); // set the initial position of the servo, as fast as
// possible, wait until done
}

void loop() {
myservo.write(180,255,true);

myservo.write(0,30,true);

//
//
//
//
//

move the servo to 180, max speed, wait until done


write(degrees 0-180, speed 1-255, wait to
complete true-false)
move the servo to 180, slow speed, wait until
done

!
!

You can probably see the similarities and dierences between the original Sweep sketch
and this one. We include the library and create the myservo object reference. We set the
servo signal pin to 9.

In the loop() function, we attached the servo at pin 9 to the myservo object.

We then send the first instruction to the servo by using the myservo.write function. This
looks the same as in the original Sweep sketch, except that is takes three arguments, not
just one.

It works like this: myservo.write(position, speed, wait);

The position argument accepts an integer, denoting the degree wed like the servo to turn
to. For example, 15 degrees.

The speed argument controls how fast the movement should be. Top speed is 255, stopped
is 0, and anything is between is allowed.

Finally, the wait argument allows us to stop the program at that line and wait for the motor
to finish its movement. To wait, we make this argument true. If we want to just continue

Peter Dalmaris

Lecture 23

Arduino Step by Step

running the sketch and let the servo finish its movement on its own, we make this argument
false.

Nice, isnt it?

What do you think happens in the loop() function?

Lets now connect the potentiometer, like we did in Demo 1b, and load the VarSpeedServo
example sketch titled Knob into the Arduino IDE.

Here it is:

#include <VarSpeedServo.h>
VarSpeedServo myservo;

// create servo object to control a servo

const int potPin = 0;


const int servoPin = 9;

// analog pin used to connect the potentiometer


// the digital pin used for the servo

int val;

// variable to read the value from the analog pin

void setup() {
myservo.attach(servoPin);
}

// attaches the servo on pin 9 to the servo object

void loop() {
val = analogRead(potPin);
// reads the value of the potentiometer (0 to 1023)
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (0 to 180)
myservo.write(val);
// sets the servo position according to the scaled value
delay(15);
// waits a bit before the next value is read and written
}

Compare this against the sketch from Demo 1b. Isnt it practically identical? Notice how the
sketch above also makes use of the myservo.write(val); function, with just a single
argument? The VarSpeedServo library allows you to use the familiar functions from the
build-in Servo library, so that any existing sketches you may have lying around will still
work. You get the additional functionality, as we saw in the Sweep sketch, for free!

An exercise
Can you build a circuit that contains a servo motor and three buttons? When you press button 1, the
motor moves to 60 degrees. When you press button 2, it moves to 90 degrees. When you press
button 3, it moves to 180 degrees.

Peter Dalmaris

Lecture 24

Arduino Step by Step

Lecture 24
LCD character screen

Liquid crystal displays, LCD screens, are one of the most common ways for a gadget to
speak to us. They come in many dierent shapes, sizes, colours and prices. It is a common
and reliable technology. It is no surprise that the Arduino makes it super easy to connect to
them with a build-in library that provides several capabilities, and several modes of
operation.

In general, we can distinguish LCD


screens in two categories: character and
TFT screens.

Character screens are those that limit their


display to show character icons only. You
can write and manipulate characters in
rows and columns. Heres an example:
[show LCD character screen image]. Their
sizes (in terms of characters), vary, but
most common are those with 2 lines, each
fitting 16 characters, or the half one at 2
lines by 8 characters.

TFT LCD screens, on the other hand, provide


you with an array of pixels on which you can
draw whatever shape you like. You can draw
text, of course, or circles, boxes, lines and
triangles, so the information you display to the
user can be a lot richer.

In this lecture I will show you how to use a


character LCD screen, and in a later lecture
well look at the TFT screen.

Demo 1: quick start guide to the parallel LCD


character screen

In this first demo, Ill show you how to connect an LCD screen to your Arduino. There are
two ways to make this connection: parallel and serial.

With a parallel connection, we connect each of the screens data pins to an individual digital
pin on the Arduino. The LCD screen Ill be using is an 8-bit device, meaning that each
message from the Arduino is made up of 8 bits. This LCD screen has one pin for each bit,

Peter Dalmaris

Lecture 24

Arduino Step by Step

so, this kind of connection will occupy 8


out of 13 digital pins on my Arduino Uno.
Not much left to connect other devices,
right?

Lucky enough, this LCD screen has a 4


bit mode. Using this mode, enables us to
only connect 4 out of the 8 data pins.
Communication will be a bit slower since
we will need to transmit the full 8 bits
over two cycles, but the dierence is
hardly noticeable for most applications.

I also mentioned a serial connection


mode, right? Yes, with serial
communication the LCD screen only
needs one pin to be connected to the
Arduino, and all 8 bits will be transmitted
through that single pin. You need some
additional hardware for this to work, so I
am going to prepare a special lecture for
this topic.

Lets move ahead and have a look at the


circuit.

In this schematic, the first pin from the left of the LCD is number one, and the last on the
right is 16.

The green wires represent the 4 data lines. From the LCD screen, pins D4, D5, D6, D7,
connect to Arduino digital pins 5, 4, 3, 2 respectively.

LCD pin 1 goes to ground, and pin 2 go to +5V. These two supply power to the display.

The potentiometer is used to control the contrast. Plug the middle pin of the potentiometer
to LCD pin 3, and the other two to power and ground, as we have done in the past.

[Show assembly and sketch video]

Peter Dalmaris

Lecture 24

Arduino Step by Step

Sketch for Demo 1

Heres the sketch for the circuit in Demo 1:

#include <LiquidCrystal.h>

// include the library code:

// initialize the library with the numbers of the interface pins


LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
lcd.print("hello, world!); // Print a message to the LCD.
}

void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
lcd.setCursor(0, 1);
lcd.print(millis()/1000); // print the number of seconds since reset:
}

We start by including the LiquidCrystal library to our sketch. This library comes build-in with
the Arduino IDE so we dont have to do anything to import it to our environment.

Then we declare and initialise the lcd object. The parameters that we pass to the initialiser
are the interface pins on the Arduino. The last four parameters are the data pins, and this is
how the Arduino knows that we will be using the four bit mode. The first two parameters are
the screen reset and enable pins. Have a look at the reference page for more details: http://
arduino.cc/en/Reference/LiquidCrystalConstructor

In setup(), we call the begin function and setup the screens number of columns and rows.
In this demo, I am using a screen with 16 columns in 2 rows. Change these numbers if you
are using a dierent sized screen.

Once we call the begin function, we can start sending content to the screen. So in the very
next line, we are printing the hello world! message, to greet the world!

In the loop() function, we make use of another function, setCursor(a,b). This function does
what you think it does: set the cursor where the next set of character will appear at a
particular column (parameter a) and row (parameter b).

And thats how you can use a parallel LCD character screen in 4-bit mode with your
Arduino!

!
!
3

Peter Dalmaris

Lecture 24

Arduino Step by Step

Demo 2: Show temperature and humidity on an LCD


character screen

In this second demo, well add a DHT22 humidity and temperature sensor and use the LCD
screen instead of the monitor to show the readings.

Refer back to Lecture 8 if you need a reminder.

Heres the Demo 2 schematic:

The only change compared to the


schematic in Demo 1 is the DHT sensor.
Connect +5V, and Gnd (pins 1 and 4),
and the data pin 2 to Arduino digital pin
7.

!
!
!
!
!
!
!
!
!
!

Peter Dalmaris

Lecture 24

Arduino Step by Step

The sketch is essentially a merge of the sketch we saw in Lecture 8, and that of Demo 1 in
this lecture. Here it is:

#include <LiquidCrystal.h>
#include "DHT.h"

#define DHTPIN 7
// what pin we're connected to
#define DHTTYPE DHT22
// DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);

// initialize the library with the numbers of the interface pins


LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
lcd.print("DHT test); // Print a message to the LCD.
dht.begin();
}

void loop() {
float h = dht.readHumidity();
float t = dht.readTemperature();

// check if returns are valid, if they are NaN (not a number)


// then something went wrong!
if (isnan(t) || isnan(h)) {
lcd.clear(); // clear the screen
lcd.setCursor(0, 0);
lcd.print("Can't get reading");
lcd.setCursor(0, 1);
lcd.print("from DHT");
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Hum: ");
lcd.print(h);
lcd.print(" %");
lcd.setCursor(0, 1);
lcd.print("Temp: ");
lcd.print(t);
lcd.print(" *C");
}

The only new function we use here are the lcd.clear() function, which clears the screen so
we can write on a clean canvas.

Peter Dalmaris

Lecture 24

Arduino Step by Step

The rest of this sketch is clear, I think. Setup the DHT sensor and the LCD screen, initialise
the objects for each sensor, start the devices, then take readings from the sensor and print
the acquired values to the screen.

Could not have been simpler!

An exercise
Can you build a circuit that contains a servo motor, an LCD screen, two potentiometers (one for the
screen and the other one for controlling the motor). As you turn the potentiometer and the servo
changes position accordingly, write the current angle on the screen. For example, if you have turned
the knob to 60 degrees, a message on the screen should show 60 degrees.

Peter Dalmaris

Lecture 25

Arduino Step by Step

Lecture 25
TFT LCD screen

The Thin-Film Transistor (TFT) liquid crystal


display screen is a member of the LCD family of
displays. TFT screens contain numerous pixels
(tiny screen elements that can be turned on an o
in order to create visible markings) organised in
rows and columns.

!
!
A TFT computer screen can contain many millions of
these pixels. In small consumer electronics, like feature
phones, there could be several tens or hundreds of
thousands.

Use a magnifying glass on your computer screen, and you


will see these tiny pixels. In this colour example, each
pixel is actually three: one for green, one for blue, and one
for red. The circuitry that controls the screen decides which ones to turn on, how bright
they should be, and how long they should stay on. The end result is rich, colourful graphics.

You can see that TFT LCD screens are far more versatile that LCD screens because there is
no restriction on the things you can display on them. While on a humble LCD screen you
can only display text, in a TFT screen you can draw anything at all.

In this example, Im displaying a clock on my Arduinos


TFT display shield. Ill show you how to do this later on in
this lecture as one out of several examples.

Because TFT screens have so many pixel elements to


control, they come equipped with a screen controller IC as
part of the package. Your Arduino communicates with this
IC via a serial connection, and makes requests for shapes
to be drawn on the screen. Because the intricacies of
communicating with the screen controller can be
complicated for anyone other than the designers of the
screen, people have created libraries, like the one we saw in the servo motor lecture.
Through such libraries, the programmer can use simple instructions, like setCircle, to draw
a circle, and setStr to draw a string of text.

Peter Dalmaris

Lecture 25

Arduino Step by Step

In this lecture I am use the first shield we play with in this course. A shield is a PCB on
which several components are mounted, with pin connectors that match exactly those of
the Arduinos headers. You plug the shield on top of the Arduino, and you are good to go.
No wiring and no soldering is required. This greatly minimises chances of making a mistake
and breaking something, and is a good way to experiment with more complicated devices,
like ethernet adaptors, SD card readers, motor controllers, etc.

Demo 1: quick start guide

To get started, you first need to download and install the library that best matches the
screen that you have. In my case, I purchase this one from ebay: http://r.ebay.com/rlUg4W.
After a little searching around on Google, I discovered that the best matching library comes
from its manufacturers website at http://www.elecfreaks.com/store/color-lcd-shieldp-462.html?zenid=d96eddbde9a0lmr9j7rkhrmmp2.

To make the library available to your Arduino project, and to get access to the example
sketches, follow the exact same procedure as you did back in the servo lecture:

1. Download and expand the archive file.

2. Once expanded, ensure that the name of the folder matches exactly the name of the .h
file inside it (the name of the folder should not contain the .h extension). For this
library, the name of the folder should be ColorLCDShield. Case is important.

!
2

Peter Dalmaris

Lecture 25

Arduino Step by Step

!
!
3. Copy the folder in your Arduinos library folder (if not sure, look at your Arduino IDE
preferences).

4. Restart the Arduino IDE.

You should now be able to see the ColorLCDScreen examples by clicking on File >
Examples > ColorLCDShield > Examples.

Next, plug the shield onto the Arduino. Because of the way the the headers are build into

the Arduino, and especially the distances between the four header segments, it is really
3

Peter Dalmaris

Lecture 25

Arduino Step by Step

impossible connecting the shield the wrong way without seriously damaging the shield by
bending its pins. Just play around with the shield and the Arduino to ensure you have
perfect pin alignment, and then apply some gentle force to make the two come together
securely.

Now that we have the shield installed, let upload one of the example sketches. Plug the
Arduino to your computer, go the the Arduino IDE, and click on File > Examples >
ColorLCDShield > Examples > ChronoLCD_Color.

Heres the sketch, I am showing you only the part that is relevant at the moment:

#include <ColorLCDShield.h>

void setup()
{

/* Initialize the LCD */


lcd.init(PHILLIPS);

The important consideration at the moment is to figure out the type of screen controller
your screen uses. There are no external markings to help you out, and often the
manufacturer does not provide any documentation either. So most often this is a game of
trial and error. The controller will either be PHILLIPS or EPSON. Mine happens to be
PHILLIPS.

Go ahead and upload this sketch and find that it doesnt work, edit this line to EPSON to
see if it fixes the problem.

Hopefully, a clock will appear on the screen after a few seconds:

Peter Dalmaris

Lecture 25

Arduino Step by Step

Theres a lot happening in this sketch, so its better to leave it alone for now, and instead
have a look at something simple.

Leave everything connected, and load this sketch into the IDE:

#include <ColorLCDShield.h>

#define BACKGROUND BLACK


#define C_COLOR RED
#define M_COLOR GREEN

!
!

// background color
// red color constant
// green color constant

LCDShield lcd;
void setup()
{
pinMode(10, OUTPUT);
analogWrite(10, 1023); //PWM control blacklight
/* Initialize the LCD, set the contrast, clear the screen */
lcd.init(PHILLIPS);
lcd.contrast(40);
lcd.clear(BACKGROUND);
lcd.setStr("STARTING", 50, 0, C_COLOR, BACKGROUND);
delay(1000);
lcd.clear(BACKGROUND);
}

void loop()
{
char* Str4[ ] = {"arduino 1","arduino 2","arduino 3"};
for (int i=0;i<3;i++)
{
printString(Str4[i], 15 * i,0);
}
}

void printString(char* toPrint, int x, int y)


{
lcd.setStr(toPrint, x, y, M_COLOR, BACKGROUND);
}

Upload it, you should see this on the screen:

The sketch starts by including the LCD library. Then, we create (define) three constants. A
constant is simply a name that we give to a value, so that when we need to use it later, we
can just use it by referring to the name. Constant also help to make code more readable,
especially when the values we assigns to them are esoteric data like hexadecimal or
binary values.

In this sketch, for example, we define the background color like this:

Peter Dalmaris

Lecture 25

Arduino Step by Step

#define BACKGROUND BLACK


Notice that there is no ending semicolon (;) necessary for ending regular lines in the C
programming language (the Arduino language is really C with the added special Arduino
libraries). BACKGROUND is the name of the constant, and BLACK is its value.

At a later part of the sketch, we find a reference to this code:

lcd.clear(BACKGROUND);
Here, we are calling the clear function of the lcd object, and passing the BACKGROUND
constant reference to it. We could have written this instead:

lcd.clear(BLACK);
and the result would be exactly the same. But consider this: the same code appears at
several places in this sketch. If at some point we decide to change the background color to
pink, we will need to find all references to the clear function and change its attribute. But
now, because we use a constant reference as an argument, we just go to the top of the
sketch, find the definition of this reference, and make the change from BLACK to PINK
there. Done!

The next line of interest is this:

LCDShield lcd;
We declare an object reference of type LCDShield. We can now use this reference, lcd, to
call all of the functions that the LCDShield object class oers.

Peter Dalmaris

Lecture 25

Arduino Step by Step

!
In the setup() function, we configure digital pin 10, which provides power to the screens
backlight.

pinMode(10, OUTPUT);
analogWrite(10, 1023);
We set it as output, and we turn its brightness to maximum by writing a 1023 value to it. If
you would like your screen to be dimmer, just reduce the value you write to pin 10.

Next, we tell the lcd object the kind of controller chip it is talking to:

lcd.init(PHILLIPS);
In my case, my screen uses a PHILLIPS controller. Remember, that the alternative is an
EPSON controller.

We then set the contrast like this:

lcd.contrast(40);
Play with this parameter to see the eect it has on the contrast.

Finally, these two instructions change whats shown on the screen:

lcd.clear(BACKGROUND);
lcd.setStr("STARTING", 50, 0, C_COLOR, BACKGROUND);
The first one makes everything black, since at the start of the sketch we defined the
constant BACKGROUND to be black. And then, we write our first piece of string using the
setStr function. This one takes several parameters:

lcd.setStr([text to show], [start vertical pixel - y], [start horizontal pixel x], [text color], [background color]);
If you wanted to write something at the top-left corner of the screen, in red, with green
background, you would do it like this:

lcd.setStr(hello, 0, 0, RED, GRENN);


Simple, isnt it?

In the loop() function, we first define an array that contains three pieces of text:

char* Str4[ ] = {"arduino 1","arduino 2","arduino 3};


Notice that the definition is char* Str4[];. The char* part tell the Arduino that the
variable that follows is a pointer (the * symbol) to a location in its memory were a bunch
7

Peter Dalmaris

Lecture 25

Arduino Step by Step

of characters (the char data type) are stored. A string of text is made up of lots of
characters, hence, char. We then give this pointer a name, Str4, and signify that this is
actually an array by using the square brackets next to the name: [].

Finally, we initialise this pointer variable to an array of strings by providing the 3 strings
inside curly brackets: {"arduino 1","arduino 2","arduino 3}.

We iterate through this array using the for function. For each item in the array, we call the
printString function, which is defined at the end of this sketch.

The printString function accepts three parameters: the string we want to write on the string,
the horizontal (x) start position and the vertical (y) start position:

void printString(char* toPrint, int x, int y)


You may also remember that void means that this function does not return a value, it just
does something (like write text on the screen) and then finishes.

Inside printString, there is a single call to the setStr function, just like we saw in the
setup() function earlier.

Now you know how to write text on the screen!

Peter Dalmaris

Lecture 25

Arduino Step by Step

Demo 2: Use the buttons

In this second demo, Ill show you how to use the 5 buttons that are integrated into the
joystick that comes with the shield.

Heres the sketch (continues to next page):

#include <ColorLCDShield.h>

#define BACKGROUND BLACK


#define C_COLOR RED
#define M_COLOR GREEN

!
!
!

LCDShield lcd;
int buttonPins[5] = {A0, A1, A2, A3, A4};
void setup()
{
/* Set up the button pins as inputs, set pull-up resistor */
for (int i=0; i<5; i++)
{
pinMode(buttonPins[i], INPUT);
digitalWrite(buttonPins[i], HIGH);
}
pinMode(10, OUTPUT);
analogWrite(10, 1023); //PWM control blacklight
/* Initialize the LCD, set the contrast, clear the screen */
lcd.init(PHILLIPS);
lcd.contrast(40);
lcd.clear(BACKGROUND);
lcd.setStr("STARTING", 50, 0, C_COLOR, BACKGROUND);
delay(1000);
lcd.clear(BACKGROUND);
}

void loop()
{
takeInput();
printString("Waiting...", 50,10);
}

void sayHello() {
char* Str4[ ] = {"arduino 1","arduino 2","arduino 3"};

for (int i=0;i<3;i++)


{
printString(Str4[i], 15 * i,0);
}

Peter Dalmaris

Lecture 25

Arduino Step by Step

!
void printString(char* toPrint, int x, int y)
{
lcd.setStr(toPrint, x, y, M_COLOR, BACKGROUND);
}

void takeInput()
{
if(!digitalRead(buttonPins[0]))
{
lcd.clear(BACKGROUND);
printString("LAST INPUT: 0", 100, 0);
}
if(!digitalRead(buttonPins[1]))
{
lcd.clear(BACKGROUND);
printString("LAST INPUT: 1", 100, 0);
}
if(!digitalRead(buttonPins[2]))
{
lcd.clear(BACKGROUND);
printString("LAST INPUT: 2", 100, 0);
}
if(!digitalRead(buttonPins[3]))
{
lcd.clear(BACKGROUND);
printString("LAST INPUT: 3", 100, 0);
}
if(!digitalRead(buttonPins[4]))
{
lcd.clear(BACKGROUND);
printString("LAST INPUT: 4", 100, 0);
}
if(!digitalRead(buttonPins[5]))
{
lcd.clear(BACKGROUND);
printString("LAST INPUT: 5", 100, 0);
}
}

Lets look at the dierences between the sketches for Demo 1 and Demo 2.

!
!
10

Peter Dalmaris

Lecture 25

Arduino Step by Step

Heres the first one:

int buttonPins[5] = {A0, A1, A2, A3, A4};

Here, we declare an array that will contain references to the five Arduino analog pins that
convey the status of the five buttons that the LCD shield provides. These five buttons are
integrated into a mini joystick soldered onto the PCB, next to the screen. We could refer to
these buttons using individually declared variables, like we have done in previous sketches.
But because we have several, it is more convenient to bundle them in a single array, and
then cycle through this array in order to set them up or to read their values using and
reusing the same code.

That is what we do in the very beginning of the setup() function:

for (int i=0; i<5; i++)


{
pinMode(buttonPins[i], INPUT);
digitalWrite(buttonPins[i], HIGH);

Here, we are cycling (looping) thew the contents of the array that contains the references to
the button pins, and first setting them as inputs, second turning on their pull up resistor.
This pull-up resistor (the opposite of the pull-down resister we saw earlier in this course),
keeps the voltage of the switch to high. When we close the switch by pressing it, the
voltage goes down, and the Arduino (guided by the code in the takeInput() function)
detects the event.

In the loop() function, we constantly call the takeInput() function and then calling the
printString function.

We have seen the printString function in Demo 1, so lets jump to takeInput() instead.

There, we individually examine the state of each button. When you push the joystick to the
side, one of the buttons creates a connection to Ground, so the digitalRead function
returns FALSE. Using the ! operator, we inverse this FALSE value and get TRUE instead.
We the if function, we examine this value, and if it turns out to be TRUE, the Arduino will
continue within the block and execute any instructions in it, like to clear the screen and
write some text in it.

So there you have it, you now know how to use the TFT LCD screen shield with the
Arduino. But there is more to learn. Best learn with an exercise.

Exercise

Have a look at the examples that come with the ColorLCDShield library. Can you figure out
how to draw a line, a rectangle and a circle?

11

Lecture 28
Keypad
Keypads represent an intuitive way for people to
provide input to gadgets and computers. Youll find
them in elevators, microwave ovens, TV remote
controls, phones, and countless other machines that
we interact with daily.

Sooner or later you will need to provide


alphanumerical input to your gadgets via a keypad,
and in this lecture Ill show you how!

Keypads come in a variety of sizes and styles. Some


are using push buttons, others use touch buttons.
Some are organised in 3 rows with 3 columns each,
others with 3 rows and 4 columns, and others with 4
rows and 4 columns.

Regardless of all that, most keypads you are likely to


use in your projects consist of an array (or matrix) of
buttons, and wiring that connects them to connectors
so that when a button is pressed, a circuit closes. A
device that reads the keypad is responsible for
figuring out which key was pressed by monitoring the
state of these circuits.

Have a look at this diagram. If you press key 3, then


a circuit that connects column 3 and row
1 is created. Current will flow through
this circuit, and some voltage dierential
will be generated. The device that
receives input from the keypad will
somehow detect this dierential and
determine that key 3 was pressed.

In this lecture, I will demonstrate how to


connect a common 4x4 keypad that
contains the numbers, letters A, B,
C, and D, a * and a #. I will do it
in two ways. First, Ill use the keypad
library that comes with the Arduino IDE
in a sketch that reads the keypad, while
the keypad is connected in parallel,
1

which means that all column and row wires from the keypad are connected to 8 of the
Arduinos digital pins.

Because this way of connecting the keypad is extremely wasteful of our precious digital
pins (the Arduino Uno only has 13), in demo 2 I will show you how to hack together a
solution that allows for a connection that uses a single signal pin.

Demo 1: easy but wasteful

In the first demo, well plug a 4x4 matrix keypad


directly into the Arduino, and configure the
sketch so that the correct symbol appears
when a button is pressed.

The ugly schematic on the right represents a


keypad with 4 rows and 4 columns. It connects
to the outside world with 8 wires, four for the
rows and four for the columns on which the
keys are placed. The blue wires connect the
rows to Arduino digital pins 2, 3, 4 and 5, and
the yellow wires connect the columns to
Arduino pins 6, 7, 8, and 9.

You can see that this way of connecting a


single peripheral device is easy but very
wasteful. Theres not many pins left for sensors
or other peripherals like LCD screens or
Ethernet adaptors. So well just play along for
now and understand how the keypad works
with the Arduino at its simplest configuration,
and then, in Demo 2, well have a look at a more
real-life configuration.

Once the connections are done, the circuit depends solely on the software side to figure out
which button has been pressed and to display the right symbol in the monitor.

Lets have a look at the sketch now.

#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the symbols on the
char hexaKeys[ROWS][COLS] =
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[COLS] = {2, 3,
byte colPins[ROWS] = {6, 7,

buttons of the keypads


{

4, 5}; //connect to the row pinouts of the keypad


8, 9}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad


Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
void setup(){
Serial.begin(9600);
}
void loop(){
char customKey = customKeypad.getKey();
if (customKey){
Serial.println(customKey);
}
}

The Keypad library provides a few convenience functions that are being used in the sketch,
so we include it in the first line. I find that this library is not absolutely necessary for our
purposes, so in the second demo I am not going to use it.

Next, we declare constants for the number of rows and columns my keypad has. These
constants are used later in the keypad object constructor. A constructor is a special
function that we use to initialise an object in a program. Ill discuss this in a bit more detail
further down.

We also need a map that assigns a symbol to each of the buttons of the keypad. We do this
by declaring a 2-dimensional array, in which each element is a character (an item of data of
type char). A 2-dimensional array is simply an array in which each element is another
array. In other words, think of it as an array within an array. To declare this array, we used
this syntax:

char hexaKeys[ROWS][COLS]

The first part is the data type of the data that the array holds in its cells, i.e. char. Next,
hexakeys is the name of the array. Finally, [ROWS][COLS] define the size for this arrays

two dimensions. Remember that at the very beginning of this sketch we defined the
constants ROWS and COLS? Well, heres the first place were these constants are being used.

To keep things simple, in the same line we also initialise the array with the data it will hold.
We do that by using curly brackets to delimit the arrays rows, and commas for the
columns.

rows by brackets
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}

columns by commas

};

Your keypad may have a dierent key layout, so this array is the place were you define the
mappings of keys vs symbols.

Before we can use the Keypad library, we need to define the digital pins on the Arduino
where the keypads row and column pins are connected. To do this, we create two arrays
that hold single bytes in each cell, rowPins[COLS] and colPins[ROWS]. Within the brackets,
we insert the values we stored in the two constants at the start of the sketch. Bytes are
integer numbers that range from 0 to 256.

We could have used the int data type to define these arrays here, but that would have been
a waste of several bytes in Arduinos limited memory. Each int occupies 2 bytes, even
though we only need 1 to store the small numbers that represent the values reported at
digital pins we use to connect the keypad.

Finally, we can go ahead and initialise the keypad object that we will be used to get the key
presses. We give this object a name, customKeypad, and a type, Keypad. We then use a
constructor function which has the same name as the type of the object. This is not by
chance: In the Arduino language, which is standard C with added libraries, a constructor is
a function with the same name as the name of the class. We know that calling such function
will create an object for that class, store it in memory, and return a pointer (or handle) to it
so that we can use it. A class can have several constructors, each accepting a dierent set
of parameters. The keypad library only has a single constructor though, so this is not an
issue here (see documentation).

So, to initialise the keypad, we pass the key map array, rowPin array, colPin array, number
of rows and number of columns to the constructor.

Then, we can make use of the keypad object by calling its getKey function in a loop to
read any keys pressed. This is what happens in the loop() function, where the Arduino
repeatedly calls customKeypad.getKey(). When you press any key on your keypad, this
4

function will return something that is other than null (null is a data type that represents
nothing - which means that in C, nothing is something!).

In the next instruction, the function if evaluates the data that getKey returned, and if it is
not null it will evaluate it as true, causing the block within the curly brackets to be executed,
and the symbol that corresponds to the key pressed to be displayed in the IDE monitor.

So there you go, in just a few lines of code (but with many wires), you can connect and use
a keypad with your project! But can we make our hardware more ecient?

Yes we can!

Demo 2a: a bit of extra work, but ecient

Occupying most of the Arduinos digital pins just for the keypad is not an ecient use of our
hardware. Although Demo 1 was simple to put together and make it work, it isnt good
enough for practical use. In Demo 2a and 2b, well improve the design so that a single pin is
used on the Arduino to transmit button pressing information.

Well do this using two dierent scripts, but the same hardware design.

Lets start with the hardware.

Have look at the schematic. First to notice


is that there is only one wire (orange) that
connects the breadboard to the Arduino
(the black and red are for power). The
connected pin is analog 0. This is really
nice, as from the 8 digital pins we used in
demo 1 we have reduced the count to just
1!

Next to notice is that the breadboard is


now fairly busy, with a series of resistors
and diodes arranged in rows and columns.
With the assistance of these resistors, what
we are doing is that when a button is
pressed, current flows through a unique
path that includes a unique combination of
one of the vertical resistors and one of the
horizontal resistors. The combined
resistance is unique, in the sense that no
other key press can match it exactly.
Therefore, that voltage as sampled by the
Arduino analog pin 0 will be unique for
each button. Based on that voltage, the
Arduino will be able to detect the identity of
the key that was pressed.

R4

R1

This table in the next page contains the


values for each resistor. When you
assemble this circuit, try to find resistors
that come close as much as possible to
these values. It is unlikely to find an exact
match because in resistors, the advertised rating is an approximation of the actual rating. In
Demo 2a, I will show you the kind of problems that this kind of imperfection creates, and in
demo 2b a way to go around it.

In the table below (left), R1 is the first resistance from the right in the schematic, R2 is the
next one to the left, and so on (counter-clock wise).

R1

1K

R2

2.2

R3

3.3

R4

220

R5

480

R6

680

R7

1.5K

A representation of the way that resistors were connected to the keypad matrix is shown
above (right). Imagine that you press one of the keys, and that current flows through the
circuit that was just created. Only two of the resistors will be included in this circuit.
Pressing any other key will engage two dierent resistors, in a unique combination. So, the
voltage produced at the analog input pin will be unique to each resistor combination
engaged by each button pressing.

Therefore, it is important to pick resistors with particular values so that we can guarantee
that there are no two keys that can produce the same voltage at the Arduinos analog input.

Next, lets have a look at the sketch that decodes these voltages and assigns them to a
symbol.

Heres the sketch (next page).

String keys=123A456B789C*0#D"; //define the symbols on the keypad as a string


int key;
//holds the index position of the key pressed
//in the keys string
boolean key_lockout=false;
//Helps to prevent multiple press
void setup(){
Serial.begin(9600);
}
void loop(){
key=getKeypad();

//call the getKeypad function to see if there was


//a key press
//if there was a key press, print the key symbol

if(key!=-1)
Serial.println(keys[key]);
delay(10);
}
int getKeypad(){
int ret=-1;

//define the variable to hold the calculated


//key symbol position. Initialise with -1 which
//indicates no key pressed

if(analogRead(A0)==0)
key_lockout=false;
else if(!key_lockout){
delay(20);
Serial.println(analogRead(A0));
ret=15-(log((analogRead(A0)-183.9)/58.24)/0.1623)+0.5; //calculate the key symbol
//position based on a formula with magic numbers
key_lockout=true;
//Lock the key to avoid multiple key detection
}
return ret;
}

This script approaches the problem of detecting the key pressed by applying a calculation
(highlighted in red) to the voltage measured in analog pin 0. The result of the calculation is
an integer that represents an index to the keys string that contains the key symbols. So, if
you press key 1, then the voltage measured in analog pin 0 will generate a reading that
once applied to the formula, will generate an index value 0. In the keys string, the symbol at
index 0 is 1.

The numbers in this formula are magic in the sense that they were calculated to
specifically match the resistors that we use in the circuit. If any of the resistors are slightly
o their advertised value, than this formula will not be able to reliably detect which keys
were pressed. Indeed, in my experiment, this happened.

Go ahead and try it your self. Some of the keys will work, but some others will not.

The lesson to take away is that although this solution is elegant (a single calculation
encapsulates the key detection logic), we have too many dependencies to worry about, and
that those dependencies are out of our control to calibrate (unless you have the ability to
create and solve an array of complicated dierential equations).

Demo 2b: less elegance, more control

So, instead lets go for a solution that is less elegant, but allows us to calibrate our circuit for
the resistors that we have in hand. I use resistors with advertised values as in the resistor
table from the previous section, but without the expectation that they are perfect. I will
show you how to deal with the variations and how to calibrate the circuit so that key
presses are identified correctly.

char* keypressed = 0;
int keyboardPin = 0;
int keyboardValue = 0;

// Analog input pin that the keypad is attached to


// value read from the keypad

void setup(){
Serial.begin(9600);
}
void loop(){
keyboardValue = analogRead(keyboardPin); // read the keyboard value (0 - 1023)
while (keyboardValue < 5){
//do nothing until a key is pressed
keyboardValue = analogRead(keyboardPin);
delay(50);
}
readkeyboard(); //get the value of key being pressed "keypressed" i.e. 0-9
}

//CONTINUES IN NEXT PAGE

Sketch, part 1

I have split the sketch in two parts. In part 1 we take a reading from analog pin 0 and if it is
valid (that is, it is not less than 5 in the pins 0 to 1023 range1), then it will call the
readkeyboard() function that will evaluate the reading and determine which key was
pressed.

As you will see in part 2, the lowest value we measure in analog pin 1 in my implementation was 242. This
means that instead of 5, we could set a value up to 241 in the test for valid keyboard input. None of this is set in
stone, however, so I can experiment for a while until I find values that are reliable and produce stable results.
1

//read the keyboard routine


void readkeyboard(){
keyboardValue = analogRead((keyboardPin)); // read the value (0-1023)
Serial.print("Pin value:");
Serial.println( keyboardValue);
if ((keyboardValue >842) && (keyboardValue < 845)){keypressed = "1";}
if ((keyboardValue >735) && (keyboardValue < 738)){keypressed = "2";}
if ((keyboardValue >639) && (keyboardValue < 642)){keypressed = "3";}
if ((keyboardValue >516) && (keyboardValue < 518)){keypressed = "4";}
if ((keyboardValue >474) && (keyboardValue < 476)){keypressed = "5";}
if ((keyboardValue >432) && (keyboardValue < 435)){keypressed = "6";}
if ((keyboardValue >349) && (keyboardValue < 351)){keypressed = "7";}
if ((keyboardValue >329) && (keyboardValue < 331)){keypressed = "8";}
if ((keyboardValue >309) && (keyboardValue < 311)){keypressed = "9";}
if ((keyboardValue >257) && (keyboardValue < 259)){keypressed = "0";}
if ((keyboardValue >269) && (keyboardValue < 272)){keypressed = "*";}
if ((keyboardValue >=245) && (keyboardValue < 247)){keypressed = "#";}
if ((keyboardValue >598) && (keyboardValue < 600)){keypressed = "A";}
if ((keyboardValue >416) && (keyboardValue < 419)){keypressed = "B";}
if ((keyboardValue >303) && (keyboardValue < 305)){keypressed = "C";}
if ((keyboardValue >242) && (keyboardValue < 245)){keypressed = "D";}
while (keyboardValue > 25) {
delay (100);
keyboardValue = analogRead((keyboardPin)); // read the value (0-1023)
} //wait until key no longer being pressed before continuing
Serial.println(keypressed);
delay(1000);

// print the value back to the Serial view window on your PC


// wait 1000 milliseconds before the next loop

Sketch, part 2

In the second part of the sketch, we look at the function that evaluates the input
measurement from analog pin 0, and determines which symbol matches the key that was
pressed.

The function starts with taking a fresh measurement from analog pin 0. Note that we could
have reused the original measurement that was taken while in the loop() function by passing
it as a parameter to the readkeyboard function. Maybe you can try out this modification on
your own once you get this version working properly.

The function then goes into a series of comparisons. It is trying to find a matching symbol
by evaluating the measurement against maximum and minimum values for each symbol.
These maximum and minimum values can be determined by trial and error. Heres how it
can work:

10

In the third line of the function, we print the measured value to the monitor. Press key 1 a
few times to see what values come out. Make a note of the maximum and minimum values.
In my implementation, the output was always within the range of 842 and 845 (not
inclusive). Yours might dier. So, take these values and use them to edit the if statement
for value 1 accordingly. What you will have is something like this:

if ((keyboardValue >842) && (keyboardValue < 845)){keypressed = 1";}

This means that if keyboardValue is greater than 842 AND keyboardValue is less than 845,
then the key that was pressed represents symbol 1. The operator && is a boolean AND,
which means that both expressions around it must be true in order for the combined
expression to be true.

Repeat this process for every key in your keypad, then do some thorough testing to make
sure there is no overlap. An overlap would cause at least one value to be possible for more
than one key. If this happens, the Arduino would always return the last match as the
corresponding symbol.

Another thing to notice is that in my implementation, each of the keys has a tolerance of 2
or 3 units, out of 1023. This is very precise spacing between the keys, which means that we
potentially have room to decode a keyboard with more keys.

Maybe another time.

Exercise

In this lecture you learned not only about how to connect a keypad to your Arduino, but
also gained some skills in calibrating your project to match exactly your specific
configuration. You also discovered that there is a range of possible solutions to the same
problem, and that solutions dier in terms of elegance and practicality.

I think you are ready now for your most challenging exercise to date.

For this project, you will need:

1. A keypad

2. An LCD screen

3. A light intensity sensor (photoresistor)

4. A DHT22

5. An Arduino

Build a project that combines these components, and works like this:

1. If the user presses key 1, the LCD screen displays the temperature.

11

2. If the user presses key 2, the LCD screen displays the humidity.

3. If the user presses key 3, the LCD screen displays the light intensity.

4. If the user presses key A, the LCD screen will say hello.

12

Peter Dalmaris

Lecture 33

Arduino Step by Step

Lecture 33
Ethernet

So far in this course, our Arduino has been capable of communicating only with its host
computer. And that communication was very limited: upload the sketch from the host
computer to the Arduino, and sent text messages from the Arduino to the computer via the
USB serial interface.

We would like to do much more with communications, and in this lecture I will show you
how to get your Arduino gadget to speak to the Internet!

There are several ways to make this work. In this lecture we will look at the Ethernet shield,
which represents the easiest (while still very capable) method. There is also Wifi, which is
technically very similar to Ethernet but wireless. I will leave wifi aside for another time.

Ethernet is the most common Local Area Network (LAN) technology around. You probably
have an Ethernet device in your home connecting your computers, printers, storage servers
etc together and to the Internet via a router.

The easiest way to add Ethernet


capability to your Arduino is via
the Ethernet shield. When this
shield was added to the
Arduinos product line up, it
opened up a world of
possibilities: your project could
now be connected to the Internet
and be part of the Internet of
Things, an Internet where
devices are represented as
virtual objects with which people
or other objects can interact. For
example, your Internetconnected fridge could report its temperature and alert you in case of malfunction, or you
garden watering system could log the soil humidity levels to an online logging service like
xively.com (more about this later in Lecture 38).

I personally find the Internet of Things a fascinating concept, and people come up with all
sorts of applications to show what is possible to do this Universe. Heres some examples of
people have done: http://postscapes.com/internet-of-things-examples/

!
!
1

Peter Dalmaris

Lecture 33

Arduino Step by Step

Demo 1: Quick setup

In this demonstration, I will show you how to connect your Ethernet shield, and how to
make your Arduino part of your local
network. Specifically, I will show you how
to connect to the network by automatically
acquiring an IP address via DHCP, or how
to acquire an IP address manually. For
each connection, your Arduino will report
the connection attributes in console.

You need:

Arduino Uno

Arduino Ethernet Shield

If you are using an Arduino Uno, then the Ethernet shield will fit perfectly on top of it. Note
that the Ethernet shield comes equipped with a mini SDcard slot. You can use this feature to make it possible
for your sketches to read data from files (like images,
CSS files etc), or for writing data onto files. For
example, you could store output from sensors in a log
file for later processing, of for uploading to an external
service periodically.

One more thing I want to quickly discuss before moving


onto the demo is that the Ethernet shield is not strictly
needed to connect your Arduino to your LAN. Especially
if you want to deploy your completed gadget in a small
package and for a slightly smaller cost, you could choose to use an Ethernet break-out
board instead, which contains only the bare essentials for providing Ethernet functionality. I
will not discuss this breakout board in this lecture, but leave it for another time.

So, plug the shield onto the Arduino, no wiring required. This is what you end up with:

Peter Dalmaris

Lecture 33

Arduino Step by Step

!
Done with the hardware!

Lets have a look at the first Ethernet sketch. This sketch simply makes the Arduino a
member of the LAN and waits for someone to connect to its Telnet server. When a client
sends it a message (simple text), the server will simply send it back to the client (echo).

I will discuss several concepts related to how Ethernet LANs work rather than being
specific to the Arduino, so please bear with me if you are already familiar with them (or just
skip ahead to Demo 2).

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.


// The IP address will be dependent on your local network.
// gateway and subnet are optional:
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
IPAddress ip(192,168,1, 177);
IPAddress gateway(192,168,1, 1);
IPAddress subnet(255, 255, 0, 0);
EthernetServer server(23); // telnet defaults to port 23
boolean gotAMessage = false; // whether or not you got a message from the client yet

void setup() {
Serial.begin(9600); // Open serial communications and wait for port to open:
while (!Serial) { // this check is only needed on the Leonardo:
; // wait for serial port to connect. Needed for Leonardo only
}

// start the Ethernet connection:


Serial.println("Trying to get an IP address using DHCP");
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
Ethernet.begin(mac, ip, gateway, subnet); // initialize the ethernet device
// not using DHCP:
}
Serial.print("My IP address: );
// print your local IP address:
ip = Ethernet.localIP();
for (byte thisByte = 0; thisByte < 4; thisByte++) {
Serial.print(ip[thisByte], DEC); // print the value of each byte of the IP address:
Serial.print(".");
}
Serial.println(); // start listening for clients
server.begin();

This sketch is one of the samples that come with the IDE. You can load it by going to
File > Examples > Ethernet > DhcpChatServer.
3

Peter Dalmaris

Lecture 33

Arduino Step by Step

At the top of the sketch we have the inclusions of the SPI and Ethernet libraries. The SPI
library provides the functions necessary for the Ethernet shield to communicate with the
Arduino using the SPI bus. The Serial Peripheral Interface bus is a full-duplex

void loop() {
EthernetClient client = server.available(); // wait for a new client:
if (client) {
// when the client sends the first byte, say hello:
if (!gotAMessage) {
Serial.println("We have a new client");
client.println("Hello, client!");
gotAMessage = true;
}

char thisChar = client.read(); // read the bytes incoming from the client
server.write(thisChar);
// echo the bytes back to the client
Serial.print(thisChar);
// echo the bytes to the server as well
}

communications standard created by Motorola to allow simultaneous two-way


communication between a master (in our case, the Arduino) and multiple slaves (for this
shield one slave is the Ethernet adaptor and the SD card). We are not going to worry about
how SPI works since the Ethernet library hides these details from us. Using the SPI library
directly is a topic for another lecture.

For a device to be a member of a LAN, it needs to have three pieces of information:

1) A MAC (Media Access Control) address, which is the physical (hardware) address of the
network controller. This is a bit like the VIN number of a car, or the serial number
marked at the back of your TV. The Ethernet protocol uses this address to figure out
which device is sending a message and who the recipient is supposed to be. The
Arduino Shield also has such an address, and it should be printed somewhere in the
packaging or on an insert sheet of paper. Look up yours and copy the information in
header of the sketch:

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };

Cant find your controllers MAC address? No problem. I have also lost mine. Chances
are that if you only have one Arduino Ethernet shield in your network, you will be just
fine by using the MAC address from this example. As long as there are no two
controllers with the same MAC address, the shield will work. If you suspect there is a
conflict, just change one of the fields of the mac[] byte array. For example, this should
also work (change in red):

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x03 };

Peter Dalmaris

Lecture 33

Arduino Step by Step

2) The IP (Internet Protocol) address is the address that any device connected to the
Internet needs to have. The IP address is also known as logical address because it
can be assigned to the device dynamically, unlike something like the MAC address
which need to be hardwired or at least statically defined (which is what you did in the
previous item). In most networks, including (most likely) your own home network, there
is a service called DHCP (Dynamic Host Configuration Protocol), which makes it
possible to just plug in an IP device and have it made part of the LAN by leasing it an IP
address (among other things). In your network, if you can just plug in your computer
and access the Internet, there are 99.999% chances that your network has a DHCP
server running. In the unlikely case that you dont, then configure your Ethernet shield
with a unique (for your network) IP address like this:

IPAddress ip(192,168,1, 177);

In my case, I had to make a change to this address (change in red):

IPAddress ip(192,168,111, 177);

That is because my LAN has addresses in the block 192.168.111.1 to 192.168.111.255.


This information is usually defined by your home network router, so you will need to
look at its settings. There are too many variations of this scenario to cover here, so if
anyone if having problems with this, post me a message.

3) Next up is the gateway. The gateway variable holds the IP address of the device to
control access to the outside world, a.k.a. the Internet. If your Arduino needs to access
a web server or web service outside your LAN, it will need to know who to ask for
access, and that is the gateway. If there is a DHCP service running in your network,
than this is a piece of information that the DHCP will provide (I will explain how this
happens in a minute). If not, or if you just want to have a fallback, you can specify this
in this line:

IPAddress gateway(192,168,1, 1);

Again, I had to edit this setting because in my network the gateway is at a dierent
address (change in red):

IPAddress gateway(192,168,111, 1);

If you are on Windows, to find out your default gateway, try out this: http://
answers.yahoo.com/question/index?qid=20100221132909AA7jMQk

On Mac, look at Preferences > Network > (Your network controller).

Linux people, I think you already know what yours is ;-).

Peter Dalmaris

Lecture 33

Arduino Step by Step

4) The last required network configuration is the subnet mask. Because the possible IP
addresses (and hosts) in a single network are 2 in the power of 32, we find it much
easier to split this pool of addresses in small parcels, and deal with each parcel as a
separate network. The subnet mask is the bit of information we need in order to know
how our network has been split. In the example, the default subnet mask is:

IPAddress subnet(255, 255, 0, 0);

Notice the two zeros at the end? This means this network allows 8 + 8 = 16 bits for the
host addresses, which means 2^16 hosts. That is 65,536 hosts. In my network, I have
lots of computers but not THAT many, so instead I am using this subnet mask:

IPAddress subnet(255, 255, 255, 0);

This allows me to allocate 255 IP addresses in my network. Thats enough for most
home networks, and most likely what your network is using too.

So that how we setup out sketch so that our Arduino becomes part of the LAN.

In the next instruction, we create an object for a server:

EthernetServer server(23);
A server is an object that constantly listens for messages send to it by clients that connect
to a particular TCP port. The parameter we specified here, 23, represents one of 65,536
such ports. We could have chosen any one of those ports, however because we will be
using Telnet in minute, its best to keep things simple and use the default port for Ethernet.
In lecture 34, we will setup a web server to run on the Arduino, so the default port for that
will be 80.

Because we want the server to only do something when a message is received, we declare
a boolean variable to keep track of these events:

boolean gotAMessage = false;


When a message is received, gotAMessage will be changed to true and this will be picked
by the server later on to send a copy of the message back to the Telnet client.

In the setup() function we first initialise the Serial connection to the IDE monitor, and then try
to setup the Ethernet controller. This instruction is very important:

Ethernet.begin(mac)
This tries to contact a DHCP server and lease an IP address, as well as to get information
about the gateway and subnet mask. If a DHCP server responds, then any values it
provides will be used to setup our Ethernet adapter. But, if the begin(mac) function fails (it
6

Peter Dalmaris

Lecture 33

Arduino Step by Step

will return a 0 if it does), then the sketch will initialise the Ethernet adaptor by using the
default values we provided at the start of the sketch.

Once this process is complete, the sketch will print out the allocated IP address. The
function

Ethernet.localIP();
returns the IP address as an array of bytes, and in the loop that follows the sketch converts
each field in that array to its equivalent decimal:

Serial.print(ip[thisByte], DEC);
Finally, at the end of the setup() function, the Sketch starts the Telnet server:

server.begin();
Now the server is active and just waiting for a message to arrive. We test for incoming
messages in the loop() function.

First, we check that a client is attempting to connect by calling the available function of
the server object, and if there is, we assign it to a new client object of type EthernetClient:

EthernetClient client = server.available();


If the client just became connected, the greet it!

Otherwise, read the transmitted character and copy it to both the serial port, and to the
server object so that it is displayed to the user via the Telnet console.

To try out this connection, start up a console (command line) and type this1:

telnet 192.168.111.61

which works for my Arduino ethernet shield, and you will probably need to adjust for
your settings. You should see something like this:

If you are using Windows, especially Windows 7, read this article for a guide on how to enable Telnet client on
your computer: http://social.technet.microsoft.com/wiki/contents/articles/910.enabling-telnet-client-inwindows-7.aspx
1

Peter Dalmaris

Lecture 33

Arduino Step by Step

When I start typing random characters, these are echoed back to my console (to the right,
with the black background):

You can see that every character I type is copied both to the monitor using the
Serial.print(thisChar) function as well as the Telnet console using the
server.write(thisChar) function. But on the console side, every character I type appears
twice: once for my original key press, and the second for the response from the server.

Dont worry about the text garbage that appears in the monitor. Well worry about this later.
For now, congratulations, you made your first Ethernet connection through your Arduino!

Demo 2: Control an LED


and read a photoresistor through a
Telnet connection
Echoing characters is a decent first step,
but we always want more! I would really
like to be able to control this hardware!

So in this demo I will show you how to


turn on and o an LED, and to read light
intensity through a Telnet connection to
your Arduino from your computer.

You need:

Arduino Uno

Arduino Ethernet Shield

Photo-resistor

LED

1K resistor

Peter Dalmaris

Lecture 33

Arduino Step by Step

jumper wires

Lets add the LED and photo-resistor to our circuit.

Lets see what this we are trying to achieve with this circuit before looking at the sketch.

. . . This part is omitted because it identical to Demo 1 . . .


int ledPin = 2;
String commandString;

void loop() {
EthernetClient client = server.available(); // wait for a new client
commandString = "";
if (client) {
// when the client sends the first byte, say hello
if (!alreadyConnected) {
client.flush(); // clear out the input buffer
commandString = ""; //clear the commandString variable
server.println("--> Please type your command and hit Return...");
alreadyConnected = true;
}
while (client.available()) {
char newChar = client.read();
// read the bytes incoming from the client
if (newChar == 0x0D) // If a 0x0D is received, a Carriage Return,
// then evaluate the command
{
server.print("Received this command: ");
server.println(commandString);
processCommand(commandString);
} else
{
Serial.println(newChar);
commandString += newChar;
}
}
}
9

Peter Dalmaris

Lecture 33

Arduino Step by Step

When a user connects via Telnets, they can type commands for the Arduino to execute. In
this version of the sketch there are three commands, but you can add as many as you
want.

Type photo, and the Arduino will respond with a reading from the photo-resistor. If you
type ledon, it will turn the LED on, and if you type ledo it will turn the LED o. Anything
will give you the instructions:

And now to the sketch:

void processCommand(String command)


{
server.print("Processing command ");
server.println(command);
if (command.indexOf("photo") > -1){
Serial.println("Photo command received");
server.print("Reading from photoresistor: " );
server.println(analogRead(0)); //Print the integer returned by analogRead
//to the server object
commandString = "";
return;
}
if (command.indexOf("ledon") > -1){
server.println("LED On command received");
digitalWrite(ledPin, HIGH);
// sets the LED on
server.println("LED was turned on");
commandString = "";
return;
}
if (command.indexOf("ledoff") > -1){
Serial.println("LED Off command received");
digitalWrite(ledPin, LOW);
// sets the LED off
server.println("LED was turned off");
commandString = "";
return;
}
commandString = "";
instructions();
}

void instructions()
{
server.println("I don't understand");
server.println("Please use one of these commands:");
server.println("* photo, to get a reading from the photoresistor");
server.println("* ledon, to turn on the LED");
server.println("* ledoff, to turn off the LED");
}
10

Peter Dalmaris

Lecture 33

Arduino Step by Step

The first part of the sketch is identical to the one in Demo 1, except for the declaration of
the ledPin integer, which contains the pin number where the LED is connected, and the
string commandString which will hold the last command we send to the Arduino.

In the loop() function, we wait for a client to connect, just like in Demo 1. Once we have a
connection, we clear the commandString variable to get it ready to store a new command.
If a client is not already connected, i.e. a new one just got connected, the clean the input
buer to make sure theres no garbage from previous connections, print out a message to
the client to let them know the Arduino is ready to receive a command, and change the
alreadyConnected variable to true.

What happens next is the most interesting part of this sketch. Here it is:

Because the Telnet connection is a serial connection, whatever command we type is


transmitted to the Arduino one character at a time. The sketch must store all these
characters as they arrive but wait until a line feed or carriage return is given before it can
evaluate the command. The client.read() instruction take a character at a time and stores
it in the newChar variable. The the sketch evaluates this character. If it is something other
than a Carriage Return, it will append it at the end of the commandString variable and wait
for the next character. But if it is a carriage return (which is the hexadecimal 0D character in
the ASCII system which Telnet uses) then it will print out the command it captured and cal
the processCommand function to evaluate it.

In processCommand (next page), the sketch checks to see if the command given matches any
of the three valid commands (photo, ledon, ledo). It does that by using a string
function:

command.indexOf(photo")
The indexOf function checks to see if the string photo exists in the string stored in the
command variable. If it does, it will return a positive integer number, but if it doesnt it will
return -1. If you want to expand the repertoire of commands for your Telnet server, just add
new blocks that test for the new commands using the indexOf function.

The content of each command block should be self-explanatory, but do ask me if


something doesnt make sense.

Once a command is found, we want the sketch to execute whatever code is in its block and
then continue listening for new commands instead of trying to match. That is why we
include the return statement at the end of every block: we want to stop the command
evaluation there.

If none of the commands available match the command we issued, the Arduino will call the
instructions function which will print out a set of instructions.

Simple!

11

Peter Dalmaris

Lecture 33

Arduino Step by Step

So what did you learn in the lecture? Quite a lot! You got through the fundamentals of
connecting a host to an Ethernet LAN and to the Internet, and you learned about getting the
Arduino connected to your LAN. But most important, you learned about controlling simple
components connected to your Arduino using Telnet. It only takes one more step to
connect to your Arduino using Telnet from the Internet, which will allow you to control your
LED, your motors, or whatever else is connected to it from anywhere in the world. Thats
the Internet of Things!

You can do this by making a configuration change to your home router and enable port
forwarding. Wikipedia has a good article to help you understand what this is, and this web
site contains an extensive list of modem/routers with specific instructions for each model.
Hopefully yours will be in this list. In a nutshell, port forward allows a user from the Internet
to access a server running inside a LAN without exposing this server to the Internet.

Exercise

I hope you are feeling excited now! How about you try out these exercises to stretch your
skills a little more

1. Add a DHT22 to your Demo 2 setup, and extend the repertoire of commands of the
Telnet server so that it also returns the temperature and humidity.

2. Add an LCD screen which displays the IP address of your Arduino when it starts up and
connects to the network. Once connected, the LCD screen displays the commands it
receives from the Telnet client.

12

Peter Dalmaris

Lecture 35

Arduino Step by Step

Lecture 35
A simple reporting web server

The Web is an open and well understood technology for disseminating information.
Equipped with an Ethernet shield, your Arduino can host a simple web server to which
clients can connect and interact with.

In the simplest of cases, an Arduino web server will be used to report readings from its
sensors to whomever is asking. In this lecture, well look into the scenario of using a web
server running on the Arduino that reports values from its sensors. We will do this reporting
in two dierent modes: First, for humans to view using HTML, and second for machines to
read where the data reported will be formatted as simple comma separated values.

Before we get started with the demos, lets go through a really quick discussion on running
a web server on the Arduino.

!
Principals of Arduino web servers
!

The Arduino is a remarkable piece of hardware, but it isnt build to be a full blown web
server. It has a single tiny processor with very limited memory when compared to build-forpurpose web servers. And this processing power is really optimised for dealing with
sensors and input/output components, not with the kind of processing that a web server is
required to do.

Another limitation is the programming language. The Arduino language is standard C with
added libraries, like the Ethernet library we saw in lecture 33. It is a bare-minimal language
that is fairly close to the hardware so that it can be compiled eciently for the AtMega
micro-controllers, and as a result it doesnt have the kind of programming sugar that highlevel languages like Ruby and PHP have. This sugar makes it a lot more easier for
programmers to build elaborate web applications with relative ease when using, for
example, Ruby, as opposed to C.

For example, take images. A jpeg image you might find in a simple web site may be 15 or
20Kbytes. The Arduino Uno only has room for 32KBytes in its RAM, so the image will not fit
and we will need to store it in an SD card or on another web server and make a reference to
it from the Arduino sketch.

What about SSL encryption? This is a standard feature for most non-trivial web sites these
days, but the Arduino simply does not have the computational power required to support
SSL.

These reasons, in a nutshell, require that any server we host on an Arduino, be it a web
server, a telnet server, or anything else, has to be minimal.

Peter Dalmaris

Lecture 35

Arduino Step by Step

!
Minimal, because we dont have much memory to spare, because programming anything
more complicate will take a lot of programming eorts, and because we want to maintain
CPU resources for sensing and control, rather than reporting.

However, with all that said, it is possible to interface the Arduino with a more capable
computer and ooad to that computer the more elaborate features we would like to enrich
our Arduino-power web site with.

Here is a possible architecture for something like this:

With this kind of arrangement, you use the Arduino for sensing and control. You also have a
very simple web server running on it, like the one well see in this lecture. But instead of
opening it up to the whole world, you allow only a single client to connect to it. The green
device in the middle of this schematic is a Raspberry Pi, a single board computer that costs
around $45. Yes, this is an actual computer which can run Linux, and that means that you
can have a full-blown web server on it build with a high-level language. You can build your
application on the Raspberry Pi (or similar) so that clients from the Internet will connect to it,
and use it as a proxy for your Arduino. This architecture makes it possible and easy to have
an Arduino-powered web site with SSL, graphics, CSS, and all the bells and whistles to
which we are accustomed.

Showing you exactly how to do this, is a topic for another lecture though. Just know that it
is possible for the time being.

With these points in mind, lets go ahead and have a look at an Arduino bare-minimal web
server.

Demo 1: The essential Arduino web server

In this Demo, Ill show you how to setup a basic reporting web server on your Arduino. Well
look at the simple web server from one of the examples that come with the IDE. In Demo 2
well make a few changes to it so that it reports data from a humidity/temperature sensor,
and a photo-resistor.

Peter Dalmaris

Lecture 35

Arduino Step by Step

To assemble the hardware, just plug the Ethernet shield on the Arduino. The sketch we will
play with takes measurements from the analog pins and shows them in a web page. You
can connect whatever analog sensors you have handy, but that is not necessary. In the
absence of actual sensors providing readings, the values on the analog pins will be random.
To load this sketch, go to File > Example > Ethernet > WebServer.

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.


// The IP address will be dependent on your local network:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);

// Initialize the Ethernet server library


// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}

!
!

// start the Ethernet connection and the server:


Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());

This block of the sketch is familiar: it is identical to the definition and setup parts of the sketch in
Lecture 33. It sets up the Ethernet connection and a server. The only dierence is that in this sketch,
the server will be listening for connections on TCP port 80 (highlighted in red).

The next block is a lot more interesting. It is there where the parsing logic of a web server is
implemented. Have a quick read but dont spent too much time on it for now. There is something
else I should show you first before the parser can make sense.

!
!
!
!
!
!
!

sketch continues next page

Peter Dalmaris

Lecture 35

Arduino Step by Step

void loop() {
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
boolean currentLineIsBlank = true;
// an http request ends with a blank line
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed
//after completion of the response
client.println("Refresh: 5"); // refresh the page automatically
// every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
// output the value of each analog input pin
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = analogRead(analogChannel);
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
client.print(sensorReading);
client.println("<br />");
}
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disonnected");
}
}

Peter Dalmaris

Lecture 35

Arduino Step by Step

Parsing a HTTP request

Web pages travel from web server to web client on top of HTTP: the Hyper Text Transfer
Protocol. This protocol has certain rules which web servers and clients must abide by if
they are to work together. A web server or client parser is a computer program that knows
how to understand HTTP. When your web browsers send a request to a web server, it
makes a HTTP request.

Lets have a look at what a HTTP request looks like first.

Ill use Requestbin, requestb.in, a website that shows me the bare content of a HTTP
request, a kind of X-ray vision for the Web. Visit this site, and you will see this:

Click on the green button, this will create a RequestBin for you, which is a URL to which
you can send an HTTP request.

Go ahead, create a new RequestBin.

Peter Dalmaris

Lecture 35

Arduino Step by Step

As a response, you will see something like this (next page):

!
In the Bin URL box, you have exactly that, a URL to which you can send HTTP requests.

In a new window or tab of your web browser (keep the page above handy), copy/paste the
URL in the Bin URL box, and hit Enter.

You will get something like this:

!
!
This just means that RequestBin received your HTTP request. Now go back to the tab or
window that contains the Bin URL box and refresh it. You will see something like this:

(see next page)

Peter Dalmaris

Lecture 35

Arduino Step by Step

!
What you see here are the raw contents of your HTTP request. In the red box, I have
highlighted the most important part of this request for our present discussion: It is the first
line that your web browser trasmitted to the server. It starts with a verb, in this case GET,
and a path for the resource that was requested, in this case pebptxpe.

There are other bits of information provided here, like in the headers section.

All this is text that the Arduino will have to parse in order to correctly respond to a clients
request.

Back to our first example now

Our Arduino sample web server sketch is only programmed to identify the end of a client
HTTP request, and then to send out its HTTP response.

Peter Dalmaris

Lecture 35

Arduino Step by Step

According to the HTTP protocol, a HTTP GET request must end with a blank line. In the box
below, you can see the complete HTTP GET request, and the last blank line.

GET / HTTP/1.1

Host: 192.168.111.177

Connection: keep-alive

Cache-Control: max-age=0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36


(KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36

Referer: http://192.168.111.177/

Accept-Encoding: gzip,deflate,sdch

Accept-Language: en-US,en;q=0.8,el;q=0.6

blank line

This blank line is identified by this statement in the sketch:

if (c == '\n' && currentLineIsBlank)

This means: if the current line is blank and the current character is a new line, then the
expression is true, so the sketch will go ahead and print its response.

The boolean currentLineIsBlank is there to keep track of new lines: when a new line
character is found (\n), then currentLineIsBlank becomes true. When anything else is
found, it becomes false. This is happening in this code block:

if (c == '\n') {
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}

So, the Arduino, will know that the HTTP request is finished if it finds two new lines (\n)
are found, one right after the other.

You may need to read these last coupe of pages a few times before you continue, but
before doing that, consider this: we did all this just so that we can detect when a HTTP
request has finished so that the server can respond. We havent done any serious parsing
yet!!!

Peter Dalmaris

Lecture 35

Arduino Step by Step

Creating the response

This request is more like a trigger, it asks the server to send back whatever it wants to send.

For the server to send a response back, it needs to be formatted in accordance with the
HTTP rules. A response needs to start with a response header, followed by the response
body.

This code implements the response header:

client.println("HTTP/1.1 200 OK");

client.println("Content-Type: text/html");

client.println("Connection: close"); // the connection will be closed after completion of the


response

client.println("Refresh: 5"); // refresh the page automatically every 5 sec

client.println();

In the first line, the server sends a 200 HTTP code, which tells the client that it understood
its request and there is no problem to worry about. Always nice to hear that!

Next line informs the client of the type of content that will be following in the body of the
response. In this case, it will be HTML text.

Next, the server tells the client that once it sends what it has to send, it will close the
connection. If the client needs something else, it will have to initiate a new connection via a
new HTTP request.

Next line contains a non-standard instruction. Refresh tells the browser to send a new
GET request to the server in order to get an updated page. Most browsers are able to
understand this instruction, even though it is not a standard HTTP instruction.

Finally, the server prints a new line. Dont forget that! In order for the client to know that the
HTTP response header has completed its transmission, there has to be a blank line!

The body of the response follows, and the Arduino will construct the HTML for it line-byline. Heres the code for this:

client.println("<!DOCTYPE HTML>");

client.println("<html>");

// output the value of each analog input pin

for (int analogChannel = 0; analogChannel < 6; analogChannel++) {

int sensorReading = analogRead(analogChannel);

client.print("analog input ");

client.print(analogChannel);

client.print(" is ");

client.print(sensorReading);

client.println("<br />");

client.println("</html>");

break;

Peter Dalmaris

Lecture 35

Arduino Step by Step

The first bit of text printed to the client stream is the HTML declaration. This is not actually
an HTML tag, but an instruction to the browser informing it about the version of HTML used
in the page that follows.

The actual HTML follows. You can see that there is a for loop that samples the analog
ports, and the prints out their captured values to the client stream.

When the loop ends, we close the HTML page.

Finally, there is a break statement. This breaks the while loop that started with the while
(client.connected()) instruction earlier. The sketch is about to close the connection by
calling the stop() function of the client object, but before doing so it waits for 1 millisecond
for the client to finish receiving the response.

Upload the sketch and fire up your browser. Visit your Arduinos web site, and this is what
you should see:

I have not connected any sensors to the analog ports, so the values you see here are
random.

With this detailed discussion on getting a web server running on the Arduino for simple
reporting, lets go ahead and try out a simple modification from this basic example sketch.

Lets connect a humidity and temperature sensor, and a photo-resistor, and report the
values they report through our web server using HTML and CSV. The HTML will be useful
for humans, while the CSV is more machine-friendly.

10

Peter Dalmaris

Lecture 35

Arduino Step by Step

Demo 2: Practical reporting for humans and


machines

In this demo, I would like to use my trusty DHT22 and photo-resistor sensors. I would like
to be able to use my web browser and get readings from the sensors like this:

If a machine makes the same request, I would like it to receive this response instead:

The two sketches that correspond to these


two scenarios are almost identical. The only
dierence is that one outputs HTML, while
the other one outputs text as commaseparated values.

Heres the hardware schematic:

It includes the DHT sensor connected to


digital pin 2, and a photo-resistor with a
10K resistor as voltage divider connected
to analog pin 0.

Have a look at the HTML version of the


sketch in the next page.

11

Peter Dalmaris

Lecture 35

Arduino Step by Step

first part of this sketch is omitted because it is identical to Demo 1


void loop() {
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
if (c == '\n' && currentLineIsBlank) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println("Refresh: 5");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
int sensorReading = analogRead(0);
client.print("analog input ");
client.print(0);
client.print(" is ");
client.print(sensorReading);
client.println("<br />");
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(t) || isnan(h)) {
Serial.println("Failed to read from DHT");
}
else {
client.print("Humidity: ");
client.print(h);
client.println("<br />");
client.print("Temperature: ");
client.print(t);
client.print(" *C");
client.println("<br />"); }
client.println("</html>");
break;
}
if (c == '\n') {
currentLineIsBlank = true;
}
else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
delay(1);
// close the connection:
client.stop();
Serial.println("client disonnected");
}
}

12

Peter Dalmaris

Lecture 35

Arduino Step by Step

!
What is new in the sketch compared to the one in demo 1 is highlighted in red. The new
sketch just takes readings from the DHT sensor and from the analog pin 0 and prints them
out in the client stream.

What about the CSV version of the sketch?

Just replace the red block with this:

int sensorReading = analogRead(0);


client.print(sensorReading);
client.print(",");
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(t) || isnan(h)) {
Serial.println("Failed to read from DHT");
}
else
{
client.print(h);
client.print(",");
client.print(t);
}

We removed any printouts of HTML tags, and add commas to delimit the values.

Although it is out of scope for this lecture, it is worth mentioning that for transmitting simple
values like the numbers in this example, the CSV format is a very ecient of going about
sending data from one machine to the other.

Conclusion

You covered a lot of ground in this lecture. You learned about how HTTP requests are
structured, and how the Arduino can host a very simple reporting server. There were a lot of
details involved, but what I think would be most useful to remember is the fact that a web
server is essentially a parser of text which interprets HTTP requests and responses.

Although the examples in this lecture did not do much parsing other than figuring out where
a HTTP request ends so that a responds can be sent, what you learn will prove very useful
in the next lecture. In that lecture, you will learn about creating a server that parses a
request so that it can find out the specific parameters of what is it that it is being requested
to do. You will learn, for example, how to get the server (i.e. the Arduino) to turn on the LED
at pin 9. I call this kind of server controlling, because it allows you to control the Arduino
via the web, not just to get readings of its status.

!
13

Peter Dalmaris

Lecture 35

Arduino Step by Step

Exercises

Try to add a couple of sensors of your choice to the HTML version of the Demo 2 sketch.
Adjust the sketch so that the values are printed nicely to the client. If you have CSS skills,
perhaps improve the looks of the output by incorporating some styling to the page that the
Arduino generates.

14

Peter Dalmaris

Lecture 37

Arduino Step by Step

Lecture 38
A simple controlling Arduino web server

In Lecture 35, you learned about the basics of parsing HTTP requests and you implemented
a simple web server. I referred to that web server as reporting because it was build to only
report the values of pins on the Arduino but did not oer any way of changing their state.

In this lecture, I will show you how to setup a web server on the Arduino that does just that.
A user will be able to connect to the Arduino using their web browser and turn LEDs on and
o. You could replace the LEDs for other devices, like motors, without having to introduce
significant changes to the sketch well see here. We will actually do this in the next lecture
on web-based motor control.

Just like in lecture 35, we first need to look at the HTTP request parsing issues that we will
need to deal with before implementing the controlling web server sketch. Because the web
browser will be sending information with instructions to the Arduino, the Arduinos web
server HTTP parser will have a lot more work to do.

Lets go through the demo, and start by looking at how HTTP deals with data going from
the client to the server.

Demo: controlling LED via HTTP

Sending data to a web server can be done in two ways: GET and POST.

Parsing a GET request

Simply speaking, in a GET request, the data that you want to send, travels to the server as
part of the URL. When you go to your browsers URL field, type in a URL like google.com
and hit the Enter key, you are triggering an HTTP GET request.

So, here is an example. If I want to sent a message to my Arduino asking it to turn the LED
in pin 8 on, I could put this in the URL:

http://192.168.111.177/?pinD8=1
In this example, you can recognise the first part of the URL, in black. It is simply the
protocol followed by the IP address of the web host, which is my Arduino. After the slash,
there is a green question mark ?. I am using this character as a marker for the location in
the URL where the instructions I want to sent begin. The parser running on my web server
on the Arduino will be looking out for this special character and once it finds it, it will start
looking with great interest for whatever follows.

The part in red is the actual instruction. I have chosen to keep things very simple, and use a
protocol that provides me some flexibility for future changes of the parser as my
requirements change. In the current iteration, my protocol says that a command should
1

Peter Dalmaris

Lecture 37

Arduino Step by Step

start with the three characters pin, followed by an integer, followed by an equal sign =,
followed by another integer. Once the parser in the web server encounters the ?, it will
then start looking for the pin instruction. Whatever character comes next will signify the
type of pin we want to manipulate. After that is an integer which signifies the pin number
that we want to manipulate. And finally, after the = character, any integer that the parser
finds signify the value that we want to write to this pin.

In the example above, I am asking the web server to write value 1 to digital (D) pin 8. If I
wanted to write value 32 to analog pin 2, according to my protocol, I would issue this URL:

http://192.168.111.177/?pinA2=32
Simple, right? The current version of the sketch that is published on Github only supports
the first example, but later on we will discuss the parser itself and you will see that
changing it to accommodate the second example is very easy.

Now, lets have a look at the raw information that travels to the Arduinos web server. This
will help us figure out exactly what is it that the parser will need to work with. To look at the
raw contents of the GET request, Ill use Chromes Inspect Element feature. We first had a
look at this really nice tool in Lecture 33.

This is what I see:

Peter Dalmaris

Lecture 37

Arduino Step by Step

To access the source of the GET request, go to any page, right click anywhere on the page,
and select Inspect Element. Then, click on Network. Click on a link on the page to trigger a
GET request, and observe how several new rows are added to the box in the right side of
the Inspect Element pane. Each one represent an HTTP request. Click on any of them to
get the requests details. The Request Headers section displays a nicely formatted view of
the information that the GET request transmitted to the server. This view is nice, but we
want to know EXACTLY was is it that the web server received, so click on view parsed to
switch to the raw view of the headers.

What you see now is what the server sees. In the case of my example, notice that the first
line (in the blue box) contains the word GET, which is the HTTP verb for this kind of
request, followed by /?led8=1. This matches the second part of the URL I typed in the
browser, right?

Well, yes, this is the simplest way to transmit data with instructions to the server. The parse
can ignore anything else below the first line (unless it is interested to know, for example,
who is sending the request, what kind of browser is used, etc.).

Parsing a POST request

An alternative to post, is to use the POST HTTP method. This method transmits the user
data to the server in the body of the message instead of the URL. This is nice in case you
dont want your user to be able to see exactly what is being transmitted. It is also preferable
if you have lots of data to transmit, since the number of characters you can fit in the URL is
limited. Lets have a look at a POST request and spot the dierences between it and a GET
request.

To switch my example from using the GET method to using the POST method, I change the
form HTML element method attribute to POST:

<form action="http://requestb.in/16pydf71" method="POST" target="_blank">


<input type='hidden' name='pin8' value='0'><input type='submit' value='Off'/>
</form>
<form action="http://requestb.in/16pydf71" method="POST" target="_blank">
<input type='hidden' name='pin8' value='1'><input type='submit' value='On'/>
</form>
The rest of the code is identical. When I click on either the On button or the O button, the
data is submitted to Request Bin (requestb.in) so I can inspect the details of the request.

Here is what I see when I click on one of the buttons:

!
3

Peter Dalmaris

Lecture 37

Arduino Step by Step

!
First and foremost, in the request header and in the URL, my data is nowhere to be seen.
However, looking at the Form Data, which is the segment of the POST request that exists in
the body of the request, I can see the data I submitted. Everything else is the same.

The conclusion of all this is that this little dierence between GET and POST requests
means that parsing a POST request is significantly harder than parsing a GET request, and
will take much longer to complete on the Arduino. While in a GET request, the information
we are sending is available in the very first line and right after the HTTP verb, for a POST
request it is tacked way down in the document. The Arduino and the parser will have to
search for this information by first scanning every single character that precedes it. This fact
alone means that there will be a significant impact on performance, not to mention the
significant programmer unhappiness (to say the least) that is unavoidable when you try to
write and debug code like this.

Bottom line: Avoid POST requests unless you really have to, and even then consider
alternatives!!!

!
!
4

Peter Dalmaris

Lecture 37

Arduino Step by Step

On with the Demo!

Well be using a circuit that has two LEDs,


a red and a yellow, the Ethernet shield, and
the Arduino.

!
!
!
!
!
!
!
!
!
The sketch that well use
implements this web page
(right).

Click on the On button, and


the LED connected to
digital pin 8 will light up.
Click on the On button, and
the same LED will turn o.

I have only implemented the


buttons for one of the two LEDs in the circuit. I left the implementation of the second set of
buttons for you to do as an exercise.

Peter Dalmaris

Lecture 37

Arduino Step by Step

Sketch

This sketch is larger than those we have seen so far. Because of this, I have added several
functions that help with the added complexity by packaging functionality in individual
functions. For example, there is special function that creates the header of the servers
response, another one that generates the HTTP form part of the web page that the server
returns, and one that implements the parser, to name a few.

Have a read first, and well discuss.

#include <SPI.h>
#include <Ethernet.h>

byte
byte
String

mac[]
ip[]
message

EthernetServer server(80);
String
get_request
boolean
reading

= { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };


= { 192,168,111,177 };
= "";
//Will hold the confirmation message
//that will be shown to the user
= "";
= false;

//Holds the GET request


//TRUE while the GET request is being received

void setup()
{
Serial.begin(9600);
Ethernet.begin(mac, ip);
server.begin();
Serial.println("ready");
}

void construct_page(EthernetClient &client, String &rmessage)


{
print_header(client);
print_form(client);
print_confirmation(rmessage, client);
end_page(client);
}

void print_header(EthernetClient &client)


{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.print("<html><head><title>");
client.print("GET request example");
client.println("</title><body>");
}

void print_confirmation(String &confirmation_message, EthernetClient &client)


{
client.print("Action(s) performed: <b>");
client.print(confirmation_message);
client.print("</b>");
}
6

Peter Dalmaris

Lecture 37

Arduino Step by Step

!
void print_form(EthernetClient &client)
{
client.println("<h2>Click buttons to turn pin 8 on or off</h2>");
client.print("<form action='/' method='GET'><p><input type='hidden' name='led8'");
client.println(" value='0'><input type='submit' value='Off'/></form>");
client.print("<form action='/' method='GET'><p><input type='hidden' name='led8'");
client.print(" value='1'><input type='submit' value='On'/></form>");
}
void end_page(EthernetClient &client)
{
client.print("</body>");
client.print("</html>");
}

String parseGetRequest(String &str) {


Serial.print(" Parsing this string:");
Serial.println(str);
int
led_index = str.indexOf("led");
int
led_pin
= str[led_index + 3] - '0';
int
led_val
= str[led_index + 5] - '0';
String return_message = "";
return_message = "Setting LED ";
return_message += led_pin;
return_message += " to ";
return_message += led_val;
executeInstruction(led_pin, led_val);
return return_message;
}

void executeInstruction(int pin, int val)


{
pinMode(pin, OUTPUT);
digitalWrite(pin, val);
}

!
the loop function is shown in the next page

!
!
!
!
!
7

Peter Dalmaris

Lecture 37

Arduino Step by Step

void loop() {
EthernetClient
client = server.available();
String return_message;
if (client) {
Serial.println("new client");
boolean sentContent
= false;
get_request
= "";
boolean
currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char
c = client.read();
if(reading && c == ' ')
{ reading = false;
parseGetRequest(get_request);
break;
}
if(c == '?'){
reading = true; //found the ?, begin reading the info

if(reading){
get_request += c;

if (reading && c=='\n')


{
break;
}
if (c == '\n' && currentLineIsBlank)
break;
}
if (c == '\n') {
currentLineIsBlank = true;
}
else if (c != '\r') {
currentLineIsBlank = false;
}

}
}
if (!sentContent){
construct_page(client, return_message);
sentContent = true;
}
delay(1);
client.stop();
Serial.println("client disonnected");
}
}

Peter Dalmaris

Lecture 37

Arduino Step by Step

Sketch disassembly

A lot is happening here, and much of this sketch you have not seen before.

Lets take it from the start.

The first few lines are familiar as thats where the EthernetServer object is being setup with a
MAC and IP address.

I am declaring a String called get_request in which the sketch will store the actual
instructions send by the GET request. For example, if my browser sends out this:

http://192.168.111.177/?pinD8=1
then the value that will be stored in the get_request variable will be pinD8=1. The work
for extracting this string from the HTTP request and storing it in this variable is done in the
loop() function as well see in a minute.

After the get_request declaration, I am setting up a boolean variable called reading. This
variable is true when the loop() function detect the ? symbol in the HTTP request. The ?
symbol, as you may remember from earlier, is used as a market that signifies the beginning
of the part of the URL that contains the instructions that the user is sending to the server.

Next are the definitions and code of several functions, starting with construct_page. This
function makes calls to other functions that implement the basic components of the
response web page (i.e. the page that the web server returns to the browser):

The header, implemented by the print_header function,


The HTML form part of the page, implemented by the print_form function,

The part of the page that contains a confirmation message for the user, implemented by
the print_confirmation function,

The ending tags of the HTML page, implemented by the end_page function.

Have a look at these functions and you should see recognisable HTML. The print_header
function is slightly dierent because it also contains the HTTP response header, with the
first two lines carrying the HTTP declaration and content type, then a blank line. The HTML
document follows.

Also have a good look at the print_form function. I have created one form per button
because when a button is clicked on I only want a single value-pair to be sent to the server.
Also notice that the form method attribute is set to GET, not POST.

You can notice that each of these functions receive one or two parameters. The
construct_page function received two parameters:

Peter Dalmaris

Lecture 37

Arduino Step by Step

The first one is called client, is of type EthernetClient. The & means that client is
actually a pointer to the memory location where the object of type EthernetClient is
stored. If we dont use this & modifier, the Arduino will actually create a copy of this
object and pass it to the function. Because memory is at a premium, we dont want to
make copies of objects for which we can simply pass around a pointer, so that is what is
happening here and anywhere else you see the & modifier.

The second one is another pointer, this time pointing to a memory location where a String
object is stored. The String rmessage contains the confirmation message that will be
shown to the user.

Now, lets move our focus to the loop() function.

Its starts as we have seen in the previous two Ethernet lectures, by acquiring a client. It
also declares a String variable that will be used later to store a message that will be
returned to the user.

Once it acquires a client, it will declare and initialise the sentContent boolean variable. This
variable is used so that for every client only a single response is sent. For a new client, the
sentContent variable is set to false, to indicate that a response has not yet been sent.
Once, at some point in time later, a response is sent, the this variable will be set to true.

Next, the get_request String is set to empty, getting it ready for the new instruction.

There is also another boolean declared and initialised to true. Its currentLineIsBlank, and
is used to remember a blank line when one is found. This is needed because according to
the HTTP protocol, a GET request ends with a blank line, which also ends with a new line
(\n).

What does currentLineIsBlank do?

Do a quick scan a few lines further down, and you will find this code:

if (c == '\n' && currentLineIsBlank) {


break;
}
if (c == '\n') {
currentLineIsBlank = true;
}
else if (c != '\r') {
currentLineIsBlank = false;
}
If a new line is found (c==\n), then we have a new line and currentLineIsBlank is set to
true, otherwise its set to false. If we have already found a blank line, and now we have
another one, then break out of this while block of code because we have reached the end
of the GET request and there is nothing else that the server needs to look into.

10

Peter Dalmaris

Lecture 37

Arduino Step by Step

The while loop

In the while loop, the Arduino assembles the instructions send by the web browser.

The client.connected() statement is true for as long as the client is sending data to the
server or there is still data for the server to read even if the client has disconnected. This
function, therefore, ensures that the server reads everything the client sends. With this
statement in a while loop, we ensure that the Arduino will keep reading data until everything
has been read.

The client.available() statement, returns the total available (not yet read) number of bytes
that the client has sent to the server. Because we are not interested in the actual number of
bytes but rather the fact that there are still bytes to be read by the server, we put this
statement in an if block.

The while and if functions make up the framework of the web server. Inside this
framework, the server will scan for instructions.

Scanning for instructions

It starts by grabbing the next byte from the byte stream send by the client and storing it in a
local char variable:

char

c = client.read();

A series of if statements follows, each checking for a particular pattern.

In the first check, it looks for the case where the Arduino is reading an instruction (reading
variable is true) AND the current character c is one white space . If this happens, then the
String variable get_request has captured the instruction sent by the client, and the sketch
will call the parseGetRequest function to parse it. It will then break the while block
because it is not interested in anything else that the client has sent. Why did I choose to
stop the parsing of the request here?

Remember that the first line of the GET request looks like this:

GET /?led8=1 HTTP/1.1


I am only interested in the red string. While the red string is being red, the boolean variable
reading is set to true. And while this is true, the c variable will eventually read the white
space character in between the 1 and the H. This is the signal that there is nothing else
to be read, so parsing can stop right here to stop wasting resources. If you wanted to read
some of the metadata that follow you could choose to not break here but to continue
reading. I will come back to the parseGetRequest function in a minute.

Next test that happens is the one that checks for the ? character that signifies the
beginning of the string that carries the client instruction. As soon as the Arduino hits this
character it sets reading to true.

11

Peter Dalmaris

Lecture 37

Arduino Step by Step

Next, it tests that the Arduino is currently reading an instruction. If this is true, it will append
the current character to the get_request String variable. The operator += is the append
operator, and adds whatever is given in the right side of the expression to the existing
contents of the variable.

The last three tests in this block we have already discussed so I will not repeat here.

In summary, the while-if loop goes through the data that the client sends to the server and
grabs the only thing our server is interested in, the instruction component of the URL. Once
it does that, the while loop breaks.

If the response has not yet been sent, then the construct_page function will be called to
do so. A 1 millisecond delay is inserted to give enough time to the client to complete
receiving the response, and then the connection is closed.

The instruction parser

The only function left to discuss is the parseGetRequest function. Its job is to receive
something like led8=1 and figure out what it means.

We have already discussed the pattern used here: the string led followed by a letter,
followed by an integer, followed by the = sign, followed by an integer.

This function implements this pattern definition in code.

int
led_index = str.indexOf(led): The indexOf function searches for the
string led inside the string str. If it finds it, the first position of the match is stored in
the led_index integer variable.

int
led_pin
= str[led_index + 3] - 0: Add three to the led_index (since the
string led contains three characters) and return the character at this position after
subtracting 0. What is happening here is ASCII arithmetic. A string like led8 is made
up of chars. According to the ASCII system (which the Arduino observes), character 8
corresponds to decimal number 561. However, what I want this expression to return is the
actual number 8, not the ASCII equivalent of character 8. So, I adjust the formula so that
it subtracts 48 from it, which is the ASCII value for character 0. And I have 56-48 = 8. If
the client had sent led6 instead, that this expression would have evaluated 54-48 = 6.

int
led_val
= str[led_index + 5] - 0: Now add 5 to the led_index so that
the value after the = sign is returned. Again, we need to adjust for the ASCII values, so
the expression subtracts the ASCII value for 0 from the character at index led_index + 5.

In the next 5 lines, the function constructs the response that will be sent to the user as part
of the HTML page.

Have a look at the ASCII table at http://ascii.cl

12

Peter Dalmaris

Lecture 37

Arduino Step by Step

And finally, action is taken by setting the LED on or o by calling the executeInstruction
function.

Conclusion

If all this has caused you a headache, I understand. You have created a web server, and
even though it is capable of understanding only simple GET requests, this is not a trivial
matter.

But I encourage you to stick with it, go through the sketch a few times on your own, change
things and learn from whatever you break. This sketch also has a lot of room for
improvement.

Feel free to post a questions if you need help, and suggestions for improvement if you have
any.

Learning is best done by doing, so try out the exercises.

Exercises

1. Upload the sketch to your Arduino, and use your browser to access it. Click one of the
buttons and make sure that the LED in pin 8 is working. Notice that according to the
Demo schematic, there is an LED in pin 7, but there is no button for it. Hmm First,
make sure that you can turn it on and o by editing the URL directly. Change this:
http://192.168.111.177/?led8=0 to this http://192.168.111.177/?led7=0. I have
highlighted the dierence in red. Can you edit the sketch so that the web page contains
an on button and an o button for the LED in pin 7?

2. For the more adventurous in you, can you edit the sketch, and specifically the
parseGetRequest and executeInstruction functions so that you can also control the
analog pins? think about the change(s) that this will require in the string pattern that the
parser will need to understand.

3. Modify the sketch so that the server will be able to both receive an instruction (like in
the default sketch) but also to report the values from a couple of sensors of your
choice. Imagine that you are building a home automation system. You want to be able
to close a window shutter by turning on a DC motor, and to confirm that the light
intensity inside the room is reduced by reporting the value of an attached photoresistor.

13

Peter Dalmaris

Lecture 37

Arduino Step by Step

14

Peter Dalmaris

Lecture 40

Arduino Step by Step

Lecture 39
Motor control through a web server

In the previous lecture, you learned about controlling the state of a digital pin through
sending GET requests with your web browser.

What if you had to control two pins at once, and if you had to send over values other than
1s and 0s?

In this lecture, Ill show you how to do something like that by demonstrating how you can
control a DC motor through your web browser.

You may remember from lecture 20, that to properly control a DC motor you need two bits
of information: speed and direction. So, in this demo, we will look at how we can send
speed and direction information to the Arduino from the browser encoded in a GET request.

This makes for slightly higher parsing complexity on the Arduino, but nothing that we cant
handle by building on our current knowledge.

Demo: motor control

In this demo, well implement a


circuit like the once from
lecture 20, that controls 2 DC
motors through an L298N
motor control break-out board.

You may want to review Lecture


20 for a detailed reminder of
the connections. Note that I am
using a battery pack instead of
an external power supply to
power the motors.

Instead of using a
potentiometer knob to control
the speed and direction of the motors, well use a web user interface composed of radio
buttons (see image in next page).

Each radio button, when clicked, sends direction and speed values to the Arduino via HTTP.
The web server running on the Arduino parses the HTTP request and isolates those values
so that it can the requested control signals to the motors.

!
1

Peter Dalmaris

Lecture 40

Arduino Step by Step

In this image, also notice the structure of the URL. You may remember that in the previous
lecture, the URL was composes of two parts: the host address and the key-value pair
containing the data that the user sent to the Arduino web server. These two were separated
by the ? character (a delimiter we chose).

In this example, the same holds true. The dierence now is that we have two key-value
pairs after the ? delimiter, instead of one. And these two value pairs are delimited by the
& character.

Lets have a closer look at the URL from this example:

192.168.111.177/?speed5=122&direction4=0
Remember that the L298N motor control break-out board uses two pins to control a motor:
one for direction and one for speed. In the colourful example above (hopefully you are not
color blind!), in orange I mark the delimiters, purple mark the keywords, green are the pins,
and blue are the values. The web server will need to use the following logic in order to
extract the necessary information from this string of characters:

1. Look for the location of the ? character. This indicates that the instruction key-value
pairs follow.

2. Look for the keyword speed.

3. Read the character immediately after the keyword speed. Convert this character to an
integer value.

4. Look for the & character.

Peter Dalmaris

Lecture 40

Arduino Step by Step

5. Read the character(s) after the = and before the & characters. Convert these
characters to an integer.

6. Look for the keyword direction.

7. Read the character immediately after the keyword direction. Convert this character to
an integer.

8. Read the character after the = and before the end of the string. Convert this character
to an integer.

The code needed to implement this pseudo-code is slightly more complicated then the
one use in the previous lecture (where there was a single key-value pair to deal with), but I
promise it is not scary at all. Lets have a look at it next.

Sketch

Heres the sketch. Highlighted in red is the part that deals with analysing the two key-value
pairs. There are also changes in the function that generates the HTML, and the function that
executes the received instructions. Everything else is the same (I am including the whole
sketch for completeness).

#include <SPI.h>
#include <Ethernet.h>

byte
mac[]
byte
ip[]
String
message
will be shown to the user
EthernetServer server(80);
String
get_request;
boolean
reading
received

= { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };


= { 192,168,111,177 };
= "";
//Will hold the confirmation message that

//Holds the GET request


= false; //TRUE while the GET request is being

void setup()
{
Serial.begin(9600);
Ethernet.begin(mac, ip);
server.begin();
Serial.println("ready");
}

continues next page

Peter Dalmaris

Lecture 40

Arduino Step by Step

void loop() {
EthernetClient
client = server.available();
char return_message[30];
if (client) {
Serial.println("new client");
boolean sentContent
= false;
get_request
= "";
boolean
currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char
c = client.read();
if(reading && c == ' ')
{ reading = false;
parseGetRequest(get_request);
break; }
if(c == '?'){
reading = true; //found the ?, begin reading the info
}
if(reading){
get_request += c; }
if (reading && c=='\n')
{ break;}
if (c == '\n' && currentLineIsBlank) { break; }
if (c == '\n') { currentLineIsBlank = true; }
else if (c != '\r') { currentLineIsBlank = false; }
}
}
if (!sentContent){
construct_page(client);//, return_message);
sentContent = true;
}
delay(1);
client.stop();
Serial.println("client disconnected");
}
}

continues next page

Peter Dalmaris

Lecture 40

Arduino Step by Step

void construct_page(EthernetClient &client)


{
print_header(client);
print_form(client);
print_confirmation(client);
end_page(client);
}
void print_header(EthernetClient &client)
{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.print("<html><head><title>");
client.print("GET motor control example");
client.println("</title><body>");
}
void print_confirmation(EthernetClient &client)
{
client.print("Action performed: <b>");
client.print(get_request);
client.print("</b>");
}
void print_form(EthernetClient &client)
{
client.print("<form action='/' method='GET'>");
client.print("<h1>Forward Speed</h1>");
client.print("<input type='radio' name='speed5' value='0'
onclick='this.form.submit()'>Stopped</input>");
client.print("<input type='radio' name='speed5' value='63'
onclick='this.form.submit()'>1/4</input>");
client.print("<input type='radio' name='speed5' value='127'
onclick='this.form.submit()'>1/2</input>");
client.print("<input type='radio' name='speed5' value='184'
onclick='this.form.submit()'>3/4</input>");
client.print("<input type='radio' name='speed5' value='254'
onclick='this.form.submit()'>FULL!</input>");
client.print("<input type='hidden' name='direction4' value='0'>");
client.print("</form>");
client.print("</br>");
client.print("<form action='/' method='GET'>");
client.print("<h1>Backward Speed</h1>");
client.print("<input type='radio' name='speed5' value='254'
onclick='this.form.submit()'>Stopped</input>");
client.print("<input type='radio' name='speed5' value='184'
onclick='this.form.submit()'>1/4</input>");
client.print("<input type='radio' name='speed5' value='127'
onclick='this.form.submit()'>1/2</input>");
client.print("<input type='radio' name='speed5' value='63'
onclick='this.form.submit()'>3/4</input>");
client.print("<input type='radio' name='speed5' value='0'
onclick='this.form.submit()'>FULL!</input>");
client.print("<input type='hidden' name='direction4' value='1'>");
client.print("</form>");
}
5

Peter Dalmaris

Lecture 40

Arduino Step by Step

void end_page(EthernetClient &client)


{
client.print("</body>");
client.print("</html>");
}
void parseGetRequest(String &str) {
//We need to parse something like this: "?speed1=50&direction1=0"
Serial.print(" Parsing this string:");
Serial.println(str);
//We need to get the speed and the direction.
//Speed will have a value made of 1 to 3 digits.
//Notice the value-pair delimiter character: "&"
int delimiter_index = str.indexOf("&");
//Get the speed
int
speed_index = str.indexOf("speed");
int
motor_number = str[speed_index + 5] - '0';
//Here's, I am trying to avoid using the substring function because I have been
//having problems with it and it seems unstable.
//Instead, I just just an array of chars and copying the speed value from the
//str variable into the array of chars.
char speed_value_array[4];
for(int i = speed_index + 7; i < delimiter_index; i++){
speed_value_array[i - 8] = str[i];
}
int
motor_speed_value = atoi(speed_value_array);
//Get the direction
int
direction_number
= str[delimiter_index + 10] - '0';
int
direction_value = str[delimiter_index + 12] - '0';
executeInstruction(motor_number, motor_speed_value, direction_number, direction_value);
}
void executeInstruction(int motor_number, int motor_speed_value, int dir_pin, int direction_value)
{
pinMode(dir_pin, OUTPUT);
pinMode(motor_number, OUTPUT);
digitalWrite(dir_pin,direction_value);
analogWrite(motor_number, motor_speed_value);
//PWM Speed Control
delay(30);
}

In the printform function, the HTML form is constructed. I am using radio buttons instead
of regular buttons enhanced with an onClick Javascript event so that the form is
submitted when the user clicks on any of the radio buttons. Each radio input tag has a
name that is made up of a keyword (either speed or direction), and the number of the
pin it is meant to control. It also has a value attribute that contains a pre-determined value
that we want send to the Arduino when the radio is clicked.

The parseGetRequest function is rewritten. The parameter is a pointer (&) to the memory
location where the char array that contains the instruction is stored. The first thing that
happens here is to find the index position in that array where the key-value pair delimiter is

Peter Dalmaris

Lecture 40

Arduino Step by Step

stored (&)1, and keeps that value handy in the delimeter_index integer variable. To do
this, we use the indexOf function that is available to strings.

Then, in the same way, it looks for the location of the string speed in the char array str
and stores that value in the speed_index variable. The motor pin is 5 characters to the right
of the speed index, so we add 5 to the speed index to extract that value from the char
array. This gives us the motor pin value, and it gets stored in the motor_number variable. Up
to now, all this is identical to what we did in the previous lecture.

The next bit is slightly more challenging, because the value we need to extract, the motor
speed value, may be made up of 1, 2, or 3 characters. So, we dont know before hand the
beginning and end of the segment in the char array that contains this value. What we do
know, are the location of the first character (right after the = character), and the location of
the last character (right before the & character - delimiter). Here, I could have used the
substring function that is available to strings, which requires two parameters, the start and
end index of the substring that I want to extract. However, in my IDE version 1.0.5, this
function seems to have a bug in its implementation and I was not able to get it to work
reliably. So, I had to resort to a more basic (lower-level) solution, which involves looping
through the char array, picking one character at a time between the two index limits (after
= and before &), and storing each char in a temporary char array of size 4.

This array, speed_value_array, has a size 4 because the max number of chars I expect to
store in it is 3, and I need an extra char to the null character (\0). The null character
signifies the end of the string stored in the array, and is a C-language requirement.
Remember here, that you only need to provide enough space for this character, you dont
actually have to set the last cell of the array to null as this is done automatically at run time.

Also remember that in C (and all C-style languages that I know about), arrays are 0indexed. This means that the first cell index is 0, not 1. For this reason, the extracted value
is stored in speed_value_array like this:

speed_value_array[i - 8] = str[i];

Notice the i-8? Because the speed_index is always 1 (unless you change the order by
which the key-value pairs are encoded in the URL - dont do that yet!), I need to subtract 8
in order to store the first character extracted from the char array to index position 0 in
speed_value_array. If you wanted to make this code able to deal with the case of the
speed_index order being dierent to first, then you could write this:

speed_value_array[i - (speed_index + 1)] = str[i];

and it would work just fine.

it is only a coincidence that the C-language memory reference operator & is the same as the HTTP key-value
pair delimeter &.
1

Peter Dalmaris

Lecture 40

Arduino Step by Step

Last important point of discussion here is the atoi function: what we have now is a string
stored in an array of chars that contains the speed value. We need to convert this to an
integer, and the atoi is a C-language function that does just that. You give it a pointer to
an array of chars, and it gives you back an integer.

A similar method is used to extract the direction pin number and direction value from the
2nd key-value pair.

We know have all the necessary information, and the sketch goes ahead to apply the
instruction to the motor by calling the executeInstruction function and passing the
extracted values as parameters.

Feel free to read this a few more times in combination with the video. It will become clear
with a bit of experimentation. Feel free to ask questions if you get stuck anywhere.

Conclusion

In this lecture you learned about sending two key-value pairs that contain information for
updating the state of a connected device, a motor in our case. From here onwards,
complexity can, of course increase, but it can be managed with a bit of planning.

Exercises

I have two exercises to recommend here. The first one I rate as easy because you can
deal with it without having to expand on what you learned here.

The seconds one is harder because you have to go beyond what you learned here. You can
use the principles regarding designing a flexible URL structure, but after that you are on
your own.

Heres te exercises:

1. Adjust the web form segment of the sketch so that you can also control a second
motor. Imagine you had a toy car with two motors: one motor for moving forward and
backward, and one for left and right. Can you create a new version of the sketch so that
you can control the car from the web browser?

2. Create a sketch so that the parser can deal with 3 key-value pairs. For example,
imagine a URL like this: GET /?var1=10&var2=20&var3=30. How can you adapt the
parser we saw in the demo to extract all the information from this URL?

Peter Dalmaris

Lecture 40

Arduino Step by Step

Lecture 40
Logging on the web

You now know how to create a web server in order to monitor activity on your Arduino. This
is quite useful for real-time monitoring, where you want to know what is happening right
now with your sensors. But what if you wish to keep historical records of your sensor
readings so you can inspect an analyse later?

In that case you will need to somehow record these readings. Broadly speaking, there are
two ways to do this: you can record readings on-board the Arduino, by using an SD card
writer. Or, you can use an online service to which your Arduino can send its readings
periodically. From there, you can use your web browser to monitor in real time, plot
historical values on a chart, or download the data to your computer.

There are a few really nice services that allow you to do that, and in this lecture we will look
at Nimbits. Nimbits is a cloud service that allows you to log and retrieve data from all kinds
of devices, from Arduinos and Raspberry Pis to web server. Anything that generates data
needing logging can use Nimbits. Did I mention that Nimbits is open-source and free to use
by the community?

Another popular service is Xively, formerly known as Pachube. Xively provides a variety of
services, of which logging is just one. It has a dierent business model to Nimbits, and
while it allows free use by developers, it does have limits that an active Arduino hacker
could reach in no time.

In the second part of this lecture we will also look at logging your sensor data to Twitter.
Twitter is often useful not so much as a logging service (this would be a bit awkward), but
for its social broadcasting and direct communication capabilities. If you would like to
expose environmental data to the whole world to access, then Twitter is for you. Or, if you
want to receive a direct message as an alert when a sensor value exceeds a set limit, again,
you can use Twitter.

Peter Dalmaris

Lecture 40

Arduino Step by Step

Demo 1: Logging on
Nimbits

The hardware for this demo requires the


Arduino, the Arduino Ethernet shield, a photoresistor to use as the sensor, and a 10K
resistor to use as a voltage divider with the
photo-resistor. Feel free to use any other analog
sensor you have handy.

!
!
!
!
!
!
As a logging service, Nimbits provides several benefits:

1. Its managed, so you dont have to worry about maintaining it.

2. Its free, supported by ads, with an option to purchase an account in exchange for an
ad-free experience.

3. You can download the software and host your own Nimbits server should your project
requirements need a privately hosted logging service. This is an important futureproofing feature that significantly safeguards your time investment to this technology.

4. Every new record is timestamped, which means that your Arduino does not need to
maintain a clock.

5. It utilises a simple HTTP (REST) interface, which means that your Arduino can talk to
Nimbits without any special libraries.

So, lets get started.

!
continues next page

Peter Dalmaris

Lecture 40

Arduino Step by Step

First, get your account on Nimbits:

Click on the Login link. Nimbits uses Google for authentication and account creation, so if
you already have a Google account, you can go straight ahead and use it to logon.

Now you have an account, lets create a new Data Point to which you will be sending your
data, and a new Read/Write key to use for authenticating your Arduinos access to this data
point.

Peter Dalmaris

Lecture 40

Arduino Step by Step

Heres the starting point for the process that will follow: the Admin Console.

When you start fresh, the console will be blank.


Lets create a Data Point first:

1. The user interface can be a bit quirky. When you add a new element, it must be
attached to an existing element in the hierarchy. Since this is the first element/data
point to add, click first on your email address to select it, and then right click to get a
list of properties. Then, select New Data Point:

2. Give it a name and click Ok:

Peter Dalmaris

Lecture 40

Arduino Step by Step

3. Create one more data point in the same way. The sketch we will look at later will be
posting data to two data points.

4. Your Data Point is now ready to receive data once your setup your read/write key. You
can also edit its properties if you want to change its privacy settings, alert trigger levels, etc.
Highly recommended spending a bit of time to play with these.

!
Lets create a new read/write key and assign it to the newly created Data Point.

1. Right click on your newly created Data Point and click on New Read/Write Key:

2. Type some random text in the Key field, and leave to the default settings as they are:

Peter Dalmaris

Lecture 40

Arduino Step by Step

!
Keep the Key handy because you will need to use it in your Arduino sketch.

You are done! If you double click on the new Data Point, you will get a pop-up window with
your Data Point chart, which for now is empty.

Lets proceed with the Arduino side now. The sketch we will use is a slightly edited sketch
written by StewieT.

continues next page

Peter Dalmaris

Lecture 40

#include <SPI.h>
#include <Ethernet.h>
#include <PString.h>

Arduino Step by Step

// from http://arduiniana.org/libraries/pstring/
// allows 'printing' to a string buffer
// larger than required for this example, resize to suit

char buffer[400];
your application
char content[200];
// larger than required for this example, resize to suit
your application
PString str(buffer, sizeof(buffer));
PString cont(content, sizeof(content));

int ana_A ;
int ana_B ;

// variables to store analog samples

!
!

/************ ETHERNET STUFF ************/


byte mac[] = { 0xDE, 0xAD, 0x45, 0xEF, 0xFE, 0xED };

// adjust these to suit your local setup.


byte ip[] = {192,168,111,177 };
byte nameserver[] = {192,168,111,1 };
byte gateway[] = {192,168,111,1 };
byte subnet[] = {255,255,255,0 };

// ethernet cards address

EthernetClient nimbitsServiceClient;
//***************************************

unsigned long lastConnectionTime = 0;


//
in milliseconds
const unsigned long postingInterval = 120000; //
logging service, 720 per 24hrs to keep within the
//
access

last time you connected to the server,


120-sec delay between updates to
1000 quota
and leave room for other types of API

// these are for your nimbits account


char mailaddr [] = your email address"; // your email address for the logging account
char key [] = your key"; // your KEY you created for the account. Not the UUID.

!
!

void setup() {
Serial.begin(9600);
// serial debug
Ethernet.begin(mac, ip, nameserver, gateway, subnet);
ethernet system
Serial.println("up and running....");
Serial.print("POST interval is ");
Serial.print(postingInterval/1000);
Serial.println(" seconds");
}

// initialise the

// =========================================================================

!
7

Peter Dalmaris

Lecture 40

Arduino Step by Step

// =========================================================================
// very simple main loop. Just constantly reads two ADC channels and then if its time to
log again, do_weblog() sends in the latest values
// of A8 and A9
void loop()
{
ana_A = analogRead(8);
// read some voltage and save it
ana_B = analogRead(9);
// read some voltage and save it
do_weblog();
}

// =========================================================================
/*
This is where it all happens.
If the posting interval is reached then a new POST is done with the latest data
If not time yet, we simply exit
*/
void do_weblog() {
// if you're not connected, and 'postinginterval' secs have passed since
// your last connection, then connect again and send data:
if(!nimbitsServiceClient.connected() && (millis() - lastConnectionTime >
postingInterval)) {
str.begin();
// reset the into-string pointer. This is the 'final' composite
string being assembled.
cont.begin();
// and for the actual content ie payload string

!
!

sendData();

// the POST gets created and sent here

delay(1);
nimbitsServiceClient.stop();
nimbitsServiceClient.flush();

// stop the client


// and tidy up

}
}

!
!

Peter Dalmaris

Lecture 40

Arduino Step by Step

void sendData() {
// Create the 'content' string to send.
cont.print("email=");
cont.print(mailaddr);
cont.print("&key=");
cont.print(key);
// next get the data and store it in the 'cont' string
cont.print("&p1=Test+DP2&v1="); // test123 is the name of a data point you created
cont.print(ana_A,DEC);
// latest analog value. Replace this with whatever
// you are logging
// now get the length of the assembled content string.
// email addr, access key, sensor data (two analog vales in this case)
int contlen = (cont.length());
// now try and connect to the web-site
Serial.println("connecting...");
if (nimbitsServiceClient.connect("cloud.nimbits.com", 80))
{
// the format of the POST section below seems to be fairly critical.
str.print("POST /service/batch HTTP/1.1\r\n");
str.print("Host: cloud.nimbits.com\r\n");
str.print("Connection: close\r\n");
str.print("Cache-Control: max-age=0\r\n");
str.print("Content-Length: ");
str.print(contlen,DEC);
str.print("\r\n");
str.print("Content-Type: application/x-www-form-urlencoded\r\n");
str.print("\r\n"); // this empty line is REQUIRED
str.print(cont);
// the actual content string 'cont' (access details, data
points)
str.print("\r\n"); // and a terminating newline
// the total string (post headers and content) is now sent to the ethernet connection in
one hit
nimbitsServiceClient.print(str); // ethernet send to nimbits
Serial.println();
Serial.print(str);
Serial.println();
// for debug
Serial.println();
// for debug
}
else {
// if you couldn't make a connection:
Serial.println();
Serial.println("Connection failed");
Serial.println("disconnecting.");
Serial.println();
}
// note the time that the connection was made
lastConnectionTime = millis();
}

Peter Dalmaris

Lecture 40

Arduino Step by Step

Sketch discussion

This code looks long and convoluted, but its not as bad as it seems. Apart from the SPI
and Ethernet libraries needed for the actual communication, the only dependency is the
PString class which help a lot with the construction of strings. To read about the details, go
to the source at http://arduiniana.org/libraries/pstring/. By using the PString class, in this
sketch we can put together a string of characters that contain the complete HTTP request.
This request, which uses the POST method, contains the headers and the data that we
want to write to the Nimbits datapoint. Once the string has been assembled, the sketch
makes a single connection to the remote service (Nimbits) and completes the request.

The method of installing this class is the same as what we have done so far with third-party
Arduino-specific libraries. PString is a class that is implemented in C++. The Arduino IDE
can compile code written in C++ just like it can do with C code. To make the code that
implements this class available to your sketch, you need to copy the folder that contains
the classs files (PString.cpp and PString.h) in the folder that contains the Arduino thirdparty libraries. Then, rename the folder that contains the PString files to PString.

With PString, you can construct a string by appending partial strings into a buer. In this
sketch, we use two buers, one for the POST HTTP header, and one for the body of the
request which contains the data. Then these two parts are added together to create the full
content of the HTTP request. It looks like this:

POST /service/batch HTTP/1.1


Host: cloud.nimbits.com
Connection: close
Cache-Control: max-age=0
Content-Length: 400
Content-Type: application/x-www-form-urlencoded
email=test@email.com&key=13jhad982jdh&p1=Test&v1=123

Request buffer
(buffer)

Content buffer
(content)

Here is the part of the code that sets up the buers and the PString objects that operate on
them:

char buffer[400];

char content[200];

PString str(buffer, sizeof(buffer));


PString cont(content, sizeof(content));

This code declares two arrays of chars, and initialises them with 400 and 200 cells
respectively. These sizes are large enough to contain the complete HTTP request (for the
buer array) and the data part (for the content array). Then, it points the str PString object

10

Peter Dalmaris

Lecture 40

Arduino Step by Step

to manipulate the buer buer, and the cont PString object to manipulate the content
buer.

There are four more variables being declared:

lastConnectionTime, contains an unsigned long integer, which means a positive integer


of 32 bits total length. This variable contains a timestamp of the time that the Arduino last
communicated with Nimbits. This time is reported via the millis() function.

postingInterval, also an unsigned long integer, which contains the frequency (in
milliseconds) by which we want the sketch to communicate with Nimbits. By default, we
set this variable to 120000, which means that data will be send to Nimbits every 120
seconds.

mailaddr, an array of char which contains the email address you used to create your
Nimbits account. This is the first element used in the authentication process.

key, also an array of char, which contains the access key. This is the second element
used in the authentication process

In the setup() function, all the code should be recognisable, so lets move to loop().

In loop(), we take to measurements from analog ports 8 and 9. Add whatever sampling
code you want in here, being digital or analog. Once you have the values you want to post,
call the do_weblog() function to attempt a post to Nimbits.

In do_weblog(), the sketch checks to determine that it is time to post a new request. It just
subtracts the time now (by calling millis()) from the time that the last post was made
(stored in the lastConnectionTime variable). If that is greater that postingInterval, then it is
time to post. This check happens with this statement:

if(!nimbitsServiceClient.connected() && (millis() - lastConnectionTime >


postingInterval))
Take note that this statement also checks that there is no active connection to Nimbits at
the moment. It uses the && boolean operator to join this check with the time check. With
this operator, if the operant on the left of the operator returns false, then the second operant
will not be evaluated and the whole expression will be false.

If it is time to POST new data, the sketch resets the two PString objects by calling their
begin() function. Then, it calls the sendData() function where the bulk of the work is done.

In sendData(), the sketch first constructs the body of the HTTP request by calling cont.print.
Each call to the print function of the cont object appends any string passed to the content
buer. The first two key-value pairs added to the buer contain the account email address
and the data point authentication key. These are used as the credentials for authentication.

11

Peter Dalmaris

Lecture 40

Arduino Step by Step

Any subsequent key-value pairs will contain the data you want to post. The pattern is the
px and vx represent a point and a value, where x is an integer starting from 1 and
incrementing depending on how many data points you want to access.

You need two key-value pairs for each data point. In this example sketch, 2 data points are
being written to, so the content string looks like this (omitting the authentication part for
clarity):

p1=Test&v1=100&p2=Test2&v2=200
This means that the data point name for p1 is Test, and its value is 100. And the data point
name for p2 is Test2, and its value is 200.

Once all the key-value pairs are in the buer, the sketch moves on to the headers. It first
attempts to connect to Nimbits (since theres no point continuing if a connection is not
possible), and then constructs the header fields line by line by calling the print function of
the str PString object.

For the content-length field, the sketch needs to calculate the actual size in bytes of the
request body. This is done by calling the length() function of the cont PString object.

After the empty line of the header is printed (which identifies the end of the header), the
sketch prints the contents of the cont buer (which contains the body data). Add a
terminating line after that, the the string the makes up the HTTP request is complete.

To finally transmit it to Nimbits, the sketch calls the print function on the
nimbitsServiceClient EthernetClient object.

Now, you should be able to double click on the datapoint row in your Nimbits console and
see the value that was just posted plotted in the chart.

After a few data point have been recorded, you will have a plotted chart similar to this:

!
Exercise

Now that you know how to post sensor values to Nimbits, go ahead and make some use of
it. Add a DHT sensor to your circuit, extract humidity and temperature values from it and
post them to your Nimbits data points. Record values for a few days and see how they
fluctuate over time. Add a barometric pressure sensor and a photo-resistor and record all
four values for a week.

Nimbits has a facility that allows you to export your data for local processing. This facility
can be invoked by clicking on Schedule a data dump option available from the right-click
menu of each data point. Get the data and plot the all together in a spreadsheet. Can you
see a correlation between the four measurements? For example, can you confirm that
humidity in your area is higher at night than it is during the day?
12

Peter Dalmaris

Lecture 41

Arduino Step by Step

Lecture 42
Social logging to Twitter

In lecture 40, we played with logging sensor data to Nimbits, a cloud service dedicated to
the task. Nimbits will collect the data from your sensors and plot them in a chart, or you can
download them in a data dump and process them on your computer.

What if youd like to post your data for anyone to see on the Internet? Well, just like people
can post their holiday adventures on Facebook, gadgets can post their worldly
observations on Twitter!

In this lecture, Ill show you a very easy way to do just this.

About Tweeting from your Arduino

Twitter is a private messaging service, owned and controlled by a corporation, Twitter Inc..
It is one of the most popular micro-blogging services in the world, if not the most popular.

To post a message to Twitter, you need an account and a Twitter client. Because Twitter has
an interest in protecting its infrastructure and users from un-authorised use, it requires that
any tweet is authorised. This makes the tweet legitimate.

Twitter, like many other web sites and services, uses an open-source authorisation protocol
called OAuth. This protocol allows a third-party application, like a tweeting Arduino board,
to gain access to Twitters application programming interface (API). So it is quite possible
for you to include code in your Arduino that implements OAuth as a client and use Twitters
API to tweet sensor data.

But there is a situation here to consider: If Twitter decides to make changes to the way it
authorises tweets, you will have to update the code on the Arduino. If the Arduino is on your
desk, that is no big deal, but if you have deployed an Arduino-based product and can no
longer access it, then you have a problem. Although changes like this are very infrequent,
they are possible, and because you have no control at all over Twitters API changes, there
is a small, but existing, possibility that this will be a problem one day.

The alternative is to use an authorisation proxy service. This is also my favourite solution to
this problem. Your Arduino will send a tweet to the proxy, with authorisation credentials that
the proxy supports, and from there the proxy will relay the message to Twitter. As long as
you have control over the proxy, you will be safe from changes to Twitters API because any
changes you will have to make are in the single proxy only.

In the demo for this Lecture, I will show you how to setup an open source proxy called
Arduino-tweet, authorise this proxy for posting tweets to Twitter, and getting the Arduino to
send tweets to the proxy. This architecture is depicted graphically like this:

Peter Dalmaris

Lecture 41

Arduino Step by Step

Arduinotweet
proxy

!
!
!

!
!
The Arduino-tweet proxy

The proxy component is an open-source piece of software that you can download from
Github (https://github.com/NeoCat/ArduinoTweetLib-server) and install on your own server.
But for convenience, you can just use a public, free and managed instance running at
http://arduino-tweet.appspot.com. You dont even need to create an account, just to get an
authentication token. This is what well do next.

I assume that you already have a Twitter account, or that you have created one specifically
for your Arduino to use. Thats probably best, because at least in the beginning your
Arduino will be posting a lot of annoying test tweets which you do not want in your ocial
timeline.

Go to arduino-tweet.appspot.com. The home page shows the three things that need to be
done:

Peter Dalmaris

Lecture 41

Arduino Step by Step

Click on the link for step one. This is direct you to Twitter, where you will need to authorise
the proxy to post on Twitter on your (or your Arduinos) behalf. This page also contains a list
of things that the proxy will be able to do with your Twitter account.

Click on the Authorize app button. This will register the proxy with authority to post
tweets, and generate a token that your Arduino will use to authenticate itself to the proxy.
Copy it and store it somewhere safe, since you will need to use it in your Arduino sketch:

Keep this secret, because any client with this token will be able to post messages to Twitter
via the proxy.

Go back to arduino-tweet.appspot.com and click on the step 2 link. You will now see
instructions on how to download and import the required library to your Arduino IDE:

Peter Dalmaris

Lecture 41

Arduino Step by Step

Click on the link in the first bullet point. Once the download is complete, extract the
contents of the ZIP file, and copy the folder to your Arduino IDE libraries folder. Rename the
folder that contains the Twitter library to Twitter. You should have something like this in
your Arduino IDE libraries folder:

Restart your IDE, and make sure that the new library shows up. You know that the library
has been imported successfully if you can see the example sketches (File > Examples
> Twitter):

!
4

Peter Dalmaris

Lecture 41

Arduino Step by Step

Finally, the next step is to try out the example sketch. Click on the link in Step 3, and the
sketch will show up.

To try this out, change the IP address to one that matches your network (blue arrow), and
copy/paste the proxy token in the twitter constructor (red arrow). You can get this sketch by
clicking on File > Examples > Twitter > Sample Post. Here it is for completeness:

continues next page

Peter Dalmaris

Lecture 41

Arduino Step by Step

#include <SPI.h>!
#include <Ethernet.h>!
#include <Twitter.h>!

byte mac[] = { 0xDE,


byte ip[] = { 10, 0,
Twitter twitter("<<<
char msg[] = "Hello,

0xAD, 0xBE, 0xEF, 0xFE, 0xED };!


0, 177 };!
your token here >>>");!
World! I'm Arduino!";!

void setup()!
{!
delay(1000);!
Ethernet.begin(mac, ip);!
Serial.begin(9600);!
Serial.println("connecting ...");!
if (twitter.post(msg)) {!
int status = twitter.wait();!
if (status == 200) {!
Serial.println("OK.");!
} else {!
Serial.print("failed : code ");!
Serial.println(status);!
}!
} else {!
Serial.println("connection failed.");!
}!
}!
void loop()!
{!
}
If this goes well, your Arduino will introduce itself to the world with a greeting: Hello, World!
Im Arduino!!

continues next page

Peter Dalmaris

Lecture 41

Arduino Step by Step

Custom tweets

Now that we know that the Arduino can tweet via the proxy, lets customise the message
that is posted. Lets make it so that it reports a value from one of the analog inputs. I would
like the Arduino to tweet regularly, say once every hour, so I must move the code
responsible for tweeting from the setup() function to the loop() function. Have a look at
this code:

#include
#include
#include
#include

<SPI.h>!
<Ethernet.h>!
<Twitter.h>!
<PString.h>

unsigned long lastConnectionTime = 0;!


const unsigned long postingInterval = 3600000;!

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };!


byte ip[] = { 192, 168, 111, 167 };!
Twitter twitter("2282862504Hae3j7Ysr6F5k8OvTA6HL0xxgJVQEBgBaaQcUNG");!
char tweet[200];!
PString tweet_pstring(tweet, sizeof(tweet));!

void setup()!
{!
Ethernet.begin(mac, ip);!
Serial.begin(9600);!
}!

void loop()!
{!
if((millis() - lastConnectionTime > postingInterval)) {!
tweet_pstring.begin();!
int ana_A = analogRead(8);!
Serial.println("connecting ...");!
tweet_pstring.print("Light intensity:");!
tweet_pstring.print(ana_A);!
if (twitter.post(tweet_pstring)) {!
int status = twitter.wait(&Serial);!
if (status == 200) {!
Serial.println("OK.");!
} else {!
Serial.print("failed : code ");!
Serial.println(status);!
}!
} else {!
Serial.println("connection failed.");!
}!
lastConnectionTime = millis();!
}!
}

Peter Dalmaris

Lecture 41

Arduino Step by Step

The Ethernet part of the sketch is familiar. Just like in Lecture 40, I am using the PString
library to help me assemble text strings.

After adjusting the IP address, and setting your proxy token, the sketch defines an array of
chars with 200 character cells in it. Twitter only allows 140 characters, so 200 is a bit of an
overkill. Finally, it declares and initialises the tweet_pstring object that will be used to
construct the tweet post string.

Inside the loop() function, we check that one hour has passed since the last tweet using
almost the same code we used in Lecture 40. You want to keep a low posting frequency
because both the proxy and Twitter have limits on how many posts they can process per
minute. If it is time to tweet, we take a measurement from analog pin 8 and store it in a local
integer variable. Then we construct the tweet using the tweet_pstring object
(tweet_pstring.print).

The actual posting happens with this command:

twitter.post(tweet_pstring)!

!This attempts to post the string to which tweet_pstring is pointing to. This command will
return a boolean, and if that boolean is true, then the sketch will go inside the if block and
check for a response from Twitter. This happens with this command:

int status = twitter.wait(&Serial);!

!The wait function of the twitter object can receive one parameter, which in this case is a
reference to the Serial port, the one that outputs text to the IDE monitor. This way, we can
see the actual text that Twitter sends back to the Arduino. If you dont need to see this text,
you can just call twitter.wait();

The wait() function eventually returns a status code. If that is 200, that we know that the
post was successful.

Before finishing the loop, the sketch gets the correct time in milliseconds since the Arduino
was booted with the millis() function and stores it in a variable so that it can later check if
it is time to post again.

Exercise

You can see that with a proxy managing the communication with Twitter, posting tweets
with the Arduino could not be any simpler. With the code for both the Arduino library and
the proxy being open source, you have peace of mind that your tweeting infrastructure can
be built on your own hardware and be in your total control if you ever need to.

As an exercise, make the necessary changes to the custom sketch so that your Arduino
tweets data from multiple sensors. Please message me at @futurshocked with your
Arduinos Twitter handle so I can check out your tweets!

Peter Dalmaris

Lecture 45

Arduino Step by Step

SD card storage
Local file storage

The Arduino has a tiny amount of memory in which a sketch can store data, or where the
sketch itself is being kept.

The ATmega micro-controllers in the Arduino contain 3 types of memory: SRAM, flash, and
EEPROM.

Static RAM (static random-access memory) is volatile, and is where your sketches store
values that belong to variables from things like sensor readings. Volatile memory is cheap
and fast, but as soon as power is lost, it is erased. Therefore, it is only used as a temporary
place to store data.

In an expression like int ledPin = 13, you are storing the number 13 in static RAM. In
the Arduino Uno where the ATmega 328 is used, there are only two thousand bytes
available in the static RAM. It sounds like its a lot, but it isnt. Your computer probably has a
million times more RAM available to the programs that run on it.

Flash memory is non-volatile, so when power is turned o, its contents remain safe. Flash is
where your sketches and the Arduino bootloader (a special program that helps the Arduino
start executing the sketch when power is applied, or with uploading a new sketch) are
stored. The ATmega 328 has 32k bytes of this memory. You dont normally use this memory
to store data, but you can if you want to (this is a topic for another lecture, but for the very
curious of you, have a look at the PROGMEM keyword).

Finally, EEPROM (Electrically Erasable Programmable Read-Only Memory), like flash, is also
non-volatile. It is a good place to store data permanently that should not be erased in case
a new sketch is uploaded. Things like serial numbers, ids and the like can be stored here.
The ATmega 328 has only 1k byte of EEPROM available, so it is definitely not mass storage.

On the Arduino, on-board storage is very limited. For applications like data logging, or
running a web server with multiple pages and images, the build-in memory is not enough,
so we turn to SD cards for help.

SD cards

SD cards have matured over the years. Their sizes have expanded
to many giga-bytes, and their prices have dropped to a few cents
per gigabyte. Compared to build-in memory, SD cards oer a really
good mass storage solution. On the Arduino, an SD card can be
used with the appropriate hardware extension and with an easy to
use library that comes with the IDE. Your Arduino Ethernet shield
comes with a micro-SD card slot, but you can also get them as a
separate breakout board.

Peter Dalmaris

Lecture 45

Arduino Step by Step

In this lecture, I will show you how to take


advantage of SD card mass storage using
a cheap (less than $2 on eBay) breakout.

You will need a breakout like the one in this


image, and an SD card. Im using an
ancient 256MB card in my demos, which
works just fine.

You could also use a micro-SD card


breakout like this one; the instructions to
get it working are identical.

Before getting into the demo, theres one


thing I need to discuss: the SPI buss.

The SPI bus

The SPI (Serial Peripheral Interface) bus is a way of connecting multiple slave devices to a
master. Unlike I2C, which we played with back in lecture 9 where we learned about the
BMP08 barometric sensor, the SPI bus provides full duplex (two-way) communication
between master and slave using two wires. The I2C interface supports half-duplex, so that
data can flow only one way at a time. There is also a wire that provides a clock signal to the
slave so that both devices are synchronised, and a fourth wire that is used for selecting one
of the many slave devices that may be available.

In summary, this table shows the pins used by the SPI bus, which we will be using to
connect the breakout board to the Arduino:

Pin

Stands for

Purpose

CS or SS

Chip Select OR Slave Select

Selects a slave device

MOSI

Master Out Slave In

The master device uses it to transmit data to the


slave device

SCLK

Shared/Serial Clock

Used to syncronise the master and slave devices

MISO

Master In Slave Out

The slave device uses it to transmit data to the


master device

The SPI bus oers itself as a topic for a full lecture, so I will not go into more details now.
For now, simply keep in mind the functions of each of the SPI bus pins.

Peter Dalmaris

Lecture 45

Arduino Step by Step

Demo 1: Connect and get card info


Here is what well do in the first Demo:

1. We will connect the SD card breakout to the Arduino.

2. We will prepare an SD card for use with the breakout.

3. We will upload a sketch that prints out information about the card and confirm that it
works.

Connection

The pins which we should use to connect


the breakout depend on the Arduino you
are using. On an Arduino Uno, these pins
are:

MOSI on digital pin 11

MISO on digital pin 12

CLK on digital pin 13

CS can vary, but to keep things tidy I use


digital pin 10.

Power: some boards work with either


3.3V or 5V, or both. The one I use in this
demo works with both, and I connected
it to the 5V pin on the Arduino. Be careful
in case yours only accepts 3.3V to not
connect it to the 5V pin on the Arduino!

Ground: connect to a GND pin on the


Arduino.

Done with the wirings, so lets move on to the sketch.

Prepare an SD card

The Arduino SD card library works with SD cards that contains FAT16 or FAT32 partitions.

Most SD cards will work out of the box. However, if you are having any issues that prevent
you from using it with the Arduino, it is a good idea to format it. On a Mac, you can do this
by using the Disk Utility, and on Windows by right-clicking on the SD Card icon and clicking
on the Format option.

Once your SD card is formatted and ready, insert it into the SD card slot and plug the
Arduino to your computer. Lets have a look at the first sketch.

Peter Dalmaris

Lecture 45

Arduino Step by Step

Sketch

Lets try something simple first: Get information about our SD card.

The sketch well look at makes use of un-documented classes in the SD library. Typically a
vendor does not provide documentation for certain features because they either had no
time to write it up, or because they dont want users to know about them. In this case, this
library has been out for some time now, so it is more likely that Arduino (the company) does
not want you to use certain features as they are probably subject to change. But since they
are used in some of the examples that come with the IDE, we can try them out and see
what they do!

Open the CardInfo sketch by clicking on File > Examples > SD > CardInfo. Heres
what you get (slightly edited from the original):

#include <SD.h>
Sd2Card card;
SdVolume volume;
SdFile root;
const int chipSelect = 10;

Sd2Card, SdVolume and SdFile are classes in the SD


library that not documented. We use them here as a way to
access information about the SD card, volumes in the card,
and the root. Because they are not documented, they
could change at any time so you should avoid using them
in your sketches.

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

Well use digital pin 10 as Slave Select for the SD breakout.

!
!
!

This tries to initialise the card object.

Serial.print("\nInitializing SD card...");
pinMode(10, OUTPUT);
// change this to 53 on a mega

if (!card.init(SPI_HALF_SPEED, chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("* is a card is inserted?");
Serial.println("* Is your wiring correct?");
Serial.println("* did you change the chipSelect pin to match your shield or
module?");
return;
} else {
Serial.println("Wiring is correct and a card is present.");
}

// print the type of card


Serial.print("\nCard type: ");
Retrieve the type of SD you are using.
switch(card.type()) {
case SD_CARD_TYPE_SD1:
Serial.println("SD1");
break;
case SD_CARD_TYPE_SD2:
Serial.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
Serial.println("SDHC");
break;
default:
Serial.println("Unknown");
}

Peter Dalmaris

Lecture 45

Arduino Step by Step

!
continues from previous page

// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32


if (!volume.init(card)) {
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted
the card");
Tries to get a handle on a valid partition
return;
}
If there is no valid partition, exit this function (program
ends)
// print the type and size of the first FAT-type volume
uint32_t volumesize;
Serial.print("\nVolume type is FAT");
Serial.println(volume.fatType(), DEC);
Serial.println();

volumesize = volume.blocksPerCluster();
volumesize *= volume.clusterCount();
volumesize *= 512;
Serial.print("Volume size (bytes): ");
Serial.println(volumesize);
Serial.print("Volume size (Kbytes): ");
volumesize /= 1024;
Serial.println(volumesize);
Serial.print("Volume size (Mbytes): ");
volumesize /= 1024;
Serial.println(volumesize);

// clusters are collections of blocks


// we'll have a lot of clusters
// SD card blocks are always 512 bytes

Gets and prints out statistics about the SD


card.

Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);
// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
}

void loop(void) {
}

!
!
!
!
!
5

Peter Dalmaris

Lecture 45

Arduino Step by Step

When you run this sketch on your Arduino, you will see something like this, assuming that
your SD card is properly formatted:

Peter Dalmaris

Lecture 45

Arduino Step by Step

Demo 2

Demo 1 was about getting the SD card


breakout working. Now, lets make use of
it. Lets start logging sensor data onto our
card, and then use the card on the
computer to do some basic data analysis
ad plotting.

Well use another slightly modified example


that comes with the IDE.

For this demo, use the hardware from


Demo 1 with the addition of a photoresistor, a thermistor, and a 1k resistor
used as voltage dividers for the sensors.

A thermistor is an analog sensor that


changes its resistance depending on the
temperature. Electrically, it works like the
photo-resistor.

Heres is the sketch. My changes are


highlighted in red, and commends are in
bubbles.

This sketch represents the recommended


way to access and use an SD card.

continues next page

Peter Dalmaris

Lecture 45

Arduino Step by Step

Include the SD library.


#include <SD.h>
const int chipSelect = 10;
Use digital pin 10 as the slave select pin (SPI bus).
void setup()
{
Serial.begin(9600);
Serial.print("Initializing SD card...");
pinMode(10, OUTPUT);

if (!SD.begin(chipSelect)) { Attempt to initialise the SD device.


Serial.println("Card failed, or not present");
return;
If the device cant be initialised, exit the setup function
and end execution of this program.
}
Serial.println("card initialized.");
}
Initialise the string use to construct the record that
void loop()
eventually will be stored in a file on the SD card.
Instead of a String, you could use a PString as was
{
shown in the Ethernet lectures.
String dataString = "";
for (int analogPin = 0; analogPin < 2; analogPin++) {
Connect analog sensors
int sensor = analogRead(analogPin);
to pins 0 and 1, and loop
dataString += String(sensor);
through them. Take a
if (analogPin < 1) {
reading from each one,
convert to a String and
dataString += ",";
add it to the dataString,
}
then append a comma
}
so that values are
separated.
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
dataFile.println(dataString);
SD.open attempts to open the file, with write
dataFile.close();
permissions. If a file cannot be opened, the
function will return FALSE. If it can, it will
Serial.println(dataString);
return an object of type File.
}
else {
You can save text to a file like
Serial.println("error opening datalog.txt"); you do with a serial connection:
just call the print or println
} Remember to call the close function on the File
function on the file object
}
object in order to commit any changes.
(datafile, in this example).
Other than the comments in the code box above, it is worth mentioning that with the
print(data) function you can write ASCII text to the SD card. If you want to write numbers,
you can use print(data, BASE), where BASE can be BIN for binary, DEC for decimal, HEX
for hexadecimal and OCT for octal.

You can also write bytes or arrays of bytes by using the write(data) or write(buer, length)
function. This way of writing to the card may have a better performance and it is something
worth while remembering if you are building a higher-speed data logger.

Peter Dalmaris

Lecture 45

Arduino Step by Step

Another point worth remembering is that the write speed


depends on several conditions: the actual speed of the SD
card (although modern SD cards are much faster than the
Arduinos ability to write on them), the speed of the SPI
bus, the sampling rate of your project, the type of data you
are writing (ASCII is slower than bytes). If you hit a
performance block, try to determine the slowest
component of the system and try to find a way to optimise
it.

Heres the monitor output as sensor data are being


captured (right):

!
Remove the SD card from the Arduino and insert it in your
computers card reader.

Youll see something like this (below):

The time stamp for the DATALOG.TXT file is 1 Jan 2000


because the Arduino does not have a real time clock, so
time will initialise to this date every time it is reset. I will
show you how to use a real time clock in another lecture.

Finally, open the DATALOG.TXT file. You will see something


like this: multiple lines containing the sensor readings,
delimited by a comma. Its a standard text file that you can
import to a spreadsheeting program for analysis and
charting.

Peter Dalmaris

Lecture 45

Arduino Step by Step

Demo 3

In this last demo, well look at how we can browse directories and files stored on your SD
card. This is useful in order to create and maintain a hierarchical file system in which files
are stored. Even though it is unusual for an Arduino sketch to be managing too many files,
basic file management can be setup by creating folders and putting files in them, instead of
placing everything in the root (which is still a folder).

Looking at the SD class documentation, you see functions like mkdir() and rmdir() which
create or remove a directory, and exists() which checks for the existence of a file or
directory.

This example sketch comes with the IDE and browses the file system on the SD card and
prints out the directories and their contents.

The sketch in this Demo contains a recursive structure, which simply means a function
that calls itself. It sounds fancy, but it is merely a convenient way to code operations that
repeat themselves.

In the sketch that follows, I have provided annotations for only those parts that we havent
already seen in Demos 1 and 2.

see next page

!
!
!
!
!
!
!
!
!
!
!
!
!
10

Peter Dalmaris

#include <SD.h>
File root;

Lecture 45

Arduino Step by Step

Include the SD library.

Declare an object of type File, that will be used as a handle


void setup()
to the root directory.
{
Serial.begin(9600);
Serial.print("Initializing SD
card...");
Declare
an object named root which is of class File. Looking
at the documentation, you learn that this kind of object can
pinMode(10, OUTPUT);
represent both normal files and directories (a directory is
if (!SD.begin(10)) {
just a special kind of file).
Serial.println("initialization failed!);
return;
}
Serial.println("initialization done.");
SD.open() tries to open the file or directory named in the
root = SD.open("/");
printDirectory(root, 0); parameter. In this case it is the root directory /. The function
open returns a reference to a File object, so we store this
Serial.println("done!");
reference to variable root.
}

Calls a new instance of his function.

void loop()
{ }

Calls the printDirectory function and passes two parameters: a


reference to the File object root (which now contains information
about the root directory), and an integer number that is used by
the function to nicely format its output (more about this below).

void printDirectory(File dir, int numTabs) {


while(true) {
This is an interesting control structure. It is a
File entry = dir.openNextFile(); loop that never ends (while(true)) but from
if (! entry) {
which the sketch exist (break) when the File
openNextFile() returns false. This happens when
break;
there is no regular file or directory left to return.
}
for (uint8_t i=0; i<numTabs; i++) { Prints out tab characters depending on the level of
the current directory. Each time a new directory is
Serial.print('\t');
found, numTabs is increased by one.
}
Serial.print(entry.name());
Print out the name of the current file (which may be
if (entry.isDirectory()) {
a directory. entry is the name of the File object
that contains this information, and name is one of
Serial.println("/");
its attributes. Hence, entry.name prints out the
printDirectory(entry, numTabs+1);
name of the file.
} else {
Serial.print("\t\t");
If variable entry is pointing to a directory, then
Serial.println(entry.size(), DEC);print a / and call (recursive operation) the function
printDirectory, so we can have a look inside. Pass
}
the entry object and increase the tabs number by
entry.close();
one to intent the file names in this directory.
}
}
Close the file.
If this is a regular file, add two tabs and print out

!
!

the size of the file in bytes, as a decimal.

11

Peter Dalmaris

Lecture 45

Arduino Step by Step

This is what the monitor output looks like:

!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!

Directory

Directory

Size
(bytes)

An exercise
You now know how to write text data to your SD card!

But what about reading? I did not show you how to read text from the card because Id like you to
work this function out your self. Have a look at the documentation page for the read function, and a
sample sketch that shows you how to read text from a text file.

12

Peter Dalmaris

Lecture 47

Arduino Step by Step

Real time clock


The Arduino, even though it can interact with its environment, cant do anything at all
without a access to sensors and all kinds of components. And unlike most computers you
are used to, it cannot tell the time. Although knowing the time is not needed in many
applications (and indeed, we have not really needed it up to now), sooner or later you will
come across a project where knowing the time is a requirement.

It is true that the Arduino has a build-in sense for time. It knows how much time has passed
since it started executing a program. You can use the millis() function to get a number that
represents this time in milliseconds. A similar function is micros(), and it does the same
thing as millis() except that it reports the elapsed time in microseconds instead of
milliseconds. There are also the time-related functions delay() and delaymicroseconds()
which add a delay in your program, the fist in milliseconds and the second in
microseconds.

Still, your sketch cannot ask the Arduino for the time. You could use an Internet time server
and poll it occasionally for the time, but this method requires Internet connectivity, a
dependency that maybe an overkill for some projects.

A real-time clock break out board is a PCB that contains a time-keeping integrated circuit.
Its like the watch you wear on your wrist. You glance at it to get the time. The Arduino will
be able to ask the real-time clock for the time too.

A simple application for a real-time clock is for time-stamping log entries recorded on an
SD card. We will look at this problem in this lecture. You can also consider applications
where certain events must be scheduled, like turning an illuminated sign on and o, or
taking sensor readings at predetermined times.

Peter Dalmaris

Lecture 47

Arduino Step by Step

Demo 1: Setting and reading the clock


In this demo, Ill show you how to use a
typical real time clock with your Arduino. I will
be using the DFRobot DS1307 RTC breakout,
which I purchased on eBay for around $4.
This device, like many others, is based on the
popular DS1307 clock IC, and it can do
anything you would expect a good clock can
do. It counts seconds, minutes, hours, days,
years, goes up to 2100 and compensates for
leap years.

EEPROM Clock

It also consumes very little power, 500nAmps,


which when using the on-board battery gives
the device a life of around 5 years (although I
have not tested this claim!).

The breakout also features an additional IC in


which you can store up to 4kbytes of data
(EEPROM 24C32), and an integrated
temperature sensor. Not bad at all for such a low cost device!

Lets do the wirings and connect the


breakout to the Arduino. The RTC uses the
IC2 serial bus for communication.
Therefore, we only need two wires for Vcc
and Gnd, one wire for data (SDA), and one
for the synchronisation clock (SCL). On the
Arduino Uno, the SDA pin is analog 2, and
the SCL pin is 1. In you have any other
board, you may want to check the location
of the SDA and SCL pins against your
boards documentation before you do the
connections.

Before looking at the sketch, lets install the


library for the device. If you are using the
TinyRTC breakout, you can download the
library from the manufacturers web site.
This clone from Adafruit also seems to be
working (thank you to Matt Hill for letting
me know about this).

!
2

Peter Dalmaris

Lecture 47

Arduino Step by Step

Download it, copy the library folder to the Arduino libraries folder, and restart the IDE. Then,
load the sketch from File > RTClib > ds1307.

This is what you will see (slightly edited to improve readability):

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

Import the Wire library so that we can use the IC2 bus.

RTC_DS1307 rtc;

Declare an RTC_DS103 object, name it rtc.

Import the RTClib library so that we can use the clock.

void setup () {
Initialise the IC2 bus.
Serial.begin(9600);
Wire.begin();
Initialise the real time clock device.
rtc.begin();
if (! rtc.isrunning()) {
This will get the time from your
Serial.println("RTC is NOT running!");
computer during compilation
and automatically set the time.
rtc.adjust(DateTime(2014,01,16,14,45,00));
// following line sets the RTC to the date & time this sketch was compiled
//RTC.adjust(DateTime(__DATE__, __TIME__));
} This will adjust the time with the
help of the C-language DateTime
Check to determine is the device is on. Since the
}
object initialiser.

device is powered by a battery when the Arduino is


off, it will continue to keep track of time and be in a
running state. As long as a time has been set and
the battery can power it, the rtc.isrunning()
function will return true. The only time you will
probably see a false returned is when you run this
sketch for the very first time.

void loop () {
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Get the time now, and store it in the now variable,
Serial.print('/');
which is of time DateTime.
Serial.print(now.day(), DEC);
Serial.print(' ');
Print time attributes to the Serial port.
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
Serial.print(" since midnight 1/1/1970 = ");
Get the number of seconds elapsed since 1/1/1970,
Serial.print(now.unixtime());
when Unix time begins.
Serial.print("s = ");
Serial.print(now.unixtime() / 86400L);
and convert that to days, since 1 day
Serial.println("d");
contains 86400 seconds.

sketch continues in next page

Peter Dalmaris

Lecture 47

Arduino Step by Step

// calculate a date which is 7 days and 30 seconds into the future


DateTime future (now.unixtime() + 7 * 86400L + 30);
Serial.print(" now + 7d + 30s: ");
Serial.print(future.year(), DEC);
Create a new object of type DateTime,
name it future and initialise it with a
Serial.print('/');
date that is 7 days and 30 second into
Serial.print(future.month(), DEC);
the future.
Serial.print('/');
Serial.print(future.day(), DEC);
Serial.print(' ');
Print future attributes to the Serial port.
Serial.print(future.hour(), DEC);
Serial.print(':');
Serial.print(future.minute(), DEC);
Serial.print(':');
Serial.print(future.second(), DEC);
Serial.println();
Serial.println();
delay(3000);
}
Once the clock has been set, it will keep the time independently of the Arduino,
compensating for leap years and the like until its onboard battery fails. All you have to do in
order to get a reading of the time is to call the now() function, which returns a DateTime
object.

Upload this sketch, and open


the monitor. You should see
something like this:

!
!

Current time reported by the RTC

Results of time/date calculations

Peter Dalmaris

Lecture 47

Arduino Step by Step

Demo 2: Logging with time stamps


Back in Lecture 39, you learn about how to
use an SD card for logging sensor
readings. Lets go ahead and improve the
design from Demo 2 so that the time of
data capture is also stored in your SD card.

Heres the new and improved circuit. It is a


merge between Lecture 39 Demo 2 and
this lectures Demo 1.

If you guessed that the sketch is also


mostly a merge between these two, you
guessed correctly.

For the SD card module connections, I


remind you the pins for the Arduino Uno:

MOSI on digital pin 11

MISO on digital pin 12

CLK on digital pin 13

CS can vary, but to keep things tidy I use


digital pin 10.

Power: some boards work with either


3.3V or 5V, or both. The one I use in this demo works with both, and I connected it to the
5V pin on the Arduino. Be careful in case yours only accepts 3.3V to not connect it to the
5V pin on the Arduino!

Ground: connect to a GND pin on the Arduino.

In the next page, I provide the merged sketch, and comments to the interesting segments.

please see next page

Peter Dalmaris

Lecture 47

Arduino Step by Step

#include <SD.h>
#include <Wire.h>
#include "RTClib.h"

Include the SD card library.

RTC_DS1307 rtc;
const int chipSelect = 10;

Import the RTClib library so that we can use the


clock breakout library.

Include the IC2 library for the real time clock.

Instead of manually setting the time like in Demo


void setup() {
1, this syntax will get the date and time from
Serial.begin(9600);
your computer during compilation time, and
Wire.begin();
reset the RTC every time the sketch is uploaded.
rtc.begin();

rtc.adjust(DateTime(__DATE__, __TIME__));
Serial.print("Initializing SD card...");
pinMode(10, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
return;
}
Serial.println("card initialized.");
}

void loop(){
Get the sensor readings.
DateTime now = rtc.now();
String dataString = "";
for (int analogPin = 0; analogPin < 2; analogPin++) {
int sensor = analogRead(analogPin);
dataString += String(sensor);
if (analogPin < 1) {
dataString += ",";
}
}
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {

Get a handle to the datalog file.


print_time(now, dataFile);
dataFile.println(dataString);
Call the print_time function which will
dataFile.close();
produce the timestamp. Pass a reference
Serial.println(dataString);
to the now object that contains the
current time, and the datafile object
}
which contains a handle to the data file.
else {
Serial.println("error opening datalog.txt)
}
Print the sensor readings to the data file.
delay(3000);
}
continues next page

Peter Dalmaris

Lecture 47

Arduino Step by Step

void print_time(DateTime capture_time, File file)


{
This function accepts a DateTime
file.print(capture_time.year(), DEC);
object which contains the current date
file.print('/');
and time, and a File object with
file.print(capture_time.month(), DEC);
contains a handle to the file we want
to print the timestamp.
file.print('/');
file.print(capture_time.day(), DEC);
file.print(' ');
Print the current date and time one
file.print(capture_time.hour(), DEC);
element at a time, to the data file.
file.print(':');
file.print(capture_time.minute(), DEC);
file.print(':');
file.print(capture_time.second(), DEC);
file.print(',');
}
There is nothing new in this sketch, just a recombination of known elements. You now have
a way to create a data-logger, which can work in remote locations, on a battery which can
be charged by a small solar panel.

An exercise
With the right hardware, keeping time is easy. Try out this exercise:

Create an LCD clock. Use a real time clock like the one in this lecture, combine it with an LCD
screen, and display the date and time on it.

!
!

For the adventurous, heres another exercise: Extend the LCD clock so that it has these features:

1.
2.
3.
4.

A toggle switch

One rotary potentiometer

A buzzer

Only keeps track of time (dont worry about the date for now)

The toggle switch will set the mode of the clock to Time Set or Alarm set. When the toggle switch is
on, then turning the potentiometer will change the time. When the switch is o, then turning the
potentiometer will change the alarm time.

Assuming the clock keeps time in 24 hour format, make your gadget so that when the alarm time is
reached, a sound will be generated by the buzzer for 10 seconds.

Peter Dalmaris

Arduino Step by Step

Lecture 50

Lecture 50
Wifi

In Lecture 33 and 34, you learned about the Arduino Ethernet shield, and connected your
Arduino to the Internet. In this lecture, well again connect the Arduino to the Internet, but
well do that using Wifi, and go completely wireless!

There are a lot of shields and breakout boards that provide Wifi functionality, with varying
prices. Shields that provide 802.11n capability can sell for over $100 with bells and whistles
like external antennas and on-board SD card modules.

I personally go for breakout boards whenever possible, because usually they oer a lower
price point, a modular and smaller package, and a single function per board which makes it
easier to learn and integrate into to my projects.

For this lecture, I chose the Adafruit


CC3000 breakout board, with an on-board
ceramic antenna. This product also is It
comes as a shield, and with a connector
for an external antenna if you need
extended range. At around $35, it oers
802.11a/g connectivity, very small size, a
nice library, and lots of documentation.

I will go through 3 demos in this lecture. In


the first one, well connect the CC3000 to
the Arduino and run one of the librarys
examples to make sure that it works and
that it can connect to our Wifi router. In the second one, Ill show you how to create a Wifi
web client, whereby the Arduino will be polling a URL, and fetching a file contains
instructions for turning an LED on or o. The polling method has an advantage over the
web server method because it is not aected by firewall or NAT restrictions. This means
that by polling an external URL to your local network, you will be able to control your
Arduino from anywhere in the Internet without having to configure your router to allow
access to the Arduino from the outside world.

In the last one I will show you an adapted version of Demo 2 from lecture 38, where we had
a web server running on the Arduino, showing us a simple user interface through which we
could turn an LED on and o.

Peter Dalmaris

Arduino Step by Step

Lecture 50

Demo 1: Connect the Wifi module and access the


LAN
Once you receive your CC3000, you will need to first
solder the header pins to it. Once you have that, your
module will look like this:

!
Adafruit maintains a Github repository with the latest
version of the library and examples. Go ahead and get it,
then copy the library into your Arduino IDEs libraries
folder as we have done before. Remember to restart the
IDE once the new library has been installed.

The CC3000 Wifi module, made by Texas Instruments, uses the SPI communications
interface to talk to the Arduino. On the PCB, notice the familiar pin markings CLK, MISO,
MOSI, and CS. We saw the exact same pins on the SD card module in lecture 45. Theres
two additional pins on the CC3000: IRQ and VBAT_EN (the actual marking is VBEN on the
PCB).

In the SD card module, the Arduino is responsible for initiating communication. The Arduino
will ask for a read or write, and the SD card module will execute it. The SD card module
never initiates communication. With the wifi module, however, it is just as likely for the
module to initiate communication as it is for the Arduino. The IRQ pin (for Interrupt
ReQuest) is used by the Wifi module to grab the attention of the Arduino when it has data
to sent. The Arduino Uno has a special pin, digital pin 3, which can detect an interrupt
request. When an interrupt is requested, the Arduino will stop whatever it is doing at that
moment and start executing a special function (part of the CC3000 library) that will deal

Peter Dalmaris

Arduino Step by Step

Lecture 50

with the interrupt. When the function is done dealing with the interrupt, the Arduino
continues doing whatever it was doing before the interrupt.

The VBAT_EN is used to start the module properly. Think of it as a reset switch.

Heres the schematic and a pinout table:

Arduino

CC3000
13 SCK
12 MISO
11 MOSI
10 CS
5 VBEN
3 IRQ
GND GND
5V VIN

!
!
!
!
!
!
!
Double-check the connections, and the plug the Arduino to your computer via the USB
port. A surface-mounted green LED will light up on the wifi board, thats means youre good
to go!

Peter Dalmaris

Arduino Step by Step

Lecture 50

Sketch

Lets look at the sketch now. The one well use for this demo is one of the many samples
that come with the CC3000 library. Fire up the IDE and load the example: File > Examples
> Adafruit_CC3000_Library > buildtest

Here is the sketch (edited to make it fit), I am highlighting the interesting parts:

#include
#include
#include
#include
#include

<Adafruit_CC3000.h>
<ccspi.h>
<SPI.h>
<string.h>
"utility/debug.h"

Import the Adafruit library so that we can use the Wifi module.
Contains SPI helper functions for the CC3000.
Import that standard SPI and String libraries.
Implements the useful foreach() and sign() functions, used in this
sketch.

#define ADAFRUIT_CC3000_IRQ
3
#define ADAFRUIT_CC3000_VBAT 5
Set pins for IRQ (fixed) and VBAT, CS (can change).
#define ADAFRUIT_CC3000_CS
10
// Use hardware SPI. On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS,
ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT, SPI_CLOCK_DIVIDER);

Initialise the CC300 object with the defined pins as parameters.

#define WLAN_SSID "myNetwork"


SPI_CLOCK_DIVIDER sets the module clock speed based on the
type of the micro-controller used.
#define WLAN_PASS "myPassword"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY WLAN_SEC_WPA2
void setup(void)
Set the Wifi credentials and security type.
{
Serial.begin(115200);
Serial.println(F("Hello, CC3000!\n")); Call
a function that displays the type of driver used (tiny or
normal).
displayDriverMode();
Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
/* Initialise the module */
Serial.println(F("\nInitialising the CC3000 ..."));
if (!cc3000.begin())
Gets RAM remaining, great for debugging memory issues.
{
Serial.println(F("Unable to initialise the CC3000! Check your wiring?"));
while(1);
Try to start the device. Assuming wiring is correct, this should work.
}
uint16_t firmware = checkFirmwareVersion();
if ((firmware != 0x113) && (firmware != 0x118)) {
Serial.println(F("Wrong firmware version!"));
for(;;);
Call a function that displays the firmware running in the module.
}
Call a function that displays the MAC address assigned to the
displayMACAddress();
module.

continues next page


4

Peter Dalmaris

#ifndef CC3000_TINY_DRIVER
listSSIDResults();
#endif

Arduino Step by Step

Lecture 50

You can load a small-footprint driver for the Wifi module. The tiny
driver will only load the essential API functions and save a lot of
RAM. See http://processors.wiki.ti.com/index.php/
Tiny_Driver_Support. Enable tiny mode by adding this definition in
your code: #define CC3000_TINY_DRIVER.

Serial.println(F("\nDeleting old connection profiles"));


if (!cc3000.deleteProfiles()) {
Unless running in tiny mode, call the listSSIDResults function
Serial.println(F("Failed!"));
and show detected WiFi networks.
while(1);
A profile is a wifi network of which the device remembers its
}
credentials. Calling deleteProfiles() deletes such networks.
More info: http://processors.wiki.ti.com/index.php/

char *ssid = WLAN_SSID;


/* Max 32 chars */
Serial.print(F("\nAttempting to connect to ")); Serial.println(ssid);
/* NOTE: Secure connections are not available in 'Tiny' mode! */
if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
Serial.println(F("Failed!"));
Attempt to connect to the Wifi access point with the security
while(1);
credentials as parameters.
}
Serial.println(F("Connected!"));
/* Wait for DHCP to complete */
Serial.println(F("Request DHCP"));
while (!cc3000.checkDHCP())
Go in a loop, until DHCP assigns network settings. If DHCP
{
has not responded yet, wait for 100msec before trying again.
delay(100);
}
/* Display the IP address DNS, Gateway, etc. */
while (! displayConnectionDetails()) {
delay(1000);
Show assigned IP and other connection details.
}
#ifndef CC3000_TINY_DRIVER
Resolve the IP address of the host
/* Try looking up www.adafruit.com */
www.adafruit.com. The IP address will be stored
uint32_t ip = 0;
to the memory address passed as the second
parameter (&ip). This is a DNS request.
Serial.print(F("www.adafruit.com -> "));
while (ip == 0) {
if (! cc3000.getHostByName("www.adafruit.com", &ip)) {
Serial.println(F("Couldn't resolve!"));
}
The ip variable was declared of type uint32_t, which is a
4-byte integer. This function will convert this integer into
delay(500);
a dot-delimited nice looking IP address like this:
}
207.58.139.247
cc3000.printIPdotsRev(ip);
/* Do a quick ping test on adafruit.com */
Ping this host and store the response in a 1Serial.print(F("\n\rPinging "));
byte (8 bit) unsigned integer. The response
the number of packets received.
cc3000.printIPdotsRev(ip); Serial.print("..."); contains

uint8_t replies = cc3000.ping(ip, 5);


Serial.print(replies); Serial.println(F(" replies"));
if (replies)
Serial.println(F("Ping successful!"));
#endif
5

Peter Dalmaris

Arduino Step by Step

Lecture 50

Serial.println(F("\n\nClosing the connection"));


cc3000.disconnect(); }
Disconnect the device from the Wi-fi network.
void loop(void){
delay(1000); }

Start of a pre-processor conditional group.


What follows (until the #endif directive) will be
compiled only if the tiny driver is used.

void displayDriverMode(void){
#ifdef CC3000_TINY_DRIVER
Serial.println(F("CC3000 is configure in 'Tiny' mode"));
#else
Print out various driver parameters. The F()
function enforces storage of these static
Serial.print(F("RX Buffer : "));
(unchanging) Strings in flash memory instead
Serial.print(CC3000_RX_BUFFER_SIZE);
of SRAM, therefore preserving SRAM for the
Serial.println(F(" bytes"));
dynamic segments of the sketch. Reminder:
Serial.print(F("TX Buffer : "));
flash memory is where the sketch is actually
stored when you upload it.
Serial.print(CC3000_TX_BUFFER_SIZE);
Serial.println(F(" bytes"));
#endif
End of the pre-processor conditional group.
}
Retrieve the firmware version running in the

uint16_t checkFirmwareVersion(void)
device, and store the major and minor versions
{
in the memory locations provided as
parameters.
uint8_t major, minor;
uint16_t version;
#ifndef CC3000_TINY_DRIVER
if(!cc3000.getFirmwareVersion(&major, &minor)) {
Serial.println(F("Unable to retrieve the firmware version!\r\n"));
version = 0;
}
else
{
Serial.print(F("Firmware V. : "));
Serial.print(major); Serial.print(F(".")); Serial.println(minor);
version = major; version <<= 8; version |= minor;
}
#endif
return version;
}

!
!
!
!
6

Peter Dalmaris

Arduino Step by Step

Lecture 50

void displayMACAddress(void){
uint8_t macAddress[6];
if(!cc3000.getMacAddress(macAddress))
{
Serial.println(F("Unable to retrieve MAC Address!\r\n"));
}
Get the devices MAC address. It contains 6
else
bytes, and those bytes are stored in the
{
macAddress array of bytes.
Serial.print(F("MAC Address : "));
cc3000.printHex((byte*)&macAddress, 6);
Print the MAC address in hexadecimal
notation, as is common.
}
}
bool displayConnectionDetails(void){
uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;
if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))
{
Serial.println(F("Unable to retrieve the IP Address!\r\n"));
return false;
Get the Wifi connection parameters. The
parameters will be stored in the memory
}
locations passed as parameters to the
else
function.
{
Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
Serial.println();
return true;
}
}
Print out the Wifi connection parameters.

!
!
!
!
!
!
!
7

Peter Dalmaris

Arduino Step by Step

Lecture 50

void listSSIDResults(void)
Search for Wifi networks. The 8-byte integer
{
index will contain the total number of networks
found.
uint8_t valid, rssi, sec, index;
char ssidname[33];
index = cc3000.startSSIDscan();
Serial.print(F("Networks found: ")); Serial.println(index);
Serial.println(F("================================================"));
while (index) {
index--;
valid = cc3000.getNextSSID(&rssi, &sec, ssidname);
Serial.print(F("SSID Name
: ")); Serial.print(ssidname);
Serial.println();
Serial.print(F("RSSI
: "));
Serial.println(rssi);
Serial.print(F("Security Mode: "));
Print out the parameters for the networks
Serial.println(sec);
found, starting with the last one.
Serial.println();
}
Serial.println(F(================================================"));
cc3000.stopSSIDscan();
Stop scanning.
}

!
Here is an example
output of this sketch:

Peter Dalmaris

Arduino Step by Step

Lecture 50

Demo 2: Web client LED control by polling a URL

Great, the Wifi module works, so lets go ahead and do something useful with it.
Automation and remote control fits well in that category. You may remember back in
Lecture 38 that you learned how to control an LED by setting up a simple web server on the
Arduino. You used your web browser to access this web server and click on buttons to turn
the LED on and o. We will adapt that sketch to use the Wifi module instead of the Ethernet
shield in Demo 3, but in this demo well try something dierent: polling-based control.

In summary, we will use instructions contained in a text file, hosted by a web server
somewhere on the Internet. The Arduino will use the Wifi module to get this file, read its
contents, and turn an LED on and o accordingly. Schematically, this is what is going to
happen:

!
!
!
!
!
!

There is a blank
line after the
instruction line.

!
!
!

Instruction: Turn LED in pin 8 ON

Peter Dalmaris

Arduino Step by Step

Lecture 50

Theres an LED connected to digital Pin 8 via a protective 1k resistor. The Arduino will use
the Wifi module to request a copy of the file titled cc3000.txt from the web server that is
hosting it. In my demo, I am using an Amazon S3 bucket, but you can use any service at all
as long as you can access it with a HTTP URL like http://myserver.com/cc3000.txt. You
may remember that the instruction contained in the first line of this file is identical to the one
that we learned about how to parse back in lecture 38. We are not learning again how to
parse this instruction, we just store it on the web instead of on the Arduino!

The nice thing about this architecture is that is is scalable. Once you stop thinking of
cc3000.txt as a text file but instead as a web resource, then you have many options to
manipulate it. You can get the Arduino to poll a URL that is controlled by a web application
which creates the LED instruction based on some user entry, a schedule, environmental
conditions somewhere else etc.

I also mentioned in the introduction of this lecture that polling, as opposed to a web server
running on the Arduino, has the additional benefit of not having to worry about local
network restrictions, especially firewalls and NAT. You Arduino will be able to get its
instructions by accessing a public URL, and you will be able to control your Arduino by
manipulating the resource at that URL.

Lets have a look at the sketch, comments are embedded:

#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
No change compared to Demo 1, except
#include <string.h>
#include "utility/debug.h"
Import the Watchdog library. See further down
#include <avr/wdt.h>
for details.
#define ADAFRUIT_CC3000_IRQ
3
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS
10
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ,
ADAFRUIT_CC3000_VBAT, SPI_CLOCK_DIVIDER);
Set the host and path to the file that contains
boolean
reading
= false;
the LED instruction. Also set a timeout
String
get_request = "";
constant. We expect the server to respond
within 3 seconds.
#define WLAN_SSID
"mynetworkid"
#define WLAN_PASS
"mynetworkpassword"
#define WLAN_SECURITY
WLAN_SEC_WPA2
#define IDLE_TIMEOUT_MS 3000
#define WEBSITE
"arduinosbs.com.s3.amazonaws.com"
#define WEBPAGE
"/cc3000.txt"
uint32_t ip; uint32_t
t; int port = 80;
No change compared to Demo 1
int connectTimeout = 5000;
Adafruit_CC3000_Client www;
Counter keeps track of how many times the
int repeat_counter = 0;
file has been polled.

10

Peter Dalmaris

Arduino Step by Step

Lecture 50

Confused? Consider revising Lecture 38!

void setup(void){
Serial.begin(115200);
Serial.println(F("Hello, CC3000!\n"));
Serial.print(F("Free RAM: ")); Serial.println(getFreeRam(), DEC);
Serial.println(F("\nInitializing..."));
if (!cc3000.begin()) {
Serial.println(F("Couldn't begin()! Check your wiring?"));
while(1); }
Broken down the functionality from the setup
connect_wifi();
function in Demo 1 to individual functions in
get_dhcp();
order to improve readability.
lookup_ip();
}
void loop(void){
repeat_counter++;
Serial.print(F("Free RAM: ")); Serial.println(getFreeRam(), DEC);
Serial.print(F("Repeat counter: ")); Serial.println(repeat_counter);
Serial.print(F("starting connection to "));
Serial.println(ip);
Enable watch dog timer (WDT). See detailed
wdt_enable(WDTO_8S);
discussion at the end of this sketch.
connect_tcp();
Call the connect_tcp() function. This function
wdt_disable();
will attempt to connect to the remote web
server.
Serial.println(F("Connecting"));
if (www.connected()) {
Disable watch dog timer (WDT). It is not
Serial.println(F("Connected"));
likely that anything else may cause the sketch
to freeze.
make_get_request();
Serial.println(F("Request sent"));
Connection to the remote web server was
} else {
successful.
Serial.println(F("Connection failed"));

return; }
Call the make_get_request function which will
construct and apply the HTTP GET request.
Serial.println(F("-------------------------------------"));
unsigned long lastRead = millis();
while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
boolean currentLineIsBlank = true;
get_request
= "";

Keeps track of the time when the


boolean sentContent
= false;
last GET request was made.
while (www.available()) {

char c = www.read();
A response from the server is expected within
Serial.print(c);
3 seconds. The IDLE_TIMEOUT_MS constant
if(reading && c == '\n')
was set at the start of the sketch.
{ reading = false;
parseGetRequest(get_request);
break;
The server has started sending its response,
lets start parsing it.
}

Grab a character
from the response.

If we are currently reading, and this char is a new line, then reading is
finished, so lets parse the instruction. Nothing else to do here.
11

Peter Dalmaris

Arduino Step by Step

if(reading){
get_request += c; }

if (reading && c==\n') {


break; }

if (c == '\n' && currentLineIsBlank)


reading = true;
}
if (c == '\n') {
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}

Lecture 50

The HTTP response parser, continues.


It is essentially identical to the one
from Lecture 38 except for the green
segment. The content the parser is
looking for is in the body of the HTTP
response (not the query string like in
Lecture 38). The HTTP response is
found after the response header, and
is detected by looking for a new line
(\n) after a blank line.

Close the connection to the web

}
server.
www.close();
Serial.println(F("-------------------------------------"));
delay(10000); }
void parseGetRequest(String &str) {
Serial.print(F("Parsing this string:"));
Serial.println(str);
int
led_index = str.indexOf("led");
int
led_pin
= str[led_index + 3] - '0';
int
led_val
= str[led_index + 5] - '0';
executeInstruction(led_pin, led_val); }
void executeInstruction(int pin, int val){

Serial.println(F("Executing instruction"));
pinMode(pin, OUTPUT);
digitalWrite(pin, val);
Serial.println(F(Done!"));}

Instruction parser, identical to the one


in Lecture 38.

Execute instruction function, identical


to the one in Lecture 38.

bool displayConnectionDetails(void){
uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;
if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv)){
Serial.println(F("Unable to retrieve the IP Address!\r\n"));
return false; } else {
Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
Serial.println();
return true;
}
}
12

Peter Dalmaris

Arduino Step by Step

Lecture 50

void make_get_request(){
Get request is assembled by printing to the
www.fastrprint(F("GET "));
remote server represented by the www object.
www.fastrprint(WEBPAGE);
www.fastrprint(F(" HTTP/1.1\r\n"));
www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r
\n"));
www.fastrprint(F("\r\n"));
www.println(); }
void connect_tcp(){
t = millis();
do {
www = cc3000.connectTCP(ip, port); }
while((!www.connected()) && ((millis() }

Attempt to connect to the remote server if at


least 5 seconds (set in the connectTimeout
variable) have elapsed since the last connection.

t) < connectTimeout));

void connect_wifi(){
if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
Serial.println(F("Failed!"));
while(1); }
Serial.println(F(Connected!"));
}
void get_dhcp(){
Serial.println(F("Request DHCP"));
while (!cc3000.checkDHCP())
{
delay(100); }
while (! displayConnectionDetails()) {
delay(1000);
}
}

Attempt to connect to the Wifi access point.

Get network settings from the DHCP server.


Lookup the IP address of the remote server by
making a DNS request.

void lookup_ip(){
ip = 0;
Serial.print(WEBSITE); Serial.print(F(" -> "));
while (ip == 0) {
if (! cc3000.getHostByName(WEBSITE, &ip)) {
Serial.println(F("Couldn't resolve!"));
}
delay(500);
}
cc3000.printIPdotsRev(ip);
}

13

Peter Dalmaris

Arduino Step by Step

Lecture 50

About the WatchDog Timer

The Arduino, just like a normal computer, occasionally may hung or, in other words,
become unresponsive. This can be a result of hardware issues, like faulty sensors or
communications devices, or bugs in a sketch. As I was playing around with the CC3000
Wifi module while preparing this demo, I noticed that the Arduino would hung after a few
(around 20) loops. Each loop represents a poll of the control text file from the web server. I
discovered that the most likely cause of this behaviour was memory fragmentation. Memory
fragmentation occurs when data in RAM is erased and saved in a way that over some
period of time even though there is a lot of memory available, it is only available in small
chunks; this makes it almost usefulness unless you only want to store a byte or so at a
time. Have a look at this screenshot from the Microsoft Windows Disk Defragmenter utility:

http://i.stack.imgur.com/00nX7.jpg

The hard disk that is visualised in this map contains free space (shown in white), but that
space is not contiguous, so you can only store small files in it. A normal computer has the
resources to defrag, that is to re-arange the contents of the memory (or hard disk) in order
to create larger and more useful contiguous segments of free memory.

Working on this demo, I realised that the connectTCP function would, over time, fragment
the SRAM until the free space available could not be used, and then the ATMega would
freeze.

On the Arduino, there is no practical way to achieve defragmentation other than reseting the
micro-controller. To make this work, I used a feature build-in to ATMegas called Advanced
Watchdog Timer (http://www.atmel.com/Images/doc2551.pdf). This feature makes it
possible to set a timer so that if by the time the timer reaches a set limit the watchdog has
14

Peter Dalmaris

Arduino Step by Step

Lecture 50

not detected any activity ((heart beat) it assumes that the micro-controller has become
unresponsive. The watchdog will then reset the micro-controller, and the sketch will start
executing with a clear slate - and a de-fragmented memory.

The way I set the watchdog timer is this:

1. I identified the segment of the sketch that seems to be causing fragmentation and/or is
aected by it. I used lots of Serial.print statements to figure out where the sketch
hangs. In the Demo 2 sketch, this was the call to the connect_tcp() function.

2. Just before the oending call, add the call to wdt_enable(WDTO_8S). This enables the
WatchDog Timer and sets a timer for 8 seconds. This time I think was enough for
nothing to happen. In other words if 8 seconds pass with no activity, reset the device.

3. After the oending call, add the call to wdt_disable(). This disables the WatchDog Timer.
If anything outside this block causes my sketch to hung, I want to know about, so I
dont want the WDT
to reset the device
and mask such
behaviour.

Yes, I could potentially


dig into the source code
of the CC3000 that
causes this problem
(the connectTCP
function), and I might
actually do this once I
can allocate some time
to it, however the WDT
oers a simple and
cheap solution.

Output
Execute this sketch, and
you will get something like
this:

Connecting to Wifi access point.

Device and network details.


IP of remote web server resolved.

Connect and transmit HTTP request to


remote web server.

Receive HTTP response and find


the string that contains the
instruction.

Parse the instruction and then


execute it.

Re-start the HTTP GET/response


process.
15

Peter Dalmaris

Arduino Step by Step

Lecture 50

Demo 3: Control an LED via Wifi and a web server


running on the Arduino

For this last demo, we will modify the sketch from Lecture 38 Demo 2 so that instead of
working with an Ethernet shield, it will work with the CC3000 Wifi breakout.

We will use the exact same circuit as in Demo 2. Lets go straight to the sketch and see
whats dierent

Sketch

This sketch is a hybrid between the sketch in Demo 2 and that of Lecture 38 Demo 2.
Comments are embedded.

#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include "utility/debug.h"
#include <stdlib.h>
#define ADAFRUIT_CC3000_IRQ
3
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS
10
define WLAN_SSID
"yournetworkssid"
define WLAN_PASS
yournetworkpassword"
#define WLAN_SECURITY
WLAN_SEC_WPA2
#define LISTEN_PORT
80

Inclusions and definitions as in the previous


examples, with the addition of LISTEN_PORT
which defines the TCP port on which the web
server will listen for connections.

Create the device object.

Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS,


ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,SPI_CLOCK_DIV2);
// Create server
In Lecture 38, we used the
Adafruit_CC3000_Server ledServer(LISTEN_PORT);
EthernetServer class to create the
String
get_request = "";
server. Here, we use the custom
boolean
reading
= false;
Adafruit_CC3000_Server class.
continues next page

16

Peter Dalmaris

Arduino Step by Step

Lecture 50

void setup() {
Serial.begin(115200);
Start the device.
Serial.println(F("\nInitializing..."));
if (!cc3000.begin()) {
Serial.println(F("Couldn't begin()! Check your wiring?"));
while(1); }
if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
Serial.println(F("Failed!"));
while(1); }
Connect to the Wifi access point.
Serial.println(F("Connected!"));
Serial.println(F("Request DHCP"));
Get network parameters from the
while (!cc3000.checkDHCP()) {
DHCP server.
delay(100); // ToDo: Insert a DHCP timeout!
}
Show network parameters leased
while (! displayConnectionDetails()) {
from the DHCP server.
delay(1000); }
ledServer.begin();
Serial.println(F("Listening for connections..."));
}
Start the web server

void loop() {
Adafruit_CC3000_ClientRef client = ledServer.available();
String return_message;
if (client) {
The contents of the loop() function are
boolean currentLineIsBlank = true;
virtually identical to that from Lecture
38, Demo 2, with the exception of the
get_request
= "";
client object. Here we use the
boolean sentContent
= false;
Adafruit_CC_3000_ClientRef class
while (client.available()) {

instead of EthernetClient.
char c = client.read();
if(reading && c == ' ')
{ reading = false;
return_message = parseGetRequest(get_request);
break;
}
if(c == '?'){
reading = true;
}

if(reading){
get_request += c;
}
if (reading && c=='\n')
{

break;
}
if (c == '\n' && currentLineIsBlank) {
break;
}
}

!
17

Peter Dalmaris

Arduino Step by Step

if (!sentContent){
construct_page(client, return_message);
sentContent = true;
}
delay(5);
client.close();
Serial.println("client disconnected");
result = "";

Lecture 50

}
}
void construct_page(Adafruit_CC3000_ClientRef &client, String &rmessage)
{
print_header(client);
print_form(client);
print_confirmation(rmessage, client);
end_page(client); }
void print_header(Adafruit_CC3000_ClientRef &client)
{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.print("<html><head><title>");

client.print("GET request example");


client.println("</title><body>");
}

These functions are identical to the


ones from Lecture 38, Demo 2 with
one exception only: instead of
passing a reference to a
EthernetClient object, here we pass a
reference to an
Adafruit_CC3000_ClientRef object.

void print_confirmation(String &confirmation_message, Adafruit_CC3000_ClientRef


&client)
{
client.print("Action(s) performed: <b>");
client.print(confirmation_message);
client.print("</b>");
}
void print_form(Adafruit_CC3000_ClientRef &client)
{
client.println("<h2>Click buttons to turn pin 8 on or off</h2>");
client.print("<form action='/' method='GET'><p><input type='hidden'
name='led8'");
client.println(" value='0'><input type='submit' value='Off'/></form>");
client.print("<form action='/' method='GET'><p><input type='hidden'
name='led8'");
client.print(" value='1'><input type='submit' value='On'/></form>");
}

18

Peter Dalmaris

Arduino Step by Step

Lecture 50

String parseGetRequest(String &str) {


Serial.print(" Parsing this string:");
Serial.println(str);
int
led_index = str.indexOf("led");
int
led_pin
= str[led_index + 3] - '0';
int
led_val
= str[led_index + 5] - '0'; These functions are identical to the
ones from Lecture 38, Demo 2.
String return_message = "";
return_message = "Setting LED ";
return_message += led_pin;
return_message += " to ";
return_message += led_val;
executeInstruction(led_pin, led_val);
return return_message; }
void executeInstruction(int pin, int val){
pinMode(pin, OUTPUT);
digitalWrite(pin, val);}

bool displayConnectionDetails(void){
uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;
if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))
{
Serial.println(F("Unable to retrieve the IP Address!\r\n"));
return false; }
else {
Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
Serial.println();
return true;
}
}

19

Peter Dalmaris

Arduino Step by Step

Lecture 50

Using the sketch from Demo 2 in Lecture 38 as a building block, we now have the same
capability to control the state of an LED using a web browser but wirelessly. Running this
sketch generates this output in the monitor:

!
!
!
!
!
!
!
!
!
!
!
!
!

The Arduino is listening at this IP


address.

A connection from a web client was


made, an instruction was parsed.

Use a web browser and go to your Arduinos IP address, you should see the same user
interface as in Lecture 38, Demo 2:

!
!
!
!
!
!
!
!
20

Peter Dalmaris

Arduino Step by Step

Lecture 50

An exercise

In this lecture, we covered a lot of ground in regards to using the Adafruit CC3000 wifi
module to control our Arduino wirelessly. The module we used still has its supporting
library under development, so I expect that its features and stability will improve over time.
The module comes in two types, one with a build-in ceramic antenna, and one with a
connector for an external antenna. An external antenna can be used for projects where
range is important, like when you want to control your quad-copter outdoors.

As an exercise for this lecture, how about you try to extend the Demo 2 and Demo 3
examples with the ability to control more devices? For example, for Demo 2, add a couple
of lines in the instructions file so that you can control additional LED, or motors (you may
want to review Lecture 39 for this). Because polling takes place every few minutes, you
would use the Demo 2 sample in a project like home automation and control, where realtime is not necessary.

21

Peter Dalmaris

Lecture 54

Arduino Step by Step

Lecture 54
Single Wire LCD screen

In Lecture 24, you learned how to display text in a LCD screen. Although this was a simple
way to show useful information to the user, the sheer number of wires required to make the
LCD screen work makes this solution far from elegant.

In this lecture, I will show you a much improved solution to the same problem, one that
involves a single data wire (plus power).

The dierence is stark. Have a look at the before (left) and after (right) images for the
exact same result.

To achieve this reduction in total number of wires we have to switch the type of interface we
use to connect the screen to the Arduino. Natively, the screen uses a parallel interface,
where each of the 8 bits that make up a character encoding uses up a wire. You may
remember that in Lecture 24, use used a 4-bit parallel mode instead of the full 8-bits in
order to save 4 wires. Still, even 4 wires are too many for transferring data. We also needed
wires for power, and for the screen backlit.

To improve the design, well use an adaptor that allows us to connect the parallel LCD
screen to the Arduino using the I2C serial bus. We have used I2C before, but here is a quick
recap:

Uses 1 wire for data (SDA - pin A4 on the Arduino Uno)

Uses 1 wire for clock (SCL - pin A5 on the Arduino Uno)

Uses 1 wire for +5V power and 1 for ground

Can be shared amongst multiple I2C devices, which means that you can connect multiple
compatible devices to your Arduino without increasing the wire count.

Peter Dalmaris

Lecture 54

Arduino Step by Step

The adaptor Ill use in the demos is the 1602LCD


Display I2C board, like the one in this image.

It contains two rows of connectors: the long one


that connects to the 16x2 LCD screen, and the
short one that implements the I2C interface and
connects to the Arduino. On the board there is also
a potentiometer that you can use to adjust the
brightness of the screen, and the micro-controller
that handles that conversion and communications
workload.

In Demo 1, Ill show you how to connect the


1602LCD to the screen and the Arduino. In Demo 2, I will add a second I2C device to the
circuit, a real-time clock, and show you how the same I2C wires can be used to drive both
devices by displaying the time from the clock to the LCD screen.

Demo 1: Connect the 16x2 LCD screen via I2C

When you purchase the


1602LCD adaptor, it typically
arrives without the headers
attached, so you will have to
the soldering your self. The
spacing and configuration of
the 16 pins in the long row
match exactly that of the pins
on the LCD screen PCB.

Use a mini breadboard if you


have one, and line up the
LCD screen and the adaptor
like in this image.

On the adaptor, check the markings of the 4 pins. Connect the GND to GND on the
Arduino, VCC to 5V. Then, connect SDA (DAta) to analog pin 4 on the Arduino Uno, and
DCL (CLock) to analog pin 5. You are not done with the wirings!

You now need to install an LCD I2C library that will replace the original LiquidCrystal library
that comes with the IDE. There are several options that you could use, but the one that I
found easy to use and tested for this lecture is the LiquidCrystal_I2C available here.
Download the ZIP archive from this page and install it in your IDEs Libraries folder. Dont
forget to restart the IDE for the install process to complete!

!
2

Peter Dalmaris

Lecture 54

Arduino Step by Step

Sketch

Heres the sketch, with annotations embedded.

This library implements the I2C protocol.


#include <Wire.h>
#include <LCD.h>
This library allows you to use various LCD displays.
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


void setup(){
lcd.begin(16,2);
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Hello world!");
lcd.setCursor(0, 1);
lcd.print("Row number: ");
lcd.setCursor(12, 1);
lcd.print("2");
}
void loop(){
}
Same use of LCD functions
as we saw in lecture 24.

This library allows you to use the functionality offered


by the standard LCD library via the I2C bus.
Initialise the lcd object that well use to write to the
screen. The first parameter 0x27 is the I2C address
of the adaptor (more about this further down). The
rest of the parameters are:

1: Device address
2: LCD screen enable (En) pin
3: LCD screen read/write (R/W) pin
4: LCD screen reset (Rs) pin
5: LCD screen data 0 pin
6: LCD screen data 1 pin
7: LCD screen data 2 pin
8: LCD screen data 3 pin
9: LCD screen backlight pin
10: LCD screen backlight polarity (POSITIVE or
NEGATIVE)

About I2C addresses

Because I2C is a shared serial bus, we need a way for each connected device to be able to
detect which of the messages that are flowing through the common wires is meant to be
read by them. On the flip side, the Arduino (or any master device) needs to be able to
determine which of the connected devices transmitted a message.

This is achieved by setting an address for each connected device. This address needs to
be unique within the group of the devices that are sharing the bus. Most devices, like the
LCD adaptor in this demo, come with an I2C address preset from factory that, in my
experience, does not conflict with addresses from other devices as long as they are not of
the same type. For example, if you connect an LCD screen adaptor and a real-time clock to
the same I2C bus, chances are that there will be no conflict with their preset addresses and
they will work out of the box.

But lets say you wanted to attach two LCD screens to the same I2C bus, using two
separate, but of the same type, LCD adaptors. In this case, you will need to change the
address of one of the two adaptors. Most I2C devices provide a way to do this, usually by
changing the configuration of jumpers or soldering address pins.

Peter Dalmaris

Lecture 54

Arduino Step by Step

If you take a look at the front side


of the 1602LCD board, you will
notice 3 pads. By bridging those
pads vertically (a bit of solder will
do), you can change the I2C
address of the device. The
1602LCD provides 3 pairs of
pads, so you can have a total of 7
possible addresses.

Demo 2: I2C bus sharing by a LCD screen and a


real-time clock

In the second demo, well combine 2 devices on the same I2C bus. Well use the LCD
adaptor from Demo 1, and the real-time clock from Lecture 48.

Here is what we are going to build:

1. Plug the DS1307 real-time clock at


the left end of the mini breadboard.

2. Plug the 16x2 LCD screen at the


right bottom end of the
breadboard.

3. Plug the LCD adaptor so that its


pins are aligned correctly with the
LCD screen, like we did in Demo 1.

4. Plug the Arduino GND and 5V pins


to the power strip at the top of the
breadboard.

4
3

5,6
1

5. Using the breadboard socket


column where the real-time clock
PCB is connected, connect the
SDA and SCL pins of the LCD adaptor to the corresponding pins of the real-time clock.

6. Using the same columns as in step 5, connect the SDA wire to Arduino Uno analog pin
4 and the SCL wire to the Arduino Uno analog pin 5.

7. Connect the power wires from the LCD adaptor and the real-time clock to the
breadboards top power power strip.

By default, the DS1307 is listening to I2C address 0x68 while the LCD adaptor to address
0x27 so there is no conflict.

Peter Dalmaris

Lecture 54

Arduino Step by Step

Sketch

Lets have a look at the sketch. Comments are embedded.

#include <Wire.h>
#include "RTClib.h"
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
RTC_DS1307 rtc;
Same as in Demo 1

void setup () {
Add the real-time clock library
Serial.begin(9600);
Start the I2C bus.
Wire.begin();
lcd.begin(16,2);
Start the LCD screen with 16 columns, 2 rows, and
lcd.backlight();
turn backlight on.
rtc.begin();
the real-time clock module, and set the time
rtc.adjust(DateTime(__DATE__, __TIME__)); Start

and date to the system time and date during


}
compilation.

void loop () {
DateTime now = rtc.now();
Serial.print(now.year(), DEC); Serial.print('/');
Serial.print(now.month(), DEC); Serial.print('/');
Serial.print(now.day(), DEC); Serial.print(' ');
Serial.print(now.hour(), DEC); Serial.print(':');
Serial.print(now.minute(), DEC); Serial.print(':');
Serial.print(now.second(), DEC); Serial.println();
lcd.setCursor(0, 0);
lcd.print(now.year(), DEC); lcd.print('/');
if (now.month()<10)
{ lcd.print("0"); }
lcd.print(now.month(), DEC); lcd.print('/');
if (now.day()<10)
{ lcd.print("0"); }
lcd.print(now.day(), DEC);
lcd.setCursor(0, 1);
if (now.hour()<10)
{ lcd.print("0"); }
lcd.print(now.hour(), DEC); lcd.print(':');
if (now.minute()<10)
{ lcd.print("0"); }
lcd.print(now.minute(), DEC); lcd.print(':');
if (now.second()<10)
{ lcd.print("0"); }
lcd.print(now.second(), DEC);

delay(100);
}

Get the time from the real-time


clock and print it to the Serial
monitor.

Set the LCD cursor to column 0,


row 0, and print the year in
decimal notation, followed by a
/.
If the month is single digit, then
add a 0 in before printing the
month digit so that the month
segment always aligns well.
Print the month, followed by a /.
Similarly to printing out the month,
add a 0 in front of single digit
days, hours, minutes and seconds.

Peter Dalmaris

Lecture 54

Arduino Step by Step

Conclusion and exercise

You now know how to connect an LCD screen to your Arduino using a single data wire, and
how to combine multiple devices on a single I2C bus.

In this lecture, we used a real-time clock with an LCD parallel to serial adaptor. As an
exercise, try to add one or two additional IC2 devices. Heres some recommendations:

* Add a BMP085 temperature and barometric sensor. We saw this device in lecture 9.
Display the temperature and humidity in the LCD screen.

* Add an SD card module. We saw this device in lecture 45. Store BMP085 readings in a
log file.

* A total of 127 can be attached to an I2C bus. Here is a sketch that can detect and report
all connected devices, try it out: http://playground.arduino.cc/Main/I2cScanner

* Although we have not yet discussed adding external EEPROM modules to your Arduino,
understanding how they work easy based on your existing knowledge. You can consider
the AT24C256 Serial EEPROM device, an inexpensive way to add memory to your
project. It uses the I2C interface, and is easy to use with the appropriate library.

Peter Dalmaris

Interrupts

Arduino Step by Step

Interrupts
!

Up to now in our examples, we have been using the loop() function to periodically poll
things like sensors and buttons for their values. For example, in the push button lecture we
used this sketch to check on whether the button was pressed or not and light up an LED if
it was (only showing the loop() function and the code that is relevant here):

void loop()
{
int val = digitalRead(inputPin); // read input value
Turn an LED on if the inputPin is HIGH
}
The Arduino checks (digitalRead) the voltage level in the inputPin and then does some
processing depending on the value that was read. The digitalRead will execute regardless
of whether the button was actually pressed or not. If we execute this code on an
Atmega328 which typically runs at 8MhZ will roughly poll the inputPin 8 million times per
second, and every one of these measurements will come out false since most of the time
the button is not pressed. This is a great waste of resources.

But it can get worse. If the Arduino needs to do other work within the loop, like check on
other sensors or communicate with a web service, it is possible that when the user presses
on the button, the Arduino will never notice because it had not yet reached the digitalRead
instruction at the time of the button press. The Arduino was busy doing something else.

This problem can be solved with an Atmega 328 feature called Hardware Interrupt. This
lecture will show you how to use the hardware interrupt. In the this lecture, I will also show
you how to use a relevant feature called the Time Interrupt.

Hardware Interrupt

A hardware interrupt provides the ability to tie a special pin with a function in your sketch
that will be executed with priority when the state of the pin changes in a particular way.

You can configure the pin and the kind of signal you want to generate an interrupt request,
and tie this to a small interrupt request function. This function is meant to handle the
interrupt. I will give you an example in a minute.

Each Atmega micro-controller has a specific set of pins that can be used as interrupt pins.
For the Atmega328p (which you find in the Arduino Uno) these are digital pins 2 and 3. The
Arduino Mega, which is based on the Atmega2560, provides interrupts in pins 2, 3, 18, 19,
20, and 21.

Each interrupt is identified by a interrupt number, like 0, 1, 3, etc.

Peter Dalmaris

Interrupts

Arduino Step by Step

This table contains the interrupt numbers and associated pins for the more popular
Arduinos:

Table 1: Interrup IDs and pins for some popular Arduinos


Board

int.0

int.1

int.2

int.3

int.4

int.5

Uno,
Ethernet

Mega2560

21

20

19

18

Leonardo

Lets have a look at our first hardware interrupt example and discuss some of the
implementation details.

Demo 1

In this first demo, well take the circuit from Lecture 16 and only modify the sketch it so that
the LED is lit as a response to an interrupt generated by the button, instead of by polling the
state of the button a few million times per second.

Well use the same circuit as in Lecture 16. We


have a push button and a pull-up resistor
connected to digital pin 2, and an LED with its
protective resistor connected to digital pin 13.
You can skip this LED if you prefer and just use
the build LED on the Arduino itself.

Heres the list of parts:

A standard push button

A pull-up resistor, around 40k.

A 5mm LED

A 1k resistor for the LED.

Thats simple enough, lets move to the sketch.


Comments are embedded.

Peter Dalmaris

Interrupts

const int ledPin = 13;


const int inputPin = 2;

Arduino Step by Step

Well connect the button to digital pin 2. This pin


corresponds to interrupt number 0 for the Uno.

Set the LED pin to 13.


void setup() {
pinMode(ledPin, OUTPUT);
attachInterrupt(0,buttonPressed,FALLING);
}

void loop()
{
}

Nothing
happening
here!

void buttonPressed()
{
if (digitalRead(ledPin))
digitalWrite(ledPin,LOW);
else
digitalWrite(ledPin,HIGH);
}

Setup the interrupt handler. Here are the parameters:


- 0: Interrupt ID 0, which is digital pin 2
- buttonPressed: the name of the interrupt handler
function
- FALLING: an interrupt is captured when the signal
level in pin 2 goes from HIGH to LOW

The interrupt handler function. You cant pass any


parameters of return any data. Keep processing to
a minimum.

In this small sketch, notice how the loop() function is empty. We are going to handle the
button presses in a separate function, buttonPressed(). The name of the function is not
important, you can choose an valid identifier.

In the setup() function, we create the interrupt by calling the attachInterrupt function. This
function requires three parameters:

1. The interrupt ID. This is an integer that corresponds to the ping where we attach the
interrupt device. The IDs for some of the popular Arduinos are shown in Table 1. In the
sketch, we use ID 0, which corresponds to digital pin 2.

2. The interrupt handler function name. This function contains a small amount of code,
just enough to handle the interrupt and then allow the Arduino to continue with
whatever it was doing before the interrupt.

3. Interrupt mode, which is the kind of event that should trigger an interrupt. With this
parameter you are telling the Arduino the type of electrical event it should be monitoring
which would be perceived as an interrupt. In the example sketch, the literal FALLING
tells the Arduino to look out for voltage that goes from HIGH to LOW, and when it
detects that to interpret it as an interrupt. Table 2 (below) contains a list of valid
interrupt modes.

Peter Dalmaris

Interrupts

Arduino Step by Step

Table 2: Interrupt modes


Mode

Description

LOW

Trigger the interrupt whenever the pin is LOW

CHANGE

Trigger the interrupt whenever the pin changes value

RISING

Trigger when the pin goes from LOW to HIGH

FALLING

Trigger the interrupt when the pin goes from HIGH to LOW

HIGH

Trigger the interrupt whenever the pin is HIGH (only available in the
Arduino Due)

In the sketchs present form, the LED will light up when you press and release the button,
then light down when you press and release again. Try this small variation: change the line

attachInterrupt(0,buttonPressed,FALLING);
to

attachInterrupt(0,buttonPressed,CHANGE);
then compile and upload the sketch. Press the button a few times and observe the
behaviour of the LED. What do you see? (Hint: The LED now lights-up when you press the
button, and remains lit until you release the button).

Things to remember about hardware interrupts

Hardware interrupts have certain constraints that you need to keep in mind when you
design your app. Here they are in a nutshell.

1. You cannot pass a parameter to the interrupt handler function.

Hardware interrupts are designed to capture simple events from the outside world. As a
result, parameters like those passed to functions make no sense.

2. The interrupt handler function cannot return any data (a way around this problem is
suggested in Demo 2), and their return type should always be void.

Same thinking goes here. The interrupt originated from the outside world, something like a
button. It makes no sense to return a value to a button. However, there is a use case where
we need the interrupt handler to update the value of a variable in our sketch, like a counter.
This is possible, and Ill show you how in Demo 2.

3. Interrupt request handlers should be as small as possible.

While the interrupt request handler is running, all interrupts on the micro-controller are
disabled. If you have attached a second button to the second interruptible pin on the
Arduino Uno and you press it while the micro-controller is in the handler of the first button,
4

Peter Dalmaris

Interrupts

Arduino Step by Step

then the second button press will be ignored. In fact, anything that uses interrupts will not
work while an interrupt request is being serviced. This includes things like the delay() and
millis() functions, and the loop() function also will be stuck to the line it was at when the
interrupt happened.

4. It is possible to disable hardware interrupts anywhere in your sketch. To do this, use the
interrupts() and noInterrupts() functions. The former one will enable interrupts, while the
second one will disable them. You may want to do something like this in cases where you
are timing an event and you want your measurement to be accurate, when you are writing
serial data to an external device like an SD card or similar. Your code could look a bit like
this:

void loop()
Turn off hardware interrupts.
{
noInterrupts();
Heres the code that should not be interrupted.
// critical, time-sensitive code here
interrupts();
Turn on hardware interrupts.
// other code here
}
The critical code that should not be interrupted can simply be code that modifies a variable
that may also be modified from inside a interrupt handler function. More about such
variables is discussed in Demo 2.

Peter Dalmaris

Interrupts

Arduino Step by Step

Demo 2: Use a volatile variable

In the second demo, well add a volatile variable which the code in the interrupt request
function will be able to access and update.

This variable will keep track of the number of times that we have pressed on the button.

Heres the sketch with comments embedded, a discussion follows.

const int ledPin = 13;


const int inputPin = 2;
volatile byte counter = 0;

We declare a byte (8 bits) variable named counter


and initialize it to zero. We mark it with the volatile
keyword to indicate to the compiler that this variable
may change at any time and should not be cached in
a CPU register but instead should be always loaded
from the RAM.

void setup() {
pinMode(ledPin, OUTPUT);
attachInterrupt(0,buttonPressed,FALLING);
Serial.begin(9600);
}
void loop()
{

}
void buttonPressed()
{
counter++;
Serial.println(counter, DEC);
if (digitalRead(ledPin))
digitalWrite(ledPin,LOW);
else
digitalWrite(ledPin,HIGH);
}

Increase the counter by 1.


Print the value stored in counter, format it as a
decimal.

In this sketch, the only dierence is the addition of the volatile byte variable counter and
the increment operator on this counter in the interrupt handler function. We also print the
value of this counter every time it gets updated.

So what exactly is the purpose of the volatile keyword? If the keyword is not used, then
the compiler will generate machine code that optimises the use of this variable by caching it
in a CPU register whenever possible. For example, if the counter variable is used inside a
loop, then it is possible that instead of storing the value of the variable in RAM, it will be
stored in one of the available registers. A CPU register is several times faster than the RAM,
and therefore this caching represents a gain in performance. By indicating to the compiler
that counter is volatile, the compiler mark it so that it will never be cached in a register.
Instead, it will be always stored and fetched from the RAM, meaning that it will be always

Peter Dalmaris

Interrupts

Arduino Step by Step

current, regardless of whether it is manipulated by code in the loop() function or in an


interrupt handler function.

Before finishing the Demo, consider the case where you would like to print (or just access)
the value stored in the counter variable inside the loop function. You can add the code for
this inside the loop function like this:

loop(){
Serial.println(counter);
}
The problem with this is that the println instruction may try to access the counter variable at
the precise moment when an interrupt request is generated by the button. In this case, the
value that is printed is not possible to determine. to guard against such situation, we
enclose the instruction that accesses the volatile variable within a noInterrupts() and
interrupts() block, like this:

loop(){
noInterupts();
Serial.println(counter);
interrupts();
}
With this guard in place, a button press during the time that the Serial.println instruction is
being executed will be ignored. The chances of this happening while an actual button press
are few, as long as you keep the processing that is happening within the noInterupts() and
interrupts() block to a minimum.

Peter Dalmaris

Interrupts

Arduino Step by Step

Demo 3: Timer interrupts

A timer interrupt is an interrupt that the Atmega generates using an internal timer, rather
than an external event.

You could create, for example, a sketch that checks on a sensor every 5 seconds without
using the delay function. A timer interrupt can be easily set with the help of the TimerOne
library and can be use to create timers from 1ms to 8,388,480 or around 8.4 seconds.

In this demo, well make an LED blink by setting a timer to trigger an interrupt once every
second. The sketch follows, with embedded comments:

#include <TimerOne.h>

A library that makes it easy to use timer interrupts,


written by Simon Monk.

int ledPin = 13;


volatile int ledState = HIGH;
Initialize the timer and set the period duration. The
void setup()
parameter is in microseconds. One second is one
{
million microseconds.
pinMode(13, OUTPUT);
Timer1.initialize(1000000);
Timer1.attachInterrupt(toggleLED);
}

void loop(){ }
void toggleLED()
{
digitalWrite(ledPin, ledState);
ledState = !ledState;
}

Attach the timer interrupt to a handler function.

The interrupt handler simply toggles that state


of the LED.

First, include the TimerOne library in the sketch. The one I used is a newer and enhanced
fork of the original TimerOne, and you can download it from https://github.com/
PaulStoregen/TimerOne.

In the setup() function, we initialize the timer with a value that represents the period duration
in microseconds. So, 1 second is equal to 1 million microseconds. Then, we attach the
timer interrupt to a function that will handle it, by name.

In the interrupt handler, we set the LED state, which is updated every time the function is
called. The instruction ledState = !ledState takes whatever value is currently stored in
ledState, flips it, and stores the new value to itself.

!
!
8

Peter Dalmaris

Interrupts

Arduino Step by Step

Demo 4: High-definition PWM

The TimerOne library also contains several other useful functions that you can explore. One
of them provides that ability to create very accurate PWM output. Normally, using the
analogWrite function, you can create PWM output on a scale from 0 to 255.

Calling this:

analogWrite(127);
will create a PWM waveform with a duty cycle of 49.80% (since 255 -> 100%).

Calling this:

analogWrite(128);
(notice that we just went from 127 to 128), will create a PWM waveform with duty cycle
of 50.19%.

If you are trying to generate more accurate waveforms, you can do it using the TimeOne
library like this:

Timer1.pwm(pin, duty);
where pin is a digital pin that the library supports, and duty is an integer from 0 to
1024.

In the Arduino Uno, we can use pins 9 and 10. See the librarys documentation for
information on pin support in other models.

So, this:

Timer1.pwm(9,300);
would have a duty cycle of 29.29% (since 1024 -> 100%), and

Timer1.pwm(9,301);
would have a duty cycle of 29.39%. You can see how with TimeOne you have much finer
control over the waveform that your PWM pin is able to produce.

Peter Dalmaris

Interrupts

Arduino Step by Step

Connect the LED to digital pin 9, and try out this sketch:

#include <TimerOne.h>
int ledPin = 9;

Set the overall period to 1000 microseconds. Playing


around with this value does not produce any
dramatic effect, so dont worry too much about it.

void setup()
{
Timer1.initialize(1000);
Timer1.pwm(ledPin,0);
pinMode(ledPin, OUTPUT);
}

Initialise the initial PWM duty cycle to 0 out of 1024.


We need to use the pwm function at least once
before using the setPwmDuty to change the duty
cycle later.

void loop(){
Timer1.setPwmDuty(ledPin,
delay(1000);
Timer1.setPwmDuty(ledPin,
delay(1000);
Timer1.setPwmDuty(ledPin,
delay(1000);
Timer1.setPwmDuty(ledPin,
delay(1000);
}

250);
500);
800);

Change the PWM duty cycle to a new level, then


wait for a second.

1024);

You should see that the LED lights up very gradually and finely, the eect of the small
increase in the PWM duty cycle will every loop cycle.

Conclusion

In this lecture you learned about hardware and timer interrupts, how to handle them, where
they might be useful, and some of their limitations.

Often, interrupts are the ideal solution to getting the Arduino to respond to events that are
infrequent without unnecessary waste of resources. But think carefully before you make use
of them, they can often be dicult to debug, especially when you have implemented more
than trivial functionality.

10

Peter Dalmaris

Shift Registers

Arduino Step by Step

Shift registers
The Arduino only has a relatively small number of digital outputs. While there are enough of
them to get us through the examples in this course, in most real life projects they will be not
enough.

Take, for example, the the case of a gadget that contains a character LCD screen, a couple
of status LED, a couple of buttons, and a couple of sensors and a Wifi breakout. You will
need 2 pins for the screen (using the serial to parallel adaptor), 2 for the LEDs, 2 for the
buttons, at least 2 for the sensors, and 6 for the Wifi breakout. That more or less exhausts
the available ports.

Sooner or later you will need a way to multiply the available inputs and outputs so that you
can connect a larger variety of peripherals.

In this lecture, Ill show you how to use shift registers to multiply the available digital
outputs. In a later lecture I will also introduce you to I2C-driven port expanders. These
technologies make it possible to design ever larger and realistic gadgets using a single low
cost micro-controller.

Before getting into it, I should highlight that more available ports do not automatically
guarantee that you will be able to create larger gadgets. Once the input/output port
availability is dealt with, the next potential show stopper is memory. At 32Kbytes of flash
memory, it becomes dicult to create sketches that match the ever growing hardware they
are supposed to drive. So, also in a later lecture I will talk about ways to manage and
optimise memory use.

Peter Dalmaris

Shift Registers

Arduino Step by Step

What is a shift register?

Think of a shift register as a single-byte memory. Each of the bits in this memory is
connected to the outside world via a pin on the package of the chip that contains the
memory. You use a single data pin from the Arduino to write each bit, one at a time.

Because each bit is written individually, and all bits can be read all at once, we say that a
shift-register is a device that supports serial in and parallel out.

To support the serial transfer of bits from the Arduino to the shift register chip, we need a
second pin that provides a clock signal. Every time the clock ticks, one bit is transmitted
from the Arduino to the shift register. Once the new bit is received by the shift register, all
existing bits are shifter by one bit to make room for the new one. This shifting process is
what gave the name shift register to this device. Heres a graphical way to look at this
process:

Lets say that wed like to store the byte 11001101 in the shift register represented by this
table. At start, the shift register has an undeterminable state, so Ill represent this with a
question mark.

This is Step 0:

In Step 1, well take the least significant bit (first from the right - 11001101), wait for the
clock to tick, and shift it in the register. We could have chosen to start with the most
significant bit just the same.

This is Step 1:

Notice the grey box at the end of the register. This is an additional overflow bit memory
that stores the bit that was shifted into it from the bit on its left. We will be using this
overflow bit in Demo 2 when we create a circuit that uses two shift registers connected in
series.

In Step 2, well take the next least significant bit (second from the right - 11001101), wait for
the clock to tick, and shift it in the register. Notice that the original first most significant bit
(1) is greyed out to show that it has already been transmitted to the register. We now also
have the first bit that shifts out of the overflow bit and is lost for all eternity. Im only
including it here outside the register to emphasise the outcome of the shift function.

This is Step 2:

In Step 3, the same process continues: clock ticks, next bit in 11001101 is sent to the
shift register, and all existing bit in the register are shifted one position to the right to make
room for the new bit.

This is Step 3:

??

I will speed up the rest of the sequence:


2

Peter Dalmaris

Shift Registers

Arduino Step by Step

This is Step 4 11001101:

!
!

???

????

?????

??????

???????

This is Step 5 11001101:

!
!

This is Step 6 11001101:

!
!

This is Step 7 11001101:

!
!

This is Step 8 11001101:

!
!

And finally, the complete byte has been shifted into the shift register. You can sent single
bits to the register, its not necessary to do so for a whole byte (though most libraries make
the latter easier than the former). For example, lets say that you wanted to sent a 0 to the
register, which already contains the values from the previous experiment. You would end up
with these new contents in the register:

!
!

????????

The original least significant bit from the first experiment has now been shifted into the
overflow bit cell to make room for the new value at the left end of the register.

Another way to think about the way that this register operates is FIFO: First bit in is First
bit out.

I hope you have a solid understanding of this process now, it will make it easy to
understand what is happening with Demo 1 which follows. If you feel unclear about
something, read this section again or ask a question in the forum.
3

Peter Dalmaris

Shift Registers

Arduino Step by Step

Demo 1: Drive 8 LEDs with a single data wire

Normally, to drive an LED you need to connect it to one of the Arduinos outputs. If you
need to drive two LEDs, then you need 2 outputs. Etc. Etc.

In this demo, well drive LEDs by using a single data wire, with the help of a shift register.
Shift register chips are very cheap and made by many dierent companies. A typical one is
the 74HC595N. This device provides 8-bit storage, plus one for the overflow. The particular
one I used is made by NXP, and you can find its datasheet here. The first thing you want to
look at in the datasheet is the pin out diagram so that you can see the functionality of each
pin. I have grabbed this from the datasheet. I define the pin functions in the table next to
the diagram.

Pin # Symbol Description


1-7

Q1-Q7

Data out pins 1 to 7. Notice that Q0 is


on pin 15

8 GND

Ground

9 Q7S

This is the overflow bit. It will store the


bit shifted out of Q7.

10 MR
Master reset. If this pin is grounded,
inverted the chip is reset. Well keep it
connected to 5V.

11 SHCP

Clock input. This pin will receive the


clock pulses from the Arduino. With
each clock pulse, the bits are shifted.

12 STCP

Latch. Make this LOW while the bits


are shifting to prevent devices
connected to the outputs from
reading transient values (values are
frozen to those before shifting
begun). Once the bit shifting is
complete, make this HIGH to allow
the connected devices to read the
new values.

13 OE
Enable or disable output pins. We will
inverted keep it always connected to GND so
that outputs are always enabled.
14 DS

The data pin. The Arduino will use this


pin to sent the bit values to the shift
register.

15 Q0

Data out for bit 0.

16 Vcc

Power in (5V)

Peter Dalmaris

Shift Registers

Arduino Step by Step

The circuit for this demo is this:

!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
Well use 220 or close resistors for each LED. Start with the 74HC595N chip on one side
of the breadboard, then connect the LEDs and their resistors. Then, do the wiring between
the LEDs and the D0-D7 pins on the chip.

Then, connect the chip to the Arduino like this:

Chip Pin 11 to Arduino Pin 12

Chip Pin 12 to Arduino Pin 8

Chip Pin 14 to Arduino Pin 11

Peter Dalmaris

Shift Registers

Arduino Step by Step

Connect the 5V breadboard rail to Pins 16 and 10 on the chip, and ground to Pin 8 on the
chip. Chip pins 9 and 13 are not connected to anything at the moment.

If everything is connected properly, then once you apply power for the first time, the LEDs
will light up at a random pattern. They will show whatever is stored in the shift register. Lets
have a look at the sketch and see how we can change the pattern.

const int latchPin = 9;


const int clockPin = 10;
const int dataPin = 8;

Set the Data, Clock and Latch pins. These are


pins 14, 9, and 10 respectively on the chip.

void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
Serial.begin(9600);
randomSeed(analogRead(0));
}
void loop() {
byte randNumber1 = random(255);
writeLeds(randNumber1);
delay(100);
}

All three pins are outputs, so configure them as


such.
Well use an Arduino function that generates
pseudorandom numbers. Here, we use
randomSeed to initialize the generator with a
random value obtained from pin 0. When this pin
is not connected to anything, its value is as
random as it can get, so it is a good seed for the
generator.
Create a new random number, from 0 to 255.
Store this as a byte. Because the maximum
decimal is 255, which in binary is 11111111, we
ensure that a full random byte is generated. Then,
pass this random byte as a parameter to the
writeLeds function, which will pass it to the shift
register, and wait for 100 milliseconds.

void writeLeds(byte pattern)


{
digitalWrite(latchPin, LOW);
Serial.println(pattern,BIN);
shiftOut(dataPin, clockPin, MSBFIRST, pattern);
digitalWrite(latchPin, HIGH);
}

!
!
!

With the shifting process


completed, we can now
restore the Latch value to
HIGH so that the new
values are revealed to the
LEDs.

We are about to shift bits into


the register, so take the Latch
LOW to hide the new values
until we are ready to reveal
them (the full byte has been
shifted in).

Use the shiftOut function to handle the shifting of the byte, so


we dont have to worry about clock timing and bit manipulation.
Pass the data and clock pin numbers, indicate which bit should
be shifted first (we choose Most Significant bit First here, i.e.
the first bit from the left), and the byte to be shifted out.

Plug in your Arduino and upload the sketch. You should see the LEDs blinking in random
patterns, like this (next page):

!
!
!
6

Peter Dalmaris

Shift Registers

Arduino Step by Step

!
!

!
Perhaps now you can see how a shift register can be used to allow your sketch to control
an arbitrary number of external devices. Instead of LEDs, you could be controlling relays or
transistors as switches for higher loads (that is, devices that require a lot of power to run). It
is even possible to use shift registers as an input, whereby the shift register reads all inputs
in parallel, and then shifts them out in a serial manner to a reading device (like the Arduino).
An example of such a parallel-in serial-out register is the SN74ALS164A (link will open its
data sheet).

Another consideration is power. The 74HC595N can provide less than 20mA for each
output pin, and in our circuit it draws this power from the Arduinos power supply. If the
load placed on it exceeds a certain limit, the circuit will either not work or it will be damaged
if it is forced to exceed its specifications. In such situations, you can consider providing a
separate power supply for the 74HC595N and for its loads (like the LEDs). You can do this
with a simple transistor amplifier circuit, or by segmenting the driver circuit (the 74HC595N
and the Arduino) from its load with relays.

Peter Dalmaris

Shift Registers

Arduino Step by Step

Demo 2: upgrade to 16 LEDs

In demo 2, well add a second 74HC595N to our circuit and drive an impressive 16-LED
array, all lighting up in random patterns, while still only using a single data wire on the
Arduino (plus latch and clock). Heres the circuit, it really is simpler than what it looks:

The circuit from Demo 1 is on the left of the breadboard. The new part on the right is made
of the same arrangement of LEDs and resistors, plus the second 74HC595N. Because
theres so many LEDs drawing a few mA of power each at random times, there will be a
strain on the Arduinos power supply. To smooth out spikes in consumption, I have added
an electrolytic capacitor directly on the power rails of the breadboards. The one I used in
my circuit is 220F. Be careful of the polarity, it is clearly marked on the package of the
capacitor. If you remember, we used a capacitor in the exact same way in the servo motor
lecture.

Lets concentrate on the second 74HC59N (Chip 2) for a moment. The first 74HC59N is
Chip 1. Connect it like this:

Chip 2 Pin 11 to Chip 1 Pin 11

Chip 2 Pin 12 to Chip 1 Pin 12

Chip 2 Pin 14 to Chip 1 Pin 9 Q7S (this establishes the daisy chaining of the two chips)

Peter Dalmaris

Shift Registers

Arduino Step by Step

Connect the 5V breadboard rail to Pins 16 and 10 on Chip 2, and ground to Pin 8 on Chip 2.
Chip 2 pins 9 and 13 are not connected to anything.

This is the sketch. Its almost identical to the sketch in demo 1. The only dierences are
highlighted below.

const int latchPin = 9;


const int clockPin = 10;
const int dataPin = 8;
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
Serial.begin(9600);
randomSeed(analogRead(0));
}
void loop() {
byte randNumber1 = random(255);
byte randNumber2 = random(255);
writeLeds(randNumber1);
writeLeds(randNumber2);
delay(100);
}

Generate a second random byte, just like in Demo


1. Write the second random byte to the 16-bit
shift register by calling writeLeds twice.

void writeLeds(byte pattern)


{
digitalWrite(latchPin, LOW);
Serial.println(pattern,BIN);
shiftOut(dataPin, clockPin, MSBFIRST, pattern);
digitalWrite(latchPin, HIGH);
}

!
The only change to the sketch is the addition of a second random byte, and a second call
to the writeLeds function. The first call will transmit the first random byte, and the second
call will transmit the second random byte.

This is what is happening: as the bits stored in the first 74HC59N are shifted out by the bits
of the second byte, one by one they are pushed into the overflow bit cell. This is Pin 9 Q7S
on Chip 1. As Chip 2 has its Pin 14 (Data pin) connected to Chip 1 Pin 9, it will pick the
overflow bit and start shifting it in its own cells. Since Chip 1 and 2 share the same latch
and clock signals, they will be synchronised and work together as a single 16-bit shift
register. You can daisy chain as many 74HC59N units you like like this, the concept is the
same.

Peter Dalmaris

Shift Registers

Arduino Step by Step

The Demo 2 circuit in operation.

Conclusion
Shift registers operate on a very simple principle, however from experience I know it is a topic that
tends to confuse new makers. Hang in there, read again, experiment with the circuits, and ask if you
run into trouble. Once you understand the basics, you will be able to use them without much eort.

!
!

I will come back to shift registers in an upcoming lecture on 7-segment displays.

As an exercise, try this: modify the sketch for Demo 1 so that you can type in a number from 0 to 255
and have the binary representation of that number show in on the LEDs. You will need to figure out
how to enter text in the console (I have shown you how to do this in a previous lecture).

You can also try this: modify the sketch from Demo 1 so that the number of LEDs lit depends on the
value coming out of a potentiometer. When the potentiometer is turn all the way to one direction, you
will have no LEDs lit, when its all the way to the other direction you will have all of the LEDs lit, and
accordingly for all other positions.

10

Peter Dalmaris

Arduino Step by Step

EEPROM

EEPROM
The Atmega microcontroller, as we have seen already, contains 3 types of memory: Theres
flash (where the sketch is stored), SRAM (where temporary data are stored), and EEPROM.

SRAM (Static RAM) can store data for as long as power is provided. Turn o the power, and
everything is the SRAM is lost.

Both flash and EEPROM memories persist after the power is cut, so you could use either
one for long term data storage, a bit like a hard disk works. But heres the dierence: flash
memory can only be changed when a new program is uploaded to the Arduino. People
often refer to this process as flashing. Once flashing is completed and the newly
uploaded sketch is in place, you cannot change anything in the flash memory.

Thats where EEPROM comes in. EEPROM stands for Electrically Erasable Programmable
Read-Only Memory, and you can use it to store data that must be preserved even after
power is lost. You could use EEPROM to store configuration values for your sketch that the
user can modify, passwords, sensor logs and things of that sort.

In this lecture, you will learn how to use internal and external EEPROM. As a bonus, I will
show you how to create a small library so that you can simplify your sketch organisation
and reuse utility code.

Demo 1: Using the Internal EERPOM

The Atmega328 contains 1KByte of internal EEPROM. That means that you can store and
persist 1024 words, where each word is made up of 8 bits in your Arduino Uno. For this
demo, we will not use any external hardware, just plug your Arduino to your computer and
youre good to go.

In this first demo, well use two sketches to write and read a pin number for a basic security
system. The writing sketch will write the default pin in a specific internal EEPROM memory
location, and the reading sketch will simply go to that location and read back the pin.
Keeping things simple, we are not going to worry about LCD screens, a keypad for the pin
entry, or encryption for storing the pin securely.

The pin well write and read is an integer. On the Atmega, integers consume two bytes, and
we will need to take this into account in our sketch since EEPROMs are byte-addressable.
This means that each byte has its own address, and we cant simple store an integer like
we do with the RAM, where the compiler knows how to deal with integer (and other datatype) addressing. With the EEPROM, while using the basic facilities that come with the IDE,
we have to split an integer to two bytes, store each byte individually, and then again
separately retrieve the two bytes and concatenate them so that we end up with the original
integer. Bear with me for now, in Demo 2 well simplify this process a lot.

!
1

Peter Dalmaris

Arduino Step by Step

EEPROM

Heres the writing sketch (Demo1_writer), lets execute it and then go through it to explain
how it works.

#include <EEPROM.h>
int addr = 0;

A very basic library that comes with the IDE,


allows your to read or write one byte at a time.
The internal EEPROM address of the byte where
the sketch will write the first byte of the pin.

void setup()
{
Heres the Pin, its an integer that needs to bytes
Serial.begin(9600);
of storage.
int myPin=1234;
highByte is a build-in function that
EEPROM.write(addr, highByte(myPin));
extracts the left-most byte (high-order) of
EEPROM.write(addr+1, lowByte(myPin));
an integer, or the second-lowest byte of
Serial.print("My pin recorded:");
a multi-byte data type like a double
Serial.print(myPin);
(which occupies four bytes).
Serial.println(".");
Similarly to highByte, lowByte is a build}
in function that extracts the right-most
byte (low-order) of an integer, or the any
multi-byte data type.

void loop()
{ }

If we only wanted to store a byte, we would be able to just use EEPROM.write, pass an
address (from 0 to 1023), and the byte, and that would be all.

Unfortunately, the basic EEPROM library that comes with the IDE and we use in this sketch,
can only understand bytes, not integers or other multi-byte data types, so we have to take
care of some basic binary arithmetic.

The pin we selected, 1234, converted in binary format, looks like this:

high byte

00000100

11010010

low byte

The byte on the right is the low byte, and the byte on the left is the high byte. We need to
store each one individually, so we call EEPROM.write, twice:

1. EEPROM.write(addr, highByte(myPin));
2. EEPROM.write(addr+1, lowByte(myPin));
First, take the high byte of the pin and store it in address 0, then take the low byte of the pin
and store it in address 0+1 = 1.

Thats all, the pin is now stored in the internal EEPROM. You would do the exact same thing
if you wanted to store a user setting. For example, if you had built an alarm clock, the user
could enter an alarm time, and you would store the time components in the EEPROM to
safe guard against power loss.

Now lets have a look at how to retrieve the pin.

Peter Dalmaris

Arduino Step by Step

EEPROM

In this sketch (Demo1_reader), we read the two bytes we stored earlier from the EEPROM,
and then we concatenate them so that we can recreate the original pin.

!
#include <EEPROM.h>
int addr = 0;
Declare the byte variables that will eventually

void setup()
contain the two bytes of the original pin.
{
Serial.begin(9600);
Retrieve the bytes from addresses 0 and
byte retrievePinHigh;
1, and store them in RAM.
byte retrievePinLow;
retrievePinHigh = EEPROM.read(addr);
Do some binary arithmetic (<< bit shift
retrievePinLow = EEPROM.read(addr+1);
left) to assemble the pin from its two
Serial.println(retrievePinHigh);
parts.
Serial.println(retrievePinLow);
Serial.print("My pin is:");
Serial.print((retrievePinHigh << 8) + retrievePinLow);
Serial.println(".");
}
void loop()
{ }

!
Fetching the two bytes from the EEPROM is straight-forward. We use EEPROM.read, pass
the address of the byte we want to fetch, and store what is retrieved in a variable in RAM.

But how do we re-assemble the pin correctly? For that, we use the bitshift left operator.
There is also bitshift right.

Bitshift operators to exactly what their name says, they take a byte and move its bits left or
right by as many positions as we request.

For example, take this byte, and lets bitshift it to the left by 3 positions:

original

shifted

11001101
11001101000

Notice how all this operator did was to add three zeros to the right side of the byte, and
push everything to the left. We now have a binary number with 11 bits. Thats 8 original bits,
and 3 inserted bits.

Peter Dalmaris

Arduino Step by Step

EEPROM

If you do the opposite, i.e. bitshift to the right by 3 positions, you will end up with this
number:

11001
Notice how the bitshift right operator pushed the byte to the right, and this resulted to the
first three bits disappearing into the binary ether, and ending up with a 5 bit number.

So, this expression:

(retrievePinHigh << 8) + retrievePinLow


first shifts the high byte by 8 positions to the left, eectively creating a 16 bit word, and
then adds the low byte. As a result, we have the original pin reconstructed. Here is the
whole thing:

High byte
High byte shifted to
the left by 8 bits.
Low byte
Shifted high byte and
low byte added.

00000100
00000100 00000000
11010010
00000100 11010010

!
And there you have it, your pin has been retrieved!

!
!

Peter Dalmaris

Arduino Step by Step

EEPROM

Demo 2: Gaining data type flexibility with the


EEPROM

Dealing with raw bytes may seem daunting at first, but with a bit of practice thinking in
bytes becomes almost second nature. Still, I find that often such low-level implementation
details slow us down. You really want to build a prototype quick, not to be caught up in
binary arithmetic, even when its as simple as what we saw in Demo 1. Personally, I find it
more ecient for my own productivity to work at a high-level (logical) rather than having to
worry about the hardware too much. If your gadget qualifies the prototyping phase, you can
always go back for a round of optimisations. So, in this demo, Ill show you a way to
abstract the way that data is written to and read from the EEPROM in a bid to speed up
your personal productivity.

We will make use of the EEPROMex library, or EEPROM Extended. This library extends the
one that comes with the IDE so that it knows about all the common datatypes that we are
likely to use in Arduino sketches, not just the byte.

With EEPROMex, if you want to store or fetch an integer or a double, you just call the
appropriate method and the job is done. No need to think about bits, bytes, and bitshifting.

This abstraction and flexibility comes at the cost of flash memory - adding the library adds
a couple of kilobytes to your project sketch.

Get the library from its Github repository, install it in the Libraries folder, and restart the IDE.

The library is a drop-in replacement of the default EEPROM library, meaning that you can
just replace one for the other, and your sketch will still work. The extended library adds
functions for longs, ints, floats and doubles. You can also manipulate single bits (great for
better managing storage resources), arrays, strings, C structs, and it even provides an
update function that checks if a new value already exists in the EERPOM before saving it
again, thus extending its life span.

Heres the updated write sketch (Demo2_write):

#include <EEPROMex.h>

Replace EEPROM.h with EEPROMex.h

int addr = 0;
void setup()
{
Serial.begin(9600);
int myPin=1234;
EEPROM.writeInt(addr, myPin);
Serial.print("My pin recorded:");
Serial.print(myPin);
Serial.println(".");
}

Use EEPROM.writeInt to write an integer. No need


to worry about high and low bytes, and addresses
for each byte. Just pass the EEPROM address
where the integer should be store, and the
integer.

Peter Dalmaris

Arduino Step by Step

EEPROM

void loop()
{
}
Once the original library has been replaced with EEPROMex.h, all we need to do is to use
the appropriate function depending on the data type we are working with. In the example,
EEPROM.writeInt will write the integer myPin to address addr.

Reading is just as easy:

#include <EEPROMex.h>
int addr = 0;
Used EEPROM.writeInt to write and integer? then
void setup()
use EEPROM.readInt to read it back from the
{
EEPROM.
Serial.begin(9600);
int retrievePin;
retrievePin = EEPROM.readInt(addr);
Serial.println(retrievePin);
Serial.print("My pin is:");
Serial.print(retrievePin);
Serial.println(".");
}

void loop()
{
}
You only need to use the corresponding read function for whichever write function you used
to write a value.

Peter Dalmaris

Arduino Step by Step

EEPROM

Demo 3: Using an external EEPROM

You now know how to use the internal EEPROM, but since its only 1KByte in size, you may
wonder what you can do in order to store more data. You may remember from the SD card
lecture, that SD cards is a good way to store lots of data persistently. However the SD card
module is a bit pricey (you can get one for $2-$10 depending on its bells and whistles), and
then you still need to add the cost and the size of the SD card itself (over $5), and the
complexity of using the card itself.

An external EEPROM is a good alternative. You can get a 256KByte external EEPROM for
around $1.5, store a lot more data in it as compared to the internal capacity, and you only
need a tiny amount of space on your printed circuit board. So lets check this out.

I am using the Atmel


24C256 chip, which
provides 256KBytes of
EEPROM memory. It
communicates with the
Arduino via I2C, which is
great, you can connect
several chips if your
memory needs grow. The
module I purchased on
eBay also makes it easy
to change the device
address by bridging the
pins marked A0, A1, and
A2.

Here are the connections:

!
!
!
!
!
!
!

Arduino

EEPROM module

5V

VCC

GND

GND

A4

SDA

A5

SCL

Peter Dalmaris

Arduino Step by Step

EEPROM

To communicate with an I2C device, we need to know its I2C address. I had no idea what
my EEPROMs address was, so I used an I2C device scanner sketch to find it out.

I have the sketch in the courses Github account. It isnt too important to discuss how the
scanner works, well cover that in a lecture dedicated to I2C. But for now it is enough to say
that the scanner loops through the 127 possible I2C addresses, send a message to each
one, and if the message is acknowledged then we assume that a device is connected and
listening at that address.

With my I2C EEPROM device only connected, I uploaded the scanner sketch, and this
output came out:

!
!
!
!
!
!
!
!
!
So, we now know that the EEPROM device is listening at address 50. Well use this
information in the sketches that follow.

To demonstrate how to use the external EEPROM, well follow the pattern from Demos 1
and 2: there will be a sketch that writes a pin in the ROM, and one that reads it back.
Because the external EEPROM communicates via I2C, we will need to use the I2C protocol
to communicate with it. Well combine the two into one sketch, where the writing will take
place in the setup() function, and the reading in the loop() function.

Because I dont want to deal with the low-level implementation details of the I2C interface
and its EEPROM protocol for the chip I am using (the 24C256), I decided to use some code
that adds a layer of abstraction. This means that instead of having to worry about the actual
I2C commands required to store or retrieve an integer or a byte, I can just call a function
like i2c_eeprom_write_byte with some parameters and be done with it.

Such code exists in the Arduino Playground, but unfortunately it is not available as a library.
Instead of just including it into your project, you have to copy and paste the code into your

Peter Dalmaris

Arduino Step by Step

EEPROM

sketch. This adds baulk, makes it harder to debug, and fails in the principle of reusing utility
code.

Creating a simple library

I took this as an opportunity to show you how to create a small Arduino library. The code
that follows is the code that I want to convert into a library so that I can reuse it in my
sketches by simply including the name of the library.

You can choose to not read the next section and jump straight to the external
EEPROM demo. There will be a separate lecture which will be a more gentle
introduction to Arduino libraries.
Here it is:

void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data )


{
int rdata = data;
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddress >> 8)); // MSB
Wire.send((int)(eeaddress & 0xFF)); // LSB
Wire.send(rdata);
Wire.endTransmission();
}
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte*
data, byte length ) {
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddresspage >> 8)); // MSB
Wire.send((int)(eeaddresspage & 0xFF)); // LSB
byte c;
for ( c = 0; c < length; c++)
Wire.send(data[c]);
Wire.endTransmission();
}
byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
byte rdata = 0xFF;
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddress >> 8)); // MSB
Wire.send((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,1);
if (Wire.available()) rdata = Wire.receive();
return rdata;
}

Peter Dalmaris

Arduino Step by Step

EEPROM

void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte


*buffer, int length ) {
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddress >> 8)); // MSB
Wire.send((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,length);
int c = 0;
for ( c = 0; c < length; c++ )
if (Wire.available()) buffer[c] = Wire.receive();
}
Again, dont worry too much about the details in this code, I am including it here for the
sake of completeness. I am only highlighting the names of the functions (in blue) since we
will be calling them from our sketch later. These names make up the user interface of our
new library.

An Arduino library is made up of two files: the header file, and the implementation file.

The header file contains a list of functions and variables that are publicly available. The
implementation file contains the actual code that implements the functions. Lets create the
header first. Just choose a name, I went with EEEPROM, short for External EEPROM.

10

Peter Dalmaris

Arduino Step by Step

EEPROM

Create a new folder, name it EEEPROM, and in it create a new file named EEEPROM.h:

#ifndef EEEPROM_h
#define EEEPROM_h
#include <Arduino.h>
#include <Wire.h> //I2C library

ifndef is a compiler directive. If by any chance our


sketch has already included this library, then dont
include it again and save some flash memory
space.
Define the name of this library.

class EEEPROM
This library will make
use of Wire.h, so
{
The Arduino library provides access to all Arduino
include it.
data types and constants.
private:
public:
EEEPROM();
void i2c_eeprom_write_byte( int deviceaddress, unsigned int
eeaddress, byte data );
void i2c_eeprom_write_page( int deviceaddress, unsigned int
eeaddresspage, byte* data, byte length );
byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress
);
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int
eeaddress, byte *buffer, int length );
};
#endif

!
!
!
!

These are markers for the private


and public variables of functions.
We dont have anything in private,
and the public section is populated
with the function definitions for our
library.

Here are the function definitions. The first one, EEEPROM()


is a constructor. Its implementation is empty at the
moment, but I plan to add some initialisation code in it
later. The rest of the definitions are fully implemented in the
.cpp file.

Think of the header file as the skeleton of our library. Its just a declaration of what the
outside world should know about it, without any internal details.

11

Peter Dalmaris

Arduino Step by Step

EEPROM

Lets have a look at the implementation. Create a new file named EEEPROM.cpp and add
this code in it:

#include <Arduino.h>
#include <Wire.h> //I2C library
#include <EEEPROM.h>
EEEPROM::EEEPROM(){

The Arduino library provides access to all Arduino


data types and constants.
A blank constructor - I will add some initialisation
code here later.

void EEEPROM::i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress,


byte data ) {
int rdata = data;
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.write(rdata);
Wire.endTransmission();
}
// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a
buffer of 32 bytes
void EEEPROM::i2c_eeprom_write_page( int deviceaddress, unsigned int
eeaddresspage, byte* data, byte length ) {
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddresspage >> 8)); // MSB
Wire.write((int)(eeaddresspage & 0xFF)); // LSB
byte c;
for ( c = 0; c < length; c++)
Wire.write(data[c]);
Wire.endTransmission();
}
byte EEEPROM::i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
byte rdata = 0xFF;
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,1);
if (Wire.available()) rdata = Wire.read();
return rdata;
}

!
continues

Implementation of the first three functions. Notice the EEEPROM::,


this just declares that the function that follows is part of the EEEPROM
class.
12

Peter Dalmaris

Arduino Step by Step

EEPROM

// maybe let's not read more than 30 or 32 bytes at a time!


void EEEPROM::i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress,
byte *buffer, int length ) {
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,length);
int c = 0;
for ( c = 0; c < length; c++ )
if (Wire.available()) buffer[c] = Wire.read();
}

!
!

Completes the implementation.

There is one more file we need to create, it is called keywords.txt and it contains a list of
keywords that the Arduino IDE should be able to recognise and highlight in the text editor.
Inside the EEEPROM folder, create a new file named keywords.txt with these contents:

i2c_eeprom_write_byte
i2c_eeprom_write_page
i2c_eeprom_read_byte
i2c_eeprom_read_buffer

!
!
!

KEYWORD2
KEYWORD2
KEYWORD2
KEYWORD2

These keywords (the function


names from the header file) will
be highlighted by the Arduino
IDE syntax highlighter.

These keywords (the function names from the


header file) will be highlighted by the Arduino
IDE syntax highlighter. The convention is this:

KEYWORD1 Classes, datatypes, and C++


keywords
KEYWORD2 Methods and functions
KEYWORD3 setup and loop functions, as
well as the Serial keywords
LITERAL1 Constants
LITERAL2 Built-in variables (unused by
default)

I am using KEYWORD2 to highlight the function names, as per the convention. Heres what
the result is like in the IDE:

!
!
!
!

You can find the latest version of this library on Github. Copy the EEEPROM folder into the
Arduino IDE libraries folder and restart to complete the import process.

!
13

Peter Dalmaris

Arduino Step by Step

EEPROM

Using the EEEPROM library with the 24C256 EEPROM

Finally, lets use the new library so that we can read and write some data from the external
EEPROM chip. Instead of an integer, lets deal with a string. Heres the sketch:

#include <Wire.h> //I2C library


#include <EEEPROM.h>
EEEPROM eeeprom = EEEPROM();

Include the EEEPROM library we just created.


Create an EERPROM object, call it eeeprom.

void setup()
We will write this string (array of char) to the EEPROM.
{
char somedata[] = "this is data from the eeprom";
Wire.begin();
Serial.begin(9600);
eeeprom.i2c_eeprom_write_page(0x50, 0, (byte *)somedata, sizeof(somedata));
delay(10); //add a small delay
Serial.println("Memory written"); Call i2c_eeprom_write_page, which writes multiple
bytes to the EEPROM. Pass the I2C address of the
}

device (0x50), the address where the first byte of


this string should be stored (0), a pointer to the array
of char that contains our data, and the size of the
array.

void loop()
{
int addr=0;
byte b = eeeprom.i2c_eeprom_read_byte(0x50, 0);
while (b!=0)
{
Serial.print((char)b);
addr++;
b = eeeprom.i2c_eeprom_read_byte(0x50, addr);
}
Serial.println(" ");
delay(2000);
}

!
!

Repeat this reading block for as


long as there are characters to
read.

Well read the string one byte


(character) at a time. Start with the
first byte at memory location 0. As
parameters, pass the I2C address
of the device and the byte address
we want to retrieve.

Print the character that was previously read in the


console, then increment the byte address by one,
and fetch the byte in that address from the
EEPROM.

The sketch will store the string this is data from the eeprom in the external EEPROM, the
retrieve it and print it to the console every two seconds. By including the EEEPROM.h
library, we have simplified the sketch a lot.

There is still room for improvement though. Notice how the I2C address 0x50 has to be
provided as a parameter every time we call one of the library functions? Can you think of a
way to only provide this address once by improving the way that the library is constructed
and used?

14

Peter Dalmaris

Arduino Step by Step

EEPROM

Conclusion

Try to be as frugal as possible when using EEPROM. These memories have a limited lifespan, usually 100,000 read/write cycles. This is indeed a large number, however if you do
reading and writing in a loop, like when storing sensor log data every few seconds, you
could wear it out before you know it.

In general, it is a really bad idea to put write calls to the EEPROM in a loop as it is possible
to burn out those bytes in a few minutes. That is a big reason behind only playing with the
EERPOM inside the setup loop in the demos of this lecture, never inside the loop function.

15

Peter Dalmaris

Hardware Debouncing

Arduino Step by Step

Hardware debouncing
In cases where you need to use a push button, relays or switch (or anything mechanical
used to close a circuit), like we saw in Lectures 15 and 28, we have a situation where metal
comes in contact with metal in order to close the circuit. These contacts are never perfect,
and as a result instead of getting one clean connection, you get multiple ones.

Have a look at the oscilloscope screenshot below (I took this from Wikipedia):

The vertical lines in the centre of the measurement shows that this switch made contact
and lost it several times within the space of a couple of milliseconds. If your Arduino was
connected to this switch via a hardware interrupt pin, then the interrupt service routine
would have been called multiple times.

In many cases, like when we just want to switch on an LED, this doesnt really matter. In
other cases, like when we use a 4x4 keypad to enter a password, it does. Any number key
that you press on the keypad will generate several logical key-presses and this will make it
hard for the Arduino to determine what keys you actually pressed.

This phenomenon is called bouncing, as the voltage of the sampling pin of your switch
bounces from one state to the other before it eventually settles.

In this lecture, we will look at how we can achieve de-bouncing, which means how to get
contacts to output a clean signal when they are closing or opening.

!
1

Peter Dalmaris

Hardware Debouncing

Arduino Step by Step

Software debouncing for the Arduino

It is possible to write a software de-bouncer that will do the job. It is not my preferred
option since it is tying up the Arduino doing house-hold maintenance and adds unnecessary complexity to your sketch. I am mentioning it here for the sake of completeness
and because the relevant sketch comes with the IDE.

You can find it at File > Examples > Digital > Debounce. It looks like this:

const int buttonPin = 2;

const int ledPin = 13;

int ledState = HIGH;

int buttonState;

int lastButtonState = LOW;


long lastDebounceTime = 0;
long debounceDelay = 50;
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, ledState);
}
void loop() {
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}
digitalWrite(ledPin, ledState);
lastButtonState = reading;
}
Inside the loop, there is continuous sampling of the value of pin 2. The sketch waits for a
period of time after the last bounce was detected, and if it exceeds a certain amount of
time (debounceDelay), then the button is interpreted as pressed.

To implement this software solution we had to add four variables and 8 lines of code that
operate in the loop, and this is far less than ideal.

Peter Dalmaris

Hardware Debouncing

Arduino Step by Step

Lets have a look at a simple hardware solution.

A simple capacitor-based de-bouncer

You can build a simple de-bouncer by inserting a small capacitor in parallel to the button or
switch.

In this example, you can see the switch (S1) in


parallel to a 100nF capacitor. The Vout is connected
to the Arduino sampling digital pin.

The capacitor will start charging as soon as the


switch is closed, and while it is charging Vout will
be LOW (as it is connected to GND via the pull
down resistor). Once the capacitor is finally fully
charged, Vout will be 5V and the Arduino will detect
this as HIGH. The mechanical switch will still be
bouncing, but the capacitor is now shielding Vout
from the eects of this bouncing.

This is a much better solution than the software debouncing we saw already. However, if the button is
connected to digital electronics like a microcontroller, the smooth transition that the capacitor
creates between LOW and HIGH is problematic.

In digital electronics, such transitions are bad:

!
But sudden, clean transitions are good:

!
This is not to say that you cant use such a simple debouncing circuit with your Arduino, of
course. You could. But it is possible to improve and create a clean transition between LOW
and HIGH without much extra eort.

What I would like to show you next is a cost-eective solution that takes care of debouncing without adding complexity.

Introducing, the Schmitt Trigger.

Peter Dalmaris

Hardware Debouncing

Arduino Step by Step

Schmitt Trigger as a de-bouncer

A Schmitt Trigger device is designed for removing noise in digital circuits. They are
commonly found in applications where bouncing from mechanical switches is a problem.
Logically, a Schmitt Trigger will invert an input signal.

The following schematic (taken from Wikipedia), shows the function of the Schmitt Trigger.

!
!
!
!
!
!
!
!
!
!
U is the original, unconditioned (noisy) signal. B is the output of the Schmitt signal, a
nice digital signal without bouncing. In the red boxed area, notice how B is HIGH when U is
above the top dotted green line and stays HIGH until U falls below the bottom green line.

In the green box area, notice how the same happens even though the U waveform bounces
up and down significantly, however it does not fall below the bottom green line. Thats
exactly what the Schmitt trigger does.

These two green dotted lines mark the high and low thresholds levels.

The A waveform is the waveform that comes out of a component of the Schmitt trigger
called a comparator. The comparator is very simple, a kind of binary amplifier, that just
outputs HIGH when its input voltage goes above a certain threshold (represented by the red
line) and LOW when it falls below that same threshold. That, on its own, is not very useful.
As you can see from its waveform, it doesnt do much to debounce the original noisy signal.

Peter Dalmaris

Hardware Debouncing

Arduino Step by Step

To achieve the 2 green threshold levels that we need for a proper de-bouncer, we create a
positive feedback (B - which is also the output of the Schmitt Trigger) which reinforces the
input to the comparator (A), like is shown in the schematic below (also from Wikipedia).

!
To recap, a Schmitt trigger is a device that provides de-bouncing by conditioning the
original noisy signal. The output of the Schmitt Trigger depends on the upper and lower
threshold levels. Usually, the upper threshold level is 66% of the rail voltage (in the case of
the Arduino, that is 66% of 5V) and the lower threshold level is 33% of the rail voltage.

The 74HC14 Schmitt Trigger IC

A commonly used Schmitt Trigger IC is the the 74HC14. It contains 6 Schmitt Triggers. We
will use this IC to debounce a push button in this demo.

!
5

Peter Dalmaris

Hardware Debouncing

Arduino Step by Step

Demo - Using the 74HC14 to de-bounce a button

In this demo we will de-bounce a push button using one of the 6 Schmitt Triggers in the
74HC14 IC.

The schematic is provided below.

Well use the Schmitt Trigger to debounce the push button. When the button is pressed, the
LED will turn on.

Connect the IC like this:

!
!
!
!
!
!
!

IC Pin

Connects to
14 5V
7 GND
1 To button via a 100
resistor (or without the
resistor)
2 To Arduino pin 2

All unused
inputs

Connect unused inputs


to 5V or GND to avoid
unwanted oscillation

For the button:

Button pin

!
!
!
!

Connects to

1 To 74HC14 pin 1 via


100 resistor (or
without the resistor)
1 To 5V via 10k resistor
2 To ground
1-2 Optional: a 20uF
capacitor between the
two pin of the button

Last, connect the red LED to pin 1 to 3 via a


protective 220 resistor.

Peter Dalmaris

Hardware Debouncing

Arduino Step by Step

Here is the sketch, it is similar to the one from the lecture on interrupts.

const int ledPin = 13;


const int inputPin = 2;
volatile boolean ledState = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
attachInterrupt(0,buttonPressed,FALLING);
}
void loop()
{
}
void buttonPressed()
{
if (ledState==LOW)
{
ledState=HIGH;
digitalWrite(ledPin,HIGH);
} else
{
ledState=LOW;
digitalWrite(ledPin,LOW);
}
}
Load the sketch from the Interrupts lecture and press the button. Press the button slowly at
first to make sure it works, then increase your press rate to see if you can reach its limit of
reliability.

Try the same things with various buttons and switches that you may have at hand. I find in
my experiments that dierent buttons behave very dierently to one another. The capacitor
and pull up resistor of the button can be tweaked in order to find their optimal values for
each particular button. There is an amazing article in the Ganslee Group blog that analyses
contact de-bouncing in great detail and that I strongly recommend you read at some point.
The article covers the causes and eects of bouncing and provides alternative de-bouncing
techniques that work well in the real world. You will not think of wires and switches the
same way again once you read this article!

Peter Dalmaris

Hardware Debouncing

Arduino Step by Step

In conclusion

De-bouncing switches has an element of art because every switch has its own analog
characteristics and imperfections. Using Schmitt Triggers is one of several techniques
available to us. The Schmitt Trigger is a common way of conditioning (cleaning) the signal
going into a digital circuit. In this lecture, we saw how to use a Schmitt Trigger to debounce a button, without having to make any software changes to our sketches.

I suspect that because of the large variation between the buttons that I use and those that
you will use, your results will be dierent to mine. Spent a bit of time tweaking your circuit
to get a feel of its behaviour. Start with large changes, like for example, try to remove the
capacitor and see what the eect on the reliability of the switch is. Try to go for a larger or
smaller capacitor, or increase/decrease the value of the pull-up resistor. Those two
components can be used to calibrate the sensitivity of the Schmitt Trigger inside the IC for
the particular characteristics of your button.

Peter Dalmaris

Arduino Step by Step

Internal Pull Up Resistors

Internal Pull Up Resistors


In the lecture on buttons (Lecture 15), we encountered the pull-up and pull-down resistors.
This is an arrangement where in a logic circuit, a large resistor connects a pin from where
we obtain a HIGH or LOW reading to either a (logical) HIGH source, or the ground. If this
resistor was connected to a logical HIGH, then we call it a pull-up, and if it was
connected to a logical LOW we call it a pull-down. This way, when the button is not
pressed and its measurement pin is hanging free or floating free (i.e. its not connected
to a HIGH or LOW pin) then through the pull-up resistor we can essentially assign it with a
known value.

In Lecture 15, we saw this circuit:

!
!
!
!
!
!
!
!
!
!
!
!
!
The measurement pin of the button is connected to both digital pin 2 on the Arduino and
(via a large 50k resistor) to the GND pin of the Arduino. Therefore, this is a pull-down
resistor. The large resistor ensures that when the button is not pressed, the yellow jumper
wire transmits a LOW reading to digital pin 2. When the sketch detects this, it can safely
conclude that the buttons is not pressed.

Keep in mind that we could just as easily had used a pull-up resistor. Connect the resistor
to 5V, and the other pin of the button to GND. We would just modify our sketch so that a

Peter Dalmaris

Arduino Step by Step

Internal Pull Up Resistors

HIGH means that the buttons was not pressed, and a LOW means that the button was
pressed.

The Atmega micro-controller contains large (between 20k and 50k depending on the
model) that we can enable so that we can remove the external resistor from our circuit. In
the Arduino Due, the pull-up is between 50k and 150k.

Lets do that now.

Demo: Using an internal pull-up resistor


Update the circuit so that it looks like this:

!
!
!
!
!
!
!
!
!
!
!
The circuit is much the same with the exception that the pull-up/down resistor has been
removed. We just connect the pins of the button to GND and digital pin 2 from where we
will detect the state of the button. The LED is there just to visualise the state of the button.

Now lets move to the sketch, and see how to enable the pull-up resistor. This resistor is, by
default, disabled.

Peter Dalmaris

Arduino Step by Step

Internal Pull Up Resistors

Any pin that can be configured as input, contains a pull-up resistor in series.

const int buttonPin = 2;


const int ledPin = 13;
int buttonState = 0;

Set the button and LED pin number, and initialize


the button state.
Set the ledPin to be output.

void setup() {
pinMode(ledPin, OUTPUT);

Set buttonPin to be an input, and enable the pullpinMode(buttonPin, INPUT_PULLUP); up resistor.

We can now throw away the external


pull-up.
}
void loop(){
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {

digitalWrite(ledPin, LOW);
} else {
digitalWrite(ledPin, HIGH);
}
}

Take a measurement from the button


pin.
We now use a pull-up resistor. So, if
the state of the button pin is HIGH, we
know that the button is not pressed,
and well keep the LED to LOW.

As you can see, enabling the pull-up for an input pin is just a matter of passing the
appropriate configuration constant INPUT_PULLUP.

Conclusion

Internal pull-up resistors only apply to pins configured as inputs, and dont have any eect
in the output behaviour. Notice how the LED has a protective resistance in series? It would
be convenient to be able to replace it with an internal one, but that is technically not a
reasonable thing to do. Each LED or other load needs a current limiting resistor appropriate
for its characteristics, and it would be too expensive to come up with a way to create a
configurable resistance inside the micro-controller.

You can have a look at your micro-controllers data sheet to find out the exact value of its
pull-up resistors, if this is important for your design. For example, you may want to know
how much current will be flowing through the internal pull-up so you will need the exact
value of the resistor to do the current calculation.

A couple of terms relating to pull-up and down resistors are strong and weak. A strong
pull-up (or down) is a large resistor that only allows a small amount of current to flow
through it, while a weak pull-up (or down) is a smaller resistor that allows more current to
flow through it.

When you have a choice of a resistor to use for pull-up, you want to choose that that is
large enough to not allow too much current to flow through it (thats a waste of energy), but
you also dont want it to be too large as at some point you will end up with the same

Peter Dalmaris

Arduino Step by Step

Internal Pull Up Resistors

problem you had at the very beginning: the voltage when the button is pressed will be hard
to determine if the current is insucient to raise a voltage.

Large pull-up resistors can also be too slow to respond to quick voltage changes, and in
high-speed circuits, like in USB serial communications. In USB circuits, you will typically
find pull-ups in the range of 1k to 4.7k (in our examples of external pull-ups we typically
use resistors between 50k and 60k).

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

Memory
In a couple of past lectures, namely lectures 64 on EEPROM, and 45 on the SD Card, we
had a quick look at the memory architecture of the Atmega micro-controller. We learned, for
example, that there are 3 types of memory that we have under our control (this table
contains a summary):

Volatile Use

Size (Arduino
Uno)

Life expectancy

Flash

No

Program

32KBytes

100,000 write cycles

SRAM

Yes

Variable data

2KBytes

Very large

EEPROM

No

Variable/user data

1KByte

100,000 write cycles

Theres not much memory to go


around, so we need to take care
of it. Although we have not
reached the limit of any of these
memories in our lectures, you will
once you start creating projects.
For example, in my DMD
Notification System, the memory
footprint of the sketch dictated
the use of the Ethernet shield
instead of the Wi-fi breakout. The
library required for the Wifi
breakout was simply too large to
fit in the Flash memory without
serious optimisation.

It is worth knowing that the memory architecture that the Atmega and most microcontrollers use is called Harvard architecture. A computer build based on this architecture
has a separate dedicated memory for the instructions (program) and for the program data,
and it looks like this:

Data memory

CPU

Instructions
memory

!
!
1

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

Your regular PC follows the Von Neumann architecture, where the same physical memory is
used for instructions (program) and data. While Harvards architecture can yield better
performance, Von Neumanns is more flexible for general purpose applications. Since
micro-controllers are meant to perform a particular task reliably and eciently, it makes
sense to design them based on the Harvard architecture.

In this lecture, well look at some design and programming principles you can follow to
make better use of your Arduinos limited memory resources.

Flash

Flash memory is usually our first


consideration since it is the first
memory we consume when we
upload a sketch.

When you hit the upload button, the


Arduino IDE will compile the sketch
into machine code and then attempt
to upload it to the micro-controller. If
all goes well and the sketch is below
the Flash memory limit, you will get
this nice message: Done uploading,
followed by the binary sketch size
figure in the console.

In this case, there is plenty of space


left, nothing to worry about.

!
But, if your sketch is at least one byte larger than that 32,256 available flash bytes of the
Arduino Uno, you will get this instead (see next page):

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

!
To generate this error, I simply found a sketch that required 31KBytes of Flash storage and
included a new library. The compiler will include this library in the machine code that it
produces even though there is not a single call to any of its methods.

So, how can one best manage the size of a sketch so that it only consumes the amount of
Flash memory it really needs, and no more?

Here are some suggestions.

Remove bloat

Just like in my example above, during prototyping it is often true that you will go from one
version of a sketch to another without remembering to clean up in the process. You could,
for example, create a function in version 1, which is not used in version 2. If you dont
remove it, the compiler will include it in the compiled sketch. Same thing applies to unused
libraries, variables and code in general.

So, try to keep your sketch lean by cleaning regularly as you move through its iterations.

Remove prints

We often use print and println functions to trace the operation of the sketch while we are
debugging it. Each print function consumes around 500 bytes of memory in flash. Often in
my sketches, I find so many references to println or print that removing them frees up 2 or 3
KBytes of flash memory.

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

Use constants

When you declare a variable and you know that its value is not going to change, you can
declare it as constant. A constant allows the compiler to optimise the way that it labels it
and references it in memory.

So, make this:

int ledPin = 13;


into this:

const int ledPin = 13;


By marking a variable as a constant, you save 2 bytes in the declaration itself, plus 2 bytes
every time it is used in the sketch.

Remove the bootloader

This is a technique for more experienced makers. It enables you to save almost 2.5KBytes
of flash memory.

The bootloader is a component of the Arduino


ecosystem that makes it so easy to use the
Arduino platform. The bootloader is responsible
for working with the Arduino IDE to upload a
new sketch into the Flash memory. Without a
bootloader, you would have to use a special
device called an AVR programmer.

You can still use the Arduino IDE to write your


sketches as per normal, but with the bootloader
gone, you will need to use this additional piece of hardware to get it uploaded.

!
!

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

SRAM

SRAM is much smaller than Flash, only 2KBytes in the Uno, and in real life it tends to cause
more problems. Heres a couple of examples:

* If you decide to use an SD card in your project, you will immediately dedicate 512 bytes
of SRAM as buer space required by the SD Card library.

* Want a monochrome LCD display? you need 1 byte for every 8 pixels, so depending on
the resolution of the screen you would be using up a large part of your SRAM capacity.

Lets have a look at things you can do to make ecient use of your available SRAM.

Know your data types and structures

The Arduino provides several data types, of which most people end up using only 3 or four.
Knowing which one most eciently fulfils its intending purpose can save you a lot of
wasted space.

This table contains the available data types and the amount of space they consume in the
SRAM.
Type

Bytes

boolean

char

unsigned char

byte

int

unsigned int

word

long

unsigned long

short

float

double

4 (8 bytes on the
Due)

string

An array of chars,
so 2 bytes * number
of chars

Lets pretend that you are creating an array to hold these numbers: 1, 5, 25, 125.

If you declare this array like this:

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

int myNumbers[] = {1, 5, 25, 125};


you will consume 4 * 2 bytes = 8 bytes. But if you declare it like this:

const byte myNumbers[] = {1, 5, 25, 125};


you will only consume 4 * 1 byte = 4 bytes, since each number occupies only 1 byte. The
numbers in the array are all smaller than 255, so it makes absolutely no dierence to my
sketch the loss of a byte per number. You even save a bit of space thanks to the const
modifier for each reference of the array in your sketch.

Only use larger size data types like long and float if you have a very good reason. My self, I
rarely use them.

Avoid recursion

Recursion is a programming technique that in certain cases can simplify the programming
eort. Here is a typical example:

unsigned int factorial(unsigned int n) {


if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
This code calculates the factorial of a number (n). You can see that the function body
contains a call to itself. This is what recursion is, a segment of code that calls it self.

In PCs and computers with lots of memory, this is a good way of solving a problem that can
be broken down into small identical pieces. The trouble is that every recursion adds a full
copy of the function and its data to the program stack, which is stored in SRAM. The larger
the n is in this example, the deeper the stack will be, bringing the sketch closer to
exhausting its available memory.

The good news is that every recurve problem can be solved with simple iteration. This may
produce slightly messier code, but at least we will not have the memory stack problem.
Here is the factorial problem solved using iteration (see next page):

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

unsigned int factorial(int n)


{
int f = 1;
int i;
for(i = 1; i <= n; i++)
{
f *= i;
}
return f;
}
This code is a bit longer and harder to understand, but it will use the same amount of
memory every time, no matter what the n parameter is.

Variable names dont matter

Some people believe that shorter variable names, like i or j, can result in smaller
memory footprint. This is not true, as the compiler will replace these mnemonic names
(meant to be read by the programmer, not the compiler) with labels that it computes
dynamically.

Store strings in Flash

There is a handy macro, F(), that makes the compiler store strings in Flash memory instead
of SRAM. This macro is useful in cases where you have a call to print or println where the
string parameter does not change.

For example, this:

System.println(Hello world!);
can be changed into this:

System.println(F(Hello world!));
so that the string Hello world! is stored in Flash.

Use PROGMEM for data

You can use the PROGMEM modifier to instruct the compiler to store data in Flash instead
of RAM. This is similar to the eect that the F() macro has on string.

PROGMEM doesnt work with all data types, only with those that the pgmspace library
supports. To use this modifier, start by including its library:

#include <avr/pgmspace.h>
then declare the variable and mark it with the PROGMEM keyword:

PROGMEM

prog_uint16_t charSet[]

= { 65000, 32796, 16843, 10, 11234};

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

Notice that the type of the charSet array is prog_uint16_t, not just int. If you wanted to
store a 1-byte number, you would use the prog_int8_t data type, and for a 2-byte number
you would use prog_int16_t.

Reading is also a little tricky. You cant just say:

charSet[0];
to access the first item of the array, because this would result in the micro-controller
looking for this data item in SRAM, not Flash. Instead, you need to use one of the functions
that the library provides:

pgm_read_word_near(charSet + 0);
and this will retrieve the data stored in the 1st item location of the array. If you wanted
the second item, you would say:

pgm_read_word_near(charSet + 1);
and so on.

Have a look at the documentation for pgmspace for details on all the data types and
functions that it provides.

Report free memory

There is a very useful library that you can include in your sketch so that you can profile its
memory use. Its called MemoryFree.

Install the library, include it, and use the freeMemory() function to get a reading of your
SRAM available memory. Place freeMemory() at strategic locations throughout your sketch
to get an understanding of how memory is used, and then when your prototype settles you
can remove it. This will release a bit of flash memory.

Peter Dalmaris

Memory & Memory Management

Arduino Step by Step

One thing to note is that freeMemory() will only report the amount of SRAM available that is
continuous. If SRAM is fragmented, it will report a lot less space available.

EEPROM

EEPROM was covered in detail in Lecture 64, please check it out if you havent done so
already!

Wrap it up

Memory is a limited resource on the Arduino, and as such it must be managed with care.
Unlike programming PCs, though, memory management on embedded devices comes
down to a few simple rules and habits. This lecture described the bulk of the things that you
can do to get the most out of your Arduinos memory.

Peter Dalmaris

Seven segment display

Arduino Step by Step

The Seven Segment Display


The Seven Segment Display (SSD from now on), is a device that contains seven LEDs in a
pattern that makes it possible to create a number from 0 to 9 by
enabling or disabling them.

Commonly, SSDs also contain a dot LED at the bottom right corner,
so they should probably be called 7+1 Segment Displays or
something like that.

It is possible to combine multiple SSD to create multi-digit displays.


Although we can use LCD displays as we saw in lecture 25, SSD are
much brighter and easier to read even from a distance.

In this lecture, we will build on our knowledge from Lecture 60, where
you learned how to use a shift register in order to control multiple
LEDs using only three wires: one for data, one for clock, and one for
the latch. Because there are so many SSD out there, I will assume
that you dont have your particular displays datasheet and have no idea which pin controls
the pins. I will describe the process of figuring out the correct wiring and then constructing
the numerical symbols in the sketch.

Wiring

In the demo for this lecture, we will end up


constructing a circuit that looks like the one
in this schematic.

You can use this schematic to wire up the


595 shift register to the Arduino, but wiring
the shift register to the SSD depends on how
the SSD is made. There are a couple of main
types, the common cathode and the common
anode. The one that I happen to use is of the
common anode variety, in which the middle
pins of each row is connected to the positive
voltage. I will explain how to figure out which
one you have further down.

Another consideration is power. You will


potentially have up to 8 LEDs lit at one time,
and if you decide to add more SSDs, you will
have multiples of 8. If each LED requires 15mA of current, you will need a total of 120mA,
which the Arduino cant provide. In the schematic, I have attached a breadboard power
supply from which I power the LED and the shift register. You can also connect a power

Peter Dalmaris

Seven segment display

Arduino Step by Step

supply to the Arduino via its barrel connector, and this can provide power to the breadboard
via the +5 pin.

Common anode or common cathode?

The easiest way I have found to figure out what kind of SSD you
have, is you use a 1.5V button battery to probe that pins on the
SSD. To see how this works, take a 5mm LED and connect its
two pins to the battery, like I am showing in this image.

The long leg of the LED is the anode and needs to be connected
to the positive (+) side of the battery. The cathode is connected
to the negative side.

For the SSD, first have a look at the back. There are two rows of
pins. In both rows, the middle pins are either the anode or the
cathode. They are connected to each other, so it doesnt matter which one you end up
using. You can confirm that by testing for continuity with your multimeter, if you have one.

Now plug the SSD into the breadboard. Connect a red wire in
one of the two middle pins, and another wire to any of the
other pins, it doesnt matter which one. Test to see if the
middle pin is the anode by
connecting the red wire to the
positive side of the button
battery and the other wire to
the negative.

If any of the LEDs lights up,


then you have established that
you have a common-anode
type of SSD. If nothing happens, try connecting the battery
the other way around. If one of the LEDs lights up, then you
have a common-cathode SSD.

Knowing what kind of SSD you have is important because


it dictates how to connect it to the circuit. I will assume that
you have a common-anode SSD, but if you actually have a common-cathode one just
reverse all the connections for the LEDs: my positives will be your negatives and my
negatives will be your positives.

Peter Dalmaris

Seven segment display

Arduino Step by Step

Notes on wiring

The shift register allows you to control 8 LEDs, since it can store 8
bits. We want to connect each LED to the shift register in an
organised way, because that will help us a lot with the sketch.

Each LED segment on the display is given a letter as a designation,


like in this picture. I will be using these designations later when I am
constructing the numerical symbols in the sketch. I am also including
the pin-out of the 595 shift register IC because I will be referring to its
pin numbers.

I always start by connecting the dot (DP) to pin 15 of the IC


(Q0). How do you know which pin on the SSD activates the
dot LED? Use the method we used to detect the kind of SSD
we have. Leave the red wire connected to the anode pin, and
connect the other wire to the other pins (while still connected
to the batter), until the dot LED lights up. For me, this pin
happens to be the bottom-right one. I suspect that this is true
for most SSDs.

From there, I continue clock-wise, and connect the pin to the


left of the dot pin to pin 1 on the IC (Q1). Continuing
clockwise, skip the next pin because its the common anode,
and connect the next one to pin 2 (Q2) on the IC.

Once you finish with the bottom row of the SSD, continue
with the right-most pin of the top row. Connect that to pin 4
(Q4) on the IC. Continue moving towards the left, and connect the rest of the pins (except
for the middle common anode one) to pins 5, 6, and 7 on the IC. You are now finished with
connecting the SSD to the IC. Finish up with the SSD by connecting the common anode pin
to the 5V rail via a single 220 protective resistor (I do both top and bottom pins in order to
distribute the current, but you could connect either one or the other without risk).

Next, continue wiring the IC. You can find the details in Lecture 60, but in summary
remember that IC pin 14 goes to Arduino pin 8 (data pin), IC pin 12 goes to Arduino pin 9
(latch pin) and IC pin 13 goes to Arduino pin 10 ( clock pin).

You should now have a circuit that resembles the one in the schematic at the start of the
Wiring section.

Peter Dalmaris

Seven segment display

Arduino Step by Step

Sketch

We will now create a sketch that once loaded, will implement a counter, that uses the SSD
to display numbers from 0 to 9.

This sketch will be based on the one we saw in Lecture 60, Demo 1. The dierence is that
in the new sketch we are about to create, we dont want the LEDs in the SSD to light up
randomly, we want it to show legible numbers.

Lets start with the skeleton of the sketch and build it up.

const int latchPin = 9;


const int clockPin = 10;
const int dataPin = 8;
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop() {
}
void writeLeds(byte pattern)
{
digitalWrite(latchPin, LOW);
Serial.println(pattern,BIN);
shiftOut(dataPin, clockPin, MSBFIRST, pattern);
digitalWrite(latchPin, HIGH);
}
This sketch doesnt do anything at the moment. Our objective is to create a data structure
that associates a numerical symbol, like the zero 0, with a bit pattern. When we pass this
bit pattern to the writeLeds() function, a zero symbol will appear on the SSD.

We will need ten such patterns, one pattern per numerical symbol (I will not be using the
dod in this sketch). The easiest data structure that I can think of that allows us to store ten
bit patterns is an array. I will start with declaring a default array of ten items that holds
bytes, and then tweak each byte separately to get it to display the symbol I want.

Peter Dalmaris

Seven segment display

Arduino Step by Step

So, lets start with this:

const byte
const byte
B11111111,
B11111111,
B11111111,
B11111111,
B11111111,
B11111111,
B11111111,
B11111111,
B11111111,
B11111111
};

CHAR_COUNT = 10;
symbols[CHAR_COUNT] = {
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9

For the time being, all bytes are 11111111. At the end of the setup function, add this
instruction:

writeLeds(symbols[0]);
and then run the sketch. The byte in the 0-index position of the array (the first cell) will be
sent to the shift register. Because its all 1s, and this is a common-anode SSD, all the LEDs
will be o. Now try to make a change, for example change the first bit of the first byte to 0,
so that you have this pattern:

B01111111
Run the sketch again, and you will see that LED G is now lit.

The first item in the array should represent a zero, so LED G should
be on. We need to find the bits that activate LEDs A, B, C, D, E and
F. Since we now know which bit controls LED G, we know that we
need to activate all others in order to create the zero symbol.

So, now we now that zero is encoded in bit pattern B10000001.

Edit the array so that the first cell contains this bit pattern and upload the sketch again. You
should see a zero symbol appearing on the SSD.

Lets try for a symbol 1, which is encoded by the second cell in the array. First, update the
setup function so that the call to writeLeds() is like this:

writeLeds(symbols[1]);
Now, try to find out which bits activate LED segments B and C. With a bit of trial and error,
you will figure it out. The pattern for 1 is B11101101. Segment B is controlled by bit 5
and segment C by bit 2.

Peter Dalmaris

Seven segment display

Arduino Step by Step

Update the array and upload the sketch to confirm.

After a few rounds of this method, you will have a table that shows the relation between
SSD segments and bits for each bit pattern. You can use pen and paper to make notes,
and it will eventually look something like this:

Bit #

Segment

DP

When you have completed this, your symbols array will look like this:

const byte
B10000001,
B11101101,
B01000011,
B01001001,
B00101101,
B00011001,
B00010001,
B11001101,
B00000001,
B00001001
};

symbols[CHAR_COUNT] = {
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9

With this, getting the count-up eect that we are looking for is simple. Here is the
completed sketch (next page), with comments embedded:

Peter Dalmaris

const
const
const
const

Seven segment display

int latchPin = 9;
int clockPin = 10;
int dataPin = 8;
byte CHAR_COUNT = 10;

const byte
B10000001,
B11101101,
B01000011,
B01001001,
B00101101,
B00011001,
B00010001,
B11001101,
B00000001,
B00001001
};

symbols[CHAR_COUNT] = {
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9

Arduino Step by Step

Each rows contains a bit pattern that is passed


to the shift register in order to activate the
appropriate SSD segments and produce the
symbol we want.

void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop() {
pattern1();
}
void pattern1()
{
int i=0;
while(i<CHAR_COUNT)
{
writeLeds(symbols[i]);
i = i+1;

delay(500);
}
}

Call to function that creates the count-up


effect.

The while() block calls the writeLeds() function


and passes an appropriate symbol bit pattern
from the symbols array. Each time, it
increments the counter by 1. Once it reaches
the last item of the, it ends.

void writeLeds(byte pattern)


{
digitalWrite(latchPin, LOW);
Serial.println(pattern,BIN);
shiftOut(dataPin, clockPin, MSBFIRST, pattern);
digitalWrite(latchPin, HIGH);
}

Peter Dalmaris

Seven segment display

Arduino Step by Step

!
Multiple seven segment displays

In most real-life applications, a single SSD will not be


enough. Just to display a clock, you need four. You can
use this architecture to daisy-chain multiple SSDs
together, just like you learned in Lecture 60. You can
also purchase components that contain multiple SSDs,
including a controller, usually one or more 595 shift
registers, such as this one.

Still, with most of these components, you will need to


apply the principals you learned in this lecture:

* You need to know whether you have a commonanode or common-cathode display,

* You will need to at least confirm that your symbol


array contains the correct bit patterns for the symbols you want to display.

Alphanumerical displays

If you need to display letters as well as numbers, then you are


looking for an alphanumerical display. Heres an example (image
to the right).

These displays are similar to the seven segment displays we just


saw, except that they contain more segments, and therefore more
pins. You can find such displays with 16 or 14 segments, and to
drive them you will need larger general purpose shift registers or
a dedicated controller, like in this example from Sparkfun, or LED IC controllers like the
MM5450.

I will try to create a lecture that will demonstrate how to use the MM5450, although I think
that with a little eort, you will be able to work it out (hint: it really is just a shift register with
35 bits capacity).

Wrap it up

Working with seven segment displays is straight forward once you become familiar with
their principle of operation and the way you can interface them to the Arduino.

As an exercise, add a second SSD to your circuit, controlled by a second shift register. Wire
the second SSD to the second shift register in the same way you did for the first one, and
wire the second shift register to the first in a daisy-chain fashion like you learn in Lecture
60.

Peter Dalmaris

Seven segment display

Arduino Step by Step

Adjust the sketch so that now it can count up from 00 to 99. If you do that, then you have
mastered the seven segment display!

Peter Dalmaris

The MCP23017 port expander

Arduino Step by Step

Multiply your Arduinos digital I/O


The Arduino Uno has 14 digital I/O pins. That sounds a lot, but it isnt consider that all these
pins are multi-functional, so that they are used for tasks other than pure input/output, like
Pulse Width Modulation, serial and SPI communications. We saw in an earlier lecture,
number 60, that shift registers can be used to provide us with additional digital outputs.

But what about additional digital inputs? In this lecture, Ill show you how to use the
MCP23017 IC to easily add a total of 16 digital I/O pins to your Arduino project.

About the MCP23017

The MCP23017 is an integrated circuit that communicates with the outside world using the
I2C interface, and provides 16 pins that can be configured individually as digital inputs or
outputs. Using the I2C interface means that you can potentially add up to 128 of these
devices to your project, for a grand total of 128*16 = 2048 digital I/O pins.

Any kind of simple device that provides a digital input or output can be connected: buttons,
LEDs, relays, keypads, seven segment display, and much more.

Lets have a quick look at the chip, and get a


basic understanding of its characteristics
before going ahead with the demos.

The I/O pins are arranged in two sets, or


banks. Bank A is on the right taking up pins
21 to 28, and Bank B is on the left taking up
pins 1 to 8.

We will be configuring these pins as input or


output, and reading or writing values on them.

Pins 15, 16, and 17 are used for setting up the I2C device address. You can set one of the
possible 128 I2C addresses by connecting these pins to +5V or Ground.

Pins 12 and 13 are used for the I2C communication. Pin 12 is the clock and 13 the data. On
the Arduino Uno, you connect these to analog pins 5 and 4 respectively.

Pin 18 is the reset. If you take this pin to LOW, it will reset the device. Well be keeping it to
HIGH (5V) via a10K pull up resistor.

Pins 19 and 20 are used for hardware interrupts. We will not be using these ports in this
lecture.

Pins 9 and 10 are +5V power and Ground.

Pins 11 and 14 are not connected to anything, just leave them floating.

Peter Dalmaris

The MCP23017 port expander

Arduino Step by Step

Lets go ahead with the first Demo!

Demo 1: Digital out

For this first demo, well get the port expander connected to the Arduino, and write a simple
sketch that sets one of the expanders pins as a digital out, connect an LED to it and make
it blink. Instead of an LED, you could use some other kind of digital load, like a small 5V
relay switch.

Heres the schematic:

Notice that the pull-up resistors for


pins 12 and 13 (I2C clock and data)
are required, and are 10K each.

I am also using a 4.7K pull up


resistor on pin 18 (reset).

The LED is connected to pin 28 on


the port expander via a 220
resistor.

For the sketch, the objective is to


use the I2C protocol and transmit
instructions to the port expander so
that the LED is turned on and o.

For this, we can use the low-level


functions that come with the Wire
library, like this:

(see next page)

Peter Dalmaris

The MCP23017 port expander

#include Wire.h"
void setup()
{
Wire.begin();
Wire.beginTransmission(0x20);
Wire.write(0x00);
Wire.write(0x00);
Wire.endTransmission();
}
Send the instructions and
close the connection.
void loop()
{
delay(100);
Wire.beginTransmission(0x20);
Wire.write(0x12);
Wire.write(B10000000);
Wire.endTransmission();
delay(100);
Wire.beginTransmission(0x20);
Wire.write(0x12);
Wire.write(B00000000);
Wire.endTransmission();

Arduino Step by Step

Well be using functions from the Wire


library (implements the I2C interface).
Start I2C
Start talking to the port expander at its
default I2C address.
Select the register that controls Bank A.
Set all pins for Bank A to be outputs. If
you wanted them to be inputs just leave
this line out since all pins are inputs by
default.
Select the pins in Bank A. See Table
1-4 in the datasheet.
Sent a byte to Bank A. Each bit
corresponds to one of the pins. The first
bit controls pin 28 (GPA7), and turns the
LED on. Nothing is connected to the rest
of the pins, so leave them off (0).
After a 100msec delay, sent a new byte to
the pins of Bank A. This time, the first bit
is 0, so the LED is turned off.

!
In a way, controlling the pins of the port expander as outputs is similar to using a shift
register. Just sent out a byte that contains the bit pattern that you want your outputs to
have.

In most cases you will only have one or two output devices youd like to control, and for
that you might not want to deal with bytes, registers and pin banks. Instead, you could this
convenient library from Adafruit. The library is Adafruit_MCP23017. Download it from
Github and install it in your IDE.

You can achieve that same output as the sketch above, like this (see next page):

Peter Dalmaris

The MCP23017 port expander

Arduino Step by Step

#include <Wire.h>
#include "Adafruit_MCP23017.h"

Include the necessary libraries.

Adafruit_MCP23017 mcp;

Create the mcp object, this will be our


interface to the port expander.

void setup() {
mcp.begin();
mcp.pinMode(7, OUTPUT);
}
void loop() {
delay(100);
mcp.digitalWrite(7, HIGH);
delay(100);
mcp.digitalWrite(7, LOW);
}

Start the device and set I/O 7 to output.


7 corresponds to GPA7 from the device
pinout diagram.

Write HIGH to I/O pin 7, turns the LED on.


Write LOW to I/O pin 7, turns the LED off.

Much easier and concise, isnt it?

How about we try to control two LEDs, one connected to a pin in Bank A, and the other one
to a pin in Bank B?

Demo 2: Digital outs at both Banks

In this demo, Ill show you how to control output pins in either Bank (A or B), either using
the lower-level Wire library or the Adafruit library.

Adjust your circuit so that it


contains a second LED, connected
to pin 1 of the port expander
(GPB0).

First, lets get both LEDs to blink


using only the Wire library (see
sketch in next page):

Peter Dalmaris

The MCP23017 port expander

#include "Wire.h"
void setup()
{
Wire.begin();
Wire.beginTransmission(0x20);
Wire.write(0x00);
Wire.write(0x00);
Wire.endTransmission();
Wire.beginTransmission(0x20);
Wire.write(0x01);
Wire.write(0x00);
Wire.endTransmission();

Arduino Step by Step

Set ports in Bank A (0x00) to be all


outputs.

Set ports in Bank B (0x01) to be all


outputs.

}
void loop()
{
delay(100);
Wire.beginTransmission(0x20);
Wire.write(0x12);
Wire.write(B10000000);
Wire.endTransmission();
Wire.beginTransmission(0x20);
Wire.write(0x13);
Wire.write(B00000001);
Wire.endTransmission();

Set the bit pattern for the port in Bank A


(0x12). This will turn on the LED
connected to to pin 28 on the port
expander.
Set the bit pattern for the port in Bank B
(0x13). This will turn on the LED
connected to to pin 1 on the port
expander. Notice how the least significant
bit controls the state of pin 1.

delay(100);
Wire.beginTransmission(0x20);
Wire.write(0x12);
Wire.write(B00000000);
Wire.endTransmission();

Wire.beginTransmission(0x20);
Wire.write(0x13);
Wire.write(B00000000);
Wire.endTransmission();
}
Lets have a look at the equivalent sketch using the Adafruit library (next page):

Peter Dalmaris

The MCP23017 port expander

Arduino Step by Step

#include <Wire.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp;
void setup() {
mcp.begin();
mcp.pinMode(8, OUTPUT);
mcp.pinMode(7, OUTPUT);
}
void loop() {
delay(100);
mcp.digitalWrite(8,
mcp.digitalWrite(7,
delay(100);
mcp.digitalWrite(8,
mcp.digitalWrite(7,
}

Set I/O 8, which is pin 1, to be output.


Count I/O numbers counter clockwise
starting from IC pin 21 being 0 (GPA0).
GPA7 is I/O 7, GPB1 is I/O 8, GPB2 is I/O
9 etc.

HIGH);
HIGH);
LOW);
LOW);

Next, lets have a look at digital inputs using a button.

Demo 3: Digital inputs

In this demo, well connect a button to one of the digital inputs. When the button is
pressed, an LED connected to a digital
output will be turned o.

Heres the circuit:

The button is connect to pin 21, which is


GPA0. Dont forget the pull down resistor
(10K).

The sketch that reads the state of the


button and updates the state of the LED
could not be any easier, see next page:

Peter Dalmaris

The MCP23017 port expander

Arduino Step by Step

#include <Wire.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp;
void setup() {
mcp.begin();
mcp.pinMode(7, OUTPUT);
mcp.pinMode(0, INPUT);
}

Set I/O 7, which is pin 1 (GPA7), to be


output.
Set I/O 0, which is pin 21 (GPA0), to be
input.

void loop() {
mcp.digitalWrite(7, mcp.digitalRead(0));
}

!
!
!

Use digitalRead to read the state of the


button, then update the LED with
digitalWrite.

Wrap-up

Using the MCP23017 port expander is almost trivial. The Adafruit library hides all the lowlevel detail without adding much fat to the overall size of your sketch (it adds around 1,000
bytes to the amount of memory that the Wire library requires).

You could also use the MCP23017 as an I2C-based shift register and control 16 LEDs, or
an array of 8x8 LEDs. Just remember that each pin can provide a maximum of 15mA, so
you will need to consider your displays power requirements.

You could also control relays and through them much larger loads, like motors and lights,
and make this part of your home automation system.

Vous aimerez peut-être aussi