Arduino SBS Draft Notes May 2015
Arduino SBS Draft Notes May 2015
[email protected]
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.
5. Shields
6. Components
1
Peter Dalmaris Lecture 2 Arduino Step by Step
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.
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.
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".
3
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.
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.
4
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 effective creative tool because it accelerates prototyping dramatically.
!
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.
1
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:
2. Solderless Breadboards
3. Jump wires
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.
1. Voltage AC and DC
2. Resistance
!
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.
!
!
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!
3
Peter Dalmaris Lecture 3 Arduino Step by Step
Any other colours can be used to signify the connection of different 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 off.
2. If your circuit becomes large enough so that the Arduino can't provide enough
power
Here are three things you can do to deal with such situations:
A battery pack
!
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!
5
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.
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
1
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 difference 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.
2
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.
!
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 off 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().
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:
4
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.
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);
Then we call digitalWrite again, but this time we change the state of pin 9 to LOW,
which is 0 Volts.
digitalWrite(9, LOW);
5
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
off, giving us a much nicer visual effect to look at. Before that, please complete the Lecture
4 quiz.
6
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 off. 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 off accordingly.
!
!
!
!
!
!
!
!
!
1
Peter Dalmaris Lecture 5 Arduino Step by Step
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;
2
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 effect 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:
...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.
3
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
• Vibration
• Pressure
• Electrical fields
• Sound
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.
1
Peter Dalmaris Lecture 6 Arduino Step by Step
In the lectures in this section, we will play with the following sensors:
• 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.
2
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?
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 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.
1
Peter Dalmaris Lecture 7 Arduino Step by Step
Notice how you connected the green cable in column 4, where the resistor and the photo-
resistor 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):
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.
2
Peter Dalmaris Lecture 7 Arduino Step by Step
The sketch
Here's our program for this exercise:
void setup() {
Serial.begin(9600);
void loop() {
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.
Serial.begin(9600);
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
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 differences in the components you used in your
circuit compared to mine, and of course the lighting conditions in our two labs are probably
different. 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.
5
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.
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 thermistor
1
Peter Dalmaris Lecture 8 Arduino Step by Step
Assembly
Time to put the demo circuit together. We will need:
• The Arduino
• A DHT11 or DHT22
• A 10kOhm resistor
2
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.
void setup() {
void loop() {
if (isnan(t) || isnan(h)) {
Serial.println("Failed to read from DHT"); //*problem*
} else {
Serial.print("Humidity: ");
Serial.print(h); //*Print humidity reading*
Serial.print(" %\t"); //*This outputs a tab*
Serial.print("Temperature: ");
Serial.print(t); //*Print temperature reading*
Serial.println(" *C”);
Notice that there is an inclusion of the DHT.h library in the first line.
3
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.
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.
4
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 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
2
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:
void setup() {
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
//*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.
4
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 office automation, where you could
get the lights to turn on and off automatically depending on whether someone is still in the
room or turning on the flood light in your driveway as
your car approaches.
!
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
!
!
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
• One LED
2
Peter Dalmaris Lecture 10 Arduino Step by Step
!
Sketch
Done with the assembly, let work on the sketch now.
/*
*/
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;
}
3
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:
4
Peter Dalmaris Lecture 10 Arduino Step by Step
if (pirState == LOW) {
Serial.println("Motion detected!");
pirState = HIGH;
}
with only:
Serial.println("Motion detected!");
if (pirState == HIGH){
Serial.println("Motion ended!");
pirState = LOW;
}
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 effect 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.
5
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 off to avoid accidental
touchscreen input.
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.
!
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
!
Sketch
Done with the assembly, let work on the sketch now.
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
!
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.
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.
1
0.5
0
!
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
different temperatures, the speed of sound is calculated by adjusting 331.5m/s for the
temperature by multiplying by 0.6:
We need to convert the seconds to microseconds and the length from meters to
centimetres:
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.
4
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.
!
!
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
• An ADXL335 3-axis
accelerometer.
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.
3
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.
Assembly
Let's puts together this circuit and test out the motion
sensor.
We will need:
• The Arduino
!
!
1
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:
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
}
2
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.
Here is what a tilt sensor looks like from the outside (right - top)…
!
!
1
Peter Dalmaris Lecture 14 Arduino Step by Step
Assembly
To put this circuit together, we'll just
use the Arduino, no breadboard is
required.
!
!
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 different
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.
3
Peter Dalmaris Lecture 15 Arduino Step by Step
Lecture 15:
Button
!
A button is a simple on-off 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.
!
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".
1
Peter Dalmaris Lecture 15 Arduino Step by Step
Experiment
Let's create a simple circuit to demonstrate a
button.
!
Once assembled, the project will look like this
(below):
2
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
*/
void setup() {
pinMode(ledPin, OUTPUT); // choose the pin for the LED
// choose the input pin (for a
// pushbutton)
// declare LED as output
// declare pushbutton as input
pinMode(inputPin, 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!
3
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
!
!
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.
So there you have it, a potentiometer is nothing more than a variable voltage divider.
2
Peter Dalmaris Lecture 16 Arduino Step by Step
Sketch
Here's the sketch that drives this circuit:
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!
3
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?
4
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.
There's lots of other uses, like in biometrics, in fitness products, and in gaming devices.
1
Peter Dalmaris Lecture 17 Arduino Step by Step
Assembly
This is what we are going to build:
• The Arduino
!
Here’s 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);
}
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?
3
Peter Dalmaris Lecture 18 Arduino Step by Step
Lecture 18
Membrane potentiometer
A rather unusual type of potentiometer is the
membrane potentiometer.
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.
• The Arduino
• A membrane potentiometer
• 3 Jumper wires
!
!
1
Peter Dalmaris Lecture 18 Arduino Step by Step
The monitor output is essentially the same as with the potentiometer. The only difference is
that the actual resistance of the voltage divider will be different between the two devices so
the actual reading will be different in analog pin 0.
2
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 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 different lengths
of the resistor, and closes a circuit, thereby
implementing the voltage divider.
3
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.
Assembly
This is what we'll make:
We will need:
• The Arduino,
• A buzzer,
• 7 jumper wires.
!
1
Peter Dalmaris Lecture 19 Arduino Step by Step
!
!
2
Peter Dalmaris Lecture 19 Arduino Step by Step
Sketch
The only difference between this script and the one from Lecture 16 is the variable name for
the buzzer pin. ledPin is now buzzerPin.
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.
3
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
effective 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. I’ll explain what these are in a minute. Here’s what we are going to build in this
lecture:
• First, we’ll just hook the motors to the Arduino via the motor break-out board, and make
them spin in a single direction.
• Second, we’ll get the motors spinning forwards and backwards using a potentiometer as
a controller.
• Third, we’ll 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.
!
!
1
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.
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.
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.
!
!
!
3
Peter Dalmaris Lecture 20 Arduino Step by Step
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 real-
life applications, we need to provide external
power to the motor, and only signalling from
the Arduino.
You can get these devices fully assembled and ready to use on eBay for a couple of dollars.
4
Peter Dalmaris Lecture 20 Arduino Step by Step
!
!
And here’s 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 2 3 4 5 6 7 8 9 10 11
Out1 Out2 Out3 Out4 In1 In2 In3 In4 12V+ Gnd 5V+
!
Try to match these pins against the marked connectors in your break-out board and you
should be ok.
I’ll 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 differential 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.
5
Peter Dalmaris Lecture 20 Arduino Step by Step
In1 and In3 control the direction of spin for motor 1 and motor 2 respectively.
[VIDEO]
!
!
6
Peter Dalmaris Lecture 20 Arduino Step by Step
!
//Arduino PWM Speed Control:
int E1 = 5;
int M1 = 4;
int E2 = 6;
int M2 = 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 off.
7
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?
!
!
!
!
!
8
Peter Dalmaris Lecture 20 Arduino Step by Step
!
//Arduino PWM Speed Control:
int E1 = 5;
int M1 = 4;
int E2 = 6;
int M2 = 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?
9
Peter Dalmaris Lecture 20 Arduino Step by Step
!
Sketch for Demo 2, version 2: control speed and
direction with a potentiometer
!
There’s 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 I’d 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 Neutral - Motors move
! anti-clickwise motors don’t clickwise
! move
!
!
!
!
We are only going to make an adjustment to the sketch to make this happen, no need to
modify the circuit at all.
!
//Arduino PWM Speed Control:
int E1 = 5;
int M1 = 4;
int E2 = 6;
int M2 = 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);
Block 1
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); Block 2
analogWrite(E1, mappedVal); //PWM Speed Control
analogWrite(E2, mappedVal); //PWM Speed Control
delay(30);
}
}
!
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 difference
that now we now need to recognise that the potentiometer’s 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
effectively 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 difference 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.
If you are having any difficulty understanding what is going on in Blocks 1 and 2,
experiment with the sketch. Try changing the map function values to something different.
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 difference in behaviour? Can you explain any differences or
similarities?
We’ll 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, effectively slowing down our prototype
vehicle. Otherwise, it will forge ahead full speed.
!
!
!
!
!
!
!
!
!
!
!
!
!
!
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:
13
Peter Dalmaris Lecture 20 Arduino Step by Step
Serial.print(distance);
Serial.print(" cm - ");
Serial.println(mappedVal);
digitalWrite(M1,HIGH);
digitalWrite(M2, HIGH);
analogWrite(E1, 255-mappedVal); //PWM Speed Control
analogWrite(E2, 255-mappedVal); //PWM Speed Control
delay(30);
}
}
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 effect 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 sufficient? 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 don’t 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.
!
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.
1
Peter Dalmaris Lecture 23 Arduino Step by Step
But that’s 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 300μF or more and you’ll 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. That’s 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.
We’ll using this library first, and then I’ll show you an alternative third-party library that
provides additional functionality.
2
Peter Dalmaris Lecture 23 Arduino Step by Step
Demo 1a sketch
Here’s the sketch:
#include <Servo.h>
void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop()
{
for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // Block 1
waits 15ms for the servo to reach the position
}
for(pos = 180; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); Block 2
// waits 15ms for the servo to reach the position
}
}
!
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 effect 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?
3
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?
#include <Servo.h>
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!
!
!
!
!
!
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.
6
Peter Dalmaris Lecture 23 Arduino Step by Step
#include <VarSpeedServo.h>
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); // move the servo to 180, max speed, wait until done
// write(degrees 0-180, speed 1-255, wait to
// complete true-false)
myservo.write(0,30,true); // move the servo to 180, slow speed, wait until
// done
}
!
!
You can probably see the similarities and differences 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.
The position argument accepts an integer, denoting the degree we’d 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
7
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”.
Let’s 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>
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. Isn’t 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.
8
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 different 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.
With a parallel connection, we connect each of the screen’s data pins to an individual digital
pin on the Arduino. The LCD screen I’ll 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,
1
Peter Dalmaris Lecture 24 Arduino Step by Step
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.
2
Peter Dalmaris Lecture 24 Arduino Step by Step
We start by including the LiquidCrystal library to our sketch. This library comes build-in with
the Arduino IDE so we don’t 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 screen’s 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 different 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 that’s 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
!
!
!
!
!
!
!
!
!
!
4
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.
5
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.
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”.
6
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 off
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.
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.
1
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 Arduino’s 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.
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:
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 Arduino’s library folder (if not sure, look at your Arduino IDE
preferences).
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.
Here’s 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 doesn’t work, edit this line to EPSON to
see if it fixes the problem.
4
Peter Dalmaris Lecture 25 Arduino Step by Step
There’s a lot happening in this sketch, so it’s 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 // background color
#define C_COLOR RED // red color constant
#define M_COLOR GREEN // 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);
}
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:
5
Peter Dalmaris Lecture 25 Arduino Step by Step
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.
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!
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 offers.
6
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);
lcd.contrast(40);
Play with this parameter to see the effect it has on the contrast.
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:
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:
In the loop() function, we first define an array that contains three pieces of text:
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:
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.
8
Peter Dalmaris Lecture 25 Arduino Step by Step
#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);
}
}
9
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);
}
}
Let’s look at the differences between the sketches for Demo 1 and Demo 2.
!
!
10
Peter Dalmaris Lecture 25 Arduino Step by Step
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 let’s 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. You’ll find
them in elevators, microwave ovens, TV remote
controls, phones, and countless other machines that
we interact with daily.
1
which means that all column and row wires from the keypad are connected to 8 of the
Arduino’s 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.
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.
2
#include <Keypad.h>
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. I’ll 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 array’s
3
two dimensions. Remember that at the very beginning of this sketch we defined the
constants ROWS and COLS? Well, here’s 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 array’s rows, and commas for the
columns.
rows by brackets
{
{'1','2','3','A'}, columns by commas
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
Your keypad may have a different 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 keypad’s 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 Arduino’s 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 different 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 efficient?
Yes we can!
5
Demo 2a: a bit of extra work, but efficient
Occupying most of the Arduino’s digital pins just for the keypad is not an efficient use of our
hardware. Although Demo 1 was simple to put together and make it work, it isn’t good
enough for practical use. In Demo 2a and 2b, we’ll improve the design so that a single pin is
used on the Arduino to transmit button pressing information.
We’ll do this using two different scripts, but the same hardware design.
R4
Next to notice is that the breadboard is R1
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.
6
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 different 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 Arduino’s analog input.
Next, let’s have a look at the sketch that decodes these voltages and assigns them to a
symbol.
7
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(key!=-1) //if there was a key press, print the key symbol
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
off 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.
8
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 differential equations).
char* keypressed = 0;
int keyboardPin = 0; // Analog input pin that the keypad is attached to
int keyboardValue = 0; // value read from the keypad
void setup(){
Serial.begin(9600);
}
void loop(){
readkeyboard(); //get the value of key being pressed "keypressed" i.e. 0-9
}
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 pin’s 0 to 1023 range1), then it will call the
readkeyboard() function that will evaluate the reading and determine which key was
pressed.
1As 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.
9
//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";}
Serial.println(keypressed); // print the value back to the Serial view window on your PC
delay(1000); // 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. Here’s 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 differ. So, take these values and use them to edit the “if” statement
for value 1 accordingly. What you will have is something like this:
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.
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 differ in terms of elegance and practicality.
I think you are ready now for your most challenging exercise to date.
1. A keypad
2. An LCD screen
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.
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. Here’s some examples of
people have done: http://postscapes.com/internet-of-things-examples/
!
!
1
Peter Dalmaris Lecture 33 Arduino Step by Step
You need:
• Arduino Uno
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 SD-
card 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.
So, plug the shield onto the Arduino, no wiring required. This is what you end up with:
2
Peter Dalmaris Lecture 33 Arduino Step by Step
!
Done with the hardware!
Let’s 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
}
}
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 };
Can’t find your controller’s 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 };
4
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 don’t, 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 different
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 ;-).
5
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. That’s 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.
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, it’s 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:
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:
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:
1If 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-in-
windows-7.aspx
7
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.
Don’t worry about the text garbage that appears in the monitor. We’ll worry about this later.
For now, congratulations, you made your first Ethernet connection through your Arduino!
You need:
• Arduino Uno
• Photo-resistor
• LED
• 1KΩ resistor
8
Peter Dalmaris Lecture 33 Arduino Step by Step
• jumper wires
Let’s see what this we are trying to achieve with this circuit before looking at the sketch.
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 “ledoff” it will turn the LED off. Anything
will give you the instructions:
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
buffer to make sure there’s 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:
In processCommand (next page), the sketch checks to see if the command given matches any
of the three valid commands (“photo”, “ledon”, “ledoff”). 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 doesn’t 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.
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. That’s
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 your’s 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, we’ll 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 different 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, let’s 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 isn’t build to be a full blown web
server. It has a single tiny processor with very limited memory when compared to build-for-
purpose 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 efficiently for the AtMega
micro-controllers, and as a result it doesn’t have the kind of programming “sugar” that high-
level 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.
1
Peter Dalmaris Lecture 35 Arduino Step by Step
!
Minimal, because we don’t have much memory to spare, because programming anything
more complicate will take a lot of programming efforts, 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 offload to that computer the more elaborate features we would like to enrich
our Arduino-power web site with.
!
!
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 we’ll 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, let’s go ahead and have a look at an Arduino bare-minimal web
server.
!
Demo 1: The essential Arduino web server
In this Demo, I’ll show you how to setup a basic reporting web server on your Arduino. We’ll
look at the simple web server from one of the examples that come with the IDE. In Demo 2
we’ll make a few changes to it so that it reports data from a humidity/temperature sensor,
and a photo-resistor.
2
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 difference 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 don’t 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 …
!
!
!
3
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");
}
}
4
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.
I’ll 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.
5
Peter Dalmaris Lecture 35 Arduino Step by Step
!
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.
!
!
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:
6
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 client’s
request.
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.
7
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
Referer: http://192.168.111.177/
Accept-Encoding: gzip,deflate,sdch
blank line
Accept-Language: en-US,en;q=0.8,el;q=0.6
!
This blank line is identified by this statement in the sketch:
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 haven’t done any serious parsing
yet!!!
8
Peter Dalmaris Lecture 35 Arduino Step by Step
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.
client.println("Content-Type: text/html");
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. Don’t 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-by-
line. Here’s the code for this:
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.print(analogChannel);
client.print(" is ");
client.print(sensorReading);
client.println("<br />");
client.println("</html>");
9
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.
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 Arduino’s 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, let’s 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
If a machine makes the same request, I would like it to receive this response instead:
11
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.
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 efficient 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 offer 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
off. You could replace the LEDs for other devices, like motors, without having to introduce
significant changes to the sketch we’ll 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 Arduino’s web
server HTTP parser will have a lot more work to do.
Let’s go through the demo, and start by looking at how HTTP deals with data going from
the client to the server.
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, let’s have a look at the raw information that travels to the Arduino’s 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, I’ll use Chrome’s “Inspect Element” feature. We first had a
look at this really nice tool in Lecture 33.
2
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 request’s 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.).
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>
</form>
The rest of the code is identical. When I click on either the On button or the Off button, the
data is submitted to Request Bin (requestb.in) so I can inspect the details of the request.
!
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 difference 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
!
!
!
!
!
!
!
!
!
The sketch that we’ll use
implements this web page
(right).
5
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 server’s
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.
#include <SPI.h>
#include <Ethernet.h>
!
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,111,177 };
String message = ""; //Will hold the confirmation message
//that will be shown to the user
EthernetServer server(80);
String get_request = ""; //Holds the GET request
boolean reading = false; //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>");
}
!
… 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 (!sentContent){
construct_page(client, return_message);
sentContent = true;
}
delay(1);
client.stop();
Serial.println("client disonnected");
}
}
8
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.
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 we’ll 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 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 different 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:
9
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 don’t 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 don’t 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.
It’s 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. It’s 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”).
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 “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.
char c = client.read();
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:
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.
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.
• “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.
In the next 5 lines, the function constructs the response that will be sent to the user as part
of the HTML page.
12
Peter Dalmaris Lecture 37 Arduino Step by Step
And finally, action is taken by setting the LED on or off 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.
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 off 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 difference in red. Can you edit the sketch so that the web page contains
an on button and an off 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 photo-
resistor.
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, I’ll 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 can’t
handle by building on our current knowledge.
Instead of using a
potentiometer knob to control
the speed and direction of the motors, we’ll 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 difference 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.
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.
3. Read the character immediately after the keyword “speed”. Convert this character to an
integer value.
2
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.
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. Let’s have a look at it next.
Sketch
Here’s 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[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,111,177 };
String message = ""; //Will hold the confirmation message that
will be shown to the user
EthernetServer server(80);
String get_request; //Holds the GET request
boolean reading = false; //TRUE while the GET request is being
received
!
void setup()
{
Serial.begin(9600);
Ethernet.begin(mac, ip);
server.begin();
Serial.println("ready");
}
3
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");
}
}
4
Peter Dalmaris Lecture 40 Arduino Step by Step
5
Peter Dalmaris Lecture 40 Arduino Step by Step
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
6
Peter Dalmaris Lecture 40 Arduino Step by Step
stored (“&”)1, and keeps that value handy in the delimeter_index integer variable. To do
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 don’t 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 don’t
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 0-
indexed. 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 - don’t 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 different to first, then you could write this:
1it is only a coincidence that the C-language memory reference operator “&” is the same as the HTTP key-value
pair delimeter “&”.
7
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.
Here’s 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?
8
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 Pi’s 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 different 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.
1
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 photo-
resistor 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:
2. It’s 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 future-
proofing “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.
!
… continues next page …
2
Peter Dalmaris Lecture 40 Arduino Step by Step
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, let’s create a new Data Point to which you will be sending your
data, and a new Read/Write key to use for authenticating your Arduino’s access to this data
point.
3
Peter Dalmaris Lecture 40 Arduino Step by Step
Here’s the starting point for the process that will follow: the Admin Console.
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:
4
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.
!
Let’s 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:
5
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.
Let’s proceed with the Arduino side now. The sketch we will use is a slightly edited sketch
written by StewieT.
6
Peter Dalmaris Lecture 40 Arduino Step by Step
#include <SPI.h>
#include <Ethernet.h>
#include <PString.h> // from http://arduiniana.org/libraries/pstring/
// allows 'printing' to a string buffer
char buffer[400]; // larger than required for this example, resize to suit
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 ; // variables to store analog samples
int ana_B ;
!
!
/************ ETHERNET STUFF ************/
byte mac[] = { 0xDE, 0xAD, 0x45, 0xEF, 0xFE, 0xED };
!
// adjust these to suit your local setup.
byte ip[] = {192,168,111,177 }; // ethernet cards address
byte nameserver[] = {192,168,111,1 };
byte gateway[] = {192,168,111,1 };
byte subnet[] = {255,255,255,0 };
!
EthernetClient nimbitsServiceClient;
//***************************************
!
unsigned long lastConnectionTime = 0; // last time you connected to the server,
in milliseconds
const unsigned long postingInterval = 120000; // 120-sec delay between updates to
logging service, 720 per 24hrs to keep within the 1000 quota
// and leave room for other types of API
access
!
// 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); // initialise the
ethernet system
Serial.println("up and running....");
Serial.print("POST interval is ");
Serial.print(postingInterval/1000);
Serial.println(" seconds");
}
!
// =========================================================================
!
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(); // stop the client
nimbitsServiceClient.flush(); // and tidy up
}
}
!
!
8
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();
}
9
Peter Dalmaris Lecture 40 Arduino Step by Step
Sketch discussion
This code looks long and convoluted, but it’s 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 class’s files (“PString.cpp” and “PString.h”) in the folder that contains the Arduino third-
party 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 buffer. In this
sketch, we use two buffers, 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:
[email protected]&key=13jhad982jdh&p1=Test&v1=123
Content buffer
(“content”)
Here is the part of the code that set’s up the buffers 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
buffer 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 buffer buffer, and the cont PString object to manipulate the content
buffer.
• 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 let’s 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:
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
buffer. The first two key-value pairs added to the buffer 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 buffer, the sketch moves on to the headers. It first
attempts to connect to Nimbits (since there’s 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 buffer (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 you’d 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, I’ll show you a very easy way to do just this.
To post a message to Twitter, you need an account and a Twitter client. Because Twitter has
an interest in protecting it’s 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 Twitter’s 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 Twitter’s
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 Twitter’s 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 Twitter’s 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:
1
Peter Dalmaris Lecture 41 Arduino Step by Step
!
Arduino-
tweet
!
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 don’t even need to create an account, just to get an
authentication token. This is what we’ll do next.
I assume that you already have a Twitter account, or that you have created one specifically
for your Arduino to use. That’s 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 “official”
timeline.
Go to arduino-tweet.appspot.com. The home page shows the three things that need to be
done:
2
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 Arduino’s) 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:
3
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:
5
Peter Dalmaris Lecture 41 Arduino Step by Step
#include <SPI.h>!
#include <Ethernet.h>!
#include <Twitter.h>!
!
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };!
byte ip[] = { 10, 0, 0, 177 };!
Twitter twitter("<<< your token here >>>");!
char msg[] = "Hello, 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!
I’m Arduino!”!
6
Peter Dalmaris Lecture 41 Arduino Step by Step
Custom tweets
Now that we know that the Arduino can tweet via the proxy, let’s customise the message
that is posted. Let’s 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 <SPI.h>!
#include <Ethernet.h>!
#include <Twitter.h>!
#include <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("2282862504-
Hae3j7Ysr6F5k8OvTA6HL0xxgJVQEBgBaaQcUNG");!
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();!
}!
}
7
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).
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:
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
Arduino’s Twitter handle so I can check out your tweets!
8
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 isn’t. 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 off, 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 don’t 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 offer 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.
1
Peter Dalmaris Lecture 45 Arduino Step by Step
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:
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 offers 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.
2
Peter Dalmaris Lecture 45 Arduino Step by Step
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:
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. Let’s have a look at the first sketch.
3
Peter Dalmaris Lecture 45 Arduino Step by Step
Sketch
Let’s try something simple first: Get information about our SD card.
The sketch we’ll 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 don’t 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. Here’s
what you get (slightly edited from the original):
!
… continues from previous page …
Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);
!
!
!
!
!
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:
6
Peter Dalmaris Lecture 45 Arduino Step by Step
Demo 2
Demo 1 was about getting the SD card
breakout working. Now, let’s make use of
it. Let’s start logging sensor data onto our
card, and then use the card on the
computer to do some basic data analysis
ad plotting.
7
Peter Dalmaris Lecture 45 Arduino Step by Step
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(buffer, 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.
8
Peter Dalmaris Lecture 45 Arduino Step by Step
!
Remove the SD card from the Arduino and insert it in your
computer’s card reader.
!
You’ll 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. It’s a standard text file that you can
import to a spreadsheeting program for analysis and
charting.
9
Peter Dalmaris Lecture 45 Arduino Step by Step
Demo 3
In this last demo, we’ll 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 haven’t
already seen in Demos 1 and 2.
!
!
!
!
!
!
!
!
!
!
!
!
!
10
Peter Dalmaris Lecture 45 Arduino Step by Step
void setup()
Declare an object of type File, that will be used as a handle
{
to the root directory.
Serial.begin(9600);
Serial.print("Initializing SD card...");
Declare an object named root which is of class File. Looking
pinMode(10, OUTPUT);
at the documentation, you learn that this kind of object can
if (!SD.begin(10)) {
represent both normal files and directories (a directory is
just a special kind of file).
Serial.println("initialization failed!”);
return;
}
Serial.println("initialization done.");
root = SD.open("/");
SD.open() tries to open the file or directory named in the
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 the printDirectory function and passes two parameters: a
void loop()
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).
!
!
!
!
!
!
!
!
! 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 I’d 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
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.
It’s 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 off, or
taking sensor readings at predetermined times.
1
Peter Dalmaris Lecture 47 Arduino Step by Step
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.
#include <Wire.h>
Import the Wire library so that we can use the IC2 bus.
#include "RTClib.h"
Import the RTClib library so that we can use the clock.
RTC_DS1307 rtc; Declare an RTC_DS103 object, name it “rtc”.
void setup () {
Serial.begin(9600);
Initialise the IC2 bus.
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
rtc.adjust(DateTime(2014,01,16,14,45,00));
and automatically set the time.
// 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
void loop () {
“running” state. As long as a time has been set and
DateTime now = rtc.now();
the battery can power it, the “rtc.isrunning()”
Serial.print(now.year(), DEC);
function will return true. The only time you will
Serial.print('/');
probably see a “false” returned is when you run this
sketch for the very first time.
Serial.print(now.month(), DEC);
Serial.print('/');
Get the time now, and store it in the “now” variable,
Serial.print(now.day(), DEC);
which is of time DateTime.
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 = ");
Serial.print(now.unixtime());
Get the number of seconds elapsed since 1/1/1970,
Serial.print("s = ");
when Unix time begins.
Serial.print(now.unixtime() / 86400L);
… and convert that to days, since 1 day
Serial.println("d");
contains 86400 seconds.
3
Peter Dalmaris Lecture 47 Arduino Step by Step
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.
!
Results of time/date calculations
4
Peter Dalmaris Lecture 47 Arduino Step by Step
In the next page, I provide the merged sketch, and comments to the interesting segments.
5
Peter Dalmaris Lecture 47 Arduino Step by Step
RTC_DS1307 rtc;
Import the RTClib library so that we can use the
const int chipSelect = 10; clock breakout library.
void loop(){
DateTime now = rtc.now();
Get the sensor readings.
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) {
print_time(now, dataFile);
Get a handle to the datalog file.
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);
}
6
Peter Dalmaris Lecture 47 Arduino Step by Step
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, here’s another exercise: Extend the LCD clock so that it has these features:
!
1. A toggle switch
3. A buzzer
4. Only keeps track of time (don’t 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 off, 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.
7
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, we’ll again connect the Arduino to the Internet, but
we’ll 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 offer 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.
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 off.
1
Peter Dalmaris Arduino Step by Step Lecture 50
!
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 IDE’s 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. There’s
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
2
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.
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, that’s means you’re good
to go!
3
Peter Dalmaris Arduino Step by Step Lecture 50
Sketch
Let’s look at the sketch now. The one we’ll 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 <Adafruit_CC3000.h> Import the Adafruit library so that we can use the Wifi module.
#include "utility/debug.h" 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
#define WLAN_PASS "myPassword"
type of the micro-controller used.
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY WLAN_SEC_WPA2
4
Peter Dalmaris Arduino Step by Step Lecture 50
#ifndef CC3000_TINY_DRIVER
You can load a small-footprint driver for the Wifi module. The tiny
listSSIDResults();
driver will only load the essential API functions and save a lot of
RAM. See http://processors.wiki.ti.com/index.php/
#endif
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!"));
while(1);
Attempt to connect to the Wifi access point with the security
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
Serial.print(F("www.adafruit.com -> "));
parameter (“&ip”). This is a DNS request.
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
delay(500);
4-byte integer. This function will convert this integer into
}
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 1-
Serial.print(F("\n\rPinging "));
byte (8 bit) unsigned integer. The response
cc3000.printIPdotsRev(ip); Serial.print("..."); contains the number of packets received.
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
void loop(void){
delay(1000); } Start of a pre-processor conditional group.
What follows (until the #endif directive) will be
void displayDriverMode(void){
compiled only if the tiny driver is used.
#ifdef CC3000_TINY_DRIVER
Serial.println(F("CC3000 is configure in 'Tiny' mode"));
#else
Print out various driver parameters. The F()
Serial.print(F("RX Buffer : "));
function enforces storage of these static
Serial.print(CC3000_RX_BUFFER_SIZE);
(unchanging) Strings in flash memory instead
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
Serial.print(CC3000_TX_BUFFER_SIZE);
stored when you upload it.
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
uint8_t major, minor;
parameters.
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"));
}
else
Get the device’s MAC address. It contains 6
{
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
else
locations passed as parameters to the
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
uint8_t valid, rssi, sec, index;
found.
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:
8
Peter Dalmaris Arduino Step by Step Lecture 50
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 it’s
contents, and turn an LED on and off accordingly. Schematically, this is what is going to
happen:
!
1
!
!
!
! 4
! 3
There is a blank
line after the
instruction line.
!
!
Instruction: Turn LED in pin 8 ON
!
9
Peter Dalmaris Arduino Step by Step Lecture 50
There’s 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 it’s
instructions by accessing a public URL, and you will be able to control your Arduino by
manipulating the resource at that URL.
#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
#define WLAN_SSID "mynetworkid"
within 3 seconds.
#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
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); }
connect_wifi();
Broken down the functionality from the setup
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
Serial.println(F("Connecting"));
server.
if (www.connected()) {
Disable watch dog timer (“WDT”). It is not
Serial.println(F("Connected"));
likely that anything else may cause the sketch
make_get_request();
to freeze.
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();
Confused? Consider revising Lecture 38!
!
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 Lecture 50
if(reading){
The HTTP response parser, continues.
get_request += c; }
It is essentially identical to the one
if (reading && c==‘\n') {
from Lecture 38 except for the green
break; }
segment. The content the parser is
if (c == '\n' && currentLineIsBlank) {
looking for is in the body of the HTTP
response (not the query string like in
reading = true;
Lecture 38). The HTTP response is
}
found after the response header, and
if (c == '\n') {
is detected by looking for a new line
(“\n”) after a blank line.
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}
}
Close the connection to the web
}
server.
www.close();
Serial.println(F("-------------------------------------"));
delay(10000); }
Instruction parser, identical to the one
void parseGetRequest(String &str) {
in Lecture 38.
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); }
Execute instruction function, identical
void executeInstruction(int pin, int val){
to the one in Lecture 38.
Serial.println(F("Executing instruction"));
pinMode(pin, OUTPUT);
digitalWrite(pin, val);
Serial.println(F(“Done!"));}
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(){
www.fastrprint(F("GET "));
Get request is assembled by “printing” to the
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();
Attempt to connect to the remote server if at
do {
least 5 seconds (set in the connectTimeout
variable) have elapsed since the last connection.
www = cc3000.connectTCP(ip, port); }
while((!www.connected()) && ((millis() - 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 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
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.
1. I identified the segment of the sketch that seems to be causing fragmentation and/or is
affected 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 offending 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 offending 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
don’t want the WDT
to reset the device
and mask such
behaviour.
15
Peter Dalmaris Arduino Step by Step Lecture 50
We will use the exact same circuit as in Demo 2. Let’s go straight to the sketch and see
what’s different…
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>
Inclusions and definitions as in the previous
#include <string.h>
examples, with the addition of LISTEN_PORT
#include "utility/debug.h"
which defines the TCP port on which the web
#include <stdlib.h>
server will listen for connections.
#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
Create the device object.
#define LISTEN_PORT 80
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"));
while (!cc3000.checkDHCP()) {
Get network parameters from the
DHCP server.
delay(100); // ToDo: Insert a DHCP timeout!
}
while (! displayConnectionDetails()) {
Show network parameters leased
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
get_request = "";
38, Demo 2, with the exception of the
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 Lecture 50
if (!sentContent){
construct_page(client, return_message);
sentContent = true; }
delay(5);
client.close();
Serial.println("client disconnected");
result = "";
}
}
18
Peter Dalmaris Arduino Step by Step Lecture 50
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 Arduino’s 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 it’s 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 “real-
time” 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 difference 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, we’ll 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:
• Can be shared amongst multiple I2C devices, which means that you can connect multiple
compatible devices to your Arduino without increasing the wire count.
1
Peter Dalmaris Lecture 54 Arduino Step by Step
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 IDE’s Libraries folder. Don’t
forget to restart the IDE for the install process to complete!
!
2
Peter Dalmaris Lecture 54 Arduino Step by Step
Sketch
Here’s the sketch, with annotations embedded.
void setup(){
This library allows you to use the functionality offered
lcd.begin(16,2);
by the standard LCD library via the I2C bus.
lcd.backlight();
lcd.setCursor(0, 0);
Initialise the lcd object that we’ll use to write to the
lcd.print("Hello world!");
screen. The first parameter “0x27” is the I2C address
lcd.setCursor(0, 1);
of the adaptor (more about this further down). The
lcd.print("Row number: ");
rest of the parameters are:
lcd.setCursor(12, 1);
!
1: Device address
lcd.print("2");
2: LCD screen enable (“En”) pin
} 3: LCD screen read/write (“R/W”) pin
4: LCD screen reset (“Rs”) pin
void loop(){
5: LCD screen data 0 pin
} 6: LCD screen data 1 pin
7: LCD screen data 2 pin
8: LCD screen data 3 pin
Same use of LCD functions 9: LCD screen backlight pin
as we saw in lecture 24. 10: LCD screen backlight polarity (POSITIVE or
NEGATIVE)
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 let’s 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.
3
Peter Dalmaris Lecture 54 Arduino Step by Step
3
4. Plug the Arduino GND and 5V pins
to the power strip at the top of the 5,6
1
breadboard.
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
breadboard’s 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.
4
Peter Dalmaris Lecture 54 Arduino Step by Step
Sketch
Let’s 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);
Wire.begin();
Start the I2C bus.
lcd.begin(16,2);
Start the LCD screen with 16 columns, 2 rows, and
lcd.backlight();
turn backlight on.
rtc.begin();
rtc.adjust(DateTime(__DATE__, __TIME__)); Start
the real-time clock module, and set the time
and date to the system time and date during
}
compilation.
void loop () {
DateTime now = rtc.now();
Get the time from the real-time
Serial.print(now.year(), DEC); Serial.print('/');
clock and print it to the Serial
Serial.print(now.month(), DEC); Serial.print('/');
monitor.
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. Here’s 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.
6
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.
1
Peter Dalmaris Interrupts Arduino Step by Step
This table contains the interrupt numbers and associated pins for the more popular
Arduinos:
Uno, 2 3
Ethernet
Mega2560 2 3 21 20 19 18
Leonardo 3 2 0 1 7
Let’s have a look at our first hardware interrupt example and discuss some of the
implementation details.
Demo 1
In this first demo, we’ll 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.
• A 5mm LED
2
Peter Dalmaris Interrupts Arduino Step by Step
const int ledPin = 13;
We’ll connect the button to digital pin 2. This pin
const int inputPin = 2; corresponds to interrupt number 0 for the Uno.
digitalWrite(ledPin,HIGH);
}
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.
3
Peter Dalmaris Interrupts Arduino Step by Step
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 sketch’s 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).
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 I’ll show you how in Demo 2.
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();
Here’s 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.
5
Peter Dalmaris Interrupts Arduino Step by Step
This variable will keep track of the number of times that we have pressed on the button.
void loop()
{
}
void buttonPressed()
{
Increase the counter by 1.
counter++;
Serial.println(counter, DEC);
Print the value stored in “counter”, format it as a
decimal.
if (digitalRead(ledPin))
digitalWrite(ledPin,LOW);
else
digitalWrite(ledPin,HIGH);
}
In this sketch, the only difference 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
6
Peter Dalmaris Interrupts Arduino Step by Step
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.
7
Peter Dalmaris Interrupts Arduino Step by Step
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, we’ll make an LED blink by setting a timer to trigger an interrupt once every
second. The sketch follows, with embedded comments:
void setup()
Initialize the timer and set the period duration. The
{
parameter is in microseconds. One second is one
million microseconds.
pinMode(13, OUTPUT);
Timer1.initialize(1000000);
Timer1.attachInterrupt(toggleLED);
}
Attach the timer interrupt to a handler function.
void loop(){ }
void toggleLED()
{
The interrupt handler simply toggles that state
digitalWrite(ledPin, ledState);
of the LED.
ledState = !ledState;
}
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/
PaulStoffregen/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
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 library’s 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.
9
Peter Dalmaris Interrupts Arduino Step by Step
Connect the LED to digital pin 9, and try out this sketch:
#include <TimerOne.h>
Set the overall period to 1000 microseconds. Playing
int ledPin = 9; around with this value does not produce any
dramatic effect, so don’t worry too much about it.
void setup()
{
Initialise the initial PWM duty cycle to 0 out of 1024.
Timer1.initialize(1000);
We need to use the pwm function at least once
Timer1.pwm(ledPin,0);
before using the setPwmDuty to change the duty
cycle later.
pinMode(ledPin, OUTPUT);
}
void loop(){
Timer1.setPwmDuty(ledPin, 250);
delay(1000);
Timer1.setPwmDuty(ledPin, 500);
delay(1000);
Change the PWM duty cycle to a new level, then
Timer1.setPwmDuty(ledPin, 800);
wait for a second.
delay(1000);
Timer1.setPwmDuty(ledPin, 1024);
delay(1000);
}
You should see that the LED lights up very gradually and finely, the effect 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 difficult 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, I’ll 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 difficult 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.
1
Peter Dalmaris Shift Registers Arduino Step by Step
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. Here’s a graphical way to look at this
process:
Let’s say that we’d like to store the byte 11001101 in the shift register represented by this
table. At start, the shift register has an undeterminable state, so I’ll represent this with a
question mark.
This is Step 0:
? ? ? ? ? ? ? ?
In Step 1, we’ll 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:
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, we’ll 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. I’m only
including it here outside the register to emphasise the outcome of the shift function.
This is Step 2:
0 1 ? ? ? ? ? ? ? ?
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.
1 0 1 ? ? ? ? ? ? ??
This is Step 3:
2
Peter Dalmaris Shift Registers Arduino Step by Step
! 1 1 0 1 ? ? ? ? ? ???
!
This is Step 5 “11001101”:
! 0 1 1 0 1 ? ? ? ? ????
!
This is Step 6 “11001101”:
!
0 0 1 1 0 1 ? ? ?
! ?????
!
1 0 0 1 1 0 1 ? ? ??????
!
This is Step 8 “11001101”:
!
1 1 0 0 1 1 0 1 ? ???????
!
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, let’s 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:
! 0 1 1 0 0 1 1 0 1 ????????
!
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
In this demo, we’ll 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 different 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 it’s 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.
4
Peter Dalmaris Shift Registers Arduino Step by Step
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
We’ll 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.
5
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. Let’s
have a look at the sketch and see how we can change the pattern.
const int latchPin = 9;
Set the Data, Clock and Latch pins. These are
const int clockPin = 10;
pins 14, 9, and 10 respectively on the chip.
const int dataPin = 8;
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 it’s
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 Arduino’s 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 it’s 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.
7
Peter Dalmaris Shift Registers Arduino Step by Step
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
there’s so many LEDs drawing a few mA of power each at random times, there will be a
strain on the Arduino’s 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 220μF. 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.
Let’s concentrate on the second 74HC59N (Chip 2) for a moment. The first 74HC59N is
Chip 1. Connect it like this:
• Chip 2 Pin 14 to Chip 1 Pin 9 Q7S (this establishes the daisy chaining of the two chips)
8
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. It’s almost identical to the sketch in demo 1. The only differences are
highlighted below.
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);
Generate a second random byte, just like in Demo
1. Write the second random byte to the 16-bit
writeLeds(randNumber1);
shift register by calling writeLeds twice.
writeLeds(randNumber2);
delay(100);
}
!
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.
9
Peter Dalmaris Shift Registers Arduino Step by Step
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 effort.
!
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 it’s 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: There’s
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 off 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 here’s the difference: 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.
That’s 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.
In this first demo, we’ll 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 we’ll 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 can’t simple store an integer like
we do with the RAM, where the compiler knows how to deal with integer (and other data-
type) 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 we’ll simplify this process a lot.
!
1
Peter Dalmaris Arduino Step by Step EEPROM
Here’s the writing sketch (Demo1_writer), let’s execute it and then go through it to explain
how it works.
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:
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.
That’s 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.
2
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);
byte retrievePinHigh;
Retrieve the bytes from addresses 0 and
byte retrievePinLow;
1, and store them in RAM.
retrievePinHigh = EEPROM.read(addr);
retrievePinLow = EEPROM.read(addr+1);
Do some binary arithmetic (“<<“ bit shift
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 11001101
shifted 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. That’s 8 original bits,
and 3 inserted bits.
3
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.
High byte
00000100
High byte shifted to
the left by 8 bits.
00000100 00000000
Low byte
11010010
Shifted high byte and
low byte added. 00000100 11010010
!
And there you have it, your pin has been retrieved!
!
!
4
Peter Dalmaris Arduino Step by Step EEPROM
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.
int addr = 0;
void setup()
{
Use EEPROM.writeInt to write an integer. No need
Serial.begin(9600);
to worry about high and low bytes, and addresses
for each byte. Just pass the EEPROM address
int myPin=1234;
where the integer should be store, and the
EEPROM.writeInt(addr, myPin);
integer.
Serial.print("My pin recorded:");
Serial.print(myPin);
Serial.println(".");
}
5
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.
#include <EEPROMex.h>
int addr = 0;
void loop()
{ }
You only need to use the corresponding read function for whichever write function you used
to write a value.
6
Peter Dalmaris Arduino Step by Step EEPROM
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 let’s check this out.
!
Arduino EEPROM module
!
5V VCC
!
GND GND
!
A4 SDA
!
A5 SCL
!
!
7
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 EEPROM’s address was, so I used an I2C device scanner sketch to find it out.
I have the sketch in the course’s Github account. It isn’t too important to discuss how the
scanner works, we’ll 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. We’ll use this
information in the sketches that follow.
To demonstrate how to use the external EEPROM, we’ll 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. We’ll 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 don’t 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
8
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.
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:
9
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, don’t 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. Let’s 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:
!
These are markers for the private Here are the function definitions. The first one, EEEPROM()
and public variables of functions. is a constructor. Its implementation is empty at the
!
We don’t have anything in private,
and the public section is populated
moment, but I plan to add some initialisation code in it
later. The rest of the definitions are fully implemented in the
!
with the function definitions for our
library.
.cpp file.
!
Think of the header file as the skeleton of our library. It’s just a declaration of what the
outside world should know about it, without any internal details.
11
Peter Dalmaris Arduino Step by Step EEPROM
Let’s have a look at the implementation. Create a new file named EEEPROM.cpp and add
this code in it:
12
Peter Dalmaris Arduino Step by Step EEPROM
!
! 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:
! •
keywords
KEYWORD2 Methods and functions
KEYWORD3 setup and loop functions, as
! These keywords (the function
names from the header file) will •
well as the Serial keywords
LITERAL1 Constants
! be highlighted by the Arduino
IDE syntax highlighter.
• LITERAL2 Built-in variables (unused by
default)
I am using KEYWORD2 to highlight the function names, as per the convention. Here’s 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
#include <Wire.h> //I2C library
Include the EEEPROM library we just created.
#include <EEEPROM.h>
Create an EERPROM object, call it “eeeprom”.
EEEPROM eeeprom = 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
void loop()
of char that contains our data, and the size of the
{
array.
int addr=0;
byte b = eeeprom.i2c_eeprom_read_byte(0x50, 0);
while (b!=0)
{
We’ll read the string one byte
Serial.print((char)b);
(character) at a time. Start with the
first byte at memory location 0. As
addr++;
parameters, pass the I2C address
b = eeeprom.i2c_eeprom_read_byte(0x50, addr);
of the device and the byte address
}
we want to retrieve.
Serial.println(" ");
delay(2000);
}
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 life-
span, 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 doesn’t 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
You can find it at File —> Examples —> Digital —> Debounce. It looks like this:
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.
2
Peter Dalmaris Hardware Debouncing Arduino Step by Step
!
But sudden, clean transitions are good:
!
This is not to say that you can’t 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 effort.
What I would like to show you next is a cost-effective solution that takes care of de-
bouncing without adding complexity.
3
Peter Dalmaris Hardware Debouncing Arduino Step by Step
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. That’s
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 doesn’t do much to debounce the original noisy signal.
4
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.
!
5
Peter Dalmaris Hardware Debouncing Arduino Step by Step
We’ll use the Schmitt Trigger to debounce the push button. When the button is pressed, the
LED will turn on.
!
IC Pin Connects to…
! 14 5V
! 7 GND
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.
6
Peter Dalmaris Hardware Debouncing Arduino Step by Step
Here is the sketch, it is similar to the one from the lecture on interrupts.
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 it’s limit of
reliability.
Try the same things with various buttons and switches that you may have at hand. I find in
my experiments that different buttons behave very differently 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 effects 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!
7
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 de-
bounce 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 different 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 effect 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.
8
Peter Dalmaris Arduino Step by Step Internal Pull Up Resistors
!
!
!
!
!
!
!
!
!
!
!
!
!
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
1
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Ω.
!
!
!
!
!
!
!
!
!
!
!
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 let’s move to the sketch, and see how to enable the pull-up resistor. This resistor is, by
default, disabled.
2
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;
Set the button and LED pin number, and initialize
const int ledPin = 13;
the button state.
int buttonState = 0;
Set the ledPin to be output.
void setup() {
pinMode(ledPin, OUTPUT);
Set buttonPin to be an input, and enable the pull-
pinMode(buttonPin, INPUT_PULLUP); up resistor. We can now throw away the external
} pull-up.
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 don’t have any effect
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-controller’s 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 (that’s a waste of energy), but
you also don’t want it to be too large as at some point you will end up with the same
3
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 insufficient 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Ω).
4
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):
It is worth knowing that the memory architecture that the Atmega and most micro-
controllers 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:
Instructions
Data memory CPU
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 Harvard’s architecture can yield better
performance, Von Neumann’s is more flexible for general purpose applications. Since
micro-controller’s are meant to perform a particular task reliably and efficiently, it makes
sense to design them based on the Harvard architecture.
In this lecture, we’ll look at some design and programming principles you can follow to
make better use of your Arduino’s limited memory resources.
Flash
Flash memory is usually our first
consideration since it is the first
memory we consume when we
upload a sketch.
!
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):
2
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?
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 don’t
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.
3
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.
into this:
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.
!
!
4
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. Here’s a couple of examples:
* If you decide to use an SD card in your project, you will immediately dedicate 512 bytes
of SRAM as buffer 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.
Let’s have a look at things you can do to make efficient use of your available SRAM.
This table contains the available data types and the amount of space they consume in the
SRAM.
Type Bytes
boolean 1
char 1
unsigned char 1
byte 1
int 2
unsigned int 2
word 2
long 4
unsigned long 4
short 2
float 4
Let’s pretend that you are creating an array to hold these numbers: 1, 5, 25, 125.
5
Peter Dalmaris Memory & Memory Management Arduino Step by Step
…you will consume 4 * 2 bytes = 8 bytes. But if you declare it like this:
… 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 difference 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
effort. Here is a typical example:
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):
6
Peter Dalmaris Memory & Memory Management Arduino Step by Step
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.
System.println(“Hello world!”);
System.println(F(“Hello world!”));
PROGMEM doesn’t 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:
7
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.
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.
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.
8
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 haven’t 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 Arduino’s memory.
9
Peter Dalmaris Seven segment display Arduino Step by Step
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.
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 don’t have your particular display’s 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.
1
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.
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 doesn’t 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 doesn’t 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.
2
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.
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.
3
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 difference is that
in the new sketch we are about to create, we don’t want the LEDs in the SSD to light up
randomly, we want it to show legible numbers.
Let’s start with the skeleton of the sketch and build it up.
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop() {
}
This sketch doesn’t 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.
4
Peter Dalmaris Seven segment display Arduino Step by Step
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 it’s all 1s, and this is a common-anode SSD, all the LEDs
will be off. 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.
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.
Let’s 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.
5
Peter Dalmaris Seven segment display Arduino Step by Step
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 # 8 7 6 5 4 3 2 1
Segment G F A B E D C DP
When you have completed this, your symbols array will look like this:
With this, getting the count-up effect that we are looking for is simple. Here is the
completed sketch (next page), with comments embedded:
6
Peter Dalmaris Seven segment display Arduino Step by Step
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
Call to function that creates the count-up
void loop() {
effect.
pattern1();
}
void pattern1()
{
int i=0;
The while() block calls the writeLeds() function
while(i<CHAR_COUNT)
and passes an appropriate symbol bit pattern
from the symbols array. Each time, it
{
increments the counter by 1. Once it reaches
writeLeds(symbols[i]);
the last item of the, it ends.
i = i+1;
delay(500);
}
}
7
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.
Alphanumerical displays
If you need to display letters as well as numbers, then you are
looking for an alphanumerical display. Here’s an example (image
to the right).
I will try to create a lecture that will demonstrate how to use the MM5450, although I think
that with a little effort, 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.
8
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!
9
Peter Dalmaris The MCP23017 port expander Arduino Step by Step
But what about additional digital inputs? In this lecture, I’ll show you how to use the
MCP23017 IC to easily add a total of 16 digital I/O pins to your Arduino project.
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.
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. We’ll 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 11 and 14 are not connected to anything, just leave them floating.
1
Peter Dalmaris The MCP23017 port expander Arduino Step by Step
2
Peter Dalmaris The MCP23017 port expander Arduino Step by Step
!
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 you’d 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):
3
Peter Dalmaris The MCP23017 port expander Arduino Step by Step
void loop() {
delay(100);
Write HIGH to I/O pin 7, turns the LED on.
mcp.digitalWrite(7, HIGH);
delay(100);
Write LOW to I/O pin 7, turns the LED off.
mcp.digitalWrite(7, LOW);
}
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?
4
Peter Dalmaris The MCP23017 port expander Arduino Step by Step
#include "Wire.h"
void setup()
{
Wire.begin();
Wire.beginTransmission(0x20);
Set ports in Bank A (0x00) to be all
Wire.write(0x00);
outputs.
Wire.write(0x00);
Wire.endTransmission();
Wire.beginTransmission(0x20);
Set ports in Bank B (0x01) to be all
Wire.write(0x01);
outputs.
Wire.write(0x00);
Wire.endTransmission();
}
void loop()
{
delay(100);
Set the bit pattern for the port in Bank A
Wire.beginTransmission(0x20);
(0x12). This will turn on the LED
connected to to pin 28 on the port
Wire.write(0x12);
expander.
Wire.write(B10000000);
Wire.endTransmission();
Set the bit pattern for the port in Bank B
Wire.beginTransmission(0x20);
(0x13). This will turn on the LED
Wire.write(0x13);
connected to to pin 1 on the port
expander. Notice how the least significant
Wire.write(B00000001);
bit controls the state of pin 1.
Wire.endTransmission();
delay(100);
Wire.beginTransmission(0x20);
Wire.write(0x12);
Wire.write(B00000000);
Wire.endTransmission();
Wire.beginTransmission(0x20);
Wire.write(0x13);
Wire.write(B00000000);
Wire.endTransmission();
}
Let’s have a look at the equivalent sketch using the Adafruit library (next page):
5
Peter Dalmaris The MCP23017 port expander Arduino Step by Step
#include <Wire.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp;
void loop() {
delay(100);
mcp.digitalWrite(8, HIGH);
mcp.digitalWrite(7, HIGH);
delay(100);
mcp.digitalWrite(8, LOW);
mcp.digitalWrite(7, LOW);
}
6
Peter Dalmaris The MCP23017 port expander Arduino Step by Step
#include <Wire.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp;
void setup() {
Set I/O 7, which is pin 1 (GPA7), to be
mcp.begin();
output.
mcp.pinMode(7, OUTPUT);
mcp.pinMode(0, INPUT);
Set I/O 0, which is pin 21 (GPA0), to be
} input.
void loop() {
mcp.digitalWrite(7, mcp.digitalRead(0));
}
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 display’s 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.