Hallberg Gary - The Arduino Leonardo (Arduino Short Reads. Book 8) - 2021
Hallberg Gary - The Arduino Leonardo (Arduino Short Reads. Book 8) - 2021
Gary Hallberg
The idea underpinning the Arduino short reads series is to provide a comprehensive, easy to follow
tutorial set and reference guide for anybody wanting to learn about Arduino and basic electronics.
Having a short reads series means that students and hobbyists can select key topics of interest in the
field with minimal outlay. The series aims to provide an easy introduction to all topics of interest and
expand on these topics to provide a broader and deeper understanding of that focus area. The books
are currently only available in Kindle format to provide a very inexpensive package backed up by video
content and interactive social media.
The series is aimed at youngsters and adults interested in getting into electronics and it takes a modern
approach, combining the use of the inexpensive software driven Arduino controller board, with a
multitude of sensors and discreet electronic components. The experiments in this series of books are
easy to follow, inexpensive to implement and compelling for all interested in STEM education. I hope
to inspire anybody looking for a future career in technology or to simply to have fun.
The first book of this series looks at the Arduino microcontroller and explains its operation and purpose.
Experiments look to show you how to set up the programming environment and drive LEDs as well as
read input from switches, thermistors and photocells. Book 1 will give you a solid foundation of how
some basic electronic components work and how to use them to make simple designs.
Other books in the Arduino Short Reads Series focus on the following subjects:
If you find this series of books useful then please leave your review and rating on
Amazon.
Follow North Border Tech Training on Facebook and Twitter for the latest news and
insights as to how this series will develop.
Foreword
If you have followed the books in this series sequentially then you will find this book to be the final
installment. In fact, we have covered all the key areas in the Arduino ecosystem bar the special
capabilities that set the Arduino Leonardo apart from the other Arduino platforms such as the Uno. The
Arduino Leonardo supports all the capabilities of the Arduino Uno and is compatible with the many
shields that are available, but the Arduino Leonardo can emulate USB devices that would normally be
connected to any PC or laptop. It can be used emulate keyboard and mouse functionality and it is this
capability that will explore in this final installment.
Prerequisites for this Book
This book assumes you have read Book 1 of the series (‘First Steps with Arduino’) or you already have
some experience of the Arduino platform, how to set up the IDE and undertake some basic Arduino
programming tasks. Basic functions such as ‘digitalRead’ and ‘digitalWrite’ are not covered here
but are explained in Book 1.
Download the Code
You can download the Arduino Code for the experiments in this book from GitHub using the link below.
https://github.com/ghallberg-nbtt/musical-happiness
I recommend that you do this as I have removed some of the comments from the code in the book
listings to aid readability in print form. I strongly recommend that you comment your code heavily to
facilitate understanding and to become familiar with best engineering practice.
Chapter 1: An Introduction to the Arduino
Leonardo
So, what makes the Arduino Leonardo special compared to the Arduino Uno and why does it merit
special attention? In previous books of this series, we have used the USB support for basic serial data
transport. However, the standard can accomplish so much more. The unlike the Arduino Uno, the
Arduino Leonardo has native USB support built into the MCU. The Arduino Uno has a secondary USB
chip external to the MCU. This means that Arduino Leonardo can emulate non serial USB devices such
as keyboards and computer mice. We will explore what this means in later chapters, but now we will
take a closer look at the Arduino Leonardo and compare it to the Arduino Uno.
// Define variables
int val = 0; // Holds the analog reading from photocell
void setup()
{
Serial.begin(9600);
}
void loop()
{
val = analogRead(LIGHT); // Read the light sensor
Serial.println(val);
delay (500);
}
We can reuse the variable ‘val’. ‘val’ is the ADC value from the photocell. It will be proportionally
mapped to the new value between 0 and 255 and ‘val’ is overwritten with this new value for use as the
PWM output integer. There is one more point to consider. The map function does not constrain values
so if we recorded a value higher than 840, the map function will return a value below 0. This would
clearly cause and error in our code. Therefore, we must also use the ‘constrain’ function to constrain
the value of ‘val’ to between 0 and 255.
val = constrain (val, 0, 255);
These are two important functions in the Arduino programming language. Now try the full Sketch to
control the nightlight. This is shown in Listing 1-2. Review the code to make sure you understand it. We
are essentially looking for ‘HIGH’ to ‘LOW’ button transition to turn the light on or off and when on, the
photocell varies the light intensity. The switch needs to be debounced to negate the effect the
mechanical contact bounce.
/*
Nightlight
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/musical-
happiness/blob/main/LICENSE
*/
// Define variables
int val = 0; // Holds the analog reading from photocell
boolean previousButton = HIGH; // Var containing the previous button state
boolean currentButton = HIGH; // Var containing the current button state
boolean ledOn = false; // The present state of the LED (on or off)
void setup()
{
pinMode (ON_OFF_LED, OUTPUT); // on off LED
pinMode (BUTTON, INPUT_PULLUP); // Button input
}
void loop()
{
currentButton = digitalRead(BUTTON); // Read the switch state
Summary
In this chapter you were introduced to the Arduino Leonardo. You explored the pin assignments and
understood that it is compatible with the Arduino Uno from that perspective. You learnt that shields
produced for the Uno can be fitted to the Leonardo. You learnt that basic Sketch functions work in the
same way on both the Arduino Leonardo and the Arduino Uno.
Chapter 2: Keyboard Emulation using the
Arduino Leonardo
You can use the Leonardo’s unique capability to emulate USB connected peripherals to emulate a
keyboard and have it type data directly into a desktop program. We will explore this capability in this
chapter. There are 2 experiments. The first looks at sending keystrokes and key combinations to enter
data directly into a text file and then a spreadsheet program and the second looks at command functions
that we can use to control a computer running Microsoft Windows.
#include <Keyboard.h>
void setup() {
pinMode (BUTTON, INPUT_PULLUP);
Keyboard.begin(); //start keyboard emulation
}
void loop() {
currentButton = digitalRead(BUTTON); //Read the switch state
if (ledOn) {
//Collect samples
digitalWrite (ON_OFF_LED, HIGH); //Turn on LED
if (millis() % 2000 == 0) { //Collect every 2 seconds
int waterLevel = analogRead(SENSOR); //Read water level sensor
Keyboard.print (sampleNumber); //Print index
Keyboard.print (","); //Print a comma
Keyboard.println(waterLevel); //Print the water level and newline
sampleNumber++; //increment the sample number
}
}
else {
//Turn off sampling
digitalWrite (ON_OFF_LED, LOW); //Turn off
}
}
As in previous experiments, we use a switch to turn the sampling on or off. It is important to use the
switch as the Arduino Leonardo will continue to transmit key presses that may affect the application
that has current focus on your desktop. If the sampling is on, we want to collect samples every 2 seconds.
You will notice we are not using the ‘delay’ function. The ‘delay’ function is blocking and so we would
not scan for the switch state continuously. This means we would most likely not detect a button press
to turn the sampling on or off. Instead, we can use the ‘millis’ function. This provides a count of
milliseconds since the program started. If the value of ‘millis’ mod 2000 is 0 then we know 2 seconds
has elapsed since the last sample was taken. We have a neat way of executing code periodically without
blocking the scanning of the switch.
if (millis() % 2000 == 0) {
//execute code every 2 seconds
}
Printing to the keyboard is straightforward using the ‘print’ function in the ‘Keyboard’ class.
int waterLevel = analogRead(SENSOR); //Read water level sensor
Keyboard.print (sampleNumber); //Print index
Keyboard.print (","); //Print a comma
Keyboard.println(waterLevel); //Print the water level and newline
sampleNumber++; //increment the sample number
An image of my setup is shown in Figure 2-3 and a video demonstration of the experiment can be found
here (https://youtu.be/EWbKgUtMq1M).
#include <Keyboard.h>
const int LDR = A0; //LDR input
const int THRESHOLD = 400; //Light threshold
void setup() {
Keyboard.begin();
}
void loop() {
int lightLevel = analogRead (LDR); //Read light level
if (lightLevel < 400) {
//lock computer
Keyboard.press (KEY_LEFT_GUI);
Keyboard.press ('l');
delay (100);
Keyboard.releaseAll();
}
}
Listing 2-2: The Sketch to Lock your Computer using Light Levels
Listing source: The author
You can see that the Sketch is simple. When the light reading is below the set threshold the key press is
initiated. The ‘press’ function of the ‘Keyboard’ object emulates a key that is pressed and held down.
The first keypress represents the ‘Windows’ key followed by the ‘l’. After a short delay, all key presses
are released and the computer locks.
Summary
In this chapter you learnt that is it easy to emulate a computer keyboard using the Arduino Leonardo.
You learnt that the library ‘Keyboard.h’ makes this task easy. You learnt about the generic water
sensor and used a Light Dependent Resistor.
Chapter 3: Mouse Emulation using the
Arduino Leonardo
It follows that if we can emulate a computer keyboard then we can emulate a computer mouse. Like the
keyboard emulation we can utilize a library (‘Mouse.h’) to make the job easy.
#include <Mouse.h>
void setup() {
Mouse.begin();
}
void loop() {
int x = joystick(HORIZONTAL); //get horizontal movement
int y = joystick(VERTICAL); //get vertical movement
Mouse.move(x, y, 0); //move the mouse
mouseButton (LEFT_BUTTON, MOUSE_LEFT); //Left button control
mouseButton (MIDDLE_BUTTON, MOUSE_MIDDLE); //middle button control
mouseButton (RIGHT_BUTTON, MOUSE_RIGHT); //middle button control
delay (5); //this delay controls responsiveness
}
The code in the main ‘loop’ function first scans for changes in the joystick horizontal and vertical
values.
int x = joystick(HORIZONTAL); //get horizontal movement
int y = joystick(VERTICAL); //get vertical movement
We created a function named ‘joystick’ that returns either a horizontal or vertical value. We will
review the code in this function later. The next task is to move the mouse by the specified values
returned by the ‘joystick’ function. The third argument represents a mouse ‘wheel’ value that we set
to 0 as we do not have a wheel.
Mouse.move(x, y, 0); //move the mouse
The code in the Sketch then looks for button presses and acts on these presses. Again, we have created
a function that we will review later.
The delay controls the speed or responsiveness of the mouse and you may have to tweak this value.
Within the function, we first read the analog input for the joystick control and map the value to a mouse
travel in pixels. An analog value of 0 will represent one extreme and this equates to down or left, so we
map a joystick value of 0 to -10 pixels of travel. Likewise, a joystick value of 1023 is the other extreme,
so we map that to a value of +10. The value we map the joystick reading can also be tuned to optimize
the mouse’s responsiveness.
int val = analogRead(axis); //read the value
val = map (val, 0, 1023, -10, 10); //map pot readings to mouse travel
We then place a ‘dead zone’ into the mouse travel to prevent it juddering if the joystick is not being
moved. Being an analog, device the joystick will be prone to registering slightly different readings on
each pass, so having this dead zone will eliminate any mouse jitter. If the mapped value is less than or
equal to 2, or greater than or equal to -2, we return a value of 0. Otherwise, we can return the mouse
movement to the main ‘loop’ function.
if (val <= 2 && val >= -2) {
return 0; //dead zone to stop mouse jitter
} else {
return val;
}
The ‘mouseButton’ does not return any value but acts on the button press. We must pass the I/O pin
number of the button that is pressed and a predefined ‘char’ that is defined in the ‘Mouse.h’ library.
The ‘char’ represents the left, center or right button.
void mouseButton (int ioPin, char mouseCommand) {
//process button
}
We then check to see if the button is depressed by reading the state and seeing if it is ‘LOW’. We are using
pull-up resistors so a depressed state will read ‘LOW’. We then check whether the button was pressed on
a previous scan and if not, we act on the button press as if the respective mouse button is clicked. The
‘press’ function does this. If the button state is ‘HIGH’, it indicates that the button is released.
‘Mouse.isPressed’ will still be ‘TRUE’ until we execute the ‘Mouse.release’ command. Remember
that ‘mouseCommand’ is the indicator for which button is pressed.
//button pressed
if (digitalRead (ioPin) == LOW) {
if (!Mouse.isPressed(mouseCommand)) {
Mouse.press(mouseCommand);
}
} else {
//button released
if (Mouse.isPressed(mouseCommand))
{
Mouse.release (mouseCommand);
}
}
This seems a little complicated and it does take some experience to follow. Give the experiment a go
and work through the code. I have a photograph of my setup in Figure 3-3 and there is a video
demonstration of the mouse here (https://youtu.be/e4VuRX1YgcA).
void loop() {
// put your main code here, to run repeatedly:
Summary
In this chapter you learnt how to turn an Arduino Leonardo into a computer mouse. You learnt that a
library exists called ‘Mouse.h’ that makes the programming of this task easy.
Chapter 4: Game Controllers and Joysticks
Having looked at keyboards and mice the next step is to look at using the Arduino Leonardo as a game
controller or joystick like those which are commercially available. In this chapter we will look at this
subject and create a simple joystick and game controller as well as giving you a pathway to making
much more sophisticated controllers.
We need to identify Keyboard modifiers for use with the Leonardo’s Keyboard emulation control. The
standard ASCII character set normally works with printable characters. A modifier is a key on the
keyboard that modifiers the normal action of the key. This way we can initiate special functions such as
the Windows lock function of Experiment 3. The arrow keys are not printable and so modifiers have
been defined such that we can send the arrow keys codes as keypresses. The Arduino Leonardo
modifiers for the arrow keys are listed in Table 4-1.
#include <Keyboard.h>
int x, y;
int sw;
void setup() {
pinMode(BUTTON, INPUT_PULLUP);
Serial.begin(9600);
Keyboard.begin();
}
void loop() {
int x = analogRead(HORIZONTAL); //get horizontal movement
if (x == 1023)// fully right
{
Serial.println("Right");
Keyboard.press(215); //right arrow
}
else
{
Keyboard.release(215); //release the key
}
y = analogRead(VERTICAL);
if (y == 1023) //fully down
{
Serial.println("Down");
Keyboard.press(217); //down arrow
}
else
{
Keyboard.release(217); //release the key
}
sw = digitalRead (BUTTON); //see if switch pressed
Figure 4-3: Copying the Library into the Arduino Libraries Folder
Image source: The author
Next you need to add the library to your Arduino IDE. Open your IDE and select Sketch > Include
Library > Add. .ZIP Library… as shown in Figure 4-4.
Figure 4-4: Adding the Library to the IDE
Image source: The author
Select the ZIP file you just copied into the Arduino Libraries folder and click ‘open’. That is all there is
to it. I tend the restart the IDE. You can check that the library is installed by seeing if the examples are
in place as in Figure 4-5.
Figure 4-5: Checking that the Library has installed
Image source: The author
Experiment 6: Joystick Test
You can see from Figure 4-5 that the library has several examples. In this experiment we will look at
the ‘JoystickTest’ example Sketch. We will only need an Arduino Lenardo and a jumper wire for this
experiment. I will not list the code here as it would be difficult to review. The Sketch relies heavily on
calls to the classes and functions in the library so will make little sense. It is a complex task to look deep
into the library to gain a better understanding of what lies under the hood and that task would be
beyond the scope of this book. It is sufficient to know that these sorts of libraries exist and that they can
be used to build sophisticated projects. It is testament to the skills and generosity that these creators
offer such resources to the community of users.
First load the ‘JoystickTest’ example and upload it to your Arduino Leonardo. Once the upload is
complete you can check to see if the device is registered under your PC. On a Windows PC, go to
Control Panel > Hardware and Sound > Devices and Printers. Figure 4-6 shows my screen
under Windows 11.
#include <Joystick.h>
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD,
1, 0, // Button Count, Hat Switch Count
true, true, false, // X and Y, but no Z Axis
false, false, false, // No Rx, Ry, or Rz
false, false, // No rudder or throttle
false, false, false); // No accelerator, brake, or steering
void setup() {
// Initialize Button Pins
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
void loop() {
delay(10);
}
Summary
In this chapter you learnt how to use the Arduino Leonardo to emulate games controllers such as game
pads and joysticks. You learnt that you could use keyboard emulation to do this or call on a library that
gives you the tools to make sophisticated controllers. You learnt how to test these controllers in a
Microsoft Windows environment.
Epilogue
We have come to the end of this part of the journey and in fact if you have followed these books
sequentially, then you are at the end of what I can offer on this subject. We have covered all key aspects
to the Arduino ecosystem and you will have the skills in place to create the most imaginative and
complex projects.
For me it has been the most rewarding adventure and I too have learnt along the way and made many
new friends who have communicated and interacted on social media. I wish you all best wishes and
good luck on whatever part of your journey you are on, and I hope to have had a positive impact on your
learning.
If you like this book and the series of books, please leave a review on the Amazon website. For the latest
news on other books in the series you can follow my Facebook page, Twitter or follow me as an author
on Amazon.
About the Author
Gary Hallberg has over 34 years of experience in the telecommunications and data communications
industries. He started his career working with circuit switched voice and data technologies in PDH and
SDH environments and then moved on to work with early packet switched networks using Frame Relay
and ATM. His career shifted focus to IP routing when the Internet started to grow, designing large scale
service provider networks using leading edge equipment from vendors such as Juniper and Cisco. Gary
attained Cisco Certified Professional status during this time. Presently, he is working for a global
equipment vendor with a focus on Ethernet networks and is at the forefront of network evolution,
providing infrastructures for SD-WAN, Network Functions Virtualization, SDN and 5G backhaul. Gary
has a Bachelor of Engineering degree in electronic engineering and a Master of Philosophy degree in
robotics and manufacturing.