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

Datatypes in C

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

Datatypes in C

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

Getting Started with Arduino

An introduction to hardware, software tools, and the Arduino API.

AuthorKarl Söderby
Last revision08/02/2024
The Arduino platform has since its start in 2005, grown to become one of the most
recognizable brands in the space of electronics and embedded design.

But what are the cornerstones of Arduino? What is a "board", how do I write code to it, and
what are the tools needed to create my own project? The goal with this guide is to provide
you with an overview to the Arduino project.

In this guide, you will gain an overview of the Arduino Ecosystem, and a set of links leading
to more detailed articles.

Overview
This guide is divided into four main sections: hardware, software tools, Arduino API, and
Quick Reference. You can navigate to each of these sections directly through the links below:

Arduino Hardware
In this section, we will dedicate some time to learn about some fundamentals in electronics,
and about the basic operation of an Arduino board.

Anatomy of an Arduino Board


Basic Operation
Circuit Basics
Electronic Signals
Analog Signal
Digital Signal
Sensors & Actuators
Serial Communication Protocols
Memory
Embedded Sensors
Internet of Things (IoT)
Arduino API
In this section you will learn what the Arduino API is, and how to create code that can run on
your Arduino board.

Main Parts
Program Structure
The "Sketch"
Example Sketch
Libraries
Core Specific API
Arduino Software Tools
In this section you will learn how to set up your development environment as well as learning
about what options there are.

A Typical Workflow
Arduino IDE 1.8.x
Arduino IDE 2
Arduino Cloud
Web Editor
Library Manager
Arduino CLI
Quick Reference
The quick reference is an extract from the full Arduino API, containing popular functions,
structures and methods.

General
Serial Communication
GPIO / Pin Management
Structure
Arduino Hardware
Over the years, Arduino has released hundreds of hardware designs in many shapes and
forms.

Anatomy of an Arduino Board


While all Arduino boards differ from each other, there are several key components that can
be found on practically any Arduino. Let's take a look at the image below:

Key components of an Arduino board.


Key components of an Arduino board.

1. Microcontroller - this is the brain of an Arduino, and is the component that we load
programs into. Think of it as a tiny computer, designed to execute only a specific number of
things.
2. USB port - used to connect your Arduino board to a computer.
3. USB to Serial chip - the USB to Serial is an important component, as it helps translating
data that comes from e.g. a computer to the on-board microcontroller. This is what makes it
possible to program the Arduino board from your computer.
4. Digital pins - pins that use digital logic (0,1 or LOW/HIGH). Commonly used for switches
and to turn on/off an LED.
5. Analog pins - pins that can read analog values in a 10 bit resolution (0-1023).
6. 5V / 3.3V pins- these pins are used to power external components.
7. GND - also known as ground, negative or simply -, is used to complete a circuit, where the
electrical level is at 0 volt.
8. VIN - stands for Voltage In, where you can connect external power supplies.
Depending on the Arduino board, you will find many more components. The items listed
above are generally found on any Arduino board.

Basic Operation
Most Arduino boards are designed to have a single program running on the microcontroller.
This program can be designed to perform one single action, such as blinking an LED. It can
also be designed to execute hundreds of actions in a cycle. The scope varies from one
program to another.

The program that is loaded to the microcontroller will start execution as soon as it is
powered. Every program has a function called "loop". Inside the loop function, you can for
example:

Read a sensor.
Turn on a light.
Check whether a condition is met.
All of the above.
The speed of a program is incredibly fast, unless we tell it to slow down. It depends on the
size of the program and how long it takes for the microcontroller to execute it, but it is
generally in microseconds (one millionth of a second).

The basic operation of an Arduino.


The basic operation of an Arduino.

Circuit Basics
Circuits consist of at least one active electronic component, and a conductive material, such
as wires, so that current can pass through. When working with an Arduino, you will in most
cases build a circuit for your project.

A simple example of a circuit, is an LED circuit. A wire is connected from a pin on the
Arduino, to an LED via a resistor (to protect the LED from high current), and finally to the
ground pin (GND). When the pin is set to a HIGH state, the microcontroller on the Arduino
board will allow an electric current to flow through the circuit, which turns on the LED.
When the pin is set to a LOW state, the LED will turn off, as an electric current is not flowing
through the circuit.

An LED circuit with an Arduino.


An LED circuit with an Arduino.

Circuits are typically represented as schematics, which are the blueprints for your circuit. The
image below shows the schematic's representation of the same circuit shown in the image
above.

Schematics of a circuit.
Schematics of a circuit.

Electronic Signals
All communication between electronic components are facilitated by electronic signals.
There are two main types of electronic signals: analog & digital.

Analog Signal
Basics of an analog signal.
Basics of an analog signal.

An analog signal is generally bound to a range. In an Arduino, that range is typically 0-5V, or
0-3.3V.

If we for example use a potentiometer (an analog component used to change the resistance of
a circuit), we can manually adjust this range (0-5V). In the program, this is represented in a
range of 0-1023, which is a 10-bit resolution.

If we write an analog signal using Pulse-Width Modulation (PWM), we can use a range
between 0-255, as we are using an 8-bit resolution.

Read more about Analog Inputs and Analog Outputs (PWM).

Digital Signal
Basics of a digital signal.
Basics of a digital signal.

A digital signal works a bit different, representing only two binary states (0 or 1) that are read
as high or low states in the program. This is the most common signal type in modern
technology.

You can easily read and write digital signals on an Arduino, which is useful to for example
read button states, or to turn something on or off.
Digital signals might seem very basic (just 0 or 1), but are actually way more advanced. For
example, we can create a sequence by sending a high or low state rapidly a number of times.
This is known as a binary sequence or a bitstream.

Let's take a look at two binary sequences:

COPY
101101
101110001110011
Which in decimal format is:

COPY
45
23667
This is a clever way of sending large amounts of data from one point to the other, by rapidly
sending high & low signals. In order to interpret the data from the signals, we use Serial
Communication Protocols.

Sensors & Actuators


When working with Arduino, it is important to understand sensors and actuators, and the
difference between them.

What Is a Sensor?
A sensor, in simple terms, is used to sense its environment, meaning it records a physical
parameter, for example temperature, and converts it into an electronic signal.

Sensors can also take the form of just a simple button: when a state changes (we pressed a
button), the electronic signal is switched from low to high (0 to 1).

There are many types of sensors, and several ways of recording data from them. Perhaps the
easiest to use is an analog sensor, where we communicate a range of values through altering
the voltage input fed into an Arduino analog pin (usually between 0-5 volts). This simply
gives you a range between 0-1023 (a 10-bit resolution).

Digital sensors are a bit more advanced, depending on the type. They rely on Serial
Communication Protocols to send the data accordingly, and requires a bit more effort to
translate the data. As mentioned in the Electronic Signals section above, data is sent using a
binary sequence (e.g. 101101 is 45), and this needs to be addressed and configured on a
software level. Luckily, a lot of sensors are accompanied by software libraries, which makes
it a lot easier to read.

In many cases using a library, all we need is just one line of code:

COPY
sensorValue = sensor.read();

What Is an Actuator?
An actuator, in simple terms, is used to actuate or change a physical state. Some examples
are:

A light (such as an LED).


A motor.
A switch.
Actuators converts electric signals into e.g. radiant energy (light) or mechanical energy
(movement).
How actuators are controlled really depends on what type of component we have. The most
simple way is to simply turn something on/off, while more advanced is controlling the
amount of voltage a component receives (i.e. the speed of a motor).

To control actuators, it is common to use digitalWrite() and analogWrite().

COPY

Explain

Explain
digitalWrite(LED, HIGH); //turn on an LED
digitalWrite(LED, LOW); //turn off an LED

analogWrite(motor, 255); //set a motor to maximum capacity


analogWrite(motor, 25); //set a motor to 10% of its capacity
Input & Output
Sensors and actuators, are typically referred to as inputs and outputs. When we write a
program, it is common to construct conditionals that checks the state of a sensor, and decides
whether it should actuate something.

A basic example of this is a button and an LED. We can write a conditional that checks if a
button is pressed, turn on the LED, and turn it off if the button is not pressed. In an Arduino
program, it looks like this:

COPY

Explain

Explain
int buttonState = digitalRead(buttonPin); //read and store the button state (0 or 1)

if(buttonState == HIGH){ //check if state is high (button is pressed)


digitalWrite(LED, HIGH); //turn on LED
} else {
digitalWrite(LED, LOW); //turn off LED
}
Serial Communication Protocols
There are several serial communication protocols that uses the aforementioned digital signals
to send data. The most common are UART, SPI & I²C. The UART protocol is among other
things, used to send data between a computer and Arduino board, such as uploading a new
program, or reading data directly from an Arduino.

The SPI and I²C protocols are used for communication between both internal and external
components. The communication is handled by something called a serial bus, which is
attached to a specific pin on the Arduino.

Using the I²C protocol, we can connect several sensors on the same pin, and retrieve the data
accurately. Each device has an address that we need to specify in the program, which we use
when making data requests.

Find out more in the Arduino SPI Guide and Arduino I2C Guide.

Memory
The "standard" Arduino typically has two memories: SRAM and Flash memory.

The SRAM (Static Random-Access Memory) is used to for example store the value of a
variable (such as the state of a boolean). When powered off, this memory resets.

The Flash memory is primarily used to store the main program, or the instructions for the
microcontroller. This memory is not erased when powered off so that the instructions for the
microcontroller are executed as soon as the board is powered.

How much memory is available on an Arduino varies from board to board. For example the
Arduino UNO has a 32kB flash / 2kB SRAM, while a Nano 33 IoT has 256kB flash / 32kB
SRAM. You will find this information in each of the product's documentation pages, which
are available in the Arduino Hardware Documentation.

To learn more about memory on an Arduino, visit the Arduino Memory Guide.

Embedded Sensors
An IMU (Inertial Measurement Unit) on the Nano RP2040 Connect board.
An IMU (Inertial Measurement Unit) on the Nano RP2040 Connect board.

Many new Arduino boards come equipped with embedded sensors. For example, the Nano 33
BLE Sense has 7 embedded sensors, but is only 45x18mm (the size of a thumb). These are all
connected via the I²C protocol as mentioned above, and has a unique address.

Internet of Things (IoT)


Most modern Arduino boards now come equipped with a radio module, designed to
communicate wirelessly. There are several different ones: Wi-Fi, Bluetooth®, LoRa®, GSM,
NB-IoT and more. Each are designed to communicate using the various technologies
available on the market.

The u-blox NINA-W102 Wi-Fi / Bluetooth® module on the Nano RP2040 Connect board.
The u-blox NINA-W102 Wi-Fi / Bluetooth® module on the Nano RP2040 Connect board.

The most popular and inexpensive modules are the Wi-Fi & Bluetooth® modules. The Wi-Fi
modules allow your board to connect to routers, and to request and send data over the
Internet. In a way, it works the same as your computer when requesting various types of data
over the Internet, just in a smaller scale.

Bluetooth® is used to communicate with nearby devices, and is really useful for maintaining
a fast and reliable connection. For example, in real-life applications, Bluetooth® technology
for example used in wireless headphones & speakers.

Similarly to serial protocols, radio modules use their own set of protocols to communicate,
such as HTTP, MQTT and UPD.

Arduino API
Visit the Arduino Language Reference to explore the full Arduino API.

The Arduino API, aka the "Arduino Programming Language", consists of several functions,
variables and structures based on the C/C++ language.

Main Parts
The Arduino API can be divided into three main parts: functions, variables and structure:
Functions: for controlling the Arduino board and performing computations. For example, to
read or write a state to a digital pin, map a value or use serial communication.
Variables: the Arduino constants, data types and conversions. E.g. int, boolean, array.
Structure: the elements of the Arduino (C++) code, such as
sketch (loop(), setup())
control structure (if, else, while, for)
arithmetic operators (multiplication, addition, subtraction)
comparison operators, such as == (equal to), != (not equal to), > (greater than).
The Arduino API can be described as a simplification of the C++ programming language,
with a lot of additions for controlling the Arduino hardware.

Program Structure
The absolute minimum requirement of an Arduino program is the use of two functions: void
setup() and void loop(). The "void" indicates that nothing is returned on execution.

void setup() - this function executes only once, when the Arduino is powered on. Here we
define things such as the mode of a pin (input or output), the baud rate of serial
communication or the initialization of a library.
void loop() - this is where we write the code that we want to execute over and over again,
such as turning on/off a lamp based on an input, or to conduct a sensor reading every X
second.
The above functions are always required in an Arduino sketch, but you are of course able to
add several more functions, which is useful for longer programs.

The "Sketch"
In the Arduino project, a program is referred to as a "sketch". A sketch is a file that you write
your program inside. It has the .ino extension, and is always stored in a folder of the same
name.

The folder can include other files, such as a header file, that can be included in your sketch.

Example Sketch
Below is an example of a standard Arduino sketch, which contains some popular Arduino
programming elements.

COPY

Explain

Explain
/*
This is a comment at the top of a program,
it will not be recognized as code. Very good
to add an explanation of what your code does
here.

This sketch shows how to read a value from a


sensor connected to pin A1, print it out in
the Serial Monitor, and turn on an LED connected
to pin number 2 if a conditional is met.
*/

int sensorPin = A1; //define pin A1 (analog pin)


int ledPin = 2; //define pin 2 (digital pin)
int sensorValue; //create variable for storing readings
//void setup is for configurations on start up
void setup() {
Serial.begin(9600); //initialize serial communication
pinMode(ledPin, OUTPUT); //define ledPin as an output
}

void loop() {
sensorValue = analogRead(sensorPin); // do a sensor reading

Serial.print("Sensor value is: "); //print a message to the serial monitor


Serial.println(sensorValue); //print the value to the serial monitor

//check if sensorValue is below 200


if(sensorValue < 200) {
digitalWrite(ledPin, HIGH); //if it is, turn on the LED on pin 2.
}
//if sensorValue is above 200, turn off the LED
else{
digitalWrite(ledPin, LOW);
}
}
Libraries
Arduino libraries are an extension of the standard Arduino API, and consists of thousands of
libraries, both official and contributed by the community.

Libraries simplifies the use of otherwise complex code, such as reading a specific sensor,
controlling a motor or connecting to the Internet. Instead of having to write all of this code
yourself, you can just install a library, include it at the top of your code, and use any of the
available functionalities of it. All Arduino libraries are open source and free to use by
anyone.

To use a library, you need to include it at the top of your code, as the example below:

COPY
#include <Library.h>
Most libraries also have a set of examples that are useful to get started with the library.

You can browse through all official and contributed libraries in the Arduino Libraries page.

Core Specific API


Every Arduino board requires a "core", or "package", that needs to be installed in order to
program it. All packages contain the standard Arduino API, but also a specific API that can
only be used with specific boards.

For example, the classic ArduinoCore-avr package, automatically includes the EEPROM, and
SoftwareSerial libraries, and can be used freely without any additional installation. In this
package you will find the classic Arduino UNO, Nano, Mega2560 and more.

Another example is the ArduinoCore-mbed package, which includes over 40 libraries,


designed for specific board features, such as:

PDM - used for sampling audio from microphones found onboard the Nano 33 BLE Sense
and Nano RP2040 Connect.
Ethernet - for using the Ethernet functionalities of the Portenta Vision Shield.
GSM - to access GSM functionalities on the Portenta Cat. M1/NB IoT GNSS Shield.
These features are documented in the documentation landing page of each product. A list of
all hardware can be found at docs.arduino.cc.

Arduino Software Tools


The Arduino IDEs are available for download for free in the Software downloads page.

Another integral part of the Arduino ecosystem are its software tools.

The Arduino IDE, as it is commonly referred to, is an integrated development environment.


But what does that mean exactly?

In order to program your board, you need to write a program, compile that program into
machine code, and finally: send over the new program to your board.

The Arduino IDE facilitates all this, from the first line of code written, to have it executed on
the Arduino board's microcontroller. It is a program, or application, that you can download
(or use an online version), to manage all of your code development. Back in the day, this was
a complicated process, that required a good set of knowledge in electronics & computer
science. Now, anyone can learn how to do it, with the help of the Arduino IDE.

Today, there are three Arduino IDEs available:

Arduino IDE 1.8.x (classic)


Arduino IDE 2 (new)
Arduino Web Editor (online)
A Typical Workflow
To upload code to an Arduino board using the IDE, one typically does the following:

1. Install your board - this means installing the right "package" for your board. Without the
package, you can simply not use your board. Installing is done directly in the IDE, and is a
quick and easy operation.

2. Create a new sketch - a sketch is your main program file. Here we write a set of
instructions we want to execute on the microcontroller.

3. Compile your sketch - the code we write is not exactly how it looks like when uploaded to
our Arduino: compiling code means that we check it for errors, and convert it into a binary
file (1s and 0s). If something fails, you will get this in the error console.

4. Upload your sketch - once the compilation is successful, the code can be uploaded to your
board. In this step, we connect the board to the computer physically, and select the right serial
port.

5. Serial Monitor (optional) - for most Arduino projects, it is important to know what's going
on on your board. The Serial Monitor tool available in all IDEs allow for data to be sent from
your board to your computer.

Arduino IDE 1.8.x


The classic Arduino IDE.
The classic Arduino IDE.

For what is now considered the "legacy" editor, the Arduino IDE 1.8.X, or "Java IDE", is the
editor that was first released back when Arduino started.
Learn more by visiting the Arduino IDE 1 documentation.

Arduino IDE 2
The new Arduino IDE.
The new Arduino IDE.

In 2021, the Arduino IDE 2 was released. The new IDE has the same functionality, but also
supports features such as auto-completion and debugging.

Learn more by visiting the Arduino IDE 2 documentation.

Web Editor
The Web Editor.
The Web Editor.

The Arduino Web Editor is an online IDE, part of the Arduino Cloud suite. Similar in
function, this editor is completely web based, with online storage among other features. To
use the Web Editor, you will need to register an Arduino account.

Learn more by visiting the Web Editor documentation.

Arduino Cloud
The Arduino Cloud.
The Arduino Cloud.

The Arduino Cloud allows you to configure, program and control/monitor your devices - all
in one web based application. With the use of things, or your "digital twin", you can control
and monitor variables directly from dashboards. The service also supports webhooks and
integrations with other services, such as Amazon Alexa.

The Cloud is made for anyone to use, and it does not require much previous experience to get
started.

Get started by reading the Getting Started with the Arduino Cloud guide, or visit the full
documentation.

Library Manager
Library manager on IDE 1.8.x and IDE 2
Library manager on IDE 1.8.x and IDE 2

Every version of the IDE has a library manager for installing Arduino software libraries.
Thousands of libraries, both official and contributed libraries, are available for direct
download. Code examples for each library is made available on download.

To explore all available Arduino libraries, visit the Arduino Libraries page.

Arduino CLI
The Arduino CLI (Command Line Interface).
The Arduino CLI (Command Line Interface).

The Arduino CLI is a command line tool that can be used to compile and upload code to your
board. It has no visual UI, but is very useful for automation. It is designed for more advanced
users.
A proper use of the CLI can speed up your development time by far, as any operation is
executed much faster than in the regular IDE.

To learn more, visit the Arduino CLI documentation.

Quick Reference
In this section, you will find a list of some of the most common elements in the standard
Arduino API. This will help you get familiar with some key building blocks.

To explore the whole Arduino API, please refer to the Arduino Language Reference, an in-
depth wiki maintained by Arduino and its community. You will find hundreds of entries,
accompanied by code examples and elaborate descriptions.

General
setup()
The setup() function is where you make program configurations.

COPY
void setup() {
//program configurations here
}
loop()
The loop() function is where your main program is stored. It will run as long as your board is
powered.

COPY
void loop() {
//main program here
}
delay()
The delay() function pauses the program for a set number of milliseconds.

The classic blink sequence is found in the snippet below:

COPY

Explain

Explain
void loop() {

digitalWrite(LED, HIGH); //turn on an LED


delay(1000); //as program is paused, with the LED on
digitalWrite(LED, LOW); //program is unpaused, and the LED is turned off
delay(1000); //program is paused, with the LED off

}
The delay() function is an incredibly useful function, and you will find it in almost all
examples. But, for efficiency of the code, it is not the best option, as it prevents the Arduino
from doing anything for the duration of the delay.

For this, we can use the millis() function.

millis()
The millis() function is a bit more advanced, but an incredibly resourceful function. It allows
you to have multiple events happening simultaneously, without pausing the program. This is
done by measuring time (in milliseconds) passed since the program started.

Then, with the use of intervals and continuously storing the time for last event, a simple
algorithm can be made to have events happening at specific times without pausing the
program.

See the example below:

COPY

Explain

Explain
unsigned long previousMillis_1 = 0; //store time for first event
unsigned long previousMillis_2 = 0; //store time for second event

const long interval_1 = 1000; //interval for first event


const long interval_2 = 2000; //interval for second event

void setup(){

void loop() {

//check time since program started, and store in "currentMillis"


unsigned long currentMillis = millis();

//conditional that checks whether 1 second has passed since last event
if (currentMillis - previousMillis_1 >= interval_1) {
previousMillis_1 = millis();
//execute a piece of code, every *1 second*
}

//conditional that checks whether 2 seconds have passed since last event
if (currentMillis - previousMillis_2 >= interval_2) {
previousMillis_2 = millis();
//execute a piece of code, every *2 seconds*
}

}
While the millis() function is a more advanced concept than the delay() function, it is a good
to start practicing it early on.

Functions
Learn more about Arduino functions.

You can create custom functions that either just executes code and returns to the program, or
that returns a result.

Example of a void function that does not return:


COPY

Explain

Explain
int x;

void loop(){
thisFunction(); //execute the function
}

void thisFunction() {
x++; //increase x by 1 each time function is run.
}
Example of a type int function that returns a value.

COPY

Explain

Explain
int value;

void setup(){

void loop(){
value = returnFunction();
}

int returnFunction() {
int returnValue = 5 + 2;
return returnValue;
}
Variable Definition
Variables can either be created locally or globally. Variables that are defined in the loop() are
considered local, and variables defined at the top of your sketch are considered global.

COPY

Explain

Explain
int sensorReading = x; //global variable

void setup(){

void loop(){
int sensorReading = x; //local variable
}
Data Types
See all data types in the Language Reference.
There are several data types available for use, and below are some of the most common:

COPY

Explain

Explain
bool
byte
char
double
float
int
long
short
String
To store data in for example an int (integer):

COPY
int exampleNumber = 25;
For numbers with a lot of decimals, we can use float:

COPY
float exampleNumber = 22.2123002;
Or to store a string, we can use the String function:

COPY
String exampleSentence = "This is a string!";
For simple switches and true/false, we use booleans:

COPY
bool exampleSwitch = true; // true/false
Serial Communication
Read more about the Serial class.

Serial communication is essential to Arduino programming, as it is the easiest way to know


what goes on on your board.

For this, we can use the Serial class.

Serial.begin()
Initializes serial communication between board & computer. This is defined in the void
setup() function, where you also specify baud rate (speed of communication).

COPY
void setup() {
Serial.begin(9600);
}
Serial.print()
Prints data to the serial port, which can be viewed in the Arduino IDE Serial Monitor tool.

COPY
void loop() {
Serial.print();
}
Serial.read()
Reads the incoming serial data.

COPY
void loop() {
int incomingByte = Serial.read();
}
GPIO / Pin Management
Configuring, controlling and reading the state of a digital/analog pin on an Arduino.

pinMode()
Configures a digital pin to behave as an input or output. Is configured inside the void setup()
function.

COPY
pinMode(pin, INPUT); //configures pin as an input
pinMode(pin, OUTPUT); //configures pin as an output
pinMode(pin, INPUT_PULLUP); //enables the internal pull-up resistor
You can read more about digital pins in the article about Digital Pins.

digitalRead()
Reads the state of a digital pin. Used to for example detect a button click.

COPY
int state = digitalRead(pin); //store the state in the "state" variable
digitalWrite()
Writes a high or low state to a digital pin. Used to switch on or off a component.

COPY
digitalWrite(pin, HIGH); // writes a high (1) state to a pin (aka turn it on)
digitalWrite(pin, LOW); // writes a low (0) state to a pin (aka turn it off)
analogRead()
Reads the voltage of an analog pin, and returns a value between 0-1023 (10-bit resolution).
Used to read analog components.

COPY
sensorValue = analogRead(A1); //stores reading of A1 in "sensorValue" variable
analogWrite()
Writes a value between 0-255 (8-bit resolution). Used for dimming lights or setting the speed
of a motor. Also referred to as PWM, or Pulse Width Modulation.

COPY
analogWrite(pin, value); //write a range between 0-255 to a specific pin
PWM is only available on specific pins (marked with a "~" symbol).

Structure
The structure of the Arduino API is based on C++, and can be considered the building blocks
of a program.

Conditionals
Conditionals are some of the most popular used elements in any program. In Arduino, a
typical conditional consists of an if and else statement.

COPY
Explain

Explain
if(variable == true){
//do something
}
else {
//do something else
}
You can make use of several if/else statements in your code.

Loops / Iterations
The for and while loops are commonly used in programs, to execute a block of code for a set
number of times, or while a condition is met.

A basic use of a while loop to execute a block of code while variable is true.

COPY
while (variable == true) {
//do something
}
A basic use of a for loop is to execute a block of code a custom number of times (in this case,
10).

COPY
for (int x = 0; x < 10; x++) {
//do something 10 times
}
To break out of a loop, you can use break. In the snippet below, if a condition is met (variable
is true), we break out of the loop.

COPY

Explain

Explain
for (int x = 0; x <= 10; x++) {
if(variable == true) {
break;
}
}
Arithmetic Operators
Arithmetic operators are used for addition, subtraction, multiplication, division and other
mathematical calculations.

COPY

Explain

Explain
int x = 5;
int y = 2;

x + y; //result is 7
x * y; //result is 10
x - y; //result is 3
Comparison Operators
Comparison operators are used for comparing one property to another, and are a key
component of a conditional statement.

There are several comparison operators:

COPY

Explain

Explain
!= //not equal to
< //less than
<= //less than or equal to
== //equal to
> //greater than
>= //greater than or equal to
To use them in a conditional, see the following example:

COPY
if(value > 10) {
//do something
}
Boolean Operators
Boolean operators (logical NOT !, AND && and OR ||) can for example be used for more
advanced conditionals.

To use the AND && operator:

COPY
if(value > 10 && otherValue > 10){
//do something if only if *both* conditions are met
}
To use the OR || operator:

COPY
if(value > 10 || otherValue > 10){
//do something if a one *or* the other condition is met
}
To use the NOT ! operator:

COPY
if(!value){
//do something if value is false (!)
}
Compound Operators
Compound operators consists of two operators, which are used to perform two operations in
the same statement. This can for example be to add + and assign = a value at the same time.

Here are some examples:

COPY
Explain

Explain
x = 5;
y = 2;

x++; //increase by one, so x is now 6


x--; //decrease by one, so x is now 4

x += y; //x is now 7 (add and assign)


x -= y; //x is now 3 (subtract and assign)
x *= y; //x is now 10 (multiply and assign)

Language Reference
Arduino programming language can be divided in three main parts: functions, values
(variables and constants), and structure.

Functions
For controlling the Arduino board and performing computations.

Digital I/O
digitalRead()
digitalWrite()
pinMode()
Analog I/O
analogRead()
analogReadResolution()
analogReference()
analogWrite()
analogWriteResolution()
Advanced I/O
noTone()
pulseIn()
pulseInLong()
shiftIn()
shiftOut()
tone()
Time
delay()
delayMicroseconds()
micros()
millis()
Math
abs()
constrain()
map()
max()
min()
pow()
sq()
sqrt()
Trigonometry
cos()
sin()
tan()
Characters
isAlpha()
isAlphaNumeric()
isAscii()
isControl()
isDigit()
isGraph()
isHexadecimalDigit()
isLowerCase()
isPrintable()
isPunct()
isSpace()
isUpperCase()
isWhitespace()
Random Numbers
random()
randomSeed()
Bits and Bytes
bit()
bitClear()
bitRead()
bitSet()
bitWrite()
highByte()
lowByte()
External Interrupts
attachInterrupt()
detachInterrupt()
digitalPinToInterrupt()
Interrupts
interrupts()
noInterrupts()
Communication
Print
Serial
SPI
Stream
Wire
USB
Keyboard
Mouse
Variables
Arduino data types and constants.

Constants
Floating Point Constants
HIGH | LOW
INPUT | INPUT_PULLUP | OUTPUT
Integer Constants
LED_BUILTIN
true | false
Conversion
(unsigned int)
(unsigned long)
byte()
char()
float()
int()
long()
word()
Data Types
array
bool
boolean
byte
char
double
float
int
long
short
size_t
string
String()
unsigned char
unsigned int
unsigned long
void
word
Variable Scope & Qualifiers
const
scope
static
volatile
Utilities
PROGMEM
sizeof()
Structure
The elements of Arduino (C++) code.

Sketch
loop()
setup()
Control Structure
break
continue
do...while
else
for
goto
if
return
switch...case
while
Further Syntax
#define (define)
#include (include)
/* */ (block comment)
// (single line comment)
; (semicolon)
{} (curly braces)
Arithmetic Operators
% (remainder)
* (multiplication)
+ (addition)
- (subtraction)
/ (division)
= (assignment operator)
Comparison Operators
!= (not equal to)
< (less than)
<= (less than or equal to)
== (equal to)
> (greater than)
>= (greater than or equal to)
Boolean Operators
! (logical not)
&& (logical and)
|| (logical or)
Pointer Access Operators
& (reference operator)
* (dereference operator)
Bitwise Operators
& (bitwise and)
<< (bitshift left)
>> (bitshift right)
^ (bitwise xor)
| (bitwise or)
~ (bitwise not)
Compound Operators
%= (compound remainder)
&= (compound bitwise and)
*= (compound multiplication)
++ (increment)
+= (compound addition)
-- (decrement)
-= (compound subtraction)
/= (compound division)
^= (compound bitwise xor)
|= (compound bitwise or)

Using the Arduino Web Editor


The Arduino Web Editor allows you to write code and upload sketches to any official
Arduino board from your web browser.

AuthorLiam Aljundi
Last revision08/02/2024
The Arduino Web Editor allows you to write code and upload sketches to any official
Arduino board directly from your web browser (Chrome, Firefox, Safari and Edge).
However, we recommend you use Google Chrome.

This IDE (Integrated Development Environment) is part of Arduino Create, an online


platform that enables developers to write code, access tutorials, configure boards, and share
projects. Designed to provide users with a continuous workflow, Arduino Create connects the
dots between each part of a developer's journey from inspiration to implementation. Meaning,
you now have the ability to manage every aspect of your project right from a single
dashboard.

The Arduino Web Editor is hosted online, therefore it is always be up-to-date with the latest
features and support for new boards.This IDE lets you write code and save it to the Cloud,
always backing it up and making it accessible from any device. It automatically recognizes
any Arduino and Genuino board connected to your PC, and configures itself accordingly.

All you need to get started is an Arduino account. The following steps can guide you to start
using the Arduino Web Editor:

1. Install the Arduino Create Agent plugin.

2. Create a new Arduino Account at this link. Complete the registration form, then hit the
"create account" button. Then you will receive an email with a link to activate your account.
Select the link and a new page will open with your confirmed account information.

3. Log in the Arduino Web Editor.

Using the online IDE


After logging in, you are ready to start using the Arduino Web Editor. The web app is divided
into three main columns.

The Arduino Web Editor


The Arduino Web Editor

The Arduino Web Editor’s interface is as follows:

1. The first column lets you navigate between:

Your Sketchbook: a collection of all your sketches (a sketch is a program you upload on your
board).
Examples: read-only sketches that demonstrate all the basic Arduino commands (built-in tab),
and the behavior of your libraries (from the libraries tab).
Libraries: packages that can be included to your sketch to provide extra functionalities.
Serial monitor: a feature that enables you to monitor, receive and send data to and from your
board via the USB cable.
Help: helpful links and a glossary about Arduino terms.
Preferences: options to customize the look and behavior of your editor, such as text size and
color theme.
2. The second column views the content of the chosen option.

3. The third column, the code area, is the one you will use the most. Here, you can write
code, verify it and upload it to your boards, save your sketches on the Cloud, and share them
with anyone you want.

Now that you are all set up, let’s try to make your board blink!

1. Connect your Arduino or Genuino board to your computer. Boards and serial ports are
auto-discovered and selectable in a single dropdown. Pick the Arduino/Genuino board you
want to upload to from the list at the top of the third column.

2. Let’s try an example: Choose Examples on the menu on the left (first column), then Basic
and Blink. The Blink sketch is now displayed in the code area.
Finding an example
Finding an example

3. To upload it to your board, press the "Upload" button near the dropdown menu. While the
code is verifying and uploading, a "BUSY" label replaces the upload button. If the upload is
successful, the message "Success: done uploading" will appear in the bottom output area.

4. Once the upload is complete, you should see on your board the yellow LED with an L next
to it start blinking. You can adjust the speed of blinking by changing the delay number in the
parenthesis to 100, and upload the Blink sketch again. Now the LED should blink much
faster.

On-board LED blinking

Congratulations! You have successfully programmed your board to blink its on-board LED!
You can find more information about the Arduino Web Editor here.

Get to know Arduino Libraries


Libraries provide extra functionality for use in sketches, e.g. working with hardware or
manipulating data.

AuthorLiam Aljundi
Last revision08/02/2024
The Arduino environment can be extended through the use of libraries. Just like most
programming platforms, libraries provide extra functionality for use in sketches, e.g. working
with hardware or manipulating data. To use a library in a sketch, select it from Sketch >
Import Library.

Offline IDE
A number of libraries come installed with the IDE, but you can also download or create your
own. Here are some instructions for setting up a library on the offline IDE:

1. Open the IDE and click "Sketch" on the menu tab and then Include Library > Manage
Libraries.

Accessing the library manager


Accessing the library manager

2. Search for the library that you need, click on it, then select the version of the library you
want to install.

A list of libraries on the library manager


A list of libraries on the library manager

3. Finally, click on install and wait for the IDE to install the new library.

Once it has finished, an Installed tag should appear next to the Bridge library, so you can go
ahead and close the library manager.

Now the new library will be available in the Sketch > Include Library menu. If you want to
add your own library to Library Manager, follow these instructions.

Online IDE
The process of setting up libraries on the online IDE (Arduino Web Editor) is quite similar to
the offline one:
1. Login to the Arduino Web Editor.

2. Open the "Libraries" tab from the left menu, and search for libraries. The list displays read-
only libraries, authored and maintained by the Arduino team and its partners.

A list of libraries on the library manager


A list of libraries on the library manager

3. When you find the library, you can add it to your sketch by selecting the "Include" button.
You can also see the related examples, and select a specific version, if available.

Adding a library
Adding a library

4. If you can't find a specific library on the list, you can search every existing library through
the library manager. From there you also have the option to add them to your favorites list by
clicking on the star next to the library you want. Once you star a library, you can view it
under the "favorites" tab and use its examples (if available).

online library manager


An intro to the Arduino Cloud
With the Arduino Cloud desktop or mobile platform, you can quickly connect, manage and
monitor your devices from anywhere in the world.

AuthorLiam Aljundi
Last revision08/02/2024
Using the Arduino Cloud
With the Arduino Cloud desktop or mobile platform, you can quickly connect, manage and
monitor your devices from anywhere in the world.

Arduino Cloud allows you to automatically create any code to program your device with -
just add a couple of lines to customize it how you want. If you’re new to Arduino don’t worry
there’s example code for hundreds of sensors and actuators.

The following steps will guide you to start using the Arduino Cloud:

1. Install the Arduino Create Agent plugin.

2. Check if you have a cloud compatible board. The picture below shows all official Arduino
boards that are compatible.

Arduino Cloud compatible boards


Arduino Cloud compatible boards

Note: The MKR GSM 1400 and MKR NB 1500 require a SIM card to connect to the Cloud,
as they communicate over the mobile networks. The MKR WAN 1300 and 1310 board
requires a Arduino PRO Gateway LoRa to connect to the Cloud.

3. Create an Arduino account by signing up to Arduino.

4. Access the Arduino Cloud from any page on arduino.cc by clicking on the bento menu (9-
dots) on the top right corner, or you can go directly to the Arduino Cloud.

Opening the Arduino Cloud


Opening the Arduino Cloud

Creating a Thing
1. The user journey always begins by creating a new Thing. In the Thing overview, we can
choose what device to use, what Wi-Fi network we want to connect to, and create variables
that we can monitor and control.

Arduino Cloud’s interface


Arduino Cloud’s interface

2. Next we need to add a device by clicking on the "Select device" button on the Thing
overview. Here, we choose from any board that we have already been configured, or select
the Configure new device option.

Configuring a new device


Configuring a new device

3. Now we can add our first variable by clicking on the Add variable button. We can choose
name, data type, update the setting and interaction mode for our variable. There are several
data types we can choose from, such as int, float, boolean, long, char. There’s also special
variables, such as Temperature, Velocity, and Luminance that can be used. The variables we
create are automatically generated into a sketch file.

Adding a variable to your sketch


Adding a variable to your sketch

4. Finally, we need to connect to a Wi-Fi network by simply clicking the Configure button in
the network section. Enter your network credentials and click Save. This information will
also be generated into your sketch file!

Building the Sketch


Now that you are all set up, let’s have a look at the interface!

A special sketch file can now be found in the Sketch tab, which includes all of the
configurations that you have made. When the sketch has been uploaded, it will work as a
regular sketch, but it will also update the Cloud variables that we use!

Additionally, each time we create a variable that has the Interaction Mode enabled, a function
will also be generated. Every time this variable is triggered from the Cloud, it will execute the
code within this function! This means that we can leave most of the code out of the loop()
and only run code when needed.

When we are happy with our sketch, we can upload it to our board, by clicking the upload
button.

Editing a sketch in the Cloud editor


Editing a sketch in the Cloud editor

After we have successfully uploaded the code, we can open the Serial Monitor tab to view
information regarding our connection. If it is successful, it will print connected to
network_name and connected to cloud.

If it fails to connect, it will print the errors here as well. Now that we have configured the
device & network, created variables, completed the sketch and successfully uploaded the
code, we can move on to the fun part, the dashboard!
Creating the dashboard
IoT CLoud Dashboards
IoT CLoud Dashboards

Dashboards are visual user interfaces for interacting with your boards over the Cloud, and we
can set up many different setups depending on what your IoT project needs.

We can access our dashboards by clicking on the Dashboards tab at the top of the Arduino
Cloud interface, where we can create new dashboards, and see a list of dashboards created for
other Things.

Navigating to dashboards.
Navigating to dashboards.

If we click on Create new dashboard, we enter a dashboard editor. Here, we can create
something called widgets. Widgets are the visual representation of our variables we create,
and there are many different ones to choose from. Below is an example using several types of
widgets.

The different widgets available.


The different widgets available.

When we create widgets, we also need to link them to our variables. This is done by clicking
on a widget we create, selecting a Thing, and selecting a variable that we want to link.

Once it is linked, we can either interact with it, for example a button, or we can monitor a
value from a sensor. As long as our board is connected to the Cloud, the values will update
automatically!

Congratulations! Now you are ready to create your own IoT system. You can find more
information about the Arduino Cloud here.

Network Configuration
Note: that the Arduino Cloud operates with different domains and ports, which means that if
we want devices working with the Arduino Cloud, they need to be allowed access to certain
domains through your firewall.

If you are connected to your school or university networks, please provide your admin with
the following instructions:

1. Whitelist the following domains and ports in your firewall:

Domain Port
mqtts-up.iot.arduino.cc 8884
mqtts-sa.iot.arduino.cc 8883
wss.iot.arduino.cc 8443
2. Provide NTP access to time.arduino.cc, note that the NTP port for time.arduino.cc is 123
UDP.

If you are having issues connecting to the Arduino Cloud through your home network, follow
these instructions:

For Windows users


1. Navigate to your firewall, go to Start > search firewall > open Windows Firewall.

2. Click on Allow a program/app or feature through Windows Firewall.

3. Then open Change Settings

Troubleshooting Arduino Sketches


There are many pieces involved in getting a program onto your Arduino board.

AuthorLiam Aljundi
Last revision08/02/2024
There are many factors involved in uploading a program to your Arduino board, and if any of
them are missing, the upload could fail.

You can check the following suggestions to help you solve any potential problem:

1. Make sure that you chose the right board and port, and have installed all the drivers
needed.

2. If you are still running into an error, you can copy the error message and search it through
our troubleshooting guide page.

3. If you cannot find any help through our troubleshooting guide page, you can use our forum
support for help.

Below you will find further guidance on the steps mentioned.

Board & Port


The online Arduino Web Editor detects your board and port automatically, but if you are
using the offline Arduino Software IDE, you need to select both your board and port
manually using the following tips:

Make sure you have the right item selected in the Tools > Board menu. If you have an
Arduino UNO, you'll need to choose it.

Then, check that the proper port is selected in the Tools > Serial Port menu (if your port
doesn't appear, try restarting the IDE with the board connected to the computer):

On the Mac, the serial port should be something like /dev/tty.usbmodem621 (for the UNO or
Mega 2560) or /dev/tty.usbserial-A02f8e (for older, FTDI-based boards).
On Linux, it should be /dev/ttyACM0 or similar (for the UNO or Mega 2560) or
/dev/ttyUSB0 or similar (for older boards).
For Windows, it will be a COM port, but you'll need to check in the Device Manager (under
Ports) to see which one. If you don't seem to have a serial port for your Arduino board, see
the following information about drivers.
Drivers
Drivers provide a way for the software on your computer (i.e. the Arduino software) to talk to
any hardware you connect to it (i.e. the Arduino board).

The easiest way to check if the drivers for your board are installed correctly is by opening the
Tools > Serial Port menu in the Arduino software with the Arduino board connected to your
computer.
Additional menu items should appear relative to when you open the menu without the
Arduino connected to your computer. Note that it shouldn't matter what name the Arduino
board's serial port gets assigned as long as that's the one you pick from the menu.

On Windows 7 (particularly the 64-bit version), you might need to go into the Device
Manager and update the drivers for the UNO or Mega 2560. Just right click on the device (the
board should be connected to your computer), and point Windows at the appropriate .inf file
again. The .inf is in the drivers/ directory of the Arduino software (not in the FTDI USB
Drivers sub-directory of it).

If you get this error when installing the UNO or Mega 2560 drivers on Windows XP: "The
system cannot find the file specified", you might try this suggestion (about adding a
"RunOnce" key to "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\
CurrentVersion").

On Linux, the UNO and Mega 2560 show up as devices of the form /dev/ttyACM0. These are
not supported by the standard version of the RXTX library that the Arduino software uses for
serial communication. The Arduino software download for Linux includes a version of the
RXTX library patched to also search for these /dev/ttyACM* devices. There's also an Ubuntu
package (for 11.04) which includes support for these devices. If, however, you're using the
RXTX package from your distribution, you may need to symlink from /dev/ttyACM0 to
/dev/ttyUSB0 (for example) so that the serial port appears in the Arduino software.

Run:

COPY
sudo usermod -a -G tty yourUserName
sudo usermod -a -G dialout yourUserName
Log off and log on again for the changes to take effect.

Troubleshooting Guide
In the Arduino Help Center you will find articles on frequently asked questions, and
troubleshooting guides for most of the errors you might encounter. You can use our help
center by browsing through the different categories and the questions provided in each of
them, or by searching your error in the search tab.

Copying the error message


Copying the error message

Searching for the guide to solve the error


Searching for the guide to solve the error

Forum Support
If it still doesn't work, you can ask for help in the forum. Please include the following
information:

Your operating system.


What kind of board you have. If it's a Mini, LilyPad or other board that requires extra wiring,
include a photo of your circuit, if possible.
Whether you were ever able to upload to the board. If so, what were you doing with the board
before it stopped working, and what software have you recently added or removed from your
computer?
The messages displayed when you try to upload with verbose output enabled. To enable
verbose output check the box next to File > Preferences > Show verbose output during: >
upload.
Click on Copy error messages button on the right side of the box. When submitting in the
forum please use code tags button on the forum website toolbar) to post the output so that it
will be correctly formatted.

Installing additional cores


Learn how to install cores in the Arduino IDE.

Last revision08/02/2024
Starting from the Arduino Software (IDE) version 1.6.2, all Arduino AVR boards are
installed by default. Some Arduino boards require an additional core to be installed, therefore
we have implemented the Boards Manager as the preferred tool to add cores to your Arduino
Software (IDE).

Cores are necessary to make new microcontrollers compatible with your Arduino Software
(IDE) and, possibly, the existing sketches and libraries. We develop the cores for the new
microcontrollers used in our new generation boards, but anyone may develop a core for their
own boards following the rules and requirements we have issued.

How to install an Arduino core


Our board cores are already available in the Boards Manager and are updated on every new
Arduino Software (IDE) release.

Click on Tools menu and then Board > Boards Manager.

Boards manager will open and you will see a list of installed and available boards; the
download of the index file could take some time and the list appears at the end of this
process; please be patient.

Click on the Arduino SAM Boards core, choose the version in the drop-down menu and click
on Install.

Core SamD

The download time will depend on your connection speed.

After installation is complete an Installed tag appears next to the core name. You can close
the Board Manager.

Board MGR all

Now you can find the new board in the Tools > Board menu.

Core Samd Board

How to install a third party core


We have provided a solution for the easy installation of a core developed by a third party.
This requires a specific file, written in JSON format, that must be put in the dedicated field
Additional Board Manager URLs inside Arduino Software (IDE) Preferences.

Prefs Core

If you have more JSON files to add, click on the little icon on the right of the field and open a
specific window where you may input more URLs, one line at a time.

Core MoreJsons
After this procedure, the new cores will be available for install in the Boards Manager. Please
refer to the information provided by the third party core author to get more specific
instructions.

The text of the Arduino getting started guide is licensed under a Creative Commons
Attribution-ShareAlike 3.0 License. Code samples in the guide are released into the public
domain.

Digital Pins
Discover how digital pins work and how they can be configured.

Last revision08/02/2024
The pins on the Arduino can be configured as either inputs or outputs. This document
explains the functioning of the pins in those modes. While the title of this document refers to
digital pins, it is important to note that vast majority of Arduino (Atmega) analog pins, may
be configured, and used, in exactly the same manner as digital pins.

Properties of Pins Configured as INPUT


Arduino (Atmega) pins default to inputs, so they don't need to be explicitly declared as inputs
with pinMode() when you're using them as inputs. Pins configured this way are said to be in a
high-impedance state. Input pins make extremely small demands on the circuit that they are
sampling, equivalent to a series resistor of 100 megohm in front of the pin. This means that it
takes very little current to move the input pin from one state to another, and can make the
pins useful for such tasks as implementing a capacitive touch sensor, reading an LED as a
photodiode, or reading an analog sensor with a scheme such as RCTime.

This also means however, that pins configured as pinMode(pin, INPUT) with nothing
connected to them, or with wires connected to them that are not connected to other circuits,
will report seemingly random changes in pin state, picking up electrical noise from the
environment, or capacitively coupling the state of a nearby pin.

Pullup Resistors with pins configured as INPUT


Often it is useful to steer an input pin to a known state if no input is present. This can be done
by adding a pullup resistor (to +5V), or a pulldown resistor (resistor to ground) on the input.
A 10K resistor is a good value for a pullup or pulldown resistor.

Properties of Pins Configured as INPUT_PULLUP


There are 20K pullup resistors built into the Atmega chip that can be accessed from software.
These built-in pullup resistors are accessed by setting the pinMode() as INPUT_PULLUP.
This effectively inverts the behavior of the INPUT mode, where HIGH means the sensor is
off, and LOW means the sensor is on.

The value of this pullup depends on the microcontroller used. On most AVR-based boards,
the value is guaranteed to be between 20kΩ and 50kΩ. On the Arduino Due, it is between
50kΩ and 150kΩ. For the exact value, consult the datasheet of the microcontroller on your
board.

When connecting a sensor to a pin configured with INPUT_PULLUP, the other end should
be connected to ground. In the case of a simple switch, this causes the pin to read HIGH
when the switch is open, and LOW when the switch is pressed.

The pullup resistors provide enough current to dimly light an LED connected to a pin that has
been configured as an input. If LEDs in a project seem to be working, but very dimly, this is
likely what is going on.
The pullup resistors are controlled by the same registers (internal chip memory locations) that
control whether a pin is HIGH or LOW. Consequently, a pin that is configured to have pullup
resistors turned on when the pin is an INPUT, will have the pin configured as HIGH if the pin
is then switched to an OUTPUT with pinMode(). This works in the other direction as well,
and an output pin that is left in a HIGH state will have the pullup resistors set if switched to
an input with pinMode().

Prior to Arduino 1.0.1, it was possible to configure the internal pull-ups in the following
manner:

COPY
pinMode(pin, INPUT); // set pin to input
digitalWrite(pin, HIGH); // turn on pullup resistors
NOTE: Digital pin 13 is harder to use as a digital input than the other digital pins because it
has an LED and resistor attached to it that's soldered to the board on most boards. If you
enable its internal 20k pull-up resistor, it will hang at around 1.7V instead of the expected 5V
because the onboard LED and series resistor pull the voltage level down, meaning it always
returns LOW. If you must use pin 13 as a digital input, set its pinMode() to INPUT and use
an external pull down resistor.

Properties of Pins Configured as OUTPUT


Pins configured as OUTPUT with pinMode() are said to be in a low-impedance state. This
means that they can provide a substantial amount of current to other circuits. Atmega pins can
source (provide positive current) or sink (provide negative current) up to 40 mA (milliamps)
of current to other devices/circuits. This is enough current to brightly light up an LED (don't
forget the series resistor), or run many sensors, for example, but not enough current to run
most relays, solenoids, or motors.

Short circuits on Arduino pins, or attempting to run high current devices from them, can
damage or destroy the output transistors in the pin, or damage the entire Atmega chip. Often
this will result in a "dead" pin in the microcontroller but the remaining chip will still function
adequately. For this reason it is a good idea to connect OUTPUT pins to other devices with
470Ω or 1k resistors, unless maximum current draw from the pins is required for a particular
application.

See Also
pinMode
digitalWrite
digitalRead

Analog Input Pins


Find out how analog input pins work on an Arduino.

Last revision08/02/2024
A description of the analog input pins on an Arduino chip (ATmega8, ATmega168,
ATmega328P, or ATmega1280).

A/D converter
The ATmega controllers used for the Arduino contain an onboard 6 channel (8 channels on
the Mini and Nano, 16 on the Mega) analog-to-digital (A/D) converter. The converter has 10
bit resolution, returning integers from 0 to 1023. While the main function of the analog pins
for most Arduino users is to read analog sensors, the analog pins also have all the
functionality of general purpose input/output (GPIO) pins (the same as digital pins 0 - 13).
Consequently, if a user needs more general purpose input output pins, and all the analog pins
are not in use, the analog pins may be used for GPIO.

Pin mapping
The analog pins can be used identically to the digital pins, using the aliases A0 (for analog
input 0), A1, etc. For example, the code would look like this to set analog pin 0 to an output,
and to set it HIGH:

COPY
pinMode(A0, OUTPUT);
digitalWrite(A0, HIGH);
Pull-up resistors
The analog pins also have pull-up resistors, which work identically to pull-up resistors on the
digital pins. They are enabled by issuing a command such as

COPY
pinMode(A0, INPUT_PULLUP); // set pull-up on analog pin 0
Be aware however that turning on a pull-up will affect the values reported by analogRead().

Details and Caveats


The analogRead command will not work correctly if a pin has been previously set to an
output, so if this is the case, set it back to an input before using analogRead. Similarly if the
pin has been set to HIGH as an output, the pull-up resistor will be set, when switched back to
an input.

The ATmega datasheet also cautions against switching analog pins in close temporal
proximity to making A/D readings (analogRead) on other analog pins. This can cause
electrical noise and introduce jitter in the analog system. It may be desirable, after
manipulating analog pins (in digital mode), to add a short delay before using analogRead() to
read other analog pins.

Basics of PWM (Pulse Width Modulation)


Learn how PWM works and how to use it in a sketch..

Last revision08/02/2024
The Fading example demonstrates the use of analog output (PWM) to fade an LED. It is
available in the File->Sketchbook->Examples->Analog menu of the Arduino software.

Pulse Width Modulation, or PWM, is a technique for getting analog results with digital
means. Digital control is used to create a square wave, a signal switched between on and off.
This on-off pattern can simulate voltages in between the full Vcc of the board (e.g., 5 V on
UNO, 3.3 V on a MKR board) and off (0 Volts) by changing the portion of the time the
signal spends on versus the time that the signal spends off. The duration of "on time" is called
the pulse width. To get varying analog values, you change, or modulate, that pulse width. If
you repeat this on-off pattern fast enough with an LED for example, the result is as if the
signal is a steady voltage between 0 and Vcc controlling the brightness of the LED.

In the graphic below, the green lines represent a regular time period. This duration or period
is the inverse of the PWM frequency. In other words, with Arduino's PWM frequency at
about 500Hz, the green lines would measure 2 milliseconds each. A call to analogWrite() is
on a scale of 0 - 255, such that analogWrite(255) requests a 100% duty cycle (always on),
and analogWrite(127) is a 50% duty cycle (on half the time) for example.
On some microcontrollers PWM is only available on selected pins. Please consider the pinout
diagram of your board to find out which ones you can use for PWM. They are denoted with a
tilde sign (~).

Once you get this example running, grab your Arduino and shake it back and forth. What you
are doing here is essentially mapping time across the space. To our eyes, the movement blurs
each LED blink into a line. As the LED fades in and out, those little lines will grow and
shrink in length. Now you are seeing the pulse width.

Debugging Fundamentals
Learn the basics of debugging microcontroller-based systems.

AuthorJosé Bagur, Taddy Chung


Last revision08/02/2024
Embedded systems are microprocessor or microcontroller-based systems with a dedicated
operational role. Rather than being made of separate components, like desktop computers,
laptops or, gaming consoles, embedded systems integrate all the hardware and software
necessary for a particular purpose. Nowadays, embedded systems are everywhere:
automobiles, cameras, household appliances, and mobile devices are just some examples.

Embedded systems design can be challenging since it combines hardware design, firmware,
and software development, all in one particular device or product. In order to produce high-
quality embedded firmware and software for a particular device or product, debugging is a
necessary step in their development process. Debugging is the process of confirming that, one
by one, many things that we believe to be true and functional in our code are true. We find a
"bug" in our code when one our more assumptions are not valid.

People worldwide have been talking about "bugs" for a long time; even Thomas Alva Edison
used the word back in his days. The word bug has been used as an old term for "monster";
like gremlins in machinery, bugs are malicious.

The following article will discuss different debugging tools and techniques used to find bugs
in microcontroller-based systems, especially those based on Arduino® hardware.

Debugging tools and techniques


There are some basic debugging tools and techniques that we can use and implement to
validate our code:

The compiler and syntax errors.


Traditional techniques: trace code and GPIOs.
Remote debuggers.
Simulators.
In-circuit emulators and in-circuit debuggers.
Hardware tools: multimeters, logic analyzers, oscilloscopes, and software-defined radios.
Let us take a look into each one of the debugging tools and techniques.

The Compiler and Syntax Errors


Compiling is transforming high-level code into machine language that can be understood by a
processor, for example a microcontroller. In this process, the compiler also helps to identify
syntax errors. Syntax errors indicate something wrong with the program's syntax; for
example, when a semi-colon is omitted at the end of a statement in a program, the compiler
generates a syntax error.

The Arduino IDE 2 compiler showing a syntax error in a sketch.


The Arduino IDE 2 compiler showing a syntax error in a sketch.
Using the compiler for debugging syntax errors can be sometimes tricky; let us analyze two
commonly encountered situations:

The compiler shows 100 errors: This usually does not mean there are 100 errors; it often gets
thrown off track for a while when the compiler finds an error. The compiler tries to recover
and pick up again after the first error, but sometimes it reports false errors. Only the first error
message is genuinely reliable; try to fix one error at a time and then recompile the program.
Getting weird compiler messages: Compiler errors are shown in terse jargon, sometimes hard
to read and understand, but with hidden and valuable information. Read the error message
carefully; it will always tell where, inside the code, the error occurred.
Traditional Techniques: Trace Code and GPIO's
Adding trace code is probably the simplest and most basic debugging technique used in
embedded systems software design. This method adds trace code to the program to print out
messages or values of variables (using the Serial.print() function, for example) as the
program executes. For example, determining if a particular function is halting or freezing in
our code can be made with trace code as shown in the example code below:

COPY

Explain
// Print a message if the execution gets here
Serial.println("Code got here");

// Try to execute myFunction1()


myFunction1();

// Print a message if the execution gets here


Serial.println("Code got here, myFunction1 executed");

// Try to execute myFunction2()


myFunction2();

// Print a message if the execution gets here


Serial.println("Code got here, myFunction2 executed");
Using trace code for debugging is usually applicable only during the early stages of an
embedded system code development. Adding trace code to our programs takes a significant
amount of processing time and resources. Therefore, it can easily disrupt critical timing tasks
in our programs. Additionally, if we use the UART for other tasks, we can have problems
displaying trace code.

You can pass flash-memory based Strings to Serial.print() instruction by wrapping them with
F(); for example, Serial.println(F("Code got here")) prints a flash-memory based String.

Another trace code technique consists of dumping strategic information into an array at run
time, we can then observe the contents of the array at a later time (for example, when the
program terminates); this technique is also known as dump into array. Assume good and bad
are two strategic variables we want to capture. The first step is to define a debug buffer in
RAM to save the debugging measurements as shown in the code below:

COPY
#define DUMP_BUFFER_SIZE 32
unsigned char goodBuffer[DUMP_BUFFER_SIZE];
unsigned char badBuffer[DUMP_BUFFER_SIZE];
unsigned long count = 0;
The variable count is used to index into the debug buffer, it must be initialized to zero before
the debugging process begins. The code shown below dumps strategic information from the
good and bad variables into the debug buffer:

COPY

Explain
void Save_Debug_Buffer(void) {
if (count < DUMP_BUFFER_SIZE) {
goodBuffer[count] = good;
badBuffer[count] = bad;
count++;
}
}
General Purpose Input/Output (GPIO) pins can help debug purposes when the UART is in
use or adding trace code is not particularly helpful. For example, we can turn on or off the
built-in LED of an Arduino® board by inserting a digitalWrite(LED_BUILTIN, HIGH)
instruction before or after questionable areas in our programs as shown in the example code
below. If the built-in LED turns on, then we know that a particular line of code executed:

COPY

Explain
// Print a message if the execution gets here
Serial.println("Code got here");

// Try to execute myFunction1()


myFunction1();

// Turn on the built-in LED for one second to indicate that myFunction1 was executed
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);

// Try to execute myFunction2()


myFunction2();

// Turn on the built-in LED for one second to indicate that myFunction2 was executed
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
Remote Debuggers
Remote debugging is another common approach used to debug embedded systems. Remote
debuggers work by connecting a particular embedded system to a host computer and then
using software in the host computer to interact with the embedded system hardware. Remote
debuggers are helpful when the development environment is on a different architecture rather
than the target system. For example, think about developing code on a Windows-based
computer for an ARM-based microcontroller system.

Remote debuggers usually have two essential parts: a front-end debugger and a back-end
debugger.

The front-end debugger contains the user interface (can be graphical or command-line-based)
and offers the programmer choices about the execution of the code in the embedded system
hardware.
The back-end debugger, also known as the "debug monitor," is specific for a particular
processor architecture or family an usually work with an external hardware tool, like an in-
circuit emulator or an in-circuit debugger. It starts when the processor resets and handles the
runtime instruction between the front-end debugger and the embedded system hardware.
The debugger tool is a newly introduced yet less famous feature of Arduino IDE 2. Check out
this tutorial that shows how to use the Arduino® IDE 2 debugger with supported boards.

Simulators
Simulators are tools used to simulate the functionality and the instruction set of the target
processor. These tools, usually, can only simulate the target processor functionalities but not
its environment and external parts and components. Simulators are handy in the early stages
of the development process, where we only have the software but have not implemented any
hardware yet.

Tinkercad Circuits is an excellent simulator for beginners in the Arduino® ecosystem. This
tool can simulate the instruction set of an Arduino® UNO board and the functionalities of
several electronic components such as resistors, LEDs, motors, LCDs, and some sensors.

A simulation of a circuit in Tinkercad Circuits.


A simulation of a circuit in Tinkercad Circuits.

In-Circuit Emulators and In-Circuit Debuggers


An in-circuit emulator (or ICE) is a specialized tool that allows developers to examine the
state of the processor while a particular program is running. ICEs are considered embedded
systems by themselves; they are a copy of the target processor and its memory (RAM and
ROM); this is why they provide an unintrusive way to debug code at the target processor.
Historically, ICEs were the tool of choice of embedded systems developers, but as processor
complexity and clock speed increased, ICEs became more expensive, and their availability
declined considerably.

An early 1990s Mikrotek in-circuit emulator for 8086 microprocessors.


An early 1990s Mikrotek in-circuit emulator for 8086 microprocessors.

Binarysequence, CC BY-SA 3.0, via Wikimedia Commons.

An in-circuit debugger (or ICD) is also a specialized tool connected between a host computer
and a processor for debugging real-time applications faster and easier; this tool uses some
memory and GPIO pins of the target microcontroller during the debugging operations. With
an ICD, developers access an on-chip debug module which is integrated into the CPU over an
interface (for example, JTAG). This debug module allows developers to load, run, halt and
step the processor.

SEGGER J-Link EDU JTAG/SWD debug probe.


SEGGER J-Link EDU JTAG/SWD debug probe.

SEGGER Microcontroller GmbH & Co, CC BY-SA 3.0, via Wikimedia Commons.

The fundamental difference between an ICE and an ICD relies on the resources used to
control the debug target. In ICEs, resources are provided by the emulation hardware; in ICDs,
resources are provided by the target processor.

Arduino® ICD Support


The Arduino® boards with a SAMD microcontroller support ICD debugging; these boards
are the following:
Zero.
Nano 33 IoT.
MKR Zero.
MKR WiFi 1010.
MKR WAN 1300.
MKR WAN 1310.
MKR FOX 1200.
MKR NB 1500.
MKR GSM 1400.
MKR Vidor 4000.
The Arduino® Zero board features an on-board debugger, the Atmel® Embedded Debugger
(EDGB). In addition to programming and debugging support, the EDGB also offers data
streaming capabilities between the host computer and the target processor. Check out this
tutorial to learn how to use the Arduino® Zero board debugging capabilities with the Arduino
IDE 2.

Arduino® Zero EDGB.


Arduino® Zero EDGB.

Arduino® boards with a SAMD microcontroller feature native on-chip debug capabilities;
these debugging capabilities can be used with an external ICD tool over JTAG or SWD
interfaces. CMSIS-DAP compliant debug probes can be used with the Arduino IDE 2 out of
the box without any configuration file; non-standard debug probes require a special
configuration. Check out these tutorials to learn how to use an external ICD tool with SAMD
based Arduino boards and the Arduino IDE 2:

Debugging with the SEGGER J-Link.


Debugging with the Atmel-ICE.
The Arduino® Portenta H7, H7 Lite, and H7 Lite Connected boards from the Pro family also
support ICD debugging; these boards use the TRACE32 debugger from Lauterbach. The
TRACE32 debugger allows testing embedded hardware and software by using the in-circuit
debug interface of processors. Check out this tutorial to learn how to use the TRACE32
debugger with the Portenta family boards:

Lauterbach TRACE32 GDB Front-End Debugger for Portenta H7.


The Arduino® Portenta H7.
The Arduino® Portenta H7.

Hardware Tools
Embedded systems developers and typical software developers differ on a key aspect: their
"closeness" to hardware; embedded system developers are usually closer to hardware than
typical software developers. There are several tools that embedded systems developers use to
find out what is going on with the hardware, which is very helpful for low-level software
debugging. These tools are multimeters, logic analyzers, oscilloscopes, and software-defined
radios (SDRs).

Let us take a look at each one of the hardware debugging tools. A basic understanding of
these tools can significantly improve debugging skills, especially while developing embedded
systems.

Multimeters, logic analyzers, oscilloscopes and, software-defined radios help debug


interactions between the processor and other electronic parts on an embedded system. These
tools do not control the flow of execution of the code of an embedded system.

Multimeters
A digital multimeter (DMM) is a hardware tool that can be used to measure two or more
electrical values, usually voltage (in volts), current (in amps), and resistance (in ohms).
DMMs are great tools and one of the most fundamental pieces of test equipment that can be
used to debug electrical problems within an embedded system.

Digital multimeter.
Digital multimeter.

oomlout, CC BY-SA 2.0, via Wikimedia Commons.

Logic Analyzers
A logic analyzer is a hardware tool designed specifically for capturing, displaying, and
measuring electrical signals in a digital circuit. This tool consists of several digital inputs pins
capable of detecting whether an electric signal is at a specific logic level (1 or 0). Logic
analyzers are also capable of showing the relationship and timing of different electrical
signals in a digital circuit and often capable also of analyzing digital communication
protocols (for example, SPI communication protocol).

24MHz, 8-channel logic analyzer.


24MHz, 8-channel logic analyzer.

SparkFun Electronics, CC BY-SA 2.0, via Wikimedia Commons.

Oscilloscopes
An oscilloscope is a hardware tool that graphically displays electrical signals and shows how
those signals change over time. Signals are measured in an oscilloscope with the help of a
sensor.

50MHz, 4-channel oscilloscope.


50MHz, 4-channel oscilloscope.

Dave Jones from Australia, CC BY-SA 2.0, via Wikimedia Commons.

Software-Defined Radios
A software-defined radio (SDR) is a radio communication system that uses software for the
modulation and demodulation of radio signals. Traditional radio communications systems
processing relies on hardware components; this limits their reprogramming to a very low
level. SDRs are much more flexible since they can be reconfigured by software.

HackRF software-defined radio.


HackRF software-defined radio.

Alexander Neumann, Public domain, via Wikimedia Commons.

Debugging with Hardware Tools


While there may be several debugging techniques, using a LED as a pass mark for the
debugging process is the simplest yet fastest method one can utilize. The indicator will be set
in different points of interest to observe the correct execution of tasks visually. For instance,
there can be multiple points located simultaneously to turn it on or off the LED on a single
point of interest at a time for step-by-step verification. This will provide just enough
information to construct an additional layer of the code or proceed to the following structure
sector to debug its behavior. It will not give precise or in-depth information about registry or
data exchange, so it has to be used as a tool for code structures that are not complex in their
architectural nature and behave mainly in a linear trend execution. It is handy when a
debugger is not available and quickly understand how the code behaves.
Sometimes, LEDs might not be present or might not be available in a particular system; there
is no way to make a visual inspection in the system. However, we can use an oscilloscope
directly to monitor the state of GPIO pins of the system in this case. The oscilloscope, in this
case, can be used to monitor specific GPIO pins and see if the code gives specific feedback
by driving the GPIO pin to the desired logic state. A DMM can also be handy for the same
task.

To get the most out of an oscilloscope and GPIO pins is by measuring its performance, this
means to determine a signal's electrical and timing properties. For example, an unnecessary
delay in the code can be identified with this information:

COPY

Explain
void myFunction() {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("Code got here");
count++;
digitalWrite(LED_BUILTIN, LOW);
}
myFunction() execution duration can be measured by setting a GPIO pin to be driven to a
high logic level when its execution begins; when myFunction() execution ends, the GPIO pin
can be driven to a low logic level. An oscilloscope can then provide information if the
function execution took precisely the defined time, longer or shorter than expected, or if it
has any unaccounted electrical behavior that changes the expected behavior.

Now let us talk about wireless communications. Wireless communications are a key feature
in developing new Internet of Things (IoT) devices with different requirements or
specifications and for different purposes. Wireless communication is present on many
embedded systems, and Arduino® hardware is no exception for this feature. The question
now is: how do we debug wireless communications between devices?

A simple and common technique used to debug wireless communications between two or
more devices consists of using acknowledge flags. Using acknowledge flags aids in
understanding the device's behavior when communication is established between them by
providing their current status. This process is also found on physical communication
protocols, such as I2C or SPI. Because of the different protocol types in wireless
communications, using acknowledge flags as a debugging method can be applied but differ in
their own rules. The easiest way to confirm that the data exchange was successful is to check
the data log on each end device. Hardware tools mentioned earlier (DMMs, oscilloscopes,
and logic analyzers) can be used to provide more in-depth details and add more value to this
type of debugging technique.

However, not everything is connected on a physical layer, but on an abstract layer. This
abstract layer in wireless communications is where electromagnetic waves propagate through
space. Why would we need to debug electromagnetic waves propagating through space?
Sometimes, we need to verify that the wireless transceiver configuration of a particular
embedded system is correct, for example, its transmission power. SDRs can be helpful in this
situation: SDRs can be used as cheap spectrum analyzers. A spectrum analyzer is a hardware
tool that measures the magnitude of a signal versus the frequency; this tool is mainly used to
measure a signal's power spectrum. Using SDRs as spectrum analyzers is usually an optional
debugging method in the development process, ensuring a more robust system design.
Several programs can be used with SDRs; GQRX is one of the most popular software;
GQRX is open-source and with cross-platform support (Linux and macOS). AirSpy and
CubicSDR are other popular software used with SDRs and cross-platform support (Windows,
Linux, and macOS).

Shown visual representation of the signal via SDR software can now be used to verify the
transmission power outputted by the device and the amount of data transmitted. This will
help visualize the device's wireless communication configuration properties. It will be
possible to verify the transmission and reception power, the number of bytes transmitted, and
the frequency it is supposed to transmit. These properties can be debugged through the
frequency spectrum and refined to provide edge wireless communication performance on
embedded systems.

LoRa signals shown in a spectogram. Source: The Things Network.


LoRa signals shown in a spectogram. Source: The Things Network.

Debugging Techniques Example


A simple example will demonstrate the implementation of some of the debugging techniques
we discussed before and how they can be handy for the development process of code in the
Arduino® ecosystem. We will use the Arduino® Nano 33 BLE Sense board, and its onboard
inertial measurement unit (IMU) features to show the debugging process's importance. The
example code uses accelerometer, gyroscope, and magnetometer data simultaneously, having
the tasks be executed to obtain every value:

COPY

Explain
/*
Program:
- Debugging_techniques_example.ino

Description:
- This example combines data from the LSM9DS1 accelerometer, gyroscope, and
magnetometer into a single code. On top of it,
it helps to understand different methods and techniques of debugging when the code
structure combines multiple tasks.

The circuit:
- Arduino Nano 33 BLE Sense.

Code based on examples created by Riccardo Rizzo, Jose García, and Benjamin Dannegård.
Modified by Taddy Ho Chung and José Bagur (16/02/22).
*/

#include <Arduino_LSM9DS1.h>

#define DUMP_BUFFER_SIZE 32
unsigned char GoodBuffer[DUMP_BUFFER_SIZE];
unsigned char BadBuffer[DUMP_BUFFER_SIZE];
unsigned long count = 0;
uint8_t good, bad = 0;

float x, y, z, ledvalue;
int degreesX = 0, degreesY = 0;
int plusThreshold = 30, minusThreshold = -30;
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("- Started");

if (!IMU.begin()) {
Serial.println("- Failed to initialize IMU!");

bad++;
save_bebug_buffer();
disp_debug_buffer();
debug_stop();
}

accelermeter_setup();
gyroscope_setup();

void loop() {
for (int i = 0; i < 5; i++) {
accelerometer_task();
gyroscope_task();
magnetometer_task();
}

save_debug_buffer();
debug_stop();
}

// Accelerometer setup
void accelermeter_setup() {
Serial.print(F("- Accelerometer sample rate: "));
Serial.print(IMU.accelerationSampleRate());
Serial.println(F(" Hz"));
}

// Read accelerometer data in all three directions task


void accelerometer_task() {
if (IMU.accelerationAvailable()) {
Serial.println(F("- Accelerometer data ready"));
IMU.readAcceleration(x, y, z);
good++;
} else {
Serial.println(F("- Accelerometer data not ready"));
bad++;
}

if (x > 0.1) {
x = 100 * x;
degreesX = map(x, 0, 97, 0, 90);
Serial.print(F("- Tilting up "));
Serial.print(degreesX);
Serial.println(F(" degrees"));
}

if (x < -0.1) {
x = 100 * x;
degreesX = map(x, 0, -100, 0, 90);
Serial.print(F("- Tilting down "));
Serial.print(degreesX);
Serial.println(F(" degrees"));
}

if (y > 0.1) {
y = 100 * y;
degreesY = map(y, 0, 97, 0, 90);
Serial.print(F("- Tilting left "));
Serial.print(degreesY);
Serial.println(F(" degrees"));
}

if (y < -0.1) {
y = 100 * y;
degreesY = map(y, 0, -100, 0, 90);
Serial.print(F("- Tilting right "));
Serial.print(degreesY);
Serial.println(F(" degrees"));
}

delay(1000);
}

// Gyroscope setup
void gyroscope_setup() {
Serial.print(F("- Gyroscope sample rate = "));
Serial.print(IMU.gyroscopeSampleRate());
Serial.println(F(" Hz"));
Serial.println();
Serial.println(F("- Gyroscope in degrees/second"));
}

// Read gyroscope data in all three directions task


void gyroscope_task( ) {
if (IMU.gyroscopeAvailable()) {
IMU.readGyroscope(x, y, z);
Serial.println(F("- Gyroscope data ready"));
good++;
} else {
Serial.println(F("- Gyroscope data not ready"));
bad++;
}

if(y > plusThreshold) {


Serial.println(F("- Collision front"));
delay(500);
}

if(y < minusThreshold) {


Serial.println(F("- Collision back"));
delay(500);
}

if(x < minusThreshold) {


Serial.println(F("- Collision right"));
delay(500);
}

if(x > plusThreshold) {


Serial.println(F("- Collision left"));
delay(500);
}
}

// Read magnetometer data in all three directions task


void magnetometer_task(){
IMU.readMagneticField(x, y, z);

if(x < 0) {
ledvalue = -(x);
}
else {
ledvalue = x;
}

analogWrite(LED_BUILTIN, ledvalue);
delay(500);
}

// For debugging purposes


void save_debug_buffer(void) {
if (count < DUMP_BUFFER_SIZE) {
GoodBuffer[count] = good;
BadBuffer[count] = bad;
disp_debug_buffer();
count++;
}
}

// Debugging array buffer


void disp_debug_buffer() {
Serial.println(F("\n Debugging array buffer result >>"));
Serial.print(F("- Good marks: "));
Serial.println(GoodBuffer[count]);

Serial.print(F("- Bad marks: "));


Serial.println(BadBuffer[count]);
}

void debug_stop() {
Serial.flush();
exit(1);
}
As shown, the complete code unifies the accelerometer, gyroscope, and magnetometer into a
single code structure. As it involves tasks from different modules, it is separated into different
functions and executed in a more identifiable manner. The code includes a trace code
technique for debugging (dump into an array) to understand precisely how the code operates.
The good and bad marks are located at the points of interest in the code and will dump into
assigned arrays to be able to display at the end of the code.

It is crucial to know when to stop the code from debugging. While the code shown above can
be debugged at runtime, it is much easier to know when to stop or how to stop the code
operation. For instance, stopping within the first run gives the following result:

Only one runtime instance of the debugging array.


Only one runtime instance of the debugging array.

In the Arduino Serial Monitor, we can observe that it has a 1 good mark and a 1 bad mark.
The good mark came from the gyroscope having ready the data for use, while the bad mark
came from the accelerometer as the data was not ready. So it is possible to see that the
accelerometer does not have enough time to get the data ready before it gets to the
measurement task. We can try by running a certain number of instances before it gets to the
array dump sector, and the result can be seen as follows:

5 runtime instance of the debugging array.


5 runtime instance of the debugging array.

The accelerometer performed its task without any issue except the first runtime instance,
resulting in 9 good marks but 1 bad mark due to this behavior. The Serial.println(F())
instruction of module setups and task runtimes also shows us if the code could get past the
operations without any issue. By this, it is possible to know the code structure does not
misbehave, but for the first time when the device is starting, the accelerometer requires more
time to get the data ready in the first instance.

Additionally, it is possible to modify the loop code by simply adding a digitalWrite(12,


HIGH) instruction before tasks are called instruction and a digitalWrite(12, LOW) instruction
after the tasks are executed to measure the time it takes to complete them using GPIO 12 of
the board and an oscilloscope. This can also be helpful to understand the power consumption
it draws from this runtime instance:

COPY

Explain
void loop() {
for (int i = 0; i < 5; i++) {
digitalWrite(12, LOW);
accelerometer_task();
gyroscope_task();
magnetometer_task();
digitalWrite(12, HIGH);
}

save_debug_buffer();
debug_stop();
}
Using an oscillocope and a GPIO to measure the time it takes to complete tasks.
Using an oscillocope and a GPIO to measure the time it takes to complete tasks.
Final Thoughts about Debugging
Debugging is a necessary step for developing robust and reliable embedded systems software.
We can end this article by mentioning the four most essential phases of debugging stated by
Robin Knoke in this article about debugging embedded C that was published in the
Embedded Systems Programming magazine:

Testing: this phase exercises the capability of the embedded software by stimulating it with a
wide range of input values and in different environments.
Stabilization: this phase attempt to control the conditions that generate a specific bug.
Localization: this phase involves narrowing the range of possibilities until the bug can be
isolated to a specific code segment in the embedded software.
Correction: this phase involves eradicating the bug from the software.
Knowing the potential causes of bugs allows us to adopt strategies that minimize their
occurrence. Many different debugging techniques and external devices are present to aid this
process. Maybe some software designs do not require the usage of external debuggers, for
example. However, when the software involves different requirements, especially scalability,
things change drastically for the development process. The debugging techniques and the
external debuggers will support this development process, thus granting sophisticated
software. In most cases, we will know how the device will behave with the software, its
computational performance, and even achieve non-power hungry devices due to clean
memory management.

Debugging may be an overlooked aspect in developing embedded systems, but it is its most
serious yet crucial tool. If we desire to develop robust and reliable embedded systems, the
debugging process should consistently be implemented to achieve these goals.

Further Reading and Resources


Debugging is an exciting topic to study; if you want to learn more about debugging tools and
techniques, check out the following links:

Do you want to improve your debugging and engineering skills? A highly recommended
reading is Debugging: The 9 Indispensable Rules for Finding Even the Most Elusive
Software and Hardware Problems by David J. Agans.
Do you want to learn more about digital multimeters? Learn more about them in this article
from Fluke®.
Do you want to learn more about oscilloscopes? Learn more about them in this article from
Tektronix®.
Do you want to learn more about logic analyzers? Learn more about them in this article from
Saleae®.
Do you want to learn more about spectrum analyzers? Learn more about them in this article
from Tektronix®.
Do you want to learn more about SDRs? Check out the Great Scott Gadgets video series
about SDRs. The video series from Great Scott Gadgets is a complete course about SDRs.
You will learn the fundamentals of Digital Signal Processing (DSP) and build flexible SDR
applications using GNU Radio.
References
[1] P. Koopman, Better Embedded System Software. S.L.: Drumnadrochit Press, 2010.
[2] D. J. Agans, Debugging: The Nine Indispensable Rules for Finding Even the Most
Elusive Software and Hardware Problems. New York: Amacom, 2002.
[3] M. Barr and A. Massa, Programming Embedded Systems: with C and GNU Development
Tools. Johanneshov: MTM, 2013.
[4] J. W. Valvano, Embedded Systems: Introduction to ARM® Cortex™-M
Microcontrollers. United States: Self-published, 2015

Guide to 3V3 and 5V Power Supplies Differences


Design and build robust electronic circuits and devices by learning the main characteristics
and differences between 3V3 and 5V power supplies levels.

AuthorTaddy Chung, José Bagur


Last revision08/02/2024
3V3 vs. 5V
When designed, most electronic circuits and devices must choose a power supply. The
voltage of the power supply is usually determined either by convenience or the need for
power efficiency that the electronic circuit or device itself has as a requirement.

3V3 and 5V are standard voltage levels nowadays in power supplies. Although there is only a
1V7 difference between both voltages, it is enough to provide a significant difference in
power efficiency. This guide will show you why 3V3 is the current standard voltage level for
power supplies in electronic circuits and devices and some general tips when designing and
handling these voltage levels in your circuits or devices powered by Arduino.

3V3, the Standard Voltage Level


So, why is the 3.3V a standard power supply voltage level? Because power consumption has
always been a concern for designers, lower power supply voltage levels were introduced to
make more power-efficient circuits and devices. For over 30 years, powering electronic
circuits and devices using a 5V level was common practice; today, most electronic circuits
and devices use a 3V3 power supply voltage level, some are even migrating to a 2V5 level
(or even to lower voltages!).

Reducing the power supply voltage yields an exponential decrease in power consumption.

A standard exists for defining the voltage levels of input and output voltages for every power
supply voltage level; this standard was developed by The Joint Electron Device Engineering
Council (JEDEC); it is the JEDEC Standard 8-A for LV interface levels. The JEDEC
Standard 8-A for LV interface levels is described in the image shown below for 3V3 and 5V
logic families:

The JEDEC Standard 8-A for LV interface levels.


The JEDEC Standard 8-A for LV interface levels.

In the image shown above:

VOL: maximum output voltage level an electronic device will provide for a LOW signal
VIL: maximum input voltage level an electronic device will still considered as a LOW signal
Vt: threshold voltage at which an electronic device switches its interpretation of a signal from
low to high or vice versa
VIH: minimum input voltage level an electronic device will still considered as a HIGH
signal.
VOH: minimum output voltage level an electronic device will still considered as a HIGH
signal
For more in-depth information about current microelectronic standards, please look at the
JEDEC website.

How to Avoid Burning Circuits 101


Every electronic designer driving the power lines of electronic circuits and devices can cause,
accidentally or on purpose, a short circuit and, therefore, damage the electronic circuits or
devices. Accidents and mistakes always happen, but we can follow some tips and tricks to
avoid them. Let's check it out!

Color Coded Power Lines


Color coding the power lines is the easiest yet most effective visual method to avoid an
incorrect connection in the power lines of electronic circuits or devices. When prototyping an
electronic circuit or device, some developers make the common mistake of using the same
color on every cable while being jumbled all over the place, making it impossible to identify
which.

Color coding power lines makes it much easier to identify the voltage and Ground (GND)
lines. According to industry regulations and standards, red is typically used to indicate a
voltage line, while black is used to indicate a GND line; colors vary depending on the
regulation or standard.

For more information on electrical regulations and standards, please check out the National
Electrical Safety Code® from the Institute of Electrical and Electronics Engineers (IEEE).

Fuse Integration
One easy way to protect electronic devices is to integrate an onboard power protection circuit
into the device. Several circuit designs can be implemented to achieve this; one of the easiest
circuits to implement is using a fuse.

Fuse integration to electronic devices is not a complicated design process. The following
schematic shows a simple reverse polarity protection circuit that can be used in low-power
DC circuits:

Simple reverse polarity protection circuit.


Simple reverse polarity protection circuit.

This simple reverse polarity protection circuit uses a fuse and a diode that later connects to
the electronic circuit, which can be referred to as the load.

A Better Reverse Polarity Protection Circuit


Implementing complicated power protection circuit does not mean the load is absolutely
protected. Depending on the component selection and cost for implementation, the solution
can become much more elegant, and the same applies for reverse polarity protection. The
following reverse polarity protection is designed by Mehdi Sadaghdar.

Complete Reverse Polarity Protection


Complete Reverse Polarity Protection

The key points of the circuit presented above are the Transient Voltage Suppressor diode and
the MOSFET of P-Channel type. This protection circuit will help you save the Protected
Load and to have it as a good reference for protection design. Although due to its electric
components, it becomes a little more advanced to cover in the scope of this guide.

If you are interested in reading more, visit this article by Mehdi Sadaghdar.

Over-Voltage and Over-Current Protection


Sometimes the electronic device, that should receive 3.3V level of input from the supply may
receive a "dirty" tension. This causes the electronic device to suffer abnormal electronic
behaviour. As it could destabilise the system completely or change the logic forcefully due to
changed logic range to be unrecognised. There are more of this undesired behaviour, if over-
voltage or over-current is introduced to the system.

So for this matter, how do we protect the system? The solution can be based of the proper
Reverse Polarity Protection showed previously. The proper Polarity Reverse Polarith
Protection implements a bidirectional Transient Voltage Suppressor while adding the P-
Channel MOSFET with a zenerdiode and two resistors to get all its flavours.

To give quick explanation on Transient Voltage Suppressor - It is a type of a diode that helps
to protect high-spike voltages generated at the output of Power Supply.

But a simple Reverse Polarity Protection, with a Transient Voltage Suppressor diode can be
used to protect the over-voltage and over-current issues. If you want to go further into
protecting the Load from over-voltage and over-current, it is possible to integrate Surge
Stopper to provide active protection. May increase the cost, however it is a good measure to
protect the Load.

Stepping the Voltage - Level Shifters


Arduino boards relies on 3.3V and 5V levels. But sometimes there may not be available pins
that matches the voltage requirement to adequately drive the sensor or any such line. In this
section, we will take a look at how we can step up and down voltages.

We will use a bidirectional Logic Level Converter to step the voltage level, to be able to use
sensors or logics at higher or lower voltage levels. This is an option to use if tight electric
specification is implemented on the board.

The bidirectional Logic Level Converter used can be found here (SparkFun).

Stepping Down Voltage


We will begin by learning how to step down the voltage. Usually, voltage is driven down to
lower level needed by the external module or sensors. It can also be due to need of lower
voltage line to handle a separate circuit. It is crucial that you know the electric requirement
that will demand if the electronic design is more complex than usual design. Such as tight
electric specification and multiple signal lines to handle with operating at high speeds.

A voltage divider is the simplest yet easy to implement solution. It uses 2 resistors to create a
lower voltage output. So, knowing the input voltage and targeted output voltage and a
reference resistor, it is simple enough to calculate the other required resistor to implement to
produce desired voltage. Below is a voltage dividing circuit.

Voltage/Resistive Divider
Voltage/Resistive Divider

When using this circuit, you will still need to be cautious of the residing capacitance that is
connected at the output of this circuit and with the quick rise times, as for certain applications
with cautious timing requirements or modules non-response to quick rise times will be
affected.

Stepping Up
To step up voltage, you will need to use a little bit more constructive electric circuit by using
diodes. The following circuit shows how to use diodes to step up voltage.

Step Up Circuit - Diode Implementation


Step Up Circuit - Diode Implementation

You will need to biase the diodes with precaution and the resistor that is much lower than the
input impedance of the 5V gate. One of the know-hows shared by Microchip is to use
Schottky diodes to gain slight high-level voltage and reduce low-level voltage from
incrementing. Following circuit uses a different setup.
Step Up Circuit - MOSFET
Step Up Circuit - MOSFET

This circuit uses the MOSFET as a switch and takes the 5V logic from the drain. It is useful if
the logic inversion can be treated, as 3.3V logic becomes inverted. To begin with MOSFET, a
2N7000 or a BSS138 MOSFET can be used for this circuit.

Bi-Directional Logic Level Converter


Previous electric circuits are uni-directional logic level shifters. Meaning that to use different
stepping configuration, you will need to change the entire electric circuit to go from stepping
up to down, and vice-versa. On top of it, if the electronic size is factor to take it into account,
then you can use a off-the-shelf logic level converter.

You can use the Bi-Directional Logic Level Shifter from SparkFun to test and also for
deployment if the requirements enables its integration. The advantage of this particular shifter
is that it provides 4 channels to shift within the voltage references given. High Voltage level
and Low Voltage level references are injected with desired voltage level and channels are
used to transmit the data in between.

Voltage Stepping- Logic Shifter


Voltage Stepping- Logic Shifter

The circuit above uses the bi-directional logic shifter to establish I2C interface with any
sensor capable of the protocol. The SCL and SDA lines go through a High Voltage channel
and establishes communication with the sensor that is connected at its respective Low
Voltage Channel.

The configuration of the Logic Shifter usually does not change, as the the purpose is to
transmit the signal from a High to a Low Level or vice-versa, depending on the architecture
operation. Thus, the previous schematic illustrates usual global connection configuration. As
it can be to interface the Arduino board with another computing module working on a
different voltage level. Below schematic shows the specific of each channel and focus the
scope inside the schematic symbol box of the Logic Shifter.

Logic Shifter Insight


Logic Shifter Insight

Each channel is composed by two resistors and a MOSFET that will use the reference High
and Low voltages to transfer the signal from the respective module.

Further Reading and Resources


Handling different voltage levels covers vast electronic department, and without exception
for 3.3V and 5V levels which are the most used voltage levels. To get deeper into the topic
handling voltage levels, you can follow some of the links that might get our attention.

If you want to know about some know-hows from Microchip, you can read Microchip: 3V
Tips 'n Tricks to learn about wide variety of techniques used with 3.3V and 5V levels.
Level Shifting the voltage has its own science dedicated to it and Philips Semiconductor
welcomes you if you are ready learn deeper about Bi-Directional Level Shifter for I2C Bus
and Other Systems with their Application Note AN97055.
References
[1] Larsson, E. (2006). Introduction to Advanced System-on-Chip Test Design and
Optimization. Springer Publishing.
[2] Kularatna, N. (2018). DC Power Supplies Power Management and Surge Protection for
Power Electronic Systems. Amsterdam University Press.
[3] Ballan, H., & Declercq, M. (2010). High Voltage Devices and Circuits in Standard CMOS
Technologies. Springer Publishing

Arduino API
A reference to the Arduino Programming Language.

AuthorKarl Söderby
Last revision08/02/2024
Compact version of the Arduino Language Reference. This document is a TLDR; of the
Arduino API.

Please note that as of 2024/01/15, this article is still a work in progress.

Functions
Digital I/O
Method & Parameters Description Returns
int digitalRead(int pin) Reads the state of a digital pin. int
void digitalWrite(int pin, int state) Writes a state to a digital pin. Nothing
void pinMode(int pin, int mode)* Define the mode of a pin. Nothing
*Available modes are:

INPUT (0)
OUTPUT (1)
INPUT_PULLUP (2)
INPUT_PULLDOWN (3)
OUTPUT_OPENDRAIN (4)
Analog I/O
Method & Parameters Description Returns
int analogRead(int pin) Reads the value of an analog pin in a 10-bit resolution (0-
1023).* int
void analogReadResolution(int resolution) Sets ADC read resolution in bits. Nothing
void analogReference(int reference) Changes the voltage reference for a board.**Nothing
void analogWrite(int pin, int value) Writes a value to a PWM supported pin in a 8-bit
resolution (0-255).** Nothing
void analogWriteResolution(int resolution) Sets write resolution for a board. Nothing
*The value range changes based on the resolution. 0-1023 is 10-bit resolution, 0-4096 is 12-
bit and so on.
**Each board/architecture has a set of different reference voltages available.
***The value range changes based on the resolution. 0-255 is default (8-bit).
Advanced I/O
Method & Parameters Description Returns
void tone(int pin, int frequency, long duration) Generates a square wave on specified
pin, with 50% duty cycle. Nothing
void noTone(int pin) Stops generation of square wave on the specified pin. Nothing
long pulseIn(int pin, int state, long timeout) Reads a pulse (either HIGH or LOW) on a pin
and returns the length of the pulse (in microseconds) long
long pulseInLong(int pin, int state, long timeout) Returns the length of the pulse (in
microseconds) long
int shiftIn(int pin, int clockPin, int bitOrder)* Shifts in a byte of data one bit at a time,
and returns the value of the bit read. byte
void shiftOut(int pin, int clockPin, int bitOrder, byte value)** Shifts out a byte of data
one bit at a time. Nothing
*The bitOrder parameter is either MSBFIRST (1) or LSBFIRST (0) (most / least significant
bits).
**The pin used for shiftOut() needs to be configured as an OUTPUT, using pinMode()
Time
Method & Parameters Description Returns
void delay(long milliseconds)Freezes program execution for specified number of
milliseconds. Nothing
void delayMicroseconds(int microseconds) Freezes program execution for specified number
of microseconds. Nothing
long millis() Returns milliseconds passed since program start. long
long micros() Returns microseconds passed since program start. long
Math
Method & Parameters Description Returns
int abs(int value) Calculates the absolute value of a number. int
int constrain(int value, int min, int max) Constrains a number to be within a range. int
long map(long val, long min, long max, long newMin, long newMax) Re-maps a number
from one range to another. long
int max(int val1, int val2) Returns the greater of two values. int
int min(int val1, int val2) Returns the smaller of two values. int
double pow(double base, double exponent) Raises a base to the power of an exponent.
double
int sq(int value) Calculates the square of a number. int
double sqrt(double value) Calculates the square root of a number. double
Trigonometry
Method & Parameters Description Returns
cos(double angle) Calculates the cosine of an angle in radians. double
sin(double angle) Calculates the sine of an angle in radians. double
tan(double angle) Calculates the tangent of an angle in radians.double
Characters
Method & Parameters Description Returns
boolean isAlpha(char c) Checks if the character is an alphabetic character. boolean
boolean isAlphaNumeric(char c) Checks if the character is an alphanumeric character.
boolean
boolean isAscii(char c) Checks if the character is a 7-bit ASCII character. boolean
boolean isControl(char c) Checks if the character is a control character. boolean
boolean isDigit(char c) Checks if the character is a digit (0-9). boolean
boolean isGraph(char c) Checks if the character is a printable character, excluding
space. boolean
boolean isHexadecimalDigit(char c) Checks if the character is a hexadecimal digit (0-9, A-F,
a-f). boolean
boolean isLowerCase(char c) Checks if the character is a lowercase alphabetic character.
boolean
boolean isPrintable(char c) Checks if the character is a printable character, including space.
boolean
boolean isPunct(char c) Checks if the character is a punctuation character. boolean
boolean isSpace(char c) Checks if the character is a whitespace character. boolean
boolean isUpperCase(char c) Checks if the character is an uppercase alphabetic character.
boolean
boolean isWhitespace(char c) Checks if the character is a whitespace character according to
isSpaceChar() method. boolean
Random Numbers
Method & Parameters Description Returns
int random() Generates a pseudo-random number between 0 and RAND_MAX. int
void randomSeed(unsigned long seed) Seeds the random number generator. Nothing
Bits and Bytes
Method & Parameters Description Returns
boolean bit(int value, int bitNumber) Gets the value of a specific bit. boolean
void bitClear(int &value, int bit) Clears a specific bit. Nothing
boolean bitRead(int value, int bitNumber) Reads the value of a specific bit. boolean
void bitSet(int &value, int bit) Sets a specific bit. Nothing
void bitWrite(int &value, int bit, int bitValue) Writes a value to a specific bit.
Nothing
byte highByte(int value) Returns the high byte of an int. byte
byte lowByte(int value) Returns the low byte of an int. byte
External Interrupts
Method & Parameters Description Returns
void attachInterrupt(int pin, void (*function)(void), int mode) Attaches an interrupt to a
specific pin. Nothing
void detachInterrupt(int pin) Detaches an interrupt from a specific pin. Nothing
Interrupts
Method & Parameters Description Returns
void interrupts() Enables interrupts globally. Nothing
void noInterrupts() Disables interrupts globally. Nothing
Stream
Method & Parameters Description Returns
int available() Returns the number of bytes available in the serial buffer. int
int read() Reads the next byte from the serial buffer. int
void flush() Waits for the transmission of outgoing serial data to complete. Nothing
int find(char *target) Searches for a target string in the serial buffer. int
int findUntil(char *target, char *terminate) Searches for a target string until a specified
termination string is found. int
int peek() Returns the next byte in the serial buffer without removing it. int
int readBytes(char *buffer, int length) Reads characters from the serial buffer into a
buffer. int
int readBytesUntil(char terminator, char *buffer, int length) Reads characters from the serial
buffer into a buffer until a terminator is found. int
String readString() Reads characters from the serial buffer into a String until a newline
character is found. String
String readStringUntil(char terminator) Reads characters from the serial buffer into a
String until a specified terminator is found. String
int parseInt() Reads characters from the serial buffer and converts them to an integer. int
float parseFloat() Reads characters from the serial buffer and converts them to a float.
float
void setTimeout(unsigned long timeout) Sets the maximum duration for find(),
findUntil(), parseInt(), and parseFloat(). Nothing
Serial
Method & Parameters Description Returns
if(Serial) Checks if the Serial object is available. boolean
int available() Returns the number of bytes available for reading. int
int availableForWrite() Returns the number of bytes available for writing. int
void begin(unsigned long baudrate) Initializes the Serial communication with the specified
baud rate. void
void end() Ends the Serial communication. void
int find(char *target) Searches for a target string in the serial buffer. int
int findUntil(char *target, char *terminate) Searches for a target string until a specified
termination string is found. int
void flush() Waits for the transmission of outgoing serial data to complete. void
float parseFloat() Reads characters from the serial buffer and converts them to a float.
float
int parseInt() Reads characters from the serial buffer and converts them to an integer. int
int peek() Returns the next byte in the serial buffer without removing it. int
size_t print() Prints data to the serial port. size_t
size_t println()Prints data to the serial port followed by a newline character. size_t
int read() Reads the next byte from the serial buffer. int
int readBytes(char *buffer, size_t length) Reads characters from the serial buffer into a
buffer. int
int readBytesUntil(char terminator, char *buffer, size_t length) Reads characters from the
serial buffer into a buffer until a terminator is found.int
String readString() Reads characters from the serial buffer into a String until a newline
character is found. String
String readStringUntil(char terminator) Reads characters from the serial buffer into a
String until a specified terminator is found. String
void setTimeout(unsigned long timeout) Sets the maximum duration for find(),
findUntil(), parseInt(), and parseFloat(). void
size_t write(uint8_t) Writes a byte to the serial port. size_t
void serialEvent() Called when data is available in the serial buffer. void
SPI
Method & Parameters Description Returns
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) Creates an SPISettings
object with the specified clock, bit order, and data mode. SPISettings
void begin() Initializes the SPI library. void
void beginTransaction(SPISettings settings) Begins an SPI transaction with the specified
settings. void
void endTransaction() Ends the current SPI transaction. void
void end() Ends the SPI library. void
void setBitOrder(uint8_t bitOrder) Sets the bit order (MSBFIRST or LSBFIRST) for SPI
communication. void
void setClockDivider(uint8_t divider) Sets the clock divider for SPI communication.
void
void setDataMode(uint8_t dataMode) Sets the data mode for SPI communication.
void
byte transfer(byte value) Transfers a byte over SPI. byte
void usingInterrupt(int interruptNumber) Specifies which interrupt to use for SPI
transactions. void
I2C (Wire)
Method & Parameters Description Returns
void begin() Initializes the Wire library. void
void end() Ends the Wire library. void
int requestFrom(int address, int quantity) Requests data from a slave device with the
specified address and quantity of bytes. int
void beginTransmission(int address) Begins a transmission to the slave device with the
specified address. void
int endTransmission() Ends the transmission and returns the status. int
size_t write(uint8_t data) Writes a byte to the I2C bus. size_t
int available() Returns the number of bytes available for reading. int
int read() Reads a byte from the I2C bus. int
void setClock(uint32_t frequency) Sets the I2C clock frequency. void
void onReceive(void (*function)(int)) Sets a function to be called when data is
received by the slave. void
void onRequest(void (*function)(void)) Sets a function to be called when the master
requests data from the slave. void
void setWireTimeout(uint32_t timeout) Sets the timeout for I2C operations. void
void clearWireTimeoutFlag() Clears the timeout flag. void
bool getWireTimeoutFlag() Returns the timeout flag status. bool
Variables
Enums
Enum Type Enumeration Description
PinStatus HIGH / LOW Logical HIGH and LOW values (1 and 0).
PinMode INPUT / OUTPUT / INPUT_PULLUP / INPUT_PULLDOWN /
OUTPUT_OPENDRAIN Constants for specifying pin modes (0, 1, 2, 3, 4).
LED_BUILTIN Constant representing the built-in LED pin.*
true / false Boolean constants for true and false (1 and 0).
Conversion
Method & Parameter Description
(unsigned int) Type casting to unsigned int.
(unsigned long) Type casting to unsigned long.
byte() Type casting to byte.
char() Type casting to char.
float() Type casting to float.
int() Type casting to int.
long() Type casting to long.
word() Type casting to word.
Data Types
Method & Parameter Description
array Collection of variables of the same type.
bool Boolean data type.
boolean Boolean data type (synonym for bool).
byte 8-bit unsigned data type.
char 8-bit character data type.
double Double-precision floating-point data type.
float Single-precision floating-point data type.
int Integer data type.
long Long integer data type.
short Short integer data type.
size_t Unsigned integer data type.
string Sequence of characters (not a primitive type).
String() String class in Arduino.
unsigned char Unsigned 8-bit character data type.
unsigned int Unsigned integer data type.
unsigned long Unsigned long integer data type.
void Represents the absence of a type.
word 16-bit unsigned data type.
Variable Scope & Qualifiers
Method & Parameter Description
const Qualifier to define constants.
scope Not a specific keyword; refers to variable scope.
static Qualifier to declare static variables.
volatile Qualifier to declare volatile variables.
Utilities
Method & Parameter Description
PROGMEM Qualifier to store data in program memory.
sizeof() Operator to determine the size of a data type or variable.
Structure
Sketch
Method & Parameter Description
void loop() Main function for continuous code execution.
void setup() Initialization function, called once at startup.
Control Structure
Method & Parameter Description
break Exits a loop or switch statement.
continue Skips the rest of a loop iteration.
do...while Executes a block of code repeatedly while a specified condition is true.
else Part of the if-else statement.
for Creates a loop with a specified initialization, condition, and increment.
goto Transfers control to a labeled statement.
if Conditional statement for decision-making.
return Exits a function and optionally returns a value.
switch...case Multi-way branch statement.
while Creates a loop with a specified condition.
Further Syntax
Method & Parameter Description
#define (define) Macro definition for code substitution.
#include (include) Includes a file in the source code.
/* */ (block comment)Block comment for multiple lines.
// (single line comment) Single line comment.
; (semicolon) Statement terminator.
{} (curly braces) Block of code, often used with control structures.
Arithmetic Operators
Method & Parameter Description
% (remainder) Modulo operator for finding the remainder of a division.
* (multiplication) Multiplication operator.
+ (addition) Addition operator.
- (subtraction) Subtraction operator.
/ (division) Division operator.
= (assignment operator) Assignment operator.
Comparison Operators
Method & Parameter Description
!= (not equal to) Checks if two values are not equal.
< (less than) Checks if the left value is less than the right value.
<= (less than or equal to) Checks if the left value is less than or equal to the right value.
== (equal to) Checks if two values are equal.
> (greater than) Checks if the left value is greater than the right value.
>= (greater than or equal to) Checks if the left value is greater than or equal to the right
value.
Boolean Operators
Method & Parameter Description
! (logical not) Inverts the logical value, true becomes false and vice versa.
&& (logical and) Logical AND operator, returns true if both operands are true.
(logical or) Logical OR operator, returns true if at least one operand is true.
Pointer Access Operators
Method & Parameter Description
& (reference operator)Returns the memory address of a variable.
* (dereference operator) Accesses the value pointed to by a pointer.
Bitwise Operators
Method & Parameter Description
& (bitwise and) Performs bitwise AND operation.
<< (bitshift left) Shifts bits to the left.
>> (bitshift right) Shifts bits to the right.
^ (bitwise xor) Performs bitwise XOR (exclusive OR) operation.
(bitwise or) Performs bitwise OR operation.
~ (bitwise not) Inverts all bits.
Compound Operators
Method & Parameter Description
%= (compound remainder) Performs a modulo operation and assigns the result to the left
operand.
&= (compound bitwise and) Performs a bitwise AND operation and assigns the result to the
left operand.
*= (compound multiplication) Multiplies the left operand by the right operand and
assigns the result to the left operand.
++ (increment) Increments the value of the operand by 1.
+= (compound addition) Adds the right operand to the left operand and assigns the result
to the left operand.
-- (decrement) Decrements the value of the operand by 1.
-= (compound subtraction) Subtracts the right operand from the left operand and assigns
the result to the left operand.
/= (compound division) Divides the left operand by the right operand and assigns the
result to the left operand.
^= (compound bitwise xor) Performs a bitwise XOR operation and assigns the result to the
left operand.
= (compound bitwise or) Performs a bitwise OR operation and assigns the result to the
left operand.

Using Variables in Sketches


What are variables, and how can we use them in a sketch.

Last revision08/02/2024
A variable is a place to store a piece of data. It has a name, a value, and a type. For example,
this statement (called a declaration):

int pin = 13;

creates a variable whose name is pin, whose value is 13, and whose type is int. Later on in the
program, you can refer to this variable by its name, at which point its value will be looked up
and used. For example, in this statement:

pinMode(pin, OUTPUT);

it is the value of pin (13) that will be passed to the pinMode() function. In this case, you don't
actually need to use a variable, this statement would work just as well:

pinMode(13, OUTPUT);

The advantage of a variable in this case is that you only need to specify the actual number of
the pin once, but you can use it lots of times. So if you later decide to change from pin 13 to
pin 12, you only need to change one spot in the code. Also, you can use a descriptive name to
make the significance of the variable clear (e.g. a program controlling an RGB LED might
have variables called redPin, greenPin, and bluePin).

A variable has other advantages over a value like a number. Most importantly, you can
change the value of a variable using an assignment (indicated by an equals sign). For
example:

pin = 12;

will change the value of the variable to 12. Notice that we don't specify the type of the
variable: it's not changed by the assignment. That is, the name of the variable is permanently
associated with a type; only its value changes. [1] Note that you have to declare a variable
before you can assign a value to it. If you include the preceding statement in a program
without the first statement above, you'll get a message like: "error: pin was not declared in
this scope".
When you assign one variable to another, you're making a copy of its value and storing that
copy in the location in memory associated with the other variable. Changing one has no effect
on the other. For example, after:

COPY
int pin = 13;
int pin2 = pin;
pin = 12;
only pin has the value 12; pin2 is still 13.

Now what, you might be wondering, did the word "scope" in that error message above mean?
It refers to the part of your program in which the variable can be used. This is determined by
where you declare it. For example, if you want to be able to use a variable anywhere in your
program, you can declare at the top of your code. This is called a global variable; here's an
example:

COPY

Explain
int pin = 13;
void setup()
{
pinMode(pin, OUTPUT);
}
void loop()
{
digitalWrite(pin, HIGH);
}
As you can see, pin is used in both the setup() and loop() functions. Both functions are
referring to the same variable, so that changing it one will affect the value it has in the other,
as in:

COPY

Explain
int pin = 13;
void setup()
{
pin = 12;
pinMode(pin, OUTPUT);
}
void loop()
{
digitalWrite(pin, HIGH);
}
Here, the digitalWrite() function called from loop() will be passed a value of 12, since that's
the value that was assigned to the variable in the setup() function.

If you only need to use a variable in a single function, you can declare it there, in which case
its scope will be limited to that function. For example:

COPY

Explain
void setup()
{
int pin = 13;
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
}
In this case, the variable pin can only be used inside the setup() function. If you try to do
something like this:

COPY
void loop()
{
digitalWrite(pin, LOW); // wrong: pin is not in scope here.
}
you'll get the same message as before: "error: 'pin' was not declared in this scope". That is,
even though you've declared pin somewhere in your program, you're trying to use it
somewhere outside its scope.

Why, you might be wondering, wouldn't you make all your variables global? After all, if I
don't know where I might need a variable, why should I limit its scope to just one function?
The answer is that it can make it easier to figure out what happens to it. If a variable is global,
its value could be changed anywhere in the code, meaning that you need to understand the
whole program to know what will happen to the variable. For example, if your variable has a
value you didn't expect, it can be much easier to figure out where the value came from if the
variable has a limited scope.

[block scope][size of variables]

[1] In some languages, like Python®, types are associated with values, not variable names,
and you can assign values of any type to a variable. This is referred to as dynamic typing.

Using Functions in a Sketch


Learn how to define and use functions in a Sketch.

Last revision08/02/2024
Segmenting code into functions allows a programmer to create modular pieces of code that
perform a defined task and then return to the area of code from which the function was
"called". The typical case for creating a function is when one needs to perform the same
action multiple times in a program.

For programmers accustomed to using BASIC, functions in Arduino provide (and extend) the
utility of using subroutines (GOSUB in BASIC).

Standardizing code fragments into functions has several advantages:

Functions help the programmer stay organized. Often this helps to conceptualize the program.

Functions codify one action in one place so that the function only has to be thought out and
debugged once.

This also reduces chances for errors in modification, if the code needs to be changed.

Functions make the whole sketch smaller and more compact because sections of code are
reused many times. They make it easier to reuse code in other programs by making it more
modular, and as a nice side effect, using functions also often makes the code more readable.
There are two required functions in an Arduino sketch, setup() and loop(). Other functions
must be created outside the brackets of those two functions. As an example, we will create a
simple function to multiply two numbers.

Example
FuncAnatomy

To "call" our simple multiply function, we pass it parameters of the datatype that it is
expecting:

COPY

Explain
void loop(){
int i = 2;
int j = 3;
int k;

k = myMultiplyFunction(i, j); // k now contains 6


}
Our function needs to be declared outside any other function, so "myMultiplyFunction()" can
go either above or below the "loop()" function.

The entire sketch would then look like this:

COPY

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

void loop() {
int i = 2;
int j = 3;
int k;

k = myMultiplyFunction(i, j); // k now contains 6


Serial.println(k);
delay(500);
}

int myMultiplyFunction(int x, int y){


int result;
result = x * y;
return result;
}
Another example
This function will read a sensor five times with analogRead() and calculate the average of
five readings. It then scales the data to 8 bits (0-255), and inverts it, returning the inverted
result.

COPY
int ReadSens_and_Condition(){
int i;
int sval = 0;
for (i = 0; i < 5; i++){
sval = sval + analogRead(0); // sensor on analog pin 0
}

sval = sval / 5; // average


sval = sval / 4; // scale to 8 bits (0 - 255)
sval = 255 - sval; // invert output
return sval;
}
To call our function we just assign it to a variable.

COPY
int sens;

sens = ReadSens_and_Condition();
As you can see, even if a function does not have parameters and no returns is expected "("
and ")" brackets plus ";" must be given.

Arduino Sketches
Get to know how sketches work, and how they are uploaded to an Arduino.

Last revision08/02/2024
In the getting started guide (Windows, MacOS, Linux), you uploaded a sketch that blinks an
LED. In this tutorial, you'll learn how each part of that sketch works.

A sketch is the name that Arduino uses for a program. It's the unit of code that is uploaded to
and run on an Arduino board.

Comments
The first few lines of the Blink sketch are a comment:

COPY

Explain
/*

* Blink

* The basic Arduino example. Turns on an LED on for one second,

* then off for one second, and so on... We use pin 13 because,

* depending on your Arduino board, it has either a built-in LED

* or a built-in resistor so that you need only an LED.

* http://www.arduino.cc/en/Tutorial/Blink

*/
Everything between the /* and */ is ignored by the Arduino when it runs the sketch (the * at
the start of each line is only there to make the comment look pretty, and isn't required). It's
there for people reading the code: to explain what the program does, how it works, or why it's
written the way it is. It's a good practice to comment your sketches, and to keep the
comments up-to-date when you modify the code. This helps other people to learn from or
modify your code.

There's another style for short, single-line comments. These start with // and continue to the
end of the line. For example, in the line:

COPY
int ledPin = 13; // LED connected to digital pin 13
the message "LED connected to digital pin 13" is a comment.

Variables
A variable is a place for storing a piece of data. It has a name, a type, and a value. For
example, the line from the Blink sketch above declares a variable with the name ledPin, the
type int, and an initial value of 13. It's being used to indicate which Arduino pin the LED is
connected to. Every time the name ledPin appears in the code, its value will be retrieved. In
this case, the person writing the program could have chosen not to bother creating the ledPin
variable and instead have simply written 13 everywhere they needed to specify a pin number.
The advantage of using a variable is that it's easier to move the LED to a different pin: you
only need to edit the one line that assigns the initial value to the variable.

Often, however, the value of a variable will change while the sketch runs. For example, you
could store the value read from an input into a variable. There's more information in the
Variables tutorial.

Functions
A function (otherwise known as a procedure or sub-routine) is a named piece of code that can
be used from elsewhere in a sketch. For example, here's the definition of the setup() function
from the Blink example:

COPY

Explain
void setup()
{

pinMode(ledPin, OUTPUT); // sets the digital pin as output


}
The first line provides information about the function, like its name, "setup". The text before
and after the name specify its return type and parameters: these will be explained later. The
code between the { and } is called the body of the function: what the function does.

You can call a function that's already been defined (either in your sketch or as part of the
Arduino language). For example, the line pinMode(ledPin, OUTPUT); calls the pinMode()
function, passing it two parameters: ledPin and OUTPUT. These parameters are used by the
pinMode() function to decide which pin and mode to set.

pinMode(), digitalWrite(), and delay()


The pinMode() function configures a pin as either an input or an output. To use it, you pass it
the number of the pin to configure and the constant INPUT or OUTPUT. When configured as
an input, a pin can detect the state of a sensor like a pushbutton; this is discussed in the
Digital Read Serial tutorial. As an output, it can drive an actuator like an LED.
The digitalWrite() functions outputs a value on a pin. For example, the line:

COPY
digitalWrite(ledPin, HIGH);
set the ledPin (pin 13) to HIGH, or 5 volts. Writing a LOW to pin connects it to ground, or 0
volts.

The delay() causes the Arduino to wait for the specified number of milliseconds before
continuing on to the next line. There are 1000 milliseconds in a second, so the line:

COPY
delay(1000);
creates a delay of one second.

setup() and loop()


There are two special functions that are a part of every Arduino sketch: setup() and loop().
The setup() is called once, when the sketch starts. It's a good place to do setup tasks like
setting pin modes or initializing libraries. The loop() function is called over and over and is
heart of most sketches. You need to include both functions in your sketch, even if you don't
need them for anything.

Exercises
1. Change the code so that the LED is on for 100 milliseconds and off for 1000.

2. Change the code so that the LED turns on when the sketch starts and stays on.

See Also
setup()
loop()
pinMode()
digitalWrite()
delay()

FPGA HDL Basics


Learn the basics of Field Programmable Gate Arrays (FPGA) and HDL.

Last revision08/02/2024
Hardware Required
MKR Vidor 4000
Field Programmable Gate Arrays
Field Programmable Gate Arrays, in short FPGAs are a relatively old way of creating custom
hardware eliminating the costs associated with silicon foundries. Unfortunately most of the
complexity of chip design are still there and this is the reason why most people prefers to use
off the shelf chips, often accepting their limitations, rather than take the challenge to have an
optimized, efficient design with exactly the hardware they need.

As it happens with Software, where there are lots of libraries you can start from, also for
FPGAs there are "libraries" called IP blocks, however these are usually quite expensive and
lack a standardized "plug and play" interface which causes headaches when integrating
everything in a system. What Arduino is trying to do introducing FPGAs in its product line is
to take advantage of the flexibility of programmable hardware specifically to provide an
extendable set of peripherals for microcontrollers taking away most of the complexity. Of
course to achieve this it's necessary to impose some limitations and define a standard way to
interconnect blocks so that it can be done automatically.
The first step is defining a set of standard interfaces that must be strictly responding to a
given set of rules but before diving into this it's important to define which kind of interfaces
we may need. Since we are interfacing with a microcontroller the first port we need to define
is a bus to interconnect processor with peripherals. Such bus should at least exist in the
controller and peripheral flavors where signals are the same but with inverted directions. For
some additional details on buses and controller/peripheral architecture please check this
document.

A second interface, which is important but can't be standardized is the input/output signals
that connect to the external world. Here we can't define a standard as each block will provide
its own set of signals however we can just bundle a set of signals in a group which we'll call a
conduit.

Finally there is a third class of interfaces which may become useful which carries streaming
data. In this case we want to transfer a continuous stream of data but also want to be able to
pause the flow if the receiving block is not able to process it, hence along with data we also
need some kind of flow control signals pretty much like it happens on a UART.

Since we want to standardize a bit also on readability we also want to set some coding
conventions. Here of course there are many different religions which rule on spaces/tabs,
notation and so on so we're picking one we like...

Talking about religion we end up talking also about languages... we prefer (System)Verilog
over VHDL and most of our IP blocks are coded with it. The reason of our choice is that
Verilog in general is more similar to C and also allows very nice constructs that facilitate
creating parametric blocks.

Coding Conventions
We use a prefix in front of every declared entity so that it identifies its type, variable name is
completely upper case and multiple words are separated by underscores. In particular:
Prefix Description
w Wire, for all combinatorial signals, for example wDATA. Typically defined with wire
directive
r Reg, for all sequential signals, for example rSHIFTER. Typically defined with reg
directive
i Input, for all input signals in module declaration, for example iCLK. Typically
defined with input directive
o Output, for all output signals in module declaration, for example oREAD. Typically
defined with output directive
b Bidirectional, for all inout signals in module declaration, for example bSDA.
Typically defined with inout directive
p Parameter, for all parameters that can be used to parametrize block, for example
pCHANNELS. Typically defined with param directive
c Constant, for all definitions which are constant or are derived values and can't be
directly used to parametrize the block. For example cCHANNEL_BITS. Typically defined
with localparam directive
e Enumerated, for all the possible constant values used by one or more signals or
registers. For example a state machine state can be defined as eSTATE. Typically defined
with enum directive
We prefer spaces over tabs! The reason is that regardless of the tab size code always looks
good.

Indentation is set to two spaces.


Conditional statement blocks shall always have begin/end constructs even if they have a
single statement in them and begin/end should be on the same line of the if/else

Signals belonging to the same group shall share a common prefix

Interface prototypes
Lightweight Bus
A bus to interconnect peripherals. By convention data bus is 32 bits while address bus is
variable width, based on the number of registers being exposed. A bus requires the following
set of signals:

Signal Direction Direction Width Description


Controller Peripheral
ADDRESS O I var. Register address, width determines
READ O I 1 Read strobe
READ_DATA I O 32 Data being read
WRITE O I 1 Write strobe
WRITE_DATA O I 32 Data to write at a given address
BYTE_ENABLE O I 4 Optional signal to flag which bytes of the 32 bit
word are actually going to be written
WAIT_REQUEST I O 1 Optional signal to flag the peripheral is busy.
Read and write strobes will be considered valid only if this signal is not asserted.
By convention in a write cycle ADDRESS and WRITE_DATA are latched in the same clock
cycle of the WRITE strobe By contrast, in a read cycle READ_DATA is presented by
peripheral on the cycle immediately following the READ strobe, which will also indicate the
ADDRESS being read.

Pipelined Bus
A bus to interconnect complex blocks that can handle more than one command at time and
responds in variable time to requests. This bus extends the Lightweight bus by adding the
following signals:

This behavior is also referred as 1 clock read latency and basically means that while
peripheral can still have a variable number of clocks to respond to a READ or WRITE
operation using the optional WAIT_REQUEST signal, this would lock the controller
preventing it to perform other operations. In a way this can be considered similar to using
busy loops in programming versus delays which yield to OS in order to do multitasking.

Signal Direction Direction Width Description


Controller Peripheral
BURST_COUNT O I var. Number of sequential operations to perform
READ_DATAVALID I O 1 Peripheral uses this signal to flag when
data is being provided to controller. Can be asserted with any delay and there is no guarantee
on contiunity. A read operation with a burst size of 4 will assert 4 times
READ_DATAVALID per each READ strobe
The main advantage of this approach is that controller can communicate to the peripheral the
intention of reading or writing multiple data for each transaction. Both for read and write
strobes in fact the BURST_COUNT signal tells peripheral how long the transaction will be.

The controller will assert WAIT_REQUEST until it is ready to accept an operation. In case of
writes, BURST_COUNT and ADDRESS are sampled only on the first strobe, after which
peripheral will expect the WRITE strobe to be asserted for the number of words requested
and will automatically increment address. For read operations a single READ strobe,
performed when WAIT_REQUEST is not asserted, will tell the peripheral to read
BURST_COUNT words that will be returned by asserting READ_DATAVALID for the
requested number of words. After a read operation has been initiated it's up to the peripheral
to accept or not more operations but in general it should be possible to have at least two
concurrent operations to benefit from the Pipelined Bus.

Streaming interface
Coming soon

Structure of a (System)Verilog module


A SystemVerilog module declaration can be done in several ways but the one we mostly
prefer is the form where you can use parameters so that the block inputs can be customized at
compile time. This would look like:

COPY

Explain
module COUNTER #(
pWIDTH=8
)(
input iCLK,
input iRESET,
output reg [pWIDTH-1:0] oCOUNTER
);
endmodule
Here we just defined the prototype of the module and defined its input/output ports, now we
have to add some useful logic to it by adding some code between module header and the
endmodule statement.

Since we started with a counter example let's continue with that and write some code that
actually implements it:

COPY

Explain
module COUNTER #(
pWIDTH=8
)(
input iCLK,
input iRESET,
output [pWIDTH-1:0] oCOUNTER
);
always @(posedge iCLK)
begin
if (iRESET) begin
oCOUNTER<=0;
end else begin
oCOUNTER<= oCOUNTER+1;
end
end
endmodule
The code above is pretty self explanatory... at every positive clock edge, if we see input
iRESET high we reset the counter, otherwise we increment it by one... note that having a
reset signal restoring our block to a known state is often useful but not always necessary.

Now... this is interesting however we did something a bit tricky... we declared oCOUNTER
as output reg, which means we are saying this is not just a bunch of wires but it has memory.
This way we can use the <= assignment which is "registered" which means that the
assignment will be kept for as long as the next clock cycle.

Another way we could do this is removing the reg statement in the module declaration and
define the counter as follows:

COPY

Explain
module COUNTER #(
pWIDTH=8
)(
input iCLK,
input iRESET,
output [pWIDTH-1:0] oCOUNTER
);
reg [pWIDTH-1:0] rCOUNTER;
always @(posedge iCLK)
begin
if (iRESET) begin
rCOUNTER<=0;
end else begin
rCOUNTER<= rCOUNTER+1;
end
end
assign oCOUNTER=rCOUNTER;
endmodule
This is basically the same stuff but we defined a register, worked on it and then assigned with
the "continuous" = assignment it to the output signal. The differsence here is that while <=
means the signal changes only at clock edges = assigns the value continuously so the signal
will eventually change at any time, however if we assign it as we are doing in the example to
a register that changes only on clock edges the resulting signal is basically just an alias.

Interestingly assignments, like any other statement in hardware description languages are
parallel, which means that their order in the code is not so much relevant as they are all
executed in parallel so we could have assigned oCOUNTER to rCOUNTER also before the
always block. We'll come back to this as it's not completely true that order doesn't matter...

Another interesting use of continuous assignments is the possibility to create logic equations.
For example we could rewrite the counter the following way:

COPY

Explain
module COUNTER #(
pWIDTH=8
)(
input iCLK,
input iRESET,
output [pWIDTH-1:0] oCOUNTER
);
reg [pWIDTH-1:0] rCOUNTER;
wire [pWIDTH-1:0] wNEXT_COUNTER;
assign wNEXT_COUNTER = rCOUNTER+1;
assign oCOUNTER = rCOUNTER;
always @(posedge iCLK)
begin
if (iRESET) begin
rCOUNTER<=0;
end else begin
rCOUNTER<= wNEXT_COUNTER;
end
end
endmodule
We're basically still doing the same stuff but we have done it in a way that makes it a bit
more clear logically. Basically we are assigning continuously the signal wNEXT_COUNTER
to the value of the rCOUNTER plus one. This means that wNEXT_COUNTER will (almost)
immediately change as soon as rCOUNTER changes value however rCOUNTER will be
updated only on the next positive clock edge (as it has a <= assignment) so the result is still
that rCOUNTER changes only on clock edge.

Parallelism and precedence


As we wrote in the previous chapter all hardware description languages have the concept of
parallel statements which means that as opposed to software programming languages which
execute instructions sequentially, here all instructions are executed at the same time. For
example if we write a block which has the code below we will see registers changing together
at a given clock edge:

COPY

Explain
reg [pWIDTH-1:0] rCOUNT_UP, rCOUNT_DOWN;
always @(posedge iCLK)
begin
if (iRESET) begin
rCOUNT_UP<=0;
rCOUNT_DOWN<=0;
end else begin
rCOUNT_UP<= rCOUNT_UP+1;
rCOUNT_DOWN<= rCOUNT_DOWN-1;
end
end
Of course if everything gets executed in parallel we need to have a way to sequentialize
statements which can be done by creating a simple state machine. A state machine is a system
which generates outputs based on inputs AND its internal state. In a sense our counter was
already a state machine as we have an output (oCOUNTER) that changes based on the
previous state of the machine (rCOUNTER), however let's do something more interesting and
create a state machine that creates a pulse of a given length when we start it. The machine
will have three states: eST_IDLE, eST_PULSE_HIGH and eST_PULSE_LOW. In the
eST_IDLE we will sample the input command and when that is received we transition to
eST_PULSE_HIGH, where we will stay for the given number of clocks, which we'll
parametrize with pHIGH_COUNT, then we will transition to eST_PULSE_LOW where we'll
stay for pLOW_COUNT and then get back to eST_IDLE... Let's have a look at how this turns
out in code:

COPY

Explain
module PULSE_GEN #(
pWIDTH=8,
pHIGH_COUNT=240,
pLOW_COUNT=40
)(
input iCLK,
input iRESET,
input iPULSE_REQ,
output reg oPULSE
);
reg [pWIDTH-1:0] rCOUNTER;
enum reg [1:0] {
eST_IDLE,
eST_PULSE_HIGH,
eST_PULSE_LOW
} rSTATE;
always @(posedge iCLK)
begin
if (iRESET) begin
rSTATE<=eST_IDLE;
end else begin
case (rSTATE)
eST_IDLE: begin
if (iPULSE_REQ) begin
rSTATE<= eST_PULSE_HIGH;
oPULSE<= 1;
rCOUNTER <= pHIGH_COUNT-1;
end
end
eST_PULSE_HIGH: begin
rCOUNTER<= rCOUNTER-1;
if (rCOUNTER==0) begin
rSTATE<= eST_PULSE_LOW;
oPULSE<= 0;
rCOUNTER<= pLOW_COUNT-1;
end
end
eST_PULSE_LOW: begin
rCOUNTER<= rCOUNTER-1;
if (rCOUNTER==0) begin
rSTATE<= eST_IDLE;
end
end
endcase
end
end
endmodule
Here we see a number of new things we need to talk about. First of all we are defining the
rSTATE variable using enum. This helps in assigning the state to easily understandable
values rather than hard-coded numbers and has the advantage that you can insert states easily
without the need to rewrite all your state machine.

Secondly we are introducing the case/endcase block which allows us to define different
behaviours depending on the state of a signal. The syntax is very similar to C so it should be
familiar to most readers. It's important to note that the statements within the various case
blocks will still execute in parallel but since they are conditioned by different values of the
variable being examined only one at time will be enabled. Looking at the eST_IDLE case we
see that we stay in the state forever until we sense iPULSE_REQ goes high, in which case we
change state, reset the counter to the period of the high state and start outputting the pulse.

Note that since oPULSE is registered it will retain its state until it's assigned again. In the
next state things get a bit more complicated... at each clock we decrement the counter, then if
counter reaches 0 we also change state, change oPULSE to 0 AND we assign rCOUNTER
again. Since the two assignments are executed in parallel we need to know what this means
and lucky enough all HDL mandate that if two parallel statements are executed on the same
register only the last one will be really executed so the meaning of what we just wrote is that
normally we decrement the counter but when counter reaches 0 we change state and re-
initialize it to pLOW_COUNT.

At this point what happens in eST_PULSE_LOW becomes pretty clear as we just decrement
the counter and get back to eST_IDLE as soon as it reaches 0. Note that when we get back to
eST_IDLE rCOUNTER is decremented again so the result is that rCOUNTER will be 0xff
(or -1) in eST_IDLE but we don't really care as we will reset it to the proper value when we
receive iPULSE_REQ.

Although we could have reset rCOUNTER also when exiting eST_PULSE_LOW, in HDL
it's always better to do only what's really necessary as anything more will consume resources
and make our hardware slower. At the beginning this may seem dangerous but with some
experience it will become easy to see how this can help. This same concept applies to reset
logic. Unless it is really necessary, depending on how it is implemented it can consume
resources and worsen system speed so it should be used with care.

A real world example


Now let's dive in a real world example of a simple peripheral we use in Vidor, the PWM.
What we wanted to achieve is creating a small block with multiple PWM outputs with the
possibility to define the relative phase of each PWM channel.

In order to do so we need a counter and several comparators that tells us when the counter is
above given values so that we can toggle the outputs. Since we also want to have the PWM
frequency to be programmable we need to have the counter running at a frequency different
than the base one we use for our system so that its period is exactly what we need. In order to
do so we use a prescaler which basically is another counter that divides the base clock down
to a lower value in a way similar to baud rate generators used in UARTs.

Now let's look at the code:

COPY

Explain
module PWM #(
parameter pCHANNELS=16,
parameter pPRESCALER_BITS=32,
parameter pMATCH_BITS=32
)
(
input iCLK,
input iRESET,
input [$clog2(2*pCHANNELS+2)-1:0] iADDRESS,
input [31:0] iWRITE_DATA,
input iWRITE,
output reg [pCHANNELS-1:0] oPWM
);
// register declaration
reg [pPRESCALER_BITS-1:0] rPRESCALER_CNT;
reg [pPRESCALER_BITS-1:0] rPRESCALER_MAX;
reg [pMATCH_BITS-1:0] rPERIOD_CNT;
reg [pMATCH_BITS-1:0] rPERIOD_MAX;
reg [pMATCH_BITS-1:0] rMATCH_H [pCHANNELS-1:0];
reg [pMATCH_BITS-1:0] rMATCH_L [pCHANNELS-1:0];
reg rTICK;
integer i;
always @(posedge iCLK)
begin
// logic to interface with bus.
// register map is as follows:
// 0: prescaler value
// 1: PWM period
// even registers >=2: value at which PWM output is set high
// odd registers >=2: value at which PWM output is set low
if (iWRITE) begin
// the following statement is executed only if address is >=2. case on iADDRESS[0]
// selects if address is odd (iADDRESS[0]=1) or even (iADDRESS[0]=0)
if (iADDRESS>=2) case (iADDRESS[0])
0: rMATCH_H[iADDRESS[CLogB2(pCHANNELS):1]-1]<= iWRITE_DATA;
1: rMATCH_L[iADDRESS[CLogB2(pCHANNELS):1]-1]<= iWRITE_DATA;
endcase
else begin
// we get here if iADDRESS<2
case (iADDRESS[0])
0: rPRESCALER_MAX<=iWRITE_DATA;
1: rPERIOD_MAX<=iWRITE_DATA;
endcase
end
end
// prescaler is always incrementing
rPRESCALER_CNT<=rPRESCALER_CNT+1;
rTICK<=0;
if (rPRESCALER_CNT>= rPRESCALER_MAX) begin
// if prescaler is equal or greater than the max value
// we reset it and set the tick flag which will trigger the rest of the logic
// note that tick lasts only one clock cycle as it is reset by the rTICK<= 0 above
rPRESCALER_CNT<=0;
rTICK <=1;
end
if (rTICK) begin
// we get here each time rPRESCALER_CNT is reset. from here we increment the PWM
// counter which is then clocked at a lower frequency.
rPERIOD_CNT<=rPERIOD_CNT+1;
if (rPERIOD_CNT>=rPERIOD_MAX) begin
// and of course we reset the counter when we reach the max period.
rPERIOD_CNT<=0;
end
end
// this block implements the parallel comparators that actually generate the PWM outputs
// the for loop actually generates an array of logic that compares the counter with
// the high and low match values for each channel and set the output accordingly.
for (i=0;i<pCHANNELS;i=i+1) begin
if (rMATCH_H[i]==rPERIOD_CNT)
oPWM[i] <=1;
if (rMATCH_L[i]==rPERIOD_CNT)
oPWM[i] <=0;
end
end
endmodule
There are a number of new things here to learn so let's start from the module declaration.
Here we are using a built in function to establish the required bit width of the address bus.
The purpose is to limit the address span to the minimum required for the registers so for
example if we want 10 channels we need a total of 22 addresses. Since each address bit
doubles the number of addresses we can use we need a total of 5 bits which result in 32 total
addresses. In order to make this parametric we define iADDRESS width as
$clog2(2*pCHANNELS+2) and we define registers as a 2 dimensional array.

Actually there are two ways to make a multidimensional array and here we are using the
"unpacked" one, which basically defines the registers as separate entities by adding indices
on the left side of the register declaration. The other way, we are not using in this example is
the "packed" one in which indices are both on the left side of the declaration and the result is
that the 2D array can also be seen as a single big register containing the concatenation of all
the registers.

Another interesting trick here is how we define the logic that handles registers. First of all we
are just implementing write only registers so you won't find the iREAD and iREAD_DATA
signals Secondly we wanted to have a parametric register set where only the first two
registers are always present whereas the rest are dynamically defined and handled based on
the number of channels we want to implement. In order to do so we note that in a binary
number the least significant bit defines whether the number is odd or even. Since we have
two registers per channel this comes handy as we can differentiate our behaviour depending
on whether we are below address 2 or not.

If we are below address 2 we implement the common registers which are the prescaler count
and the counter period. If we are above 2 we use the LSB to decide if we are writing the
value for the high or low comparator.

Another simple example


Another simple example we can learn something from is the quadrature encoder. While it
may seem simpler than the PWM it also addresses some challenges which are not trivial. The
first issue we encounter dealing with signals from external world is that we have no guarantee
they are synchronous with our internal clock so we may encounter a phenomenon called
metastability which causes data in registers to be undefined and to potentially change during
a clock cycle. The reason for this is that if data is changing at the input of the register while
we are latching it register may get into an unstable state which may "decay" to either 1 or 0 at
any time. For this reason we need to resynchronize the input signal by adding a chain of
registers so that even if the first register goes metastable the following will have a stable state
that can feed subsequent logic without the risk of having all the logic "contaminated" by the
unstable state.

Another interesting thing we're doing here is that we are using continuous assignment to
determine a strobe and a direction from the quadrature signals out of the encoder. In the code
there are simple graphs showing how the waveforms look like, although in order to fully
understand how the waveforms come out you have to consider that the equations use signals
at different points in time. This is done by simply using the shift register used to synchronize
asynchronous inputs also to delay them so tapping into a different point of the shift register
we can see how signal was the clock before. In particular, if we move towards the input of the
shift register we get "newer" data whereas if we move towards the end we get "older" data. If
we look at the equations we see we are using the ^ operator which is a logical exclusive or
(XOR) which returns 1 if the two operands are different and 0 otherwise.

Looking at the waveforms we see that the strobe generates a pulse whenever A or B have an
edge and this is done by simply xoring each signal with its delayed version. The direction
signal instead is a bit more complex but we notice that it is constantly either 0 or 1 when the
strobe signal is high depending on the direction the encoder is rotating. Actually we see there
are pulses on the direction signal but these are not coincident with strobes so those will be
ignored.

One thing that may not look obvious at first look is that the equations are parallelly
calculating the same logic for all the inputs, in fact the rRESYNC_ENCODER registers are
packed bidimensional arrays arranged so that the first index identifies the tap of the shift
register and the second index is the encoder channel. This means that whenever we reference
rRESYNC_ENCODER with a specific index we are selecting a mono-dimensional array
containing all the encoder inputs at once delayed by the amount of clocks specified by the
index. This also means that when we perform a bitwise logic operation on an array we are
actually instantiating multiple parallel logic equations at the same time. Note that this can be
done only because the array is "packed" as with "unpacked" arrays elements are considered
separate and can't take part in equations this way and they have to be addressed singularly.

As we did for the other examples the block implements multiple inputs and does this by using
a for loop that checks for the enable signal (which again is an array as wide as the number of
channels) and when that is high it checks for the direction and based on that either increments
or decrements the counter for that channel. This is easily done using the ? : operator
(conditional expression) which works exactly like in C.

Finally the bus interface is pretty simple because the only registers we have are the read only
counters and we can implement this simply by checking the read signal and assigning output
data with the array of counters indexed by the address, pretty much like it was a RAM.

COPY

Explain
module QUAD_ENCODER #(
pENCODERS=2,
pENCODER_PRECISION=32
)(
input iCLK,
input iRESET,
// AVALON PERIPHERAL INTERFACE
input [$clog2(pENCODERS)-1:0] iAVL_ADDRESS,
input iAVL_READ,
output reg [31:0] oAVL_READ_DATA,
// ENCODER INPUTS
input [pENCODERS-1:0] iENCODER_A,
input [pENCODERS-1:0] iENCODER_B
);
// bidimensional arrays containing encoder input states at 4 different points in time
// the first two delay taps are used to synchronize inputs with the internal clocks
// while the other two are used to compare two points in time of those signals.
reg [3:0][pENCODERS-1:0] rRESYNC_ENCODER_A,rRESYNC_ENCODER_B;
// bidimensional arrays containing the counters for each channel
reg [pENCODERS-1:0][pENCODER_PRECISION-1:0] rSTEPS;
// encoder decrementing
// A __----____----__
// B ____----____----
// ENABLE __-_-_-_-_-_-_-_
// DIR __---_---_---_--
//
// encoder incrementing
// A ____----____----
// B __----____----__
// ENABLE __-_-_-_-_-_-_-_
// DIR ___-___-___-___-
wire [pENCODERS-1:0] wENABLE =
rRESYNC_ENCODER_A[2]^rRESYNC_ENCODER_A[3]^rRESYNC_ENCODER_B[2]^r
RESYNC_ENCODER_B[3];
wire [pENCODERS-1:0] wDIRECTION =
rRESYNC_ENCODER_A[2]^rRESYNC_ENCODER_B[3];
integer i;
initial rSTEPS <=0;
always @(posedge iCLK)
begin
if (iRESET) begin
rSTEPS<=0;
rRESYNC_ENCODER_A<=0;
rRESYNC_ENCODER_B<=0;
end
else begin
// implement shift registers for each channel. since arrays are packed we can treat that as a
monodimensional array
// and by adding inputs at the bottom we are effectively shifting data by one bit
rRESYNC_ENCODER_A<={rRESYNC_ENCODER_A,iENCODER_A};
rRESYNC_ENCODER_B<={rRESYNC_ENCODER_B,iENCODER_B};
for (i=0;i<pENCODERS;i=i+1)
begin
// if strobe is high..
if (wENABLE[i])
// increment or decrement based on direction
rSTEPS[i] <= rSTEPS[i]+ ((wDIRECTION[i]) ? 1 : -1);
end
// if PERIPHERAL interface is being read...
if (iAVL_READ)
begin
// return the value of the counter indexed by the address
oAVL_READ_DATA<= rSTEPS[iAVL_ADDRESS];
end
end
end
endmodule
This is probably a great example of how elegant and concise can be hardware description for
such design as we described an highly parametric design where we can change counter depth
and number of channels and the code scales up accordingly generating all the related logic in
a very readable way. Of course there are different ways of doing the same thing and this one
of the most concise that at the same time requires a bit more understanding of the capabilities
of (system)Verilog.

Arduino Memory Guide


Learn about the built-in memory blocks of Arduino® boards in this article.

AuthorArduino, José Bagur, Taddy Chung


Last revision08/02/2024
A microcontroller unit (also known as an MCU) is an integrated circuit (IC), typically used to
perform specific applications or tasks. Usually, this type of IC gathers information or data
from its surroundings, processes it, and generates specific outputs according to the gathered
data. Microcontrollers today are everywhere; they are an essential part of modern embedded
systems that can be found practically everywhere in our world, from smart watches to electric
vehicles; they are even on the Martian surface right now.

One essential part of a microcontroller is its memory; memory stores information temporarily
or permanently in microcontrollers, and can be used for several purposes. In this article, we
will explore memory organization in microcontrollers, focusing on those present in Arduino®
boards. We will also explore several ways to manage, measure, and optimize memory usage
in Arduino-based systems.

What is Memory?
Memory blocks are essential parts of modern embedded systems, especially microcontroller-
based ones. Memory blocks are semiconductor devices that store and retrieve information or
data; a microcontroller central processing unit (CPU) uses and processes data stored in
memory blocks to perform specific tasks.

As shown in the image below, memory blocks in microcontrollers are usually described as
arrays. Memory arrays are divided into cells that can store data and be accessed using a
unique identifier representing its address or position relative to the memory array.
Information in memory cells is stored using binary digits (bits), usually organized in bytes (8-
bits); it can also be retrieved later by the MCU or other components of a microcontroller-
based system.

Memory in computing systems can be volatile or non-volatile. Volatile memory is a


temporary memory, this means that data is stored while the system is running, but it is lost
forever when the system is turned off. Non-volatile memory is permanent memory; data is
not lost even if the system is turned off.

Memory Architectures 101


Computer architecture is a vast topic; we will focus on a general picture that will let us
understand how memory is organized in the microcontrollers used in Arduino® boards.

In the early days of computing, two computer architectures, i.e., the organization of the
components inside a computing system, emerged: von Neumann and Harvard.

Von Neumann Architecture


The von Neumann architecture, named after the mathematician, physicist, and computer
scientist John von Neumann, was first introduced in the mid '40s. It is also known as the
Princeton architecture. This architecture stores program data and instructions in the same
memory unit.

Von Neumann architecture.


Von Neumann architecture.

Both are accessed by the CPU using the same communications bus, as shown below. Von
Neumann's architecture is fundamental since nearly all digital computers design have been
based on this architecture.
Harvard Architecture
The Harvard architecture, named after the Harvard Mark I relay-based computer, was first
introduced in the mid '40s. This architecture's main characteristic is that it uses two separate
memory units, one for storing program instructions and one for storing program data. Both
memory units in the Harvard architecture are accessed by the CPU using different
communication buses.

Harvard architecture.
Harvard architecture.

Modern Architectures: Hybrids


Modern computing systems use hybrid architectures models that maximize performance
using the best of both worlds, the von Neumann and the Harvard models.

Microcontrollers are usually used in embedded applications. They must perform defined tasks
reliably and efficiently, with low or constrained resources; this is why the Harvard
architecture model is mainly used in microcontrollers: microcontrollers have a small program
and data memory that needs to be accessed simultaneously. However, Harvard architecture is
not always used in microcontrollers; some microcontroller families use hybrid or Von
Neumann architecture models.

Arduino® Boards Architectures


Arduino® boards are mainly based on two families of microcontrollers: AVR® and ARM®.
While AVR® family microcontrollers are based on the Harvard architecture model, ARM®
family microcontrollers can be based on either von Neuman or Harvard architectures models.
The following table summarizes Arduino boards microcontrollers architectures:

Board Microcontroller Family Architecture


UNO Mini ATmega328P AVR Harvard
UNO Rev3 ATmega328P AVR Harvard
UNO WiFi Rev2 ATmega4809 AVR Harvard
UNO Rev3 SMD ATmega328P AVR Harvard
Leonardo ATmega32u4 AVR Harvard
Mega 2560 Rev3 ATmega2560 AVR Harvard
Micro ATmega32u4 AVR Harvard
Zero ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
Portenta H7 STM32H747 Arm® Cortex®-M4/M7 Harvard
Nicla Sense ME nRF52832 Arm® Cortex®-M4 Harvard
Nano RP2040 Connect RP2040 Arm® Cortex®-M0+ Von Neumann
MKR FOX 1200 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
MKR NB 1500 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
MKR Vidor 4000 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
MKR WiFi 1010 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
MKR Zero ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
MKR1000 WIFI ATSAMW25H18 Arm® Cortex®-M0+ Von Neumann
MKR WAN 1300 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
MKR WAN 1310 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
Nano ATmega328P AVR Harvard
Nano Every ATmega4809 AVR Harvard
Nano 33 IoT ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann
Nano 33 BLE nRF52840 Arm® Cortex®-M4 Harvard
Nano 33 BLE Sense nRF52840 Arm® Cortex®-M4 Harvard
Memory Types
All the different memory units inside a microcontroller can be divided into two main types:
RAM and ROM. RAM (from Random-Access Memory) in microcontroller-based systems is
a volatile memory used to store temporary data such as the system's firmware variables.
ROM (from Read-Only Memory) in microcontroller-based systems is non-volatile memory
used to store permanent data such as the system's firmware.

RAM and ROM in microcontroller-based systems are organized into three main categories:

Flash
RAM
EEPROM
Flash
Flash memory in microcontroller-based systems is part of its ROM. The flash memory is
where the system's firmware is stored to be executed. For example, think of the famous
Blink.ino sketch: when we compile this sketch, we create a binary file that is later stored in
the flash memory of an Arduino board. The sketch is then executed when the board is
powered on.

RAM
RAM in microcontroller-based systems is where the system's temporary data or run-time data
is stored; for example, the variables created by functions of a program. RAM in
microcontrollers usually is SRAM; this is a type of RAM that uses a flip-flop to store one bit
of data. There is also another type of RAM that can be found in microcontrollers: DRAM.

EEPROM
In microcontroller-based systems, Erasable Programmable Read-Only Memory, or
EEPROM, is also part of its ROM; actually, Flash memory is a type of EEPROM. The main
difference between Flash memory and EEPROM is how they are managed; EEPROM can be
managed at the byte level (write or erased) while Flash can be managed at the block level.

Arduino® Boards Memory Allocation


As stated before, Arduino® boards are mainly based on two families of microcontrollers,
AVR® and ARM®; it is important to know that memory allocation differs in both
architectures. In Harvard-based AVR architecture, memory is organized as shown in the
image below:

AVR memory map.


AVR memory map.

Important to mention about AVR-based Arduino boards is how their SRAM is organized into
different sections:

Text
Data
BSS
Stack
Heap
The text section contains instructions loaded into the flash memory; data section contains
variables initialized in the sketch, BSS section contains uninitialized data, stack section stores
data of functions and interrupts, and heap section stores variables created during run time.

In hybrid ARM architectures, a so called memory map is implemented, with a different


address map configuration of 32-bit, 36-bit, and 40-bit that depends on the requirement of
System On a Chip (SoC) address space with extra DRAM. The Memory Map grants interface
with SoC design, while having most system control on a high level coding. Memory access
instructions can be used on high level code to manage interrupt modules and built-in
peripherals. All of this controlled by Memory Management Unit (MMU).
The memory resource is handled by the MMU. The main role of the MMU is to enable the
processor to run multiple tasks independently in its own virtual memory space; the MMU
then uses translation tables to establish a bridge between the virtual and the physical memory
addresses. Virtual Address is managed via software with memory instructions, and Physical
address is the memory system that is controlled depending on the Translation Table input
given by the Virtual Address.

An example of how memory is organized in ARM-based microcontrollers, virtually and


physically, is shown in the image below:

Memory organization in ARM-based microcontrollers.


Memory organization in ARM-based microcontrollers.

The ARM-based microcontroller's memory is organized into the following sections within the
address type mentioned previously:

Virtual address:

Kernel code and data


Application code and data
Physical address:

ROM
RAM
Flash
Peripherals
The following table summarizes a specific Arduino® board's memory allocation:

Board Microcontroller Family Architecture Flash SRAM EEPROM


UNO Mini ATmega328P AVR Harvard 32kB 2kB 1kB
UNO Rev3 ATmega328P AVR Harvard 32kB 2kB 1kB
UNO WiFi Rev2 ATmega4809 AVR Harvard 48kB 6kB 256B
UNO Rev3 SMD ATmega328P AVR Harvard 32kB 2kB 1kB
Leonardo ATmega32u4 AVR Harvard 32kB 2.5kB 1kB
Mega 2560 Rev3 ATmega2560 AVR Harvard 256kB 8kB 4kB
Micro ATmega32u4 AVR Harvard 32kB 2.5kB 1kB
Zero ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB 32kB -
Portenta H7 (basic configuration) STM32H747 Arm® Cortex®-M4/M7 Harvard
16MB 8MB -
Nicla Sense ME nRF52832 Arm® Cortex®-M4 Harvard 512kB 64kB -
Nano RP2040 Connect RP2040 Arm® Cortex®-M0+ Von Neumann -
264kB -
MKR FOX 1200 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB
32kB -
MKR NB 1500 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB
32kB -
MKR Vidor 4000 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB
32kB -
MKR WiFi 1010 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB
32kB -
MKR Zero ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB 32kB -
MKR1000 WIFI ATSAMW25H18 Arm® Cortex®-M0+ Von Neumann 256kB
32kB -
MKR WAN 1300 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB
32kB -
MKR WAN 1310 ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB
32kB -
Nano ATmega328P AVR Harvard 32kB 2kB 1kB
Nano Every ATmega4809 AVR Harvard 48kB 6kB 256B
Nano 33 IoT ATSAMD21G18 Arm® Cortex®-M0+ Von Neumann 256kB 32kB -
Nano 33 BLE nRF52840 Arm® Cortex®-M4 Harvard 1MB 256kB -
Nano 33 BLE Sense nRF52840 Arm® Cortex®-M4 Harvard 1MB 256kB -
Pro hardware SDRAM and Flash memory are highly customizable in volumes. Check out the
Pro site for more information.

Measuring Memory Usage in Arduino® Boards


Memory usage statistics help comprehend the insight of resource management affected by the
designed code structure. Memory load demand is one statistic that will give you an insight
into how efficient the code is designed. It is a crucial development consideration element
because the resources are finite inside a microcontroller-based system; software should
always perform without reaching maximum load capacity to avoid problems or issues.
Memory load could be observed either as available RAM at disposal for specific tasks or
flash storage remaining capacity for required headroom.

To avoid run-time problems, microcontroller-based systems should always run without


reaching their maximum memory capacity.

Let us talk more about memory usage measurement in Arduino® boards.

Flash Memory Measurement


Flash memory on Arduino® boards can be measured with the help of the Arduino IDE. As
stated before, Flash memory is where the application code is stored; the Arduino IDE reports
Flash memory usage through its compiler output console to let developers know how much
Flash memory resources are being used.

For example, the IDE's compiler output console an AVR-based Arduino® board, the Nano, is
shown in the image below:

Flash memory memory measurement in an AVR-based Arduino® board


Flash memory memory measurement in an AVR-based Arduino® board

The IDE's compiler output console log for an ARM-based Arduino® board, the MKR WAN
1310, is shown in the image below:

Flash memory memory measurement in an ARM-based Arduino® board


Flash memory memory measurement in an ARM-based Arduino® board

The IDE's compiler output console log for another ARM-based Arduino®, the Portenta H7, is
shown in the image below:

Flash memory memory measurement in an ARM-based Arduino® board


Flash memory memory measurement in an ARM-based Arduino® board

Notice that the compiler's output changes depending on if the board is AVR-based or ARM-
based.

SRAM Memory Measurement


Sometimes, there are situations where even when code is compiled and uploaded successfully
by the IDE into a board, it suffers from sudden halts. These issues are likely due to memory
resource-hogging or insufficient memory to allocate. It is necessary to understand which code
sector the memory demand is going beyond the available resources to solve this. The
following example code can be used to measure SRAM usage in AVR-based Arduino®
boards:

COPY

Explain
void display_freeram() {
Serial.print(F("- SRAM left: "));
Serial.println(freeRam());
}

int freeRam() {
extern int __heap_start,*__brkval;
int v;
return (int)&v - (__brkval == 0
? (int)&__heap_start : (int) __brkval);
}
Remember that the heap section is where variables created during the run time are stored. In
the code, __heap_start and __brkval are as following:

__heap_start: the beginning of the heap section.


__brkval: the last memory address pointer used by the heap.
The following example code can be used to measure SRAM usage in ARM-based Arduino®
boards:

COPY

Explain
extern "C" char* sbrk(int incr);

void display_freeram(){
Serial.print(F("- SRAM left: "));
Serial.println(freeRam());
}

int freeRam() {
char top;
return &top - reinterpret_cast<char*>(sbrk(0));
}
The code above is taken from Michael P. Flaga's library Arduino-MemoryFree.

EEPROM Memory Measurement


EEPROM memory management can be done easily using native libraries already installed
into the Arduino IDE. The EEPROM library can be used to read, write and erase the
EEPROM memory. The following code shows how a byte of information can be stored in the
EEPROM memory and then read using the write and read functions:

COPY

Explain
#include <EEPROM.h>
void setup() {
}

void loop {
// Write data into an specific address of the EEPROM memory
EEPROM.write(address, value);

// Read data of an specific address of the EEPROM memory


EEPROM.read(address);
}
Also, it is possible to clear the entire EEPROM memory by setting it to 0, as shown in the
code below:

COPY

Explain
#include <EEPROM.h>

void setup() {
}

void loop {
for (int i = 0 ; i < EEPROM.length() ; i++) {
// Clear EEPROM memory
EEPROM.write(i, 0);

}
For more information on how to manage the EEPROM memory, you can refer to this guide.

Optimizing Memory Usage in Arduino-based Systems


Knowing how code uses memory resources of a system is just the first recommended task in
the development process; a whole different task is optimizing memory usage. As the term
development may infer, the requirements may change or be adjusted depending on external
factors such as reduced device capacity due to the unavailability of the components. Thus the
code architecture may require optimization to run on the reduced limited memory resources.

The memory usage optimization process also implies reduced computational complexities,
trimming down extra time required to process tasks while using fewer memory resources to
do the same tasks. The memory usage optimization process may help the overall code
optimization process, as it will handle how the memory is managed more suitably by
requiring intelligent algorithms development.

Let us talk about some memory usage optimization techniques.

Flash Memory Optimization


Flash memory optimization is the most likely straightforward optimization possible source.
Flash memory is where the capacity used by compiled code can be significantly reduced by
considering some details.

Detach Unused Sources


Detaching new sources includes unused libraries and code residues. Code residues can be
composed of no-longer-used functions and floating variables that take up the unnecessary
space in memory. This will vastly improve the compiled code size and make a more clear
compilation process.
Modular Tasks
Modular tasks mean functions that wrap code that will be used repetitively or continuously by
receiving different parameters. It is a great way to maintain clean code structure and
performance while reducing the memory space required for additional tasks that might need
to be implemented.

This leads to a compact code structure, which is much easier to understand when debugging
is required and demands the developer consider computing complexity when designing the
code structure or such a specific algorithm.

SRAM Memory Optimization


SRAM memory is probably the most important memory unit inside a microcontroller-based
system; optimizing the SRAM usage is essential for designing reliable microcontroller-based
systems. SRAM shortages are usually the most common memory problems found; SRAM
optimization can help in reducing this type of issue.

The ideal way to use the Print Line command is to use the F() String Wrapper around the
literals. See the example below:

String Wrapper
Serial.print() or Serial.println() instructions uses SRAM space, which can be convenient but
not desirable. The ideal way to use a Serial.print() or Serial.println() instruction is with the
use of the F() String wrapper around the literals. For example:

COPY
Serial.println(F("Something"));
Wrapping the String Something with the F() wrapper will move the Strings to Flash memory
only rather than to use SRAM space also. Using the F() wrapper can be observed as
offloading such data to Flash memory instead of SRAM. Flash memory is much more
spacious than SRAM, so it is better to use Flash memory space than SRAM, which will use
heap section. This does not mean that memory space will always be available, as Flash
memory does have limited space. It is not recommended to clog code with Serial.print() or
Serial.println() instructions, but use them where they most matter inside the code.

PROGMEM
Not only Strings occupy SRAM space, but global variables also take up quite a good amount
of SRAM space. As global and static variables are streamed into SRAM space and push the
heap memory section towards the stack. The space occupied by these variables streamed into
SRAM space will be saved at its location and will not be changing, meaning more of these
variables are created, they will use more space, and consequently, the system presenting
problems and issues due to poor memory management.

PROGMEM, which stands for Program Memory, can be used to store variable data into Flash
memory space, just as the F() wrapper described before, but the use of PROGMEM presents
one disadvantage: data read speed. Using RAM will provide a much faster data read speed,
but PROGMEM, as it uses Flash memory, will be slower than RAM, given the same data
size. Thus, it is essential to design code knowing which variables are crucial and which do
not or have a lower priority.

The use of PROGMEM in an AVR-based Arduino® board is shown in the example code
below:

COPY
Explain
#include <avr/pgmspace.h>

// Basic PROGMEM structure


const PROGMEM DataType Variable_Name[] = {var0, var1, var2 ...};

// Storing an unsigned, 16-bit, integer


const PROGMEM uint16_t NumSet[] = {0, 1, 1, 2, 3, 5, 8 ...};

// Storing a char in PROGMEM


const char greetMessage[] PROGMEM = {"Something"};
You can read more about PROGMEM in the Arduino Language Reference.

For ARM-based Arduino® board, to implement similar solution, we will need to use static
const over the variables.

COPY
static const int Variable = Data;
The usage differs in different levels summarized as following:

Namespace Level

At Namespace level, we are pointing at the variables and it is differed whether static is
declared or not. If declared, it infers that the variable is explicit static; on the other hand, it is
implicit static declaration.
Function Level

If it is declared within static, any type of applicable data that is to be managed will be
between function calls.
Class Level

On a Class level, static declaration will mean any type of applicable data that is handled will
be shared in between the instances.
Non-Dynamic Memory Allocation
Dynamic memory allocation is usually a suitable method if the RAM size of the system is big
enough to get around with; however, for microcontroller-based systems, such as embedded
systems, counting every Byte of RAM is not recommended.

Dynamic memory allocations cause heap fragmentation. With heap fragmentation, many
areas of RAM affected by it cannot be reused again, leaving dead Bytes that can be taken as
an advantage for other tasks. On top of it, when dynamic memory allocation proceeds to de-
allocate to free up the space, it does not necessarily reduce the heap size. So to avoid heap or
RAM fragmentation as much as possible, the following rules can be followed:

Prioritize using the stack rather than the heap:

Stack memory is fragmentation-free and can be freed up thoroughly when the function
returns. Heap, in contrast, may not free up the space even though it was instructed to do so.
Using local variables will help to do this and try not to use dynamic memory allocation,
composed of different calls: malloc, calloc, realloc.
Reduced global and static data (if possible):

Meantime the code is running, memory area occupied by these data will not be freed up. The
data will not be modified as constant data takes up precious space.
Use short Strings/literals:
It is good to keep Strings/literals as short as possible. A single char takes one Byte of RAM,
so the shorter, the better memory space usage. This does not mean keeping it short and using
it in several different code areas is possible. Use it when required and keep it as short as
possible to spare RAM space for other tasks.

Arrays are also recommended to be at a minimum size. If it requires resizing the array, you
can always re-set the array size in code. It may be a tedious, also non-efficient method to
hard-code the array sizes. However, if the code utilizes small array sizes and less than three
arrays, it may suffice via manual resizing, knowing the requirements. An intelligent way to
do this is a resizable array with limited size. The tasks will use the array without going over
the size boundary. Thus it is suitable for extensive code. Although, the limit of the array size
must be analyzed and kept as small as possible.

Reserve Function
In tasks in code work with Strings that change in size depending on the operation outcome,
reserve() is the way to go. This function will help reserve buffer space and pre-allocate for a
String variable, changing its size and avoiding memory fragmentation. A String variable that
changes in its size could result from an int type variable wrapped to be used as a String, for
example.

The following code shows how to use the reserve() instruction:

COPY
// String_Variable is an String type variable
// Alloc_Size is the memory to be pre-allocated in number of Bytes with unsigned int type
String_Variable.reserve(Alloc_Size);
For more information about the reserve() function, visit Arduino Language Reference.

Buffer Size Control


Backend processes also require a memory pool for their processing purpose. It is something
on which the system will work according to the size of the memory pool defined. This buffer
size can be user-defined, which can be reduced to allocate a lower memory size. Think about
defining an array variable size, in which it is important not to allocate excessive size when it
uses only a third portion of the defined size.

Let us discuss an example: serial communications in Arduino. Serial communications is a


regularly used service in Arduino-based systems; Serial communications in Arduino work
using the preinstalled Serial library (external libraries can also emulate serial communications
using software). In between backend services, serial communications define the needed
memory pool as a buffer with a defined size. If high-speed serial communication is not part
of the requirements, the serial buffer size can be redefined to save some memory
consumption. This can be made easily by modifying the following code line in the
HardwareSerial.h file that can be found in the installation folder of the Arduino IDE:

COPY
#define SERIAL_TX_BUFFER_SIZE 64

#define SERIAL_RX_BUFFER_SIZE 64
External libraries can usually be modified to optimize buffer sizes used for performing
specific tasks of the libraries.

Corrective Data Type Usage


Implementation of adequate data type leads to a good overall code architecture. It may be
desirable for developers to use easiest or the most accessible data type to handle the data in
code. However, it is important to consider the amount of memory space that it takes up when
using certain data types.

Data types exist to ease data stream format and to be handled without making illegal access.
The illegal access in terms of data types are meant when the data is handled in the code with
incompatible format. So it is a good practice to not to abuse the the data type and use only
convenient types for every data bits. Rather, design and allocate memory carefully according
to the requirements, which will help to reserve some memory space if further designed tasks
needs extra space.

The following table shows basic value data types in Arduino:

Type Byte Length Range of Values


boolean 1 Limited to logic true and false
char 1 -128 to 127
unsigned char 1 0 to 255
byte 1 0 to 255
int 2 -32,768 to 32,767
unsigned int 2 0 to 65,535
word 2 0 to 65,535
long 4 -2,147,483,648 to 2,147,483,647
unsigned long 4 0 to 4,294,967,295
float 4 -3.4028235E+38 to 3.4028235E+38
double 4 -3.4028235E+38 to 3.4028235E+38
EEPROM Memory Optimization
EEPROM memory optimization is usually not required; data that are to be used by EEPROM
space do not need Flash memory as a storage source. On top of it, it is not a good practice to
offload SRAM data on EEPROM. SRAM data are placed within volatility in mind, so
offloading to EEPROM space, which is non-volatile memory, will mean the offloaded data
will be engraved into EEPROM space.

With EEPROM, it is crucial to know that write operation is limited. The read operation is
unlimited for EEPROM; however, the write operation is finite and usually capped at 100,000
cycles. Thus, it is essential to save only essential parameters for sensors or modules to work
with primarily unchanging data. Additionally, avoid implementing write operations into loops
to avoid constant write operations, these operations should be minimized while the system is
working.

EEPROM Emulation with Flash Memory


As EEPROM is limited with the write operation cycle, it also applies to Flash memory. Both
of them are subjected to data retention loss after the manufacturer's defined life cycle.
EEPROM is based on NOR-type memory, while the Flash memory is NAND type, making
the EEPROM more costly than Flash memory. EEPROM works by accessing the data byte-
wise, whereas Flash memory accesses block by block.

Sometimes the developer would have to use the EEPROM as alternative storage for task
operations, but we know it will be impractical coding due to its size and behavior properties.
It is possible to use Flash memory to emulate the EEPROM to solve this. Thanks to the
FlashStorage library created by Chrisitan Maglie, it is possible to emulate the EEPROM by
using Flash memory.

The FlashStorage library will help you to use the Flash memory to emulate the EEPROM, but
of course, please remember the EEPROM's properties when using the library. As for
EEPROM, the Flash memory is also limited in the write cycles. With two new additional
functions stated in the library, EEPROM.commit() should not be called inside a loop
function; otherwise, it will wipe out the Flash memory's write operation cycles, thus losing
data retention ability.

Further Reading and Resources


Memory architectures in microcontroller-based systems is a pretty vast topic; if you want to
learn more about this topic, check out the following links:

8-bit AVR® Core documentation in the Microchip® Developer help site. Here you can find
detailed information of the 8-bit AVR® Central Processing Unit (CPU).
ARM architecture documentation site. Here you can find detailed information of the different
ARM processors. Check out the Cortex-M0+ and Cortex-M4 Technical Reference Manuals.
References
[1] S. F. Barrett and D. J. Pack, Microchip AVR® Microcontroller Primer: Programming and
Interfacing, Third Edition (Synthesis Lectures on Digital Circuits and Systems), Morgan &
Claypool, 2019.
[2] J. Y. Yiu, The Definitive Guide to Arm® Cortex®-M0 and Cortex-M0+ Processors,
Second ed., Newnes, 2015.

[3] J. Yiu, The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors, Third
ed., Newnes, 2014.

A guide to EEPROM
Learn how to use EEPROM, short for electrically erasable programmable read-only memory,
on Arduino boards.

Last revision08/02/2024
The microcontroller on the Arduino boards have 512 bytes of EEPROM: memory whose
values are kept when the board is turned off (like a tiny hard drive).

Functions in the EEPROM class is automatically included with the platform for your board,
meaning you do not need to install any external libraries.

Hardware Required
All of the following boards have an EEPROM:

Arduino UNO R4 Minima


Arduino UNO R4 WiFi
Arduino UNO Rev.3
Arduino UNO WiFi Rev.2
Arduino Mega 2560 Rev.3
Arduino Nano Every
Arduino Micro
Arduino Leonardo
Arduino Nano
EEPROM Clear
This example illustrates how to set of all of those bytes to 0, initializing them to hold new
information, using the EEPROM.write() function.

COPY

Explain
/*
* EEPROM Clear
*
* Sets all of the bytes of the EEPROM to 0.
* Please see eeprom_iteration for a more in depth
* look at how to traverse the EEPROM.
*
* This example code is in the public domain.
*/

#include <EEPROM.h>

void setup() {
// initialize the LED pin as an output.
pinMode(13, OUTPUT);

/***
Iterate through each byte of the EEPROM storage.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduino Duemilanove: 512 B EEPROM storage.
- Arduino Uno: 1 kB EEPROM storage.
- Arduino Mega: 4 kB EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/

for (int i = 0 ; i < EEPROM.length() ; i++) {


EEPROM.write(i, 0);
}

// turn the LED on when we're done


digitalWrite(13, HIGH);
}

void loop() {
/** Empty loop. **/
}
EEPROM CRC
A CRC is a simple way of checking whether data has changed or become corrupted. This
example calculates a CRC value directly on the EEPROM values. This CRC is like a
signature and any change in the calculated CRC means a change in the stored data. The
purpose of this example is to highlight how the EEPROM object can be used just like an
array.

COPY

Explain
/***

Written by Christopher Andrews.

CRC algorithm generated by pycrc, MIT licence ( https://github.com/tpircher/pycrc ).

A CRC is a simple way of checking whether data has changed or become corrupted.

This example calculates a CRC value directly on the EEPROM values.

The purpose of this example is to highlight how the EEPROM object can be used just like
an array.
***/

#include <Arduino.h>
#include <EEPROM.h>

void setup() {

//Start serial

Serial.begin(9600);

while (!Serial) {

; // wait for serial port to connect. Needed for native USB port only

//Print length of data to run CRC on.

Serial.print("EEPROM length: ");

Serial.println(EEPROM.length());

//Print the result of calling eeprom_crc()

Serial.print("CRC32 of EEPROM data: 0x");

Serial.println(eeprom_crc(), HEX);

Serial.print("\n\nDone!");
}

void loop() {

/* Empty loop */
}

unsigned long eeprom_crc(void) {

const unsigned long crc_table[16] = {

0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,

0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,

0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,

0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c

};

unsigned long crc = ~0L;

for (int index = 0 ; index < EEPROM.length() ; ++index) {


crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4);

crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4);

crc = ~crc;

return crc;
}
EEPROM Get
The purpose of this example is to show how the put and get methods provide a different
behaviour than write and read, that work on single bytes. Getting different variables from
EEPROM retrieve a number of bytes that is related to the variable datatype.

COPY

Explain
/***

eeprom_get example.

This shows how to use the EEPROM.get() method.

To pre-set the EEPROM data, run the example sketch eeprom_put.

This sketch will run without it, however, the values shown

will be shown from what ever is already on the EEPROM.

This may cause the serial object to print out a large string

of garbage if there is no null character inside one of the strings

loaded.

Written by Christopher Andrews 2015

Released under MIT licence.

***/

#include <EEPROM.h>

void setup() {

float f = 0.00f; //Variable to store data read from EEPROM.

int eeAddress = 0; //EEPROM address to start reading from

Serial.begin(9600);

while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only

Serial.print("Read float from EEPROM: ");

//Get the float data from the EEPROM at position 'eeAddress'

EEPROM.get(eeAddress, f);

Serial.println(f, 3); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid
float.

/***

As get also returns a reference to 'f', you can use it inline.

E.g: Serial.print( EEPROM.get( eeAddress, f ) );

***/

/***

Get can be used with custom structures too.

I have separated this into an extra function.

***/

secondTest(); //Run the next test.


}

struct MyObject {

float field1;

byte field2;

char name[10];
};

void secondTest() {

int eeAddress = sizeof(float); //Move address to the next byte after float 'f'.

MyObject customVar; //Variable to store custom object read from EEPROM.

EEPROM.get(eeAddress, customVar);

Serial.println("Read custom object from EEPROM: ");

Serial.println(customVar.field1);

Serial.println(customVar.field2);
Serial.println(customVar.name);
}

void loop() {

/* Empty loop */
}
EEPROM Iteration
The purpose of this example is to show how to go through the whole EEPROM memory
space with different approaches. The code provided doesn't run on its own but should be used
as a surce of code snippets to be used elsewhere.

COPY

Explain
/***

eeprom_iteration example.

A set of example snippets highlighting the

simplest methods for traversing the EEPROM.

Running this sketch is not necessary, this is

simply highlighting certain programming methods.

Written by Christopher Andrews 2015

Released under MIT licence.

***/

#include <EEPROM.h>

void setup() {

/***

Iterate the EEPROM using a for loop.

***/

for (int index = 0 ; index < EEPROM.length() ; index++) {

//Add one to each cell in the EEPROM

EEPROM[ index ] += 1;

/***

Iterate the EEPROM using a while loop.


***/

int index = 0;

while (index < EEPROM.length()) {

//Add one to each cell in the EEPROM

EEPROM[ index ] += 1;

index++;

/***

Iterate the EEPROM using a do-while loop.

***/

int idx = 0; //Used 'idx' to avoid name conflict with 'index' above.

do {

//Add one to each cell in the EEPROM

EEPROM[ idx ] += 1;

idx++;

} while (idx < EEPROM.length());

} //End of setup function.

void loop() {}
EEPROM Put
The purpose of this example is to show the EEPROM.put() method that writes data on
EEPROM using also the EEPROM.update() that writes data only if it is different from the
previous content of the locations to be written. The number of bytes written is related to the
datatype or custom structure of the variable to be written.

COPY

Explain
/***

eeprom_put example.

This shows how to use the EEPROM.put() method.

Also, this sketch will pre-set the EEPROM data for the

example sketch eeprom_get.

Note, unlike the single byte version EEPROM.write(),


the put method will use update semantics. As in a byte

will only be written to the EEPROM if the data is actually

different.

Written by Christopher Andrews 2015

Released under MIT licence.

***/

#include <EEPROM.h>

struct MyObject {

float field1;

byte field2;

char name[10];
};

void setup() {

Serial.begin(9600);

while (!Serial) {

; // wait for serial port to connect. Needed for native USB port only

float f = 123.456f; //Variable to store in EEPROM.

int eeAddress = 0; //Location we want the data to be put.

//One simple call, with the address first and the object second.

EEPROM.put(eeAddress, f);

Serial.println("Written float data type!");

/** Put is designed for use with custom structures also. **/

//Data to store.

MyObject customVar = {

3.14f,

65,

"Working!"
};

eeAddress += sizeof(float); //Move address to the next byte after float 'f'.

EEPROM.put(eeAddress, customVar);

Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how
you can retrieve the values!");
}

void loop() {

/* Empty loop */
}
EEPROM Read
This example illustrates how to read the value of each byte EEPROM using the
EEPROM.read() function, and how to print those values to the serial window of the Arduino
Software (IDE).

COPY

Explain
/*
* EEPROM Read
*
* Reads the value of each byte of the EEPROM and prints it
* to the computer.
* This example code is in the public domain.
*/

#include <EEPROM.h>

// start reading from the first byte (address 0) of the EEPROM


int address = 0;
byte value;

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

void loop() {
// read a byte from the current address of the EEPROM
value = EEPROM.read(address);

Serial.print(address);
Serial.print("\t");
Serial.print(value, DEC);
Serial.println();

/***
Advance to the next address, when at the end restart at the beginning.

Larger AVR processors have larger EEPROM sizes, E.g:


- Arduino Duemilanove: 512 B EEPROM storage.
- Arduino Uno: 1 kB EEPROM storage.
- Arduino Mega: 4 kB EEPROM storage.

Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
address = address + 1;
if (address == EEPROM.length()) {
address = 0;
}

/***
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
EEPROM address is also doable by a bitwise and of the length - 1.

++address &= EEPROM.length() - 1;


***/

delay(500);
}
EEPROM Update
The purpose of this example is to show the EEPROM.update() method that writes data only if
it is different from the previous content of the locations to be written. This solution may save
execution time because every write operation takes 3.3 ms; the EEPROM has also a limit of
100,000 write cycles per single location, therefore avoiding rewriting the same value in any
location will increase the EEPROM overall life.

COPY

Explain
/***
EEPROM Update method

Stores values read from analog input 0 into the EEPROM.


These values will stay in the EEPROM when the board is
turned off and may be retrieved later by another sketch.

If a value has not changed in the EEPROM, it is not overwritten


which would reduce the life span of the EEPROM unnecessarily.

Released using MIT licence.


***/

#include <EEPROM.h>

/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/
int address = 0;

void setup() {
/** Empty setup **/
}
void loop() {
/***
need to divide by 4 because analog inputs range from
0 to 1023 and each byte of the EEPROM can only hold a
value from 0 to 255.
***/
int val = analogRead(0) / 4;

/***
Update the particular EEPROM cell.
these values will remain there when the board is
turned off.
***/
EEPROM.update(address, val);

/***
The function EEPROM.update(address, val) is equivalent to the following:

if( EEPROM.read(address) != val ){


EEPROM.write(address, val);
}
***/

/***
Advance to the next address, when at the end restart at the beginning.

Larger AVR processors have larger EEPROM sizes, E.g:


- Arduino Duemilanove: 512 B EEPROM storage.
- Arduino Uno: 1 kB EEPROM storage.
- Arduino Mega: 4 kB EEPROM storage.

Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
address = address + 1;
if (address == EEPROM.length()) {
address = 0;
}

/***
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
EEPROM address is also doable by a bitwise and of the length - 1.

++address &= EEPROM.length() - 1;


***/

delay(100);
}
EEPROM Write
This example illustrates how to store values read from analog input 0 into the EEPROM
using the EEPROM.write() function. These values will stay in the EEPROM when the board
is turned off and may be retrieved later by another sketch.
COPY

Explain
/*

* EEPROM Write

* Stores values read from analog input 0 into the EEPROM.

* These values will stay in the EEPROM when the board is

* turned off and may be retrieved later by another sketch.

*/

#include <EEPROM.h>

/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/
int addr = 0;

void setup() {

/** Empty setup. **/


}

void loop() {

/***

Guide to Arduino & Secure Digital (SD) Storage.


Browse through a series of examples on how to read and write to SD cards from an Arduino
board.

AuthorArduino
Last revision08/02/2024
This article was revised on 2021/11/18 by Karl Söderby.

This guide collects compatible hardware and great code examples that you can use if you
want to get started with Secure Digital (SD) cards.

The examples in this guide comes from the SD Library, which originally is based on SdFat
by William Greiman.

Hardware & Software Required


Arduino Board with SD Card Slot*
Arduino IDE (online or offline).
Formatted SD Card
*The boards/shields that have an SD card slot are listed below:

MKR Zero
MKR IoT Carrier
MKR MEM Shield
MKR SD Proto Shield
MKR ENV Shield
MKR Ethernet Shield
Arduino Education Shield
Circuit
Here is an example of how to insert an SD card into the MKR Zero board. None of the
examples below requires any additional circuit.

Insert the SD card.


Insert the SD card.

Examples
Below are a series of examples

Read and Write


This example shows how to read and write data to and from an SD card.

In setup(), create a new file with SD.open() named "test.txt". FILE_WRITE enables read and
write access to the file, starting at the end. If a file "test.txt" was already on the card, that file
would be opened.
Name the instance of the opened file "myFile".
Once opened, use myFile.println() to write a string to the card, followed by a carriage return.
Once the content is written, close the file.
Again, open the file with SD.open(). Once opened, ask the Arduino to read the contents of the
file with SD.read() and send them over the serial port. After all the contents of the file are
read, close the file with SD.close().
Note that pin 4 is default Chip Select (CS) pin for most boards. To set CS for MKR Zero, you
can use 28 instead of 4, alt. use the SDCARD_SS_PIN definition.

COPY

Explain
/*
SD card read/write

This example shows how to read and write data to and from an SD card file
The circuit:
SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

created Nov 2010


by David A. Mellis
modified 9 Apr 2012
by Tom Igoe

This example code is in the public domain.

*/

#include <SPI.h>
#include <SD.h>

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

Serial.print("Initializing SD card...");

if (!SD.begin(4)) {
Serial.println("initialization failed!");
while (1);
}
Serial.println("initialization done.");

// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
myFile = SD.open("test.txt", FILE_WRITE);

// if the file opened okay, write to it:


if (myFile) {
Serial.print("Writing to test.txt...");
myFile.println("testing 1, 2, 3.");
// close the file:
myFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}

// re-open the file for reading:


myFile = SD.open("test.txt");
if (myFile) {
Serial.println("test.txt:");

// read from the file until there's nothing else in it:


while (myFile.available()) {
Serial.write(myFile.read());
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
}

void loop() {
// nothing happens after setup
}
Card Information
This example shows how to read information about a SD card. The example reports volume
type, free space and other information using the SD library, sending it over the serial port.

COPY

Explain
/*

SD card test

This example shows how use the utility libraries on which the'

SD library is based in order to get info about your SD card.

Very useful for testing a card when you're not sure whether its working or not.

Pin numbers reflect the default SPI pins for Uno and Nano models

The circuit:

SD card attached to SPI bus as follows:

** SDO - pin 11 on Arduino Uno/Duemilanove/Diecimila

** SDI - pin 12 on Arduino Uno/Duemilanove/Diecimila

** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila

** CS - depends on your SD card shield or module.

Pin 10 used here for consistency with other Arduino examples

created 28 Mar 2011

by Limor Fried

modified 24 July 2020

by Tom Igoe

*/
// include the SD library:
#include <SPI.h>
#include <SD.h>

// set up variables using the SD utility library functions:

Sd2Card card;

SdVolume volume;

SdFile root;

// change this to match your SD shield or module;


// Default SPI on Uno and Nano: pin 10
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// MKRZero SD: SDCARD_SS_PIN

const int chipSelect = 10;

void setup() {

// Open serial communications and wait for port to open:

Serial.begin(9600);

while (!Serial) {

; // wait for serial port to connect. Needed for native USB port only

Serial.print("\nInitializing SD card...");

// we'll use the initialization code from the utility libraries

// since we're just testing if the card is working!

if (!card.init(SPI_HALF_SPEED, chipSelect)) {

Serial.println("initialization failed. Things to check:");

Serial.println("* is a card inserted?");

Serial.println("* is your wiring correct?");

Serial.println("* did you change the chipSelect pin to match your shield or module?");

while (1);

} else {

Serial.println("Wiring is correct and a card is present.");

// print the type of card

Serial.println();

Serial.print("Card type: ");

switch (card.type()) {

case SD_CARD_TYPE_SD1:

Serial.println("SD1");
break;

case SD_CARD_TYPE_SD2:

Serial.println("SD2");

break;

case SD_CARD_TYPE_SDHC:

Serial.println("SDHC");

break;

default:

Serial.println("Unknown");

// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32

if (!volume.init(card)) {

Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the


card");

while (1);

Serial.print("Clusters: ");

Serial.println(volume.clusterCount());

Serial.print("Blocks x Cluster: ");

Serial.println(volume.blocksPerCluster());

Serial.print("Total Blocks: ");

Serial.println(volume.blocksPerCluster() * volume.clusterCount());

Serial.println();

// print the type and size of the first FAT-type volume

uint32_t volumesize;

Serial.print("Volume type is: FAT");

Serial.println(volume.fatType(), DEC);

volumesize = volume.blocksPerCluster(); // clusters are collections of blocks


volumesize *= volume.clusterCount(); // we'll have a lot of clusters

volumesize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB)

Serial.print("Volume size (Kb): ");

Serial.println(volumesize);

Serial.print("Volume size (Mb): ");

volumesize /= 1024;

Serial.println(volumesize);

Serial.print("Volume size (Gb): ");

Serial.println((float)volumesize / 1024.0);

Serial.println("\nFiles found on the card (name, date and size in bytes): ");

root.openRoot(volume);

// list all files in the card with date and size

root.ls(LS_R | LS_DATE | LS_SIZE);

root.close();
}

void loop(void) {
}
Please note: the cluster size is defined at format time by the user and has some default values
that can be changed by users following some rules. In the sketch above we are using the
default size for a block that is set at 512 bytes by standards. This value is not the cluster size:
that is calculated as the number of blocks per cluster. You may find more in depth
information about cluster sizes in this article.

Dump File
This example shows how to read a file from a SD card using the SD library and send it over
the serial port.

On the SD card, there is a file named "datalog.txt". In the loop(), the file is opened when
calling SD.open(). To send the file serially to a computer, use Serial.print(), reading the
contents of the file with SD.read().

COPY

Explain
/*

SD card file dump

This example shows how to read a file from the SD card using the

SD library and send it over the serial port.


Pin numbers reflect the default SPI pins for Uno and Nano models.

The circuit:

SD card attached to SPI bus as follows:

** SDO - pin 11

** SDI - pin 12

** CLK - pin 13

** CS - depends on your SD card shield or module.

Pin 10 used here for consistency with other Arduino examples

(for MKRZero SD: SDCARD_SS_PIN)

created 22 December 2010

by Limor Fried

modified 9 Apr 2012

by Tom Igoe

This example code is in the public domain.

*/
#include <SD.h>

const int chipSelect = 10;

void setup() {

// Open serial communications and wait for port to open:

Serial.begin(9600);

// wait for Serial Monitor to connect. Needed for native USB port boards only:

while (!Serial);

Serial.print("Initializing SD card...");

if (!SD.begin(chipSelect)) {

Serial.println("initialization failed. Things to check:");

Serial.println("1. is a card inserted?");

Serial.println("2. is your wiring correct?");

Serial.println("3. did you change the chipSelect pin to match your shield or module?");
Serial.println("Note: press reset or reopen this serial monitor after fixing your issue!");

while (true);

Serial.println("initialization done.");

// open the file. note that only one file can be open at a time,

// so you have to close this one before opening another.

File dataFile = SD.open("datalog.txt");

// if the file is available, write to it:

if (dataFile) {

while (dataFile.available()) {

Serial.write(dataFile.read());

dataFile.close();

// if the file isn't open, pop up an error:

else {

Serial.println("error opening datalog.txt");

}
}

void loop() {
}
File Management
This example shows how to create and destroy a file on a SD card.

In the setup(), open a new file with SD.open() named "example.txt". FILE_WRITE enables
read and write access to the file, starting at the end. In this example though, immediately
close the file by calling myFile.close().

After checking to make sure the file exists with SD.exists(), delete the file from the card with
SD.remove.

COPY

Explain
/*
SD card basic file example

This example shows how to create and destroy an SD card file

The circuit. Pin numbers reflect the default

SPI pins for Uno and Nano models:

SD card attached to SPI bus as follows:

** SDO - pin 11

** SDI - pin 12

** CLK - pin 13

** CS - depends on your SD card shield or module.

Pin 10 used here for consistency with other Arduino examples

(for MKRZero SD: SDCARD_SS_PIN)

created Nov 2010

by David A. Mellis

modified 24 July 2020

by Tom Igoe

This example code is in the public domain.

*/
#include <SD.h>

const int chipSelect = 10;

File myFile;

void setup() {

// Open serial communications and wait for port to open:

Serial.begin(9600);

// wait for Serial Monitor to connect. Needed for native USB port boards only:
while (!Serial);

Serial.print("Initializing SD card...");

if (!SD.begin(10)) {

Serial.println("initialization failed!");

while (1);
}

Serial.println("initialization done.");

if (SD.exists("example.txt")) {

Serial.println("example.txt exists.");

} else {

Serial.println("example.txt doesn't exist.");

// open a new file and immediately close it:

Serial.println("Creating example.txt...");

myFile = SD.open("example.txt", FILE_WRITE);

myFile.close();

// Check to see if the file exists:

if (SD.exists("example.txt")) {

Serial.println("example.txt exists.");

} else {

Serial.println("example.txt doesn't exist.");

// delete the file:

Serial.println("Removing example.txt...");

SD.remove("example.txt");

if (SD.exists("example.txt")) {

Serial.println("example.txt exists.");

} else {

Serial.println("example.txt doesn't exist.");

}
}

void loop() {

// nothing happens after setup finishes.


}
List Files
This example shows how to list the files available in the directory of the SD card.

The main loop() does nothing because the function that prints out the file directory of "/" of
the SD card is called from the setup(). This because we need to see it just once.

The printDirectory function scans through the list of entries and prints on serial every file and
directory present. For files the size is printed as well.

COPY

Explain
/*

Listfiles

This example shows how print out the files in a

directory on a SD card.Pin numbers reflect the default

SPI pins for Uno and Nano models

The circuit:

SD card attached to SPI bus as follows:

** SDO - pin 11

** SDI - pin 12

** CLK - pin 13

** CS - depends on your SD card shield or module.

Pin 10 used here for consistency with other Arduino examples

(for MKRZero SD: SDCARD_SS_PIN)

created Nov 2010

by David A. Mellis

modified 9 Apr 2012

by Tom Igoe

modified 2 Feb 2014

by Scott Fitzgerald

modified 24 July 2020

by Tom Igoe
This example code is in the public domain.

*/
#include <SD.h>

const int chipSelect = 10;

Bit Masks with Arduino


Bit masks are used to access specific bits in a byte of data.

AuthorArduino
Last revision08/02/2024
Bit masks are used to access specific bits in a byte of data. This is often useful as a method of
iteration, for example when sending a byte of data serially out a single pin. In this example
the pin needs to change it's state from high to low for each bit in the byte to be transmitted.
This is accomplished using what are known as bitwise operations and a bit mask.

Bitwise operations perform logical functions that take affect on the bit level. Standard bitwise
operations include AND (&) OR (|) Left Shift (<<) and Right Shift (>>).

The AND (&) operator will result in a 1 at each bit position where both input values were 1.
For example:

COPY

Explain
x: 10001101

y: 01010111

x & y: 00000101
The OR (|) operator (also known as Inclusive Or) will result in a 1 at each bit position where
either input values were 1. For example:

COPY

Explain
x: 10001101

y: 01010111

x | y: 11011111
The Left Shift (<<) operator will shift a value to the left the specified number of times. For
example:

COPY

Explain
y = 1010

x = y << 1

yields: x = 10100
All the bits in the byte get shifted one position to the left and the bit on the left end drops off.

The Right Shift (>>) operator works identically to left shift except that it shifts the value to
the right the specified number of times For example:

COPY

Explain
y = 1010

x = y >> 1

yields: x = 0101
All the bits in the byte get shifted one position to the right and the bit on the right end drops
off.

For a practical example, let's take the value 170, binary 10101010. To pulse this value out of
pin 7 the code might look as follows:

COPY

Explain
byte transmit = 7; //define our transmit pin
byte data = 170; //value to transmit, binary 10101010
byte mask = 1; //our bitmask
byte bitDelay = 100;

void setup()
{

pinMode(transmit,OUTPUT);
}

void loop()
{

for (mask = 00000001; mask>0; mask <<= 1) { //iterate through bit mask

if (data & mask){ // if bitwise AND resolves to true

digitalWrite(transmit,HIGH); // send 1

else{ //if bitwise and resolves to false

digitalWrite(transmit,LOW); // send 0

delayMicroseconds(bitDelay); //delay

}
}
Here we use a FOR loop to iterate through a bit mask value, shifting the value one position
left each time through the loop. In this example we use the <<= operator which is exactly like
the << operator except that it compacts the statement

COPY

Explain
00000001
& 10101010

________

00000000
And our output pin gets set to 0. Second time through the loop the mask = 00000010, so our
operation looks like:

COPY

Explain
00000010
& 10101010

________

00000010
And our output pin gets set to 1. The loop will continue to iterate through each bit in the mask
until the 1 gets shifted left off the end of the 8 bits and our mask =0. Then all 8 bits have been
sent and our loop exits.

Audio Basics with Arduino


Learn how to create tones and even entire songs using an Arduino.

AuthorPaul Badger, Alexandre Quessy, Michael Smith, Samantha Lagestee, Dan Thompson
Last revision08/02/2024
This article was revised on 2022/09/28 by Hannes Siebeneicher.

This article highlights different approaches to making sounds and even entire songs with an
Arduino. In 2013 Brett Hagman created the tone() library which is a good starting point for
creating different types of sounds using an Arduino. As the examples in this article are
gathered from the Arduino playground and were mostly created before 2013 a lot of steps are
still done manually, which can be skipped when using the tone() library.

The examples are nevertheless still relevant as they explain some basic concepts of
generating tone frequencies, interpolation and even provide you with some songs to try out. If
you want to see an example for a simple melody using the tone() library and familiarize
yourself with the concept of external sound data files, you can check out this example.

Most sketches in this article use pin 8 as output for the piezo buzzer or speaker which means
you only need to connect your components a shown below and try out the different examples
by uploading them to your Arduino. Only the PCMAudio example uses pin 11 as it is making
use of PWM.

Hardware Required
Arduino board
piezo buzzer or a speaker
hook-up wires
Circuit
circuit

Schematic
schematic

Basics
Most times a piezo buzzer is used to produce sounds with an Arduino. When voltage is
applied to a piezoelectric ceramic material it causes it to vibrate rapidly, resulting in the
generation of sound waves. Every wave has an associated property called frequency which
measures how many cycles happen every second. This unit of cycles is called Hertz (Hz).
E.g., A middle C on the piano has a frequency of 262 Hz which means that the air oscillates
back and forth 262 times every second.

Another property of a wave is its period, which equals to one divided by the frequency,
measuring the length and time of the wave. So, for that middle C on the piano the cycle
repeats every 3.8 milliseconds. While a normal pure tone is a sine wave, it is much easier to
create a square wave using an Arduino by turning the pin on, waiting for a certain amount of
time, then turning the pin off and waiting again.

Freqout
The following example was created by Paul Badger in 2007. It shows a simple tone
generation function generating square waves of arbitrary frequency and duration. The
program also includes a top-octave lookup table & transportation function.

COPY

Explain
#include <math.h> // requires an Atmega168 chip

#define outpin 8 // audio out to speaker or amp


int ptime;
int k, x, dur, freq, t;
int i, j;

float ps; // variable for pow pitchShift routine

float noteval;

// note values for two octave scale


// divide them by powers of two to generate other octaves
float A = 14080;
float AS = 14917.2;
float B = 15804.3;
float C = 16744;
float CS = 17739.7;
float D = 18794.5;
float DS = 19912.1;
float E = 21096.2;
float F = 22350.6;
float FS = 23679.6;
float G = 25087.7;
float GS = 26579.5;
float A2 = 28160;
float A2S = 29834.5;
float B2 = 31608.5;
float C2 = 33488.1;
float C2S = 35479.4;
float D2 = 37589.1;
float D2S = 39824.3;
float E2 = 42192.3;
float F2 = 44701.2;
float F2S = 47359.3;
float G2 = 50175.4;
float G2S = 53159;
float A3 = 56320;

//octaves - corresponds to piano octaves


float oct8 = 4;
float oct7 = 8;
float oct6 = 16;
float oct5 = 32;
float oct4 = 64;
float oct3 = 128;
float oct2 = 256;
float oct1 = 512;
float oct0 = 1024;

//rhythm values
int wh = 1024;
int h = 512;
int dq = 448;
int q = 256;
int qt = 170;
int de = 192;
int e = 128;
int et = 85;
int dsx = 96;
int sx = 64;
int thx = 32;

// major scale just for demo, hack this

float majScale[] = {
A, B, CS, D, E, FS, GS, A2, B2, C2S, D2, E2, F2S, G2S, A3};

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

void loop(){
for(i= 0; i<=11; i++){
ps = (float)i / 12; // choose new transpose interval every loop
for(x= 0; x<=15; x++){
noteval = (majScale[x] / oct4) * pow(2,ps); // transpose scale up 12 tones
// pow function generates transposition
// eliminate " * pow(2,ps) " to cut out transpose routine
dur = 100;
freqout((int)noteval, dur);

delay(10);
}
}
}

void freqout(int freq, int t) // freq in hz, t in ms


{
int hperiod; //calculate 1/2 period in us
long cycles, i;
pinMode(outpin, OUTPUT); // turn on output pin

hperiod = (500000 / freq) - 7; // subtract 7 us to make up for digitalWrite overhead

cycles = ((long)freq * (long)t) / 1000; // calculate cycles


// Serial.print(freq);
// Serial.print((char)9); // ascii 9 is tab - you have to coerce it to a char to work
// Serial.print(hperiod);
// Serial.print((char)9);
// Serial.println(cycles);

for (i=0; i<= cycles; i++){ // play note for t ms


digitalWrite(outpin, HIGH);
delayMicroseconds(hperiod);
digitalWrite(outpin, LOW);
delayMicroseconds(hperiod - 1); // - 1 to make up for digitaWrite overhead
}
pinMode(outpin, INPUT); // shut off pin to avoid noise from other operations

}
Duration extension
In the example below some minor tweaks have been made, mostly changing the array to have
durations and a sentinel was added to mark the end. The example shown above remains as it
shows a great simplistic structure.

COPY

Explain
float EIGHTH = 1;
float QUARTER = 2;
float DOTTED_QUARTER =3;
float HALF = 4;
float ETERNITY =-1;
float TEMPO = 150;

float majScale[] = {
A,QUARTER, B,QUARTER, CS,QUARTER, D,QUARTER, E,QUARTER,
FS,QUARTER, GS,QUARTER, A2,QUARTER, B2,QUARTER,
C2S,QUARTER, D2,QUARTER, E2,QUARTER, F2S,QUARTER, G2S,QUARTER,
A3,QUARTER, REST,ETERNITY
};
float odeToJoy[] = {
F2S,QUARTER, F2S,QUARTER, G2,QUARTER, A3,QUARTER, A3,QUARTER,
G2,QUARTER, F2S,QUARTER, E2,QUARTER, D2,QUARTER,
D2,QUARTER, E2,QUARTER, F2S,QUARTER, F2S,DOTTED_QUARTER,
E2,EIGHTH, E2,HALF, F2S,QUARTER, F2S,QUARTER, G2,QUARTER,
A3,QUARTER, A3,QUARTER,G2,QUARTER, F2S,QUARTER, E2,QUARTER,
D2,QUARTER, D2,QUARTER, E2,QUARTER, F2S,QUARTER,
E2,DOTTED_QUARTER,
D2,EIGHTH, D2,HALF, E2,QUARTER, E2,QUARTER, F2S,QUARTER,
D2,QUARTER, E2,QUARTER, F2S,EIGHTH, G2,EIGHTH, F2S,QUARTER,
D2,QUARTER,
E2,QUARTER, F2S,EIGHTH, G2,EIGHTH, F2S,QUARTER, E2,QUARTER,
D2,QUARTER, E2,QUARTER, A,QUARTER, REST,ETERNITY
};

void play(float song[]) {


for(x= 0; x<10000; x=x+2) {
noteval = (song[x] / 64);
dur = TEMPO * song[x+1];
if(dur < 0) {
break;
freqout((int)noteval, dur);
delay(10);
}
}
}
Examples
Function Library

Smoothstep
This example is made by Dan Thompson in 2009 for smooth interpolation between two
values. Smoothstep is a common formula used for many different applications such as
Animation and Audio. This sketch includes a Serial Printout to help you visualize the
formula. Visit danthompsonsblog.blogspot.com for the full smoothstep tutorial as well as
many others. For a comprehensive overview of interpolation as well as some great Tips and
Tricks visit this page.

Code
COPY

Explain
///////////////////////////////////////
// Smoothstep Interpolation Example //
///////////////////////////////////////

// Dan Thompson 2009


//
// Inpired by the code and chat on this site.
// https://sol.gfxile.net/interpolation/
//
// Use this code at your own risk.
//
// This sketch was written with motion controlled timelapse photography
// in mind. I have tried to make it generic enough to understand the smoothstep
// concept so that one might adapt this powerful formula in other areas as well.
//
// For the full tutorial visit https://danthompsonsblog.blogspot.com/
//
// Usage:
// 1. Upload the sketch to the Arduino.
// 2. Click on the Serial monitor to see some visual feed back of the SMOOTHSTEP function.
// 3. Scroll through the print out to see the SMOOTHSTEP curve.
// 4. Play with the code and adapt it to your needs! ;)

#define SMOOTHSTEP(x) ((x) _ (x) _ (3 - 2 \* (x))) //SMOOTHSTEP expression.

int j = 0; //Just an Iterator.


int i = 0; //Just another Iterator.
float A = 0.0; //Input Min Value
float B = 100.0; //Input Max Value
float N = 100.0; //Input number of steps for transition
float X; //final smoothstepped value
float v; //smoothstep expression variable

void setup() {
Serial.begin(9600); //establish serial connection for debugging
}

void loop()
{
if (j < N) // Keep looping until we hit the pre-defined max number
// of steps
{
v = j / N; // Iteration divided by the number of steps.
v = SMOOTHSTEP(v); // Run the smoothstep expression on v.
X = (B _ v) + (A _ (1 - v)); // Run the linear interpolation expression using the current
//smoothstep result.
for ( i=0; i < X ; i++) // This loop could the relevant code for each time your
//motor steps.
{
Serial.print("1"); //Prints the number "1" for each step.
}
Serial.print(" "); //Puts a space between each line of steps and their
//corresponding float value
Serial.println(X); // prints the soothstepped value
Serial.println("CLICK!!!"); // this could be where you trigger your timelapse shutter
j++; // Increments j by 1.
}
}
PCMAudio
The following example was created by Michael Smith and is the precursor for the PCM
library created by David Mellis. It plays 8-bit PCM audio on pin 11 using pulse-width
modulation (PWM). It uses two timers. The first changes the sample value 8000 times a
second. The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle, depending on
the sample value. The second timer repeats 62500 times per second (16000000 / 256), which
is much faster than the playback rate (8000 Hz), so it almost sounds halfway decent, just
really quiet on a PC speaker.
Takes over Timer 1 (16-bit) for the 8000 Hz timer. This breaks PWM (analogWrite()) for
Arduino pins 9 & 10. It then takes Timer 2 (8-bit) for the pulse width modulation, breaking
the PWM for pins 11 & 13.

References:
http://tet.pub.ro/ (PDF).
https://www.evilmadscientist.com/article.php/avrdac
https://www.gamedev.net/reference/articles/article442.asp
Code
COPY

Explain
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define SAMPLE_RATE 8000

/*
* The audio data needs to be unsigned, 8-bit, 8000 Hz, and small enough
* to fit in flash. 10000-13000 samples is about the limit.
*
* sounddata.h should look like this:
* const int sounddata_length=10000;
* const unsigned char sounddata_data[] PROGMEM = { ..... };
*
* You can use wav2c from GBA CSS:
* https://thieumsweb.free.fr/english/gbacss.html
* Then add "PROGMEM" in the right place. I hacked it up to dump the samples
* as unsigned rather than signed, but it shouldn't matter.
*
* https://musicthing.blogspot.com/2005/05/tiny-music-makers-pt-4-mac-startup.html
* mplayer -ao pcm macstartup.mp3
* sox audiodump.wav -v 1.32 -c 1 -r 8000 -u -1 macstartup-8000.wav
* sox macstartup-8000.wav macstartup-cut.wav trim 0 10000s
* wav2c macstartup-cut.wav sounddata.h sounddata
*
* (starfox) nb. under sox 12.18 (distributed in CentOS 5), i needed to run
* the following command to convert my wav file to the appropriate format:
* sox audiodump.wav -c 1 -r 8000 -u -b macstartup-8000.wav
*/

#include "sounddata.h"

int ledPin = 13;


int speakerPin = 11; // Can be either 3 or 11, two PWM outputs connected to Timer 2
volatile uint16_t sample;
byte lastSample;

void stopPlayback()
{
// Disable playback per-sample interrupt.
TIMSK1 &= ~_BV(OCIE1A);
// Disable the per-sample timer completely.
TCCR1B &= ~_BV(CS10);

// Disable the PWM timer.


TCCR2B &= ~_BV(CS10);

digitalWrite(speakerPin, LOW);
}

// This is called at 8000 Hz to load the next sample.


ISR(TIMER1_COMPA_vect) {
if (sample >= sounddata_length) {
if (sample == sounddata_length + lastSample) {
stopPlayback();
}
else {
if(speakerPin==11){
// Ramp down to zero to reduce the click at the end of playback.
OCR2A = sounddata_length + lastSample - sample;
} else {
OCR2B = sounddata_length + lastSample - sample;
}
}
}
else {
if(speakerPin==11){
OCR2A = pgm_read_byte(&sounddata_data[sample]);
} else {
OCR2B = pgm_read_byte(&sounddata_data[sample]);
}
}

++sample;
}

void startPlayback()
{
pinMode(speakerPin, OUTPUT);

// Set up Timer 2 to do pulse width modulation on the speaker


// pin.

// Use internal clock (datasheet p.160)


ASSR &= ~(_BV(EXCLK) | _BV(AS2));

// Set fast PWM mode (p.157)


TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);

if(speakerPin==11){
// Do non-inverting PWM on pin OC2A (p.155)
// On the Arduino this is pin 11.
TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

// Set initial pulse width to the first sample.


OCR2A = pgm_read_byte(&sounddata_data[0]);
} else {
// Do non-inverting PWM on pin OC2B (p.155)
// On the Arduino this is pin 3.
TCCR2A = (TCCR2A | _BV(COM2B1)) & ~_BV(COM2B0);
TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

// Set initial pulse width to the first sample.


OCR2B = pgm_read_byte(&sounddata_data[0]);
}

// Set up Timer 1 to send a sample every interrupt.

cli();

// Set CTC mode (Clear Timer on Compare Match) (p.133)


// Have to set OCR1A *after*, otherwise it gets reset to 0!
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

// No prescaler (p.134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

// Set the compare register (OCR1A).


// OCR1A is a 16-bit register, so we have to do this with
// interrupts disabled to be safe.
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000

// Enable interrupt when TCNT1 == OCR1A (p.136)


TIMSK1 |= _BV(OCIE1A);

lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
sample = 0;
sei();
}

void setup()
{
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
startPlayback();
}

void loop()
{
while (true);
}
The above sketch also requires the sounddata.h file which you can find below:

COPY

Explain
// sounddata sound made by wav2c
// (wav2c modified to use unsigned samples)

/_ const int sounddata_sampleRate=8000; _/


const int sounddata_length=10000;

const unsigned char sounddata_data[] PROGMEM = {


128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 127, 129, 128,
127, 133,
117, 109, 125, 121, 116, 132, 140, 126, 114, 114, 116, 120, 114, 93, 73, 66, 76, 116, 142,
129,
128, 129, 120, 119, 118, 104, 87, 123, 181, 194, 196, 198, 189, 176, 160, 162, 172, 164, 164,
183,
197, 188, 168, 167, 170, 165, 185, 209, 206, 196, 196, 199, 185, 162, 156, 167, 176, 173,
170, 166,
151, 142, 140, 134, 130, 127, 113, 86, 67, 66, 69, 75, 73, 75, 86, 90, 91, 84, 65, 48,
41, 30, 26, 56, 91, 88, 72, 70, 73, 82, 89, 73, 57, 60, 74, 89, 92, 77, 63, 60,
53, 47, 56, 64, 63, 61, 56, 54, 52, 36, 16, 22, 51, 66, 67, 70, 76, 88, 99, 92,
77, 74, 85, 100, 106, 97, 83, 85, 96, 108, 133, 160, 164, 144, 113, 96, 91, 82, 74, 76,
89, 97, 97, 97, 82, 54, 40, 41, 41, 43, 56, 74, 78, 64, 55, 64, 72, 72, 84, 102,
108, 116, 126, 127, 124, 127, 134, 134, 138, 148, 152, 156, 164, 165, 169, 171, 160, 156,
157, 152,
151, 145, 133, 136, 153, 166, 165, 163, 165, 161, 156, 158, 155, 147, 148, 160, 185, 209,
215, 220,
220, 204, 200, 208, 205, 200, 202, 209, 214, 213, 205, 198, 194, 194, 203, 219, 231, 235,
230, 219,
200, 184, 177, 170, 170, 177, 172, 164, 163, 158, 156, 160, 163, 161, 142, 116, 103, 96, 89,
93,
101, 105, 111, 116, 120, 110, 89, 80, 78, 75, 73, 80, 93, 91, 77, 69, 70, 77, 91, 98,
89, 87, 93, 95, 95, 94, 97, 96, 91, 94, 99, 100, 101, 95, 83, 78, 79, 71, 56, 41,
37, 53, 64, 63, 72, 82, 83, 82, 80, 73, 67, 69, 69, 66, 68, 79, 99, 121, 143, 165,
180, 174, 148, 131, 122, 112, 115, 120, 121, 126, 122, 108, 87, 72, 71, 73, 79, 81, 83, 86,
83, 77, 70, 71, 85, 100, 112, 118, 130, 146, 154, 166, 174, 172, 172, 161, 147, 146, 153, 157,
161, 165, 168, 170, 162, 138, 122, 121, 121, 123, 128, 138, 151, 161, 165, 161, 153, 150,
149, 147,
136, 129, 140, 150, 156, 176, 194, 193, 179, 168, 167, 174, 185, 188, 181, 174, 164, 156,
156, 155,
163, 185, 210, 224, 229, 235, 233, 215, 195, 176, 168, 170, 171, 168, 162, 162, 163, 165,
174, 181,
184, 172, 151, 135, 125, 125, 132, 138, 139, 139, 139, 133, 121, 116, 117, 115, 104, 94, 94,
94,
92, 90, 82, 70, 64, 69, 77, 82, 87, 85, 85, 92, 97, 105, 112, 108, 103, 107, 116, 122,
121, 115, 101, 87, 80, 71, 67, 72, 70, 68, 78, 82, 78, 78, 79, 81, 79, 68, 59, 57,
53, 60, 83, 106, 125, 146, 174, 192, 188, 186, 180, 161, 155, 157, 158, 156, 152, 148, 131,
117,
111, 100, 97, 101, 104, 107, 110, 113, 112, 108, 106, 108, 122, 130, 141, 164, 175, 180, 185,
186,
186, 182, 174, 167, 155, 150, 154, 155, 143, 132, 136, 139, 127, 114, 108, 107, 104, 103,
114, 120,
124, 131, 134, 132, 123, 115, 109, 101, 108, 130, 144, 154, 161, 171, 184, 184, 171, 155,
147, 155,
165, 165, 151, 142, 144, 136, 137, 152, 158, 162, 177, 200, 209, 206, 201, 181, 163, 159,
154, 154,
151, 146, 161, 176, 170, 168, 175, 181, 176, 160, 148, 141, 138, 140, 140, 139, 140, 148,
155, 152,
146, 135, 123, 111, 103, 110, 113, 100, 81, 62, 55, 52, 40, 33, 38, 60, 86, 95, 99, 106,
111, 113, 105, 91, 87, 94, 101, 106, 103, 90, 76, 67, 63, 68, 72, 68, 63, 58, 68, 86,
82, 68, 60, 56, 53, 45, 37, 40, 58, 77, 92, 110, 128, 149, 169, 174, 161, 151, 144, 139,
142, 146, 146, 147, 142, 132, 129, 127, 116, 99, 94, 103, 113, 119, 122, 128, 133, 128, 119,
118,
132, 160, 193, 215, 221, 222, 226, 224, 217, 211, 200, 181, 166, 158, 152, 148, 139, 125,
118, 118,
119, 122, 123, 123, 124, 126, 127, 124, 127, 141, 143, 131, 118, 107, 110, 127, 146, 159,
163, 165,
166, 164, 164, 160, 146, 131, 124, 135, 147, 145, 140, 138, 130, 124, 130, 136, 145, 163,
177, 182,
181, 179, 177, 169, 159, 154, 155, 165, 176, 184, 195, 195, 183, 173, 163, 156, 158, 160,
159, 165,
171, 164, 154, 154, 159, 167, 170, 167, 157, 141, 128, 120, 115, 111, 102, 95, 87, 64, 50, 49,
45, 54, 77, 101, 123, 136, 139, 136, 128, 119, 112, 105, 101, 110, 123, 112, 94, 88, 78, 72,
83, 89, 80, 69, 65, 57, 58, 64, 59, 53, 39, 16, 18, 36, 46, 66, 92, 107, 119, 135,
145, 150, 160, 158, 147, 145, 144, 150, 160, 153, 150, 150, 140, 128, 120, 116, 104, 91, 88,
90,
106, 123, 123, 123, 114, 100, 105, 119, 142, 181, 211, 222, 220, 214, 208, 204, 201, 186,
171, 166,
162, 154, 138, 128, 120, 101, 93, 94, 103, 119, 117, 109, 109, 112, 119, 121, 121, 124, 122,
119,
117, 124, 142, 158, 174, 183, 173, 168, 165, 149, 135, 132, 126, 119, 124, 127, 125, 133,
126, 111,
116, 123, 127, 135, 145, 157, 167, 174, 176, 177, 182, 181, 184, 194, 194, 198, 213, 219,
219, 219,
206, 184, 164, 153, 154, 163, 166, 162, 165, 164, 154, 154, 160, 161, 165, 166, 158, 146,
140, 130,
122, 121, 109, 95, 89, 74, 61, 65, 74, 88, 110, 132, 149, 159, 149, 124, 107, 99, 91, 92,
98, 101, 101, 90, 81, 84, 86, 82, 82, 80, 68, 58, 56, 53, 47, 42, 37, 35, 35, 30,
28, 31, 40, 56, 74, 91, 99, 98, 101, 110, 114, 111, 110, 119, 127, 133, 140, 139, 128, 118,
116, 109, 94, 87, 83, 79, 89, 110, 119, 116, 117, 117, 114, 117, 116, 119, 137, 164, 191, 204,
192, 180, 180, 175, 161, 152, 149, 139, 128, 122, 111, 98, 89, 88, 93, 97, 94, 98, 104, 101,
107, 119, 117, 121, 140, 152, 157, 164, 165, 171, 183, 190, 194, 191, 182, 172, 166, 154,
137, 132,
134, 134, 138, 141, 130, 120, 123, 123, 120, 117, 109, 110, 125, 150, 168, 164, 163, 179,
196, 210,
218, 220, 224, 227, 230, 238, 237, 218, 205, 202, 194, 189, 188, 184, 181, 181, 182, 174,
162, 161,
168, 181, 194, 187, 176, 170, 156, 151, 143, 127, 125, 125, 116, 103, 94, 95, 107, 124, 145,
161,
159, 151, 153, 145, 123, 106, 95, 85, 82, 86, 87, 78, 74, 79, 79, 73, 64, 58, 62, 62,
64, 59, 43, 41, 53, 59, 57, 51, 47, 49, 71, 99, 107, 105, 98, 87, 93, 109, 117, 114,
110, 113, 120, 132, 136, 131, 129, 123, 112, 105, 97, 95, 103, 115, 123, 125, 130, 140, 145,
145,
137, 134, 142, 147, 157, 176, 187, 183, 171, 157, 142, 132, 132, 133, 131, 127, 111, 92, 84,
83,
81, 72, 63, 60, 69, 90, 112, 122, 115, 112, 124, 131, 135, 144, 145, 149, 161, 174, 184, 181,
171, 160, 148, 143, 138, 127, 119, 119, 126, 130, 120, 107, 100, 99, 104, 109, 105, 95, 95,
106,
121, 138, 149, 158, 165, 170, 183, 200, 214, 227, 233, 236, 236, 225, 214, 206, 194, 188,
181, 173,
174, 175, 176, 174, 164, 159, 159, 153, 149, 150, 154, 166, 172, 160, 146, 136, 130, 131,
127, 112,
96, 91, 97, 107, 117, 125, 125, 120, 119, 120, 119, 112, 96, 80, 70, 65, 67, 69, 63, 63,
61, 48, 41, 46, 58, 73, 84, 91, 90, 85, 88, 88, 84, 79, 74, 84, 94, 99, 116, 128,
122, 111, 104, 99, 96, 101, 117, 128, 127, 124, 130, 139, 139, 138, 133, 115, 105, 115, 131,
141,
147, 149, 147, 149, 159, 162, 159, 158, 155, 156, 160, 162, 168, 168, 163, 166, 168, 148,
121, 118,
128, 127, 127, 124, 108, 93, 85, 76, 67, 56, 58, 82, 102, 108, 122, 137, 135, 131, 134, 133,
135, 145, 158, 165, 166, 167, 161, 152, 151, 147, 140, 128, 117, 116, 116, 113, 117, 115,
108, 105,
105, 99, 91, 98, 112, 115, 120, 133, 145, 158, 171, 182, 188, 190, 201, 222, 235, 239, 241,
245,
239, 230, 224, 214, 196, 178, 176, 183, 191, 200, 199, 189, 175, 159, 148, 140, 135, 150,
173, 185,
185, 178, 157, 135, 125, 115, 104, 101, 102, 100, 95, 93, 91, 81, 73, 74, 80, 87, 77, 72,
72, 56, 45, 47, 45, 42, 39, 37, 27, 16, 24, 54, 82, 92, 91, 94, 92, 88, 84, 75,
73, 80, 93, 113, 127, 129, 117, 107, 100, 90, 85, 82, 83, 101, 122, 134, 139, 141, 137, 130,
126, 116, 108, 120, 145, 168, 176, 173, 165, 151, 142, 144, 146, 149, 150, 155, 163, 158,
152, 144,
136, 140, 142, 136, 132, 126, 123, 122, 118, 120, 120, 115, 115, 108, 91, 82, 85, 98, 120,
144,
163, 171, 156, 138, 134, 129, 123, 128, 140, 155, 166, 169, 157, 140, 132, 125, 121, 121,
115, 110,
115, 113, 101, 92, 87, 83, 83, 86, 85, 81, 88, 106, 120, 127, 126, 121, 126, 144, 161, 167,
166, 173, 196, 217, 224, 226, 220, 211, 213, 217, 208, 200, 197, 187, 184, 190, 194, 198,
199, 186,
174, 167, 160, 160, 173, 188, 198, 206, 200, 181, 169, 152, 130, 119, 110, 110, 125, 126,
115, 102,
83, 68, 66, 72, 75, 79, 75, 61, 51, 49, 43, 38, 40, 41, 35, 32, 39, 48, 59, 72,
87, 98, 91, 87, 92, 84, 71, 66, 73, 91, 110, 123, 127, 113, 95, 88, 82, 76, 76, 84,
96, 109, 119, 123, 129, 127, 119, 121, 122, 126, 139, 148, 162, 173, 169, 158, 142, 127, 121,
121,
124, 125, 134, 149, 154, 158, 145, 119, 114, 119, 119, 128, 140, 142, 138, 130, 123, 125,
128, 125,
128, 137, 141, 147, 157, 156, 149, 158, 174, 171, 153, 139, 127, 123, 130, 136, 151, 166,
166, 158,
144, 130, 122, 113, 110, 115, 119, 122, 122, 112, 96, 85, 82, 79, 82, 95, 108, 112, 107, 103,
111, 126, 125, 113, 118, 129, 136, 149, 162, 173, 184, 194, 198, 186, 179, 191, 197, 190,
190, 198,
201, 193, 187, 185, 188, 197, 202, 206, 212, 213, 207, 198, 191, 193, 203, 203, 191, 178,
160, 137,
123, 116, 112, 120, 129, 122, 103, 88, 80, 63, 47, 46, 56, 65, 54, 41, 42, 45, 46, 47,
54, 64, 60, 61, 77, 79, 73, 90, 111, 109, 98, 100, 102, 93, 88, 95, 116, 137, 141, 140,
137, 122, 104, 97, 99, 101, 106, 110, 115, 127, 130, 129, 139, 148, 146, 143, 147, 144, 139,
149,
168, 172, 155, 139, 129, 117, 107, 110, 121, 133, 144, 153, 154, 138, 118, 103, 94, 96, 112,
136,
150, 143, 129, 125, 129, 133, 145, 158, 156, 149, 151, 156, 160, 162, 160, 153, 143, 131,
117, 107,
107, 110, 113, 123, 134, 131, 118, 111, 112, 104, 90, 99, 118, 121, 123, 131, 121, 104, 101,
112,
127, 132, 127, 126, 128, 125, 118, 125, 133, 123, 111, 107, 113, 124, 133, 150, 170, 179,
181, 183,
184, 180, 176, 182, 188, 193, 198, 205, 213, 211, 209, 215, 222, 226, 225, 228, 232, 224,
204, 190,
192, 199, 196, 193, 186, 168, 151, 136, 126, 125, 126, 123, 112, 95, 77, 64, 53, 40, 32, 34,
43, 47, 44, 40, 42, 48, 50, 48, 51, 50, 47, 52, 57, 63, 75, 81, 88, 95, 96, 98,
97, 88, 89, 111, 137, 148, 149, 144, 125, 109, 101, 101, 109, 120, 123, 124, 135, 142, 143,
153,
160, 156, 152, 148, 141, 135, 131, 128, 129, 126, 113, 105, 108, 101, 88, 91, 99, 104, 114,
118,
116, 114, 98, 78, 78, 91, 101, 119, 134, 135, 134, 135, 142, 157, 162, 155, 150, 147, 140,
140,
151, 154, 145, 133, 119, 115, 116, 102, 91, 99, 106, 106, 109, 104, 92, 89, 87, 82, 85, 91,
102, 123, 134, 131, 129, 121, 116, 126, 133, 132, 127, 121, 113, 114, 121, 124, 123, 118,
110, 113,
119, 114, 117, 137, 153, 158, 160, 159, 158, 158, 156, 152, 154, 163, 176, 193, 210, 213,
206, 205,
209, 214, 223, 226, 220, 217, 209, 199, 198, 192, 182, 178, 178, 174, 161, 151, 153, 150,
145, 136,
119, 104, 86, 68, 60, 49, 44, 52, 61, 68, 69, 58, 52, 56, 57, 57, 60, 56, 49, 51,
59, 69, 74, 80, 95, 115, 130, 134, 133, 134, 134, 145, 168, 173, 168, 168, 162, 149, 145, 147,
154, 168, 178, 183, 184, 174, 166, 168, 175, 174, 160, 154, 152, 138, 131, 133, 126, 111,
100, 94,
97, 93, 86, 97, 105, 101, 102, 107, 108, 102, 92, 87, 89, 97, 117, 149, 170, 162, 148, 150,
159, 168, 176, 176, 165, 147, 133, 131, 137, 138, 130, 122, 119, 117, 114, 110, 104, 104,
107, 101,
96, 91, 82, 81, 83, 79, 82, 100, 122, 141, 147, 140, 132, 121, 113, 119, 125, 122, 111, 103,
108, 113, 117, 124, 120, 116, 119, 117, 128, 142, 141, 148, 159, 161, 163, 169, 171, 171,
176, 183,
186, 181, 187, 202, 205, 198, 192, 192, 193, 195, 203, 204, 191, 184, 182, 179, 189, 195,
185, 180,
176, 165, 159, 161, 162, 155, 142, 130, 121, 104, 78, 66, 65, 46, 34, 51, 65, 66, 62, 48,
35, 34, 36, 35, 42, 49, 49, 53, 57, 57, 66, 76, 84, 95, 109, 120, 130, 137, 129, 122,
133, 143, 148, 152, 152, 157, 165, 164, 168, 183, 186, 181, 188, 189, 176, 171, 173, 173,
165, 149,
140, 139, 139, 134, 127, 118, 95, 78, 82, 82, 75, 76, 69, 64, 78, 90, 85, 80, 79, 83,
98, 117, 131, 145, 153, 153, 153, 151, 151, 155, 157, 152, 146, 146, 141, 133, 136, 134, 125,
123,
121, 123, 136, 137, 117, 102, 94, 84, 90, 98, 87, 82, 93, 104, 108, 115, 130, 138, 135, 128,
125, 122, 114, 113, 112, 101, 99, 107, 109, 110, 114, 117, 113, 103, 102, 118, 141, 151, 146,
144,
151, 165, 181, 181, 176, 181, 179, 177, 185, 190, 188, 185, 182, 174, 172, 175, 172, 177,
185, 187,
187, 183, 181, 192, 203, 202, 185, 175, 188, 200, 200, 190, 175, 162, 152, 146, 141, 128,
112, 104,
94, 76, 69, 77, 78, 73, 63, 51, 36, 24, 28, 39, 47, 54, 55, 54, 59, 67, 74, 74,
73, 86, 103, 113, 121, 126, 125, 127, 136, 142, 145, 155, 169, 183, 185, 178, 170, 166, 172,
183,
190, 187, 172, 166, 172, 167, 161, 158, 145, 134, 126, 115, 108, 94, 74, 66, 67, 63, 58, 61,
62, 65, 74, 73, 66, 69, 85, 103, 117, 131, 137, 139, 148, 152, 146, 138, 138, 144, 140, 133,
140, 150, 140, 128, 129, 124, 116, 118, 121, 124, 128, 128, 116, 96, 86, 91, 105, 116, 115,
117,
127, 128, 130, 140, 147, 145, 138, 123, 118, 126, 125, 112, 102, 101, 106, 112, 110, 112,
113, 102,
92, 93, 102, 117, 141, 164, 165, 155, 161, 173, 176, 178, 181, 192, 198, 188, 181, 185, 183,
172,
165, 159, 158, 164, 163, 158, 164, 171, 169, 164, 164, 176, 190, 194, 185, 173, 169, 179,
189, 186,
179, 169, 157, 141, 127, 126, 124, 109, 93, 80, 74, 78, 77, 65, 46, 33, 32, 34, 33, 38,
51, 62, 58, 52, 59, 68, 69, 68, 79, 96, 109, 117, 120, 127, 134, 139, 148, 148, 152, 175,
191, 190, 190, 191, 183, 166, 160, 171, 189, 199, 189, 169, 157, 161, 171, 173, 166, 155,
144, 129,
112, 107, 107, 96, 86, 88, 86, 83, 82, 83, 89, 88, 89, 96, 95, 106, 133, 152, 149, 130,
123, 127, 122, 123, 131, 132, 132, 130, 124, 120, 120, 121, 123, 123, 123, 128, 132, 131,
132, 130,
118, 103, 97, 113, 142, 163, 164, 149, 132, 127, 133, 142, 146, 146, 137, 116, 102, 103, 103,
97,
95, 96, 100, 108, 106, 98, 97, 94, 87, 80, 82, 102, 138, 167, 171, 159, 151, 154, 168, 183,
189, 188, 188, 182, 172, 168, 169, 166, 154, 148, 153, 156, 155, 154, 159, 170, 169, 156,
151, 167,
193, 208, 199, 177, 169, 177, 188, 193, 191, 183, 170, 155, 139, 120, 110, 105, 96, 89, 83,
75,
71, 60, 42, 32, 28, 22, 21, 30, 51, 71, 70, 53, 42, 42, 51, 63, 75, 95, 116, 127,
128, 125, 132, 145, 153, 163, 171, 176, 184, 193, 196, 190, 183, 174, 159, 157, 173, 185,
183, 170,
160, 165, 177, 184, 176, 157, 139, 125, 107, 96, 97, 97, 98, 100, 95, 93, 97, 99, 103, 100,
89, 89, 98, 113, 137, 148, 145, 129, 106, 97, 96, 97, 102, 108, 118, 124, 119, 112, 110, 110,
116, 126, 125, 125, 139, 151, 153, 150, 137, 126, 128, 138, 156, 168, 169, 159, 150, 145,
141, 141,
145, 140, 125, 109, 95, 88, 86, 86, 92, 96, 97, 99, 99, 97, 92, 80, 67, 73, 96, 117,
139, 157, 162, 164, 160, 158, 164, 167, 169, 172, 171, 167, 160, 154, 148, 144, 142, 142,
146, 151,
153, 160, 172, 172, 168, 172, 173, 179, 192, 192, 188, 186, 178, 182, 193, 194, 194, 185,
169, 152,
133, 115, 98, 86, 84, 80, 73, 67, 56, 43, 37, 31, 24, 27, 32, 34, 51, 68, 65, 56,
54, 57, 63, 74, 91, 106, 123, 141, 154, 164, 170, 170, 173, 186, 193, 193, 199, 200, 196, 187,
172, 163, 158, 155, 167, 174, 168, 166, 166, 165, 174, 180, 167, 151, 143, 131, 115, 111,
110, 106,
106, 116, 126, 129, 122, 111, 104, 95, 85, 95, 113, 117, 122, 125, 116, 102, 86, 76, 79, 85,
86, 88, 93, 93, 95, 101, 98, 99, 109, 115, 120, 130, 136, 138, 140, 144, 147, 148, 146, 144,
153, 160, 159, 155, 146, 138, 137, 135, 127, 118, 112, 105, 97, 93, 87, 79, 83, 97, 100, 90,
87, 91, 83, 63, 62, 78, 90, 113, 150, 172, 169, 159, 153, 154, 160, 165, 166, 162, 158, 156,
156, 157, 154, 155, 161, 162, 162, 169, 169, 168, 175, 178, 180, 194, 205, 202, 197, 199,
198, 188,
178, 182, 202, 210, 190, 168, 158, 141, 123, 118, 110, 91, 77, 76, 70, 56, 51, 50, 40, 30,
28, 32, 33, 34, 50, 64, 62, 69, 80, 75, 78, 94, 105, 121, 147, 175, 196, 198, 197, 206,
214, 217, 218, 216, 210, 199, 191, 175, 160, 165, 172, 165, 164, 171, 172, 165, 158, 157,
161, 158,
152, 151, 142, 124, 117, 118, 115, 122, 141, 154, 148, 131, 120, 112, 105, 102, 108, 112,
104, 100,
105, 104, 98, 89, 76, 61, 53, 58, 62, 56, 56, 66, 72, 81, 98, 105, 101, 107, 125, 134,
135, 135, 134, 136, 139, 142, 141, 138, 140, 143, 139, 128, 118, 114, 108, 101, 101, 106,
103, 89,
75, 66, 61, 67, 83, 95, 94, 87, 76, 61, 49, 51, 62, 72, 89, 115, 139, 149, 146, 141,
139, 139, 141, 139, 131, 129, 132, 138, 143, 148, 156, 163, 164, 166, 174, 178, 172, 170,
178, 194,
217, 227, 220, 217, 225, 229, 225, 219, 213, 209, 204, 200, 194, 181, 169, 153, 132, 121,
110, 100,
98, 100, 103, 94, 74, 59, 53, 49, 47, 47, 51, 57, 73, 93, 98, 94, 91, 95, 105, 118,
141, 166, 183, 189, 192, 200, 200, 204, 214, 209, 204, 197, 181, 174, 165, 156, 160, 158,
151, 153,
156, 155, 158, 157, 156, 164, 165, 163, 163, 151, 139, 140, 141, 145, 151, 155, 158, 160,
162, 151,
127, 111, 112, 114, 110, 100, 90, 90, 98, 100, 94, 84, 70, 59, 50, 45, 47, 51, 59, 76,
90, 104, 112, 111, 114, 131, 155, 165, 155, 145, 141, 141, 146, 140, 125, 124, 129, 126, 116,
110,
106, 98, 90, 85, 82, 82, 78, 64, 47, 43, 51, 59, 65, 77, 90, 89, 73, 58, 57, 70,
87, 94, 92, 106, 127, 138, 142, 137, 133, 135, 131, 123, 117, 115, 120, 126, 130, 139, 146,
147,
148, 152, 156, 164, 168, 166, 181, 209, 230, 231, 222, 225, 236, 237, 231, 220, 210, 204,
196, 188,
174, 156, 143, 130, 114, 101, 91, 80, 69, 68, 74, 77, 73, 59, 47, 46, 49, 55, 57, 56,
63, 88, 113, 119, 120, 128, 131, 137, 153, 166, 179, 189, 193, 199, 200, 198, 200, 198, 191,
183,
174, 165, 156, 156, 158, 151, 143, 147, 153, 155, 155, 150, 147, 162, 180, 186, 177, 159,
152, 155,
153, 152, 154, 149, 146, 160, 159, 135, 120, 112, 110, 113, 107, 97, 85, 77, 84, 94, 88, 70,
61, 59, 52, 51, 53, 48, 56, 94, 130, 138, 134, 129, 134, 150, 162, 168, 164, 151, 145, 144,
137, 132, 128, 126, 129, 127, 129, 130, 115, 102, 95, 80, 74, 82, 82, 72, 61, 59, 61, 62,
74, 99, 113, 106, 92, 85, 84, 86, 91, 96, 99, 110, 129, 138, 140, 140, 138, 137, 133, 124,
120, 121, 126, 134, 140, 137, 136, 147, 161, 171, 176, 174, 170, 189, 221, 237, 238, 236,
232, 231,
231, 232, 228, 216, 201, 190, 179, 164, 155, 150, 131, 111, 101, 90, 82, 72, 64, 68, 74, 75,
76, 71, 61, 54, 49, 50, 54, 58, 78, 116, 136, 137, 132, 130, 134, 140, 153, 170, 175, 185,
197, 202, 209, 210, 197, 185, 184, 181, 171, 161, 154, 151, 147, 143, 141, 144, 151, 156,
160, 173,
190, 200, 205, 197, 180, 174, 169, 164, 165, 160, 152, 154, 155, 154, 149, 137, 122, 106, 94,
90,
86, 80, 67, 56, 64, 72, 66, 57, 48, 40, 35, 34, 46, 70, 87, 99, 118, 129, 126, 129,
135, 143, 149, 147, 147, 141, 129, 127, 132, 131, 121, 111, 120, 133, 132, 129, 121, 105, 90,
80,
81, 91, 93, 85, 82, 88, 98, 109, 117, 122, 118, 112, 114, 111, 99, 101, 102, 87, 78, 90,
113, 133, 140, 136, 128, 117, 109, 109, 109, 108, 113, 123, 131, 132, 135, 141, 148, 160,
171, 178,
186, 196, 207, 213, 219, 225, 217, 207, 209, 214, 207, 188, 181, 180, 167, 155, 151, 138,
110, 87,
80, 77, 68, 64, 65, 68, 71, 71, 69, 67, 62, 59, 64, 68, 61, 58, 78, 107, 130, 145,
145, 139, 141, 145, 151, 164, 181, 196, 205, 212, 214, 205, 191, 181, 181, 187, 191, 183,
166, 156,
155, 154, 143, 141, 157, 175, 188, 199, 205, 206, 202, 191, 181, 170, 162, 164, 167, 155,
140, 143,
147, 142, 136, 122, 100, 83, 77, 83, 89, 79, 58, 47, 52, 61, 63, 53, 45, 47, 51, 59,
71, 75, 75, 84, 97, 105, 107, 107, 112, 121, 129, 134, 138, 137, 124, 116, 118, 116, 105, 99,
112, 134, 149, 145, 129, 116, 103, 99, 109, 118, 118, 115, 121, 129, 129, 128, 123, 114, 113,
114,
115, 120, 117, 107, 106, 107, 104, 104, 115, 125, 127, 125, 121, 123, 125, 119, 116, 113,
110, 124,
147, 152, 151, 165, 173, 173, 188, 202, 203, 203, 210, 217, 221, 220, 208, 199, 204, 208,
202, 196,
186, 176, 164, 147, 129, 111, 93, 81, 74, 70, 63, 56, 55, 57, 70, 78, 74, 67, 61, 55,
55, 58, 59, 55, 59, 85, 115, 130, 139, 148, 149, 153, 170, 182, 183, 185, 188, 189, 188, 190,
195, 188, 181, 185, 188, 180, 168, 160, 163, 168, 161, 161, 179, 190, 194, 199, 200, 198,
195, 192,
177, 158, 155, 158, 157, 151, 140, 134, 132, 122, 105, 94, 85, 80, 87, 94, 91, 81, 63, 49,
55, 69, 78, 77, 72, 75, 90, 101, 100, 87, 74, 73, 87, 106, 111, 107, 110, 114, 117, 126,
132, 122, 105, 92, 92, 99, 99, 95, 106, 122, 125, 128, 126, 112, 113, 135, 144, 134, 123, 119,
119, 119, 117, 110, 106, 106, 103, 104, 114, 122, 127, 122, 112, 109, 106, 108, 117, 116,
113, 124,
132, 131, 134, 136, 126, 114, 108, 122, 152, 170, 167, 164, 173, 184, 184, 182, 182, 189,
202, 210,
212, 209, 202, 203, 208, 205, 200, 196, 188, 175, 163, 158, 151, 131, 104, 82, 74, 72, 70, 68,
67, 71, 80, 83, 79, 70, 64, 58, 52, 51, 54, 60, 74, 89, 104, 127, 151, 156, 150, 161,
179, 178, 164, 159, 168, 181, 189, 190, 190, 187, 181, 182, 187, 191, 195, 198, 193, 177,
166, 177,
195, 196, 186, 184, 189, 187, 182, 185, 189, 178, 158, 143, 140, 139, 130, 119, 112, 106, 96,
86,
85, 91, 96, 95, 87, 74, 64, 69, 81, 82, 78, 82, 91, 92, 92, 97, 97, 88, 73, 66,
78, 99, 112, 118, 118, 109, 104, 111, 116, 113, 110, 107, 103, 99, 93, 96, 104, 106, 113, 125,
128, 128, 135, 143, 145, 135, 120, 111, 108, 106, 104, 100, 96, 94, 97, 104, 109, 115, 117,
114,
114, 107, 98, 105, 116, 115, 114, 122, 122, 114, 113, 121, 126, 118, 112, 121, 136, 146, 151,
159,
172, 175, 166, 165, 175, 185, 190, 196, 203, 198, 192, 195, 195, 190, 186, 185, 181, 171,
160, 156,
155, 141, 109, 86, 77, 74, 78, 83, 83, 83, 82, 83, 82, 77, 70, 66, 61, 54, 53, 67,
84, 93, 103, 120, 133, 143, 154, 164, 173, 173, 156, 150, 162, 174, 178, 180, 180, 179, 179,
185,
195, 199, 197, 196, 189, 184, 190, 204, 203, 186, 177, 183, 187, 186, 187, 191, 194, 187,
167, 147,
136, 133, 130, 125, 121, 116, 108, 101, 95, 90, 89, 87, 85, 86, 90, 100, 100, 83, 79, 93,
100, 93, 85, 80, 81, 83, 80, 80, 90, 98, 100, 106, 108, 108, 108, 107, 106, 109, 113, 108,
100, 95, 92, 98, 103, 102, 115, 138, 146, 146, 145, 143, 150, 150, 131, 108, 94, 91, 95, 101,
103, 104, 104, 94, 88, 93, 96, 99, 104, 104, 105, 115, 119, 108, 107, 117, 122, 116, 111, 125,
147, 152, 143, 130, 129, 140, 152, 165, 173, 173, 172, 173, 176, 180, 189, 193, 189, 181,
179, 190,
199, 190, 181, 177, 165, 149, 138, 132, 133, 128, 107, 88, 81, 84, 86, 83, 79, 77, 78, 76,
68, 62, 56, 47, 40, 39, 53, 81, 98, 95, 104, 125, 143, 156, 163, 170, 176, 171, 162, 156,
150, 156, 167, 169, 172, 179, 186, 192, 192, 182, 173, 175, 179, 176, 179, 188, 187, 182,
183, 189,
197, 196, 185, 181, 182, 181, 175, 161, 147, 141, 133, 122, 122, 125, 114, 106, 100, 85, 77,
84,
92, 89, 81, 82, 88, 89, 87, 91, 93, 77, 65, 66, 65, 70, 83, 84, 85, 95, 99, 102,
111, 112, 108, 102, 96, 95, 94, 93, 89, 83, 79, 89, 104, 120, 139, 152, 154, 150, 149, 150,
150, 151, 132, 104, 94, 91, 93, 107, 116, 107, 91, 83, 88, 94, 96, 95, 95, 95, 99, 113,
128, 129, 131, 140, 139, 133, 138, 153, 163, 162, 156, 153, 158, 165, 170, 171, 174, 183,
186, 184,
188, 190, 188, 185, 177, 174, 179, 187, 199, 201, 191, 180, 170, 157, 142, 135, 135, 127,
114, 112,
117, 114, 100, 84, 82, 84, 77, 70, 64, 55, 47, 43, 38, 40, 53, 74, 94, 103, 115, 143,
161, 162, 165, 165, 167, 178, 176, 161, 158, 168, 175, 181, 188, 192, 193, 186, 174, 173,
180, 181,
176, 173, 171, 179, 194, 198, 196, 201, 203, 198, 190, 189, 197, 195, 180, 168, 158, 148,
139, 127,
119, 121, 119, 113, 105, 88, 84, 98, 97, 80, 71, 80, 96, 102, 93, 82, 79, 76, 65, 61,
71, 82, 85, 88, 94, 101, 105, 104, 100, 100, 96, 87, 81, 73, 71, 78, 76, 63, 59, 75,
104, 124, 124, 127, 140, 147, 143, 134, 127, 128, 124, 107, 91, 87, 92, 101, 105, 98, 85, 82,
81, 74, 76, 83, 85, 86, 86, 91, 109, 127, 131, 129, 134, 138, 140, 151, 161, 167, 175, 170,
163, 169, 175, 178, 183, 183, 178, 181, 189, 187, 185, 189, 187, 178, 171, 178, 194, 198,
188, 172,
156, 145, 141, 138, 129, 122, 123, 121, 120, 116, 106, 103, 99, 89, 81, 71, 57, 50, 51, 48,
46, 51, 61, 80, 100, 110, 113, 124, 137, 148, 161, 166, 166, 171, 169, 157, 155, 160, 166,
175,
184, 186, 180, 174, 168, 162, 159, 159, 157, 155, 159, 171, 184, 190, 195, 201, 201, 196,
191, 187,
188, 185, 173, 161, 152, 146, 140, 132, 125, 127, 124, 109, 93, 80, 77, 86, 90, 85, 82, 87,
88, 78, 67, 64, 69, 72, 72, 80, 91, 98, 102, 103, 103, 105, 112, 117, 115, 110, 98, 88,
80, 67, 70, 84, 85, 75, 74, 83, 102, 119, 121, 126, 141, 142, 132, 124, 120, 123, 121, 109,
103, 105, 108, 113, 114, 106, 96, 88, 82, 76, 76, 84, 90, 94, 103, 114, 126, 137, 135, 126,
128, 142, 154, 161, 168, 175, 173, 162, 159, 164, 169, 178, 187, 189, 192, 188, 178, 170,
164, 164,
171, 181, 183, 179, 178, 176, 163, 148, 140, 139, 134, 126, 118, 109, 108, 112, 115, 115,
110, 102,
95, 86, 79, 75, 69, 66, 62, 58, 62, 65, 72, 83, 89, 96, 106, 116, 129, 141, 151, 156,
161, 168, 173, 172, 164, 162, 169, 180, 190, 194, 193, 187, 175, 167, 156, 147, 160, 174,
181, 193,
200, 202, 204, 203, 201, 196, 187, 182, 179, 177, 175, 169, 160, 150, 138, 135, 135, 135,
131, 116,
102, 92, 85, 90, 103, 106, 99, 93, 90, 86, 84, 78, 78, 85, 89, 96, 102, 106, 107, 104,
105, 115, 120, 123, 130, 127, 109, 95, 93, 90, 86, 84, 89, 88, 82, 90, 101, 108, 118, 124,
124, 121, 118, 119, 118, 122, 128, 122, 110, 106, 108, 107, 103, 99, 93, 87, 84, 85, 83, 78,
80, 85, 93, 107, 114, 121, 134, 138, 138, 141, 149, 159, 164, 170, 175, 172, 176, 189, 192,
190,
193, 194, 193, 187, 178, 169, 164, 169, 177, 181, 181, 182, 175, 161, 150, 144, 138, 129,
121, 117,
111, 103, 98, 95, 96, 101, 97, 89, 83, 83, 79, 71, 65, 63, 61, 57, 55, 55, 54, 61,
68, 73, 87, 105, 119, 127, 129, 132, 142, 159, 168, 162, 155, 151, 155, 161, 165, 171, 175,
170,
162, 156, 151, 152, 161, 167, 170, 179, 188, 191, 197, 200, 195, 185, 178, 179, 181, 185,
188, 182,
172, 161, 150, 144, 136, 129, 124, 117, 107, 99, 97, 101, 109, 108, 100, 96, 94, 91, 92, 90,
86, 89, 97, 99, 97, 99, 100, 99, 99, 104, 114, 122, 126, 123, 111, 100, 96, 94, 85, 76,
75, 77, 79, 90, 108, 117, 124, 129, 129, 128, 128, 129, 128, 129, 137, 136, 119, 100, 90, 88,
87, 89, 93, 97, 99, 100, 89, 72, 70, 84, 97, 105, 107, 110, 122, 132, 133, 135, 149, 160,
159, 162, 171, 180, 185, 186, 189, 193, 194, 190, 184, 176, 169, 167, 163, 159, 163, 169,
172, 171,
165, 153, 148, 149, 139, 129, 122, 114, 109, 106, 106, 113, 112, 102, 93, 89, 93, 100, 100,
97,
99, 94, 79, 60, 48, 53, 64, 72, 81, 91, 103, 118, 124, 121, 124, 133, 145, 159, 167, 165,
159, 153, 156, 162, 169, 182, 188, 187, 183, 177, 171, 163, 158, 169, 181, 183, 185, 186,
186, 192,
194, 188, 183, 183, 182, 180, 176, 168, 160, 161, 156, 142, 139, 135, 123, 125, 127, 121,
114, 104,
98, 97, 95, 101, 102, 88, 81, 87, 87, 83, 79, 79, 81, 83, 90, 95, 94, 100, 109, 113,
112, 112, 113, 112, 107, 94, 75, 56, 51, 68, 83, 95, 108, 119, 125, 128, 132, 137, 135, 129,
125, 131, 137, 127, 109, 102, 93, 78, 80, 95, 106, 113, 111, 99, 85, 78, 81, 89, 94, 96,
101, 109, 119, 133, 146, 150, 148, 149, 154, 163, 175, 177, 172, 175, 186, 196, 201, 193,
183, 183,
179, 170, 161, 151, 147, 148, 149, 151, 147, 138, 133, 127, 121, 115, 109, 104, 106, 115,
121, 113,
102, 98, 101, 106, 104, 103, 105, 104, 104, 100, 87, 69, 57, 58, 68, 76, 92, 110, 113, 112,
119, 120, 122, 132, 141, 147, 156, 160, 156, 157, 169, 181, 188, 197, 205, 210, 214, 207,
191, 181,
173, 171, 181, 188, 187, 192, 195, 191, 189, 187, 183, 179, 176, 174, 175, 171, 160, 155,
152, 148,
143, 137, 136, 141, 148, 144, 127, 114, 111, 110, 111, 109, 104, 97, 84, 76, 83, 85, 75, 76,
81, 84, 92, 91, 87, 91, 98, 105, 115, 123, 119, 107, 96, 84, 71, 63, 68, 79, 84, 92,
110, 125, 130, 126, 124, 127, 126, 125, 122, 124, 131, 123, 107, 94, 81, 74, 77, 86, 97, 102,
103, 101, 94, 82, 75, 74, 79, 88, 100, 114, 121, 125, 132, 135, 134, 142, 150, 158, 167, 169,
171, 173, 177, 191, 204, 203, 196, 191, 191, 185, 167, 153, 150, 152, 151, 153, 149, 135,
120, 112,
115, 115, 113, 122, 130, 130, 130, 130, 125, 119, 116, 113, 110, 118, 127, 121, 110, 107, 96,
74,
67, 73, 73, 76, 89, 99, 98, 92, 96, 108, 109, 106, 115, 127, 135, 144, 154, 159, 156, 163,
188, 211, 215, 208, 205, 205, 200, 191, 188, 193, 192, 189, 187, 180, 175, 174, 177, 179,
174, 166,
161, 161, 165, 162, 150, 140, 135, 134, 144, 157, 159, 154, 147, 146, 143, 126, 117, 118,
114, 110,
107, 99, 82, 70, 72, 71, 63, 61, 69, 83, 89, 85, 86, 85, 80, 86, 104, 113, 105, 91,
74, 63, 62, 61, 67, 77, 83, 96, 108, 106, 104, 107, 114, 124, 133, 134, 128, 121, 113, 103,
92, 82, 73, 70, 79, 93, 102, 100, 92, 91, 92, 84, 78, 79, 85, 94, 102, 115, 121, 122,
135, 145, 137, 132, 141, 151, 160, 171, 178, 183, 187, 193, 207, 219, 218, 212, 202, 194,
189, 175,
159, 158, 156, 154, 152, 133, 110, 104, 105, 112, 126, 132, 132, 141, 144, 136, 126, 120,
122, 124,
128, 140, 145, 134, 116, 103, 94, 82, 75, 82, 92, 99, 102, 100, 95, 92, 99, 112, 116, 110,
109, 118, 126, 132, 142, 153, 163, 180, 199, 210, 211, 210, 212, 213, 212, 203, 193, 190,
191, 193,
193, 186, 177, 174, 177, 185, 184, 171, 159, 153, 154, 155, 148, 141, 137, 138, 154, 177,
186, 183,
178, 170, 153, 134, 124, 121, 125, 128, 121, 105, 80, 65, 61, 58, 57, 57, 62, 72, 79, 81,
78, 73, 74, 85, 99, 102, 90, 72, 61, 59, 59, 59, 68, 81, 94, 95, 83, 87, 98, 105,
121, 129, 121, 110, 98, 93, 88, 79, 72, 66, 63, 71, 85, 93, 92, 91, 93, 90, 83, 76,
81, 89, 95, 114, 133, 138, 138, 133, 127, 132, 131, 126, 133, 145, 158, 168, 168, 162, 171,
195,
219, 230, 226, 217, 207, 198, 190, 174, 158, 155, 159, 162, 151, 131, 116, 110, 118, 140,
153, 149,
143, 140, 139, 134, 131, 131, 130, 139, 146, 137, 129, 123, 112, 101, 91, 81, 80, 88, 95, 98,
92, 84, 86, 91, 90, 96, 99, 92, 88, 96, 114, 132, 144, 149, 159, 184, 204, 210, 217, 219,
213, 204, 192, 183, 182, 188, 198, 205, 205, 198, 191, 184, 178, 175, 170, 156, 145, 143,
145, 143,
134, 124, 130, 158, 196, 214, 207, 194, 182, 170, 162, 152, 137, 136, 143, 138, 121, 96, 77,
69,
63, 63, 69, 68, 62, 66, 77, 77, 70, 68, 71, 87, 104, 102, 89, 78, 68, 69, 78, 74,
71, 80, 85, 86, 92, 98, 106, 114, 113, 109, 107, 104, 99, 97, 91, 80, 71, 66, 65, 76,
87, 87, 86, 86, 84, 79, 72, 71, 79, 89, 112, 136, 145, 146, 141, 130, 122, 122, 126, 119,
112, 119, 132, 140, 143, 151, 168, 189, 217, 230, 217, 200, 189, 184, 180, 169, 157, 148,
147, 152,
150, 140, 133, 134, 141, 152, 159, 155, 149, 151, 154, 149, 141, 137, 142, 149, 151, 143,
132, 126,
119, 111, 101, 89, 86, 88, 88, 89, 84, 84, 98, 105, 101, 97, 99, 106, 113, 124, 134, 140,
148, 165, 179, 189, 200, 207, 205, 199, 194, 193, 191, 192, 195, 196, 199, 205, 201, 194,
191, 181,
165, 158, 158, 153, 143, 132, 126, 127, 133, 146, 166, 181, 199, 212, 200, 177, 161, 155,
154, 149,
136, 121, 119, 123, 116, 104, 87, 71, 69, 67, 65, 65, 57, 51, 58, 62, 62, 70, 81, 87,
93, 100, 104, 102, 91, 83, 80, 76, 73, 72, 74, 80, 82, 87, 100, 106, 104, 104, 109, 108,
100, 93, 84, 70, 64, 67, 70, 66, 67, 70, 70, 68, 61, 55, 60, 79, 97, 99, 105, 119,
127, 133, 138, 131, 123, 122, 122, 115, 104, 101, 114, 130, 141, 155, 171, 189, 205, 209,
201, 182,
162, 156, 159, 159, 155, 140, 132, 143, 150, 153, 155, 143, 138, 148, 156, 156, 144, 135,
137, 140,
142, 146, 147, 152, 158, 152, 136, 121, 110, 101, 93, 85, 81, 75, 66, 71, 81, 87, 100, 109,
110, 115, 133, 147, 139, 129, 133, 143, 161, 176, 176, 183, 198, 206, 209, 210, 208, 207,
205, 198,
196, 195, 192, 196, 198, 193, 186, 176, 164, 156, 158, 163, 157, 145, 140, 153, 179, 193,
192, 194,
205, 211, 200, 181, 168, 157, 147, 139, 129, 120, 117, 117, 107, 90, 82, 79, 72, 68, 64, 56,
46, 40, 42, 53, 71, 86, 89, 91, 106, 125, 127, 115, 102, 91, 85, 79, 70, 66, 68, 78,
90, 95, 102, 113, 115, 114, 117, 116, 109, 99, 90, 88, 84, 73, 64, 58, 62, 73, 82, 87,
82, 73, 79, 88, 86, 84, 90, 101, 109, 107, 105, 115, 121, 121, 126, 128, 119, 112, 119, 139,
154, 162, 168, 171, 181, 192, 185, 175, 170, 161, 160, 165, 160, 152, 147, 149, 158, 156,
149, 149,
148, 142, 138, 138, 142, 149, 157, 165, 167, 163, 154, 149, 149, 147, 142, 132, 119, 103, 85,
70,
65, 64, 63, 72, 87, 90, 93, 106, 119, 133, 138, 137, 141, 142, 144, 152, 159, 167, 171, 174,
181, 194, 204, 202, 193, 185, 179, 176, 174, 172, 173, 173, 166, 158, 153, 154, 159, 165,
171, 172,
168, 166, 172, 185, 193, 194, 195, 193, 193, 201, 208, 205, 193, 177, 162, 147, 126, 109,
104, 104,
101, 90, 74, 67, 67, 62, 55, 50, 51, 67, 87, 96, 103, 102, 96, 98, 106, 116, 125, 121,
110, 98, 87, 78, 75, 77, 80, 84, 87, 88, 96, 110, 120, 120, 113, 110, 115, 116, 104, 91,
83, 74, 72, 80, 85, 90, 99, 96, 80, 74, 74, 74, 74, 70, 66, 76, 93, 96, 93, 95,
98, 105, 113, 117, 124, 131, 131, 137, 147, 152, 157, 163, 171, 184, 196, 196, 187, 179, 174,
169,
161, 146, 138, 144, 150, 143, 137, 139, 137, 139, 146, 147, 155, 167, 167, 163, 156, 147,
145, 146,
143, 139, 139, 128, 109, 99, 90, 74, 65, 63, 67, 83, 97, 96, 93, 101, 115, 124, 131, 137,
150, 164, 169, 174, 178, 172, 167, 164, 165, 180, 194, 189, 179, 174, 165, 157, 155, 153,
145, 147,
158, 158, 151, 150, 153, 164, 170, 165, 171, 185, 187, 187, 192, 195, 193, 193, 206, 220,
223, 210,
187, 169, 153, 132, 114, 98, 82, 79, 84, 76, 61, 54, 50, 51, 59, 62, 76, 100, 114, 114,
105, 100, 101, 104, 105, 104, 111, 113, 104, 99, 94, 82, 71, 63, 57, 59, 73, 86, 92, 96,
99, 102, 104, 105, 112, 120, 116, 107, 96, 85, 79, 77, 84, 89, 88, 88, 84, 75, 68, 67,
66, 65, 67, 74, 93, 104, 91, 81, 79, 85, 101, 110, 121, 138, 147, 150, 155, 159, 165, 178,
188, 192, 196, 196, 189, 187, 182, 170, 157, 147, 142, 144, 156, 161, 157, 155, 155, 156,
159, 154,
152, 162, 175, 178, 174, 165, 159, 152, 141, 138, 144, 148, 141, 123, 104, 89, 73, 66, 73, 83,
97, 112, 113, 109, 110, 116, 127, 145, 164, 177, 184, 184, 179, 171, 160, 153, 160, 170, 173,
177,
175, 162, 157, 163, 161, 155, 153, 153, 159, 159, 147, 145, 153, 157, 156, 157, 164, 173,
182, 195,
205, 207, 209, 215, 219, 211, 201, 197, 185, 169, 153, 129, 104, 85, 77, 80, 86, 88, 79, 65,
55, 50, 47, 54, 76, 102, 115, 116, 111, 106, 103, 99, 93, 92, 100, 105, 99, 92, 79, 62,
53, 49, 52, 62, 74, 86, 86, 81, 85, 94, 101, 106, 108, 108, 105, 101, 96, 92, 89, 84,
79, 82, 89, 89, 84, 78, 70, 66, 63, 58, 63, 72, 77, 79, 74, 71, 76, 86, 95, 98,
105, 123, 144, 164, 179, 181, 183, 187, 181, 178, 180, 184, 191, 188, 174, 167, 161, 155,
153, 153,
160, 168, 163, 157, 154, 150, 145, 137, 139, 156, 175, 182, 178, 171, 167, 162, 160, 156,
150, 149,
144, 130, 110, 95, 88, 88, 94, 100, 116, 133, 127, 115, 114, 121, 133, 143, 153, 168, 180,
185,
178, 169, 167, 164, 163, 167, 166, 170, 180, 180, 179, 184, 185, 176, 165, 153, 150, 158,
159, 154,
153, 158, 162, 156, 151, 163, 181, 201, 217, 225, 226, 221, 210, 199, 187, 180, 174, 161,
141, 119,
103, 93, 87, 84, 84, 84, 76, 60, 44, 33, 30, 30, 45, 74, 98, 113, 113, 98, 89, 89,
92, 95, 93, 90, 88, 81, 73, 71, 72, 72, 75, 78, 75, 78, 87, 92, 95, 103, 106, 99,
91, 95, 98, 94, 96, 97, 97, 98, 101, 102, 94, 86, 82, 78, 79, 81, 77, 69, 65, 65,
69, 76, 81, 84, 84, 86, 95, 98, 103, 127, 153, 169, 186, 196, 194, 189, 183, 175, 171, 179,
184, 181, 181, 180, 169, 157, 153, 156, 155, 151, 149, 150, 146, 141, 137, 129, 125, 140,
154, 161,
169, 172, 176, 185, 183, 173, 160, 145, 132, 121, 111, 107, 104, 103, 113, 126, 125, 115,
108, 103,
106, 115, 123, 131, 141, 153, 161, 164, 167, 168, 164, 161, 166, 174, 179, 184, 193, 193,
190, 193,
190, 175, 159, 148, 142, 147, 160, 168, 170, 165, 155, 143, 143, 161, 172, 182, 210, 227,
220, 213,
211, 206, 193, 181, 171, 157, 147, 138, 126, 116, 104, 87, 76, 68, 62, 53, 42, 33, 30, 34,
53, 84, 101, 98, 92, 88, 85, 91, 103, 105, 95, 86, 80, 83, 85, 81, 75, 74, 81, 91,
90, 88, 93, 96, 96, 98, 100, 95, 91, 95, 93, 86, 93, 101, 105, 113, 115, 112, 103, 87,
79, 81, 79, 76, 72, 61, 56, 58, 64, 71, 74, 74, 76, 80, 85, 94, 114, 140, 148, 146,
165, 187, 187, 182, 184, 186, 187, 191, 200, 201, 186, 173, 169, 161, 156, 155, 151, 149,
153, 152,
146, 141, 133, 123, 122, 138, 157, 162, 168, 182, 188, 184, 182, 179, 165, 144, 133, 134,
127, 119,
119, 121, 128, 126, 113, 103, 93, 86, 87, 99, 117, 127, 138, 154, 156, 145, 141, 147, 157,
167,
179, 190, 193, 193, 193, 189, 181, 175, 170, 160, 151, 142, 134, 137, 153, 165, 158, 148,
145, 137,
132, 145, 160, 172, 194, 213, 219, 217, 211, 202, 189, 179, 180, 181, 170, 156, 140, 122,
105, 87,
67, 58, 57, 44, 29, 27, 31, 37, 52, 75, 85, 81, 85, 91, 92, 96, 106, 112, 102, 92,
98, 102, 93, 84, 83, 90, 99, 110, 119, 115, 106, 100, 91, 83, 87, 93, 93, 96, 97, 96,
102, 108, 110, 114, 115, 116, 113, 101, 97, 101, 92, 83, 77, 68, 63, 66, 67, 68, 73, 76,
73, 75, 86, 94, 102, 117, 128, 137, 162, 188, 196, 195, 192, 191, 190, 185, 189, 193, 185,
178,
170, 158, 152, 151, 151, 150, 149, 145, 139, 133, 129, 130, 136, 148, 162, 172, 181, 185,
185, 185,
183, 181, 174, 158, 150, 147, 135, 124, 118, 114, 115, 118, 115, 104, 90, 78, 72, 80, 98, 111,
125, 140, 144, 144, 155, 168, 175, 184, 193, 199, 202, 199, 199, 198, 188, 178, 173, 164,
153, 145,
144, 149, 153, 155, 154, 150, 144, 134, 128, 136, 151, 169, 198, 221, 226, 224, 212, 198,
192, 190,
195, 201, 190, 167, 142, 120, 101, 84, 73, 66, 55, 39, 29, 31, 36, 39, 46, 63, 78, 89,
96, 98, 100, 102, 104, 107, 104, 102, 107, 103, 90, 82, 84, 90, 103, 115, 114, 108, 96, 84,
82, 75, 70, 74, 80, 85, 88, 96, 112, 119, 120, 123, 120, 114, 108, 104, 107, 106, 94, 78,
65, 64, 66, 62, 62, 64, 63, 64, 65, 65, 63, 58, 68, 89, 103, 116, 146, 179, 189, 185,
184, 186, 184, 186, 192, 193, 187, 172, 157, 154, 152, 147, 145, 144, 141, 138, 137, 137,
132, 127,
137, 155, 163, 167, 176, 186, 183, 175, 171, 164, 158, 155, 151, 150, 146, 135, 121, 112,
114, 117,
111, 98, 85, 77, 75, 74, 79, 90, 105, 123, 136, 147, 162, 179, 193, 199, 200, 199, 199, 200,
200, 200, 194, 184, 173, 164, 155, 151, 155, 156, 145, 141, 148, 144, 129, 115, 118, 131,
137, 156,
195, 222, 226, 222, 211, 200, 201, 208, 214, 212, 197, 176, 153, 128, 102, 82, 70, 64, 53, 40,
39, 43, 41, 37, 41, 57, 75, 87, 90, 96, 109, 113, 107, 105, 108, 112, 113, 114, 111, 105,
101, 104, 117, 120, 113, 109, 96, 78, 72, 72, 71, 73, 73, 75, 90, 109, 120, 124, 126, 128,
121, 107, 102, 108, 111, 109, 105, 95, 79, 68, 65, 62, 61, 60, 60, 63, 62, 56, 52, 50,
53, 65, 83, 108, 140, 167, 180, 192, 201, 194, 189, 194, 200, 204, 196, 179, 168, 161, 157,
151,
144, 145, 144, 140, 145, 154, 156, 154, 157, 163, 166, 175, 184, 188, 190, 185, 174, 162,
157, 159,
165, 172, 170, 157, 138, 122, 123, 123, 107, 95, 92, 83, 73, 71, 80, 89, 97, 114, 140, 164,
178, 186, 196, 203, 200, 196, 198, 199, 195, 194, 196, 191, 182, 174, 173, 170, 161, 152,
140, 126,
119, 117, 116, 115, 114, 118, 127, 144, 177, 207, 220, 228, 226, 212, 206, 212, 212, 205,
193, 169,
145, 126, 103, 81, 64, 53, 49, 51, 51, 46, 43, 37, 38, 48, 57, 68, 84, 94, 99, 100,
96, 96, 105, 115, 127, 138, 136, 129, 125, 123, 123, 120, 110, 97, 83, 71, 62, 60, 63, 70,
85, 96, 99, 105, 112, 115, 115, 106, 95, 96, 102, 102, 102, 103, 100, 89, 79, 75, 66, 56,
53, 51, 47, 39, 35, 35, 36, 39, 50, 61, 72, 96, 130, 161, 184, 197, 198, 194, 191, 186,
183, 185, 186, 183, 181, 175, 165, 156, 155, 158, 159, 162, 166, 167, 165, 163, 165, 166,
165, 172,
181, 175, 168, 165, 159, 156, 161, 171, 178, 178, 172, 157, 140, 131, 123, 113, 109, 106, 92,
78,
70, 70, 82, 104, 126, 139, 145, 156, 172, 181, 185, 185, 188, 192, 191, 189, 187, 183, 184,
185,
188, 193, 189, 169, 145, 127, 113, 102, 100, 109, 115, 115, 120, 130, 140, 158, 184, 207,
225, 233,
233, 227, 214, 200, 192, 189, 176, 155, 135, 115, 95, 78, 64, 59, 61, 54, 44, 41, 40, 40,
43, 46, 51, 64, 81, 91, 97, 101, 106, 112, 122, 133, 137, 137, 133, 128, 131, 130, 126, 124,
113, 96, 81, 63, 49, 49, 60, 80, 99, 104, 98, 93, 95, 96, 91, 91, 101, 110, 116, 119,
116, 110, 101, 96, 96, 95, 86, 68, 52, 43, 38, 35, 33, 31, 36, 46, 55, 67, 75, 83,
110, 144, 163, 174, 181, 178, 176, 172, 165, 169, 176, 178, 182, 184, 182, 176, 169, 168,
173, 174,
171, 169, 167, 165, 172, 178, 169, 165, 170, 169, 161, 157, 157, 159, 167, 174, 172, 159,
150, 148,
143, 132, 129, 135, 133, 122, 114, 104, 86, 85, 100, 117, 136, 148, 146, 147, 158, 168, 179,
186,
186, 188, 194, 193, 184, 179, 186, 197, 198, 193, 189, 173, 146, 123, 107, 96, 96, 112, 131,
142,
151, 160, 153, 147, 162, 185, 207, 218, 217, 207, 196, 185, 170, 154, 143, 131, 116, 103, 94,
84,
75, 70, 64, 53, 44, 44, 51, 53, 56, 62, 65, 75, 92, 103, 105, 102, 103, 106, 110, 119,
123, 117, 117, 120, 116, 111, 116, 116, 104, 90, 74, 53, 41, 46, 61, 74, 87, 97, 92, 83,
84, 91, 99, 109, 120, 127, 130, 127, 118, 114, 113, 108, 100, 94, 88, 75, 58, 46, 39, 31,
24, 35, 54, 62, 71, 83, 83, 87, 116, 148, 164, 176, 181, 173, 168, 168, 167, 173, 188, 196,
191, 185, 187, 195, 196, 189, 185, 179, 174, 177, 184, 190, 193, 189, 172, 156, 157, 161,
157, 155,
155, 151, 150, 150, 149, 148, 145, 138, 131, 130, 138, 149, 151, 139, 122, 106, 97, 103, 110,
115,
130, 147, 145, 141, 158, 183, 188, 183, 177, 171, 172, 175, 177, 185, 190, 189, 184, 178,
174, 166,
151, 133, 123, 124, 130, 143, 159, 168, 171, 170, 164, 157, 162, 183, 203, 207, 202, 191,
179, 169,
151, 134, 125, 111, 93, 85, 84, 83, 78, 69, 60, 57, 60, 62, 61, 63, 74, 83, 88, 92,
97, 108, 113, 106, 100, 99, 95, 97, 108, 113, 111, 110, 106, 96, 89, 89, 84, 70, 58, 49,
45, 53, 60, 68, 84, 93, 95, 97, 100, 108, 116, 119, 121, 123, 121, 114, 108, 111, 111, 99,
85, 75, 72, 70, 61, 50, 40, 30, 30, 38, 46, 58, 73, 82, 91, 103, 119, 143, 161, 165,
167, 171, 169, 163, 168, 179, 184, 186, 183, 176, 178, 181, 176, 172, 178, 185, 185, 181,
181, 187,
191, 188, 181, 170, 163, 162, 159, 160, 163, 154, 139, 127, 130, 142, 149, 146, 138, 134,
139, 146,
145, 134, 128, 126, 123, 118, 115, 122, 142, 157, 163, 166, 171, 178, 181, 178, 173, 172,
172, 167,
170, 185, 188, 173, 158, 152, 155, 157, 151, 140, 133, 134, 141, 144, 145, 155, 175, 187,
186, 177,
177, 189, 196, 193, 190, 183, 167, 146, 127, 115, 110, 107, 98, 90, 87, 82, 71, 64, 66, 75,
83, 81, 79, 83, 93, 107, 114, 106, 100, 107, 110, 109, 110, 106, 101, 96, 92, 96, 99, 91,
80, 71, 63, 61, 63, 61, 59, 60, 61, 57, 52, 61, 88, 116, 126, 121, 115, 118, 123, 130,
136, 131, 123, 120, 114, 111, 109, 98, 85, 77, 72, 65, 54, 43, 34, 28, 28, 35, 45, 63,
87, 105, 113, 112, 117, 141, 164, 170, 171, 169, 162, 161, 164, 164, 166, 168, 169, 169, 168,
166,
164, 167, 175, 178, 173, 172, 174, 181, 192, 190, 180, 172, 167, 164, 158, 154, 151, 145,
139, 131,
129, 134, 132, 124, 128, 136, 135, 136, 137, 129, 125, 131, 137, 138, 132, 133, 154, 172,
172, 169,
172, 174, 174, 180, 185, 186, 187, 184, 180, 183, 181, 171, 167, 164, 159, 154, 144, 134,
136, 140,
138, 140, 142, 151, 178, 194, 191, 185, 180, 186, 194, 189, 181, 171, 155, 137, 123, 116,
112, 112,
111, 102, 93, 85, 77, 72, 71, 78, 86, 84, 86, 104, 121, 123, 113, 100, 94, 98, 105, 107,
105, 100, 96, 93, 86, 79, 78, 72, 58, 52, 54, 57, 65, 69, 65, 62, 60, 60, 62, 70,
92, 112, 111, 106, 114, 126, 131, 130, 130, 128, 123, 121, 121, 122, 119, 110, 99, 85, 72, 63,
54, 44, 34, 27, 31, 43, 57, 71, 94, 112, 112, 109, 111, 128, 147, 148, 147, 153, 155, 154,
150, 150, 154, 157, 157, 160, 167, 168, 166, 171, 176, 171, 163, 161, 167, 178, 193, 196,
184, 175,
166, 163, 166, 162, 156, 149, 137, 126, 121, 125, 132, 138, 137, 132, 132, 137, 144, 146,
139, 138,
143, 146, 148, 150, 157, 167, 164, 158, 159, 166, 176, 182, 188, 193, 196, 198, 198, 197,
195, 184,
169, 160, 155, 149, 151, 156, 150, 140, 137, 138, 142, 147, 164, 183, 187, 181, 173, 169,
171, 165,
153, 148, 142, 130, 118, 112, 116, 119, 115, 111, 108, 99, 87, 80, 78, 80, 84, 98, 114, 120,
125, 125, 113, 103, 98, 94, 102, 107, 102, 102, 103, 94, 78, 66, 67, 70, 66, 61, 55, 56,
70, 80, 80, 76, 67, 62, 58, 53, 69, 92, 101, 113, 123, 122, 123, 127, 131, 133, 133, 132,
129, 130, 130, 123, 109, 92, 76, 63, 55, 52, 48, 43, 46, 60, 71, 76, 95, 110, 105, 95,
89, 94, 112, 120, 124, 137, 146, 144, 137, 133, 139, 146, 153, 160, 167, 169, 166, 165, 171,
170,
164, 166, 170, 172, 176, 181, 181, 177, 171, 165, 163, 157, 145, 134, 132, 133, 125, 119,
131, 145,
145, 142, 142, 139, 139, 145, 150, 152, 155, 161, 159, 152, 156, 167, 173, 175, 174, 170,
175, 181,
185, 191, 199, 205, 203, 191, 182, 177, 172, 169, 164, 161, 165, 167, 163, 156, 154, 158,
157, 154,
158, 168, 175, 172, 163, 155, 156, 158, 151, 145, 143, 137, 127, 119, 115, 117, 125, 127,
113, 96,
84, 81, 85, 88, 98, 123, 133, 125, 125, 128, 121, 111, 98, 90, 92, 94, 92, 87, 87, 91,
85, 73, 66, 61, 61, 60, 55, 50, 49, 58, 66, 61, 51, 46, 46, 47, 54, 74, 99, 115,
116, 116, 120, 121, 119, 120, 124, 130, 132, 127, 117, 108, 108, 107, 93, 77, 65, 61, 59, 54,
59, 75, 83, 85, 91, 96, 94, 92, 91, 88, 93, 115, 134, 135, 131, 136, 142, 141, 138, 140,
149, 158, 161, 158, 153, 159, 171, 169, 166, 174, 178, 172, 171, 174, 177, 177, 168, 156,
147, 137,
131, 130, 126, 128, 137, 143, 138, 132, 135, 141, 141, 133, 131, 138, 145, 148, 150, 156,
165, 169,
169, 174, 181, 185, 184, 175, 169, 175, 182, 184, 185, 189, 191, 186, 178, 171, 167, 171,
176, 176,
171, 173, 179, 175, 172, 176, 173, 170, 172, 174, 176, 181, 182, 173, 162, 156, 154, 154,
145, 134,
134, 134, 128, 119, 115, 114, 106, 96, 89, 85, 87, 98, 117, 135, 139, 134, 134, 135, 135, 127,
112, 102, 95, 94, 99, 101, 97, 95, 95, 90, 82, 68, 52, 46, 45, 40, 35, 42, 50, 47,
44, 47, 45, 46, 65, 91, 106, 115, 124, 123, 117, 115, 118, 117, 122, 126, 122, 120, 122, 119,
110, 100, 90, 78, 68, 63, 57, 53, 62, 79, 86, 87, 93, 97, 96, 93, 88, 86, 93, 112,
130, 130, 126, 129, 136, 143, 148, 147, 144, 143, 142, 150, 159, 162, 168, 170, 171, 174,
174, 170,
169, 174, 178, 177, 175, 167, 152, 145, 141, 130, 133, 148, 156, 155, 151, 141, 134, 134,
129, 121,
121, 127, 130, 136, 149, 166, 178, 184, 193, 195, 192, 191, 184, 174, 172, 175, 180, 183,
184, 181,
178, 179, 172, 163, 163, 170, 172, 169, 168, 172, 171, 168, 167, 169, 167, 162, 162, 165,
170, 174,
174, 168, 155, 145, 141, 137, 126, 115, 117, 125, 125, 118, 108, 100, 91, 79, 74, 79, 90, 109,
128, 140, 146, 149, 153, 147, 134, 127, 118, 107, 105, 109, 112, 107, 98, 96, 94, 84, 72, 57,
43, 36, 30, 22, 21, 25, 30, 40, 46, 42, 48, 70, 91, 104, 113, 126, 136, 132, 128, 127,
126, 126, 126, 129, 137, 138, 132, 125, 113, 102, 92, 77, 67, 57, 52, 62, 72, 80, 89, 90,
93, 95, 87, 89, 99, 99, 98, 110, 123, 129, 127, 125, 127, 133, 137, 137, 140, 148, 151, 152,
156, 157, 158, 165, 172, 172, 166, 162, 166, 170, 166, 162, 162, 157, 152, 149, 145, 146,
147, 152,
162, 164, 157, 150, 140, 129, 120, 112, 105, 108, 123, 145, 163, 170, 177, 186, 192, 195,
192, 189,
187, 182, 181, 181, 181, 188, 191, 189, 189, 182, 173, 174, 176, 176, 177, 178, 174, 165,
160, 163,
167, 164, 158, 157, 162, 165, 160, 155, 153, 142, 133, 137, 140, 132, 124, 116, 110, 109,
108, 106,
102, 97, 91, 87, 83, 85, 94, 114, 135, 145, 146, 144, 142, 140, 130, 119, 115, 113, 112, 109,
106, 108, 103, 91, 87, 80, 67, 54, 42, 29, 18, 9, 5, 13, 27, 38, 48, 54, 56, 68,
91, 110, 117, 119, 121, 123, 129, 134, 135, 138, 144, 144, 144, 142, 133, 120, 105, 92, 83,
72,
62, 58, 57, 61, 70, 78, 83, 92, 99, 101, 104, 107, 106, 107, 111, 119, 129, 135, 135, 131,
129, 132, 133, 134, 136, 142, 149, 150, 149, 150, 153, 161, 169, 169, 163, 157, 157, 159,
156, 152,
155, 160, 161, 164, 169, 170, 172, 172, 173, 173, 166, 152, 137, 128, 119, 109, 109, 121,
134, 145,
156, 160, 161, 166, 174, 184, 191, 189, 186, 185, 178, 173, 182, 193, 203, 204, 198, 197,
196, 192,
187, 182, 180, 177, 175, 173, 168, 166, 169, 171, 170, 169, 168, 165, 154, 143, 134, 128,
126, 130,
133, 130, 124, 113, 101, 101, 102, 98, 98, 98, 97, 96, 99, 104, 108, 119, 131, 134, 132, 130,
132, 135, 131, 123, 121, 121, 117, 110, 105, 99, 95, 89, 85, 81, 69, 55, 43, 29, 17, 12,
16, 26, 33, 42, 55, 61, 67, 77, 91, 107, 118, 120, 125, 128, 130, 134, 140, 145, 146, 143,
142, 136, 124, 111, 96, 80, 69, 62, 59, 57, 52, 50, 56, 65, 74, 86, 96, 109, 116,
};
Rick Roll
The following example was created by Samantha Lagestee in 2017. Inspired by the popular
meme, this code rickrolls people by playing the song "Never Gonna Give You Up" by Rick
Astley on a piezo buzzer. Open the serial port to see the lyrics and sing along.

Code
COPY

Explain
/* Rick Roll Code
AUTHOR: Samantha Lagestee
Copyright 2017 samilagestee at gmail dot com

This program is free software: you can redistribute it and/or


modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

DISCLAIMER: The song "Never Gonna Give You Up" by Rick Astley
is not the creative property of the author. This code simply
plays a Piezo buzzer rendition of the song.

*/

#define a3f 208 // 208 Hz


#define b3f 233 // 233 Hz
#define b3 247 // 247 Hz
#define c4 261 // 261 Hz MIDDLE C
#define c4s 277 // 277 Hz
#define e4f 311 // 311 Hz
#define f4 349 // 349 Hz
#define a4f 415 // 415 Hz
#define b4f 466 // 466 Hz
#define b4 493 // 493 Hz
#define c5 523 // 523 Hz
#define c5s 554 // 554 Hz
#define e5f 622 // 622 Hz
#define f5 698 // 698 Hz
#define f5s 740 // 740 Hz
#define a5f 831 // 831 Hz

#define rest -1

// change these pins according to your setup


int piezo = 8;
int led = 9;

volatile int beatlength = 100; // determines tempo


float beatseparationconstant = 0.3;

int a; // part index


int b; // song index
int c; // lyric index

boolean flag; // play/pause

// Parts 1 and 2 (Intro)

int song1_intro_melody[] =
{c5s, e5f, e5f, f5, a5f, f5s, f5, e5f, c5s, e5f, rest, a4f, a4f};

int song1_intro_rhythmn[] =
{6, 10, 6, 6, 1, 1, 1, 1, 6, 10, 4, 2, 10};

// Parts 3 or 5 (Verse 1)

int song1_verse1_melody[] =
{ rest, c4s, c4s, c4s, c4s, e4f, rest, c4, b3f, a3f,
rest, b3f, b3f, c4, c4s, a3f, a4f, a4f, e4f,
rest, b3f, b3f, c4, c4s, b3f, c4s, e4f, rest, c4, b3f, b3f, a3f,
rest, b3f, b3f, c4, c4s, a3f, a3f, e4f, e4f, e4f, f4, e4f,
c4s, e4f, f4, c4s, e4f, e4f, e4f, f4, e4f, a3f,
rest, b3f, c4, c4s, a3f, rest, e4f, f4, e4f
};

int song1_verse1_rhythmn[] =
{ 2, 1, 1, 1, 1, 2, 1, 1, 1, 5,
1, 1, 1, 1, 3, 1, 2, 1, 5,
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3,
1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 4,
5, 1, 1, 1, 1, 1, 1, 1, 2, 2,
2, 1, 1, 1, 3, 1, 1, 1, 3
};

char\* lyrics_verse1[] =
{ "We're ", "no ", "strangers ", "", "to ", "love ", "", "\r\n",
"You ", "know ", "the ", "rules ", "and ", "so ", "do ", "I\r\n",
"A ", "full ", "commitment's ", "", "", "what ", "I'm ", "thinking ", "", "of", "\r\n",
"You ", "wouldn't ", "", "get ", "this ", "from ", "any ", "", "other ", "", "guy\r\n",
"I ", "just ", "wanna ", "", "tell ", "you ", "how ", "I'm ", "feeling", "\r\n",
"Gotta ", "", "make ", "you ", "understand", "", "\r\n"
};

// Parts 4 or 6 (Chorus)

int song1_chorus_melody[] =
{ b4f, b4f, a4f, a4f,
f5, f5, e5f, b4f, b4f, a4f, a4f, e5f, e5f, c5s, c5, b4f,
c5s, c5s, c5s, c5s,
c5s, e5f, c5, b4f, a4f, a4f, a4f, e5f, c5s,
b4f, b4f, a4f, a4f,
f5, f5, e5f, b4f, b4f, a4f, a4f, a5f, c5, c5s, c5, b4f,
c5s, c5s, c5s, c5s,
c5s, e5f, c5, b4f, a4f, rest, a4f, e5f, c5s, rest
};

int song1_chorus_rhythmn[] =
{ 1, 1, 1, 1,
3, 3, 6, 1, 1, 1, 1, 3, 3, 3, 1, 2,
1, 1, 1, 1,
3, 3, 3, 1, 2, 2, 2, 4, 8,
1, 1, 1, 1,
3, 3, 6, 1, 1, 1, 1, 3, 3, 3, 1, 2,
1, 1, 1, 1,
3, 3, 3, 1, 2, 2, 2, 4, 8, 4
};

char* lyrics_chorus[] =
{ "Never ", "", "gonna ", "", "give ", "you ", "up\r\n",
"Never ", "", "gonna ", "", "let ", "you ", "down", "", "\r\n",
"Never ", "", "gonna ", "", "run ", "around ", "", "", "", "and ", "desert ", "", "you\r\n",
"Never ", "", "gonna ", "", "make ", "you ", "cry\r\n",
"Never ", "", "gonna ", "", "say ", "goodbye ", "", "", "\r\n",
"Never ", "", "gonna ", "", "tell ", "a ", "lie ", "", "", "and ", "hurt ", "you\r\n"
};

void setup()
{
pinMode(piezo, OUTPUT);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
Serial.begin(9600);
flag = true;
a = 4;
b = 0;
c = 0;
}

void loop()
{
// edit code here to define play conditions
/*
if (CONDITION 1) { // play
flag = true;
}
else if (CONDITION2) { // pause
flag = false;
}
*/

// play next step in song


if (flag == true) {
play();
}
}

void play() {
int notelength;
if (a == 1 || a == 2) { // Intro
// intro
notelength = beatlength * song1_intro_rhythmn[b];
if (song1_intro_melody[b] > 0) { // if not a rest, play note
digitalWrite(led, HIGH);
tone(piezo, song1_intro_melody[b], notelength);
}

b++;
if (b >= sizeof(song1_intro_melody) / sizeof(int)) {
a++;
b = 0;
c = 0;
}
} else if (a == 3 || a == 5) { // Verse 1
// verse
notelength = beatlength * 2 * song1_verse1_rhythmn[b];
if (song1_verse1_melody[b] > 0) {
digitalWrite(led, HIGH);
Serial.print(lyrics_verse1[c]);
tone(piezo, song1_verse1_melody[b], notelength);
c++;
}
b++;
if (b >= sizeof(song1_verse1_melody) / sizeof(int)) {
a++;
b = 0;
c = 0;
}
} else if (a == 4 || a == 6) { //chorus
// chorus
notelength = beatlength * song1_chorus_rhythmn[b];
if (song1_chorus_melody[b] > 0) {
digitalWrite(led, HIGH);
Serial.print(lyrics_chorus[c]);
tone(piezo, song1_chorus_melody[b], notelength);
c++;
}

b++;
if (b >= sizeof(song1_chorus_melody) / sizeof(int)) {
Serial.println("");
a++;
b = 0;
c = 0;
}
}

delay(notelength); // necessary because piezo is on independent timer


noTone(piezo);
digitalWrite(led, LOW);
delay(notelength * beatseparationconstant); // create separation between notes
if (a == 7) { // loop back around to beginning of song
a = 1;
}
}
MusicalAlgoFun
This is a simple song with the Arduino created by Alexandre Quessy in 2006.

Code
COPY

Explain
/\*

- Au Clair de la Lune with an Arduino and a PC speaker.


- The calculation of the tones is made following the mathematical
- operation:
-
- timeUpDown = 1/(2 * toneFrequency) = period / 2
- )c( Copyleft AlexandreQuessy 2006 http://alexandre.quessy.net
- Inspired from D. Cuartielles's http://www.arduino.cc/en/Tutorial/PlayMelody
\*/

int ledPin = 9;
int speakerOut = 8;

/_ 2 octavas :: semitones. 0 = do, 2 = re, etc. _/


/_ MIDI notes from 48 to 71. Indices here are from 0 to 23. _/

int timeUpDown[] = {3822, 3606, 3404, 3214, 3032, 2862,


2702, 2550, 2406, 2272, 2144, 2024,
1911, 1803, 1702, 1607, 1516, 1431,
1351, 1275, 1203, 1136, 1072, 1012};
/_ our song. Each number is a (MIDI note - 48) on a beat. _/

byte song[] = {12,12,12,14, 16,16,14,14, 12,16,14,14, 12,12,12,12,


14,14,14,14, 9,9,9,9, 14,12,11,9, 7,7,7,7};
// do do do re mi re do mi re re do...

byte beat = 0;
int MAXCOUNT = 32;
float TEMPO_SECONDS = 0.2;
byte statePin = LOW;
byte period = 0;
int i, timeUp;

void setup() {
pinMode(ledPin, OUTPUT);
pinMode(speakerOut, OUTPUT);
}

void loop() {
digitalWrite(speakerOut, LOW);
for (beat = 0; beat < MAXCOUNT; beat++) {
statePin = !statePin;
digitalWrite(ledPin, statePin);

timeUp = timeUpDown[song[beat]];

period = ((1000000 / timeUp) / 2) * TEMPO_SECONDS;


for (i = 0; i < period; i++) {
digitalWrite(speakerOut, HIGH);
delayMicroseconds(timeUp);
digitalWrite(speakerOut, LOW);
delayMicroseconds(timeUp);
}
/* Uncomment this if you want notes to be discrete */
/* delay(50); */

}
digitalWrite(speakerOut, LOW);
delay(1000);
}
Improved version
COPY

Explain
/\*

- Square wave tune with an Arduino and a PC speaker.


- The calculation of the tones is made following the mathematical
- operation:
-
- timeUpDown = 1/(2 \* toneFrequency) = period / 2
- )c( Copyleft 2009 Daniel Gimpelevich
- Inspired from AlexandreQuessy's https://playground.arduino.cc/Code/MusicalAlgoFun
\*/

const byte ledPin = 13;


const byte speakerOut = 11; /_ This makes a standard old PC speaker connector fit nicely
over the pins. _/

/_ 10.5 octaves :: semitones. 60 = do, 62 = re, etc. _/


/_ MIDI notes from 0, or C(-1), to 127, or G9. _/
/_ Rests are note number -1. _/

unsigned int timeUpDown[128];

/_ our song. Each number pair is a MIDI note and a note symbol. _/
/_ Symbols are 1 for whole, -1 for dotted whole, 2 for half, _/
/_ -2 for dotted half, 4 for quarter, -4 for dotted quarter, etc. _/

const byte BPM = 120;


const char song[] = {
64,4,64,4,65,4,67,4, 67,4,65,4,64,4,62,4,
60,4,60,4,62,4,64,4, 64,-4,62,8,62,2,
64,4,64,4,65,4,67,4, 67,4,65,4,64,4,62,4,

Bit Math with Arduino


Learn about bit math and how to manipulate individual bits in your Arduino sketches.
AuthorDon Cross
Last revision08/02/2024
This article was revised on 2022/09/28 by Hannes Siebeneicher.

Often when programming in the Arduino environment (or on any computer, for that matter),
the ability to manipulate individual bits will become useful or even necessary. Here are some
situations where bit math can be helpful:

Saving memory by packing up to 8 true/false data values in a single byte.


Turning on/off individual bits in a control register or hardware port register.
Performing certain arithmetic operations involving multiplying or dividing by powers of 2.
In this article, we first explore the basic bitwise operators available in the C++ language.
Then we learn how to combine them to perform certain common useful operations. This
article is based on the bit math tutorial by CosineKitty.

The Binary System


To better explain the bitwise operators, this tutorial will express most integer values using
binary notation, also known as base two. In this system, all integer values use only the values
0 and 1 for each digit. This is how virtually all modern computers store data internally. Each
0 or 1 digit is called a bit, short for binary digit.

In the familiar decimal system (base ten), a number like 572 means 5*10^2 + 7*10^1 +
2*10^0. Likewise, in binary a number like 11010 means 1*2^4 + 1*2^3 + 0*2^2 + 1*2^1 +
0*2^0 \= 16 + 8 + 2 = 26.

It is crucial that you understand how the binary system works in order to follow the
remainder of this tutorial. If you need help in this area, one good place to start is the
Wikipedia article on the binary system.

Arduino allows you to specify binary numbers by prefixing them with 0b, e.g., 0b11 == 3.
For legacy reasons, it also defines the constants B0 through B11111111, which can be used in
the same way.

Bitwise AND
The bitwise AND operator in C++ is a single ampersand, &, used between two other integer
expressions. Bitwise AND operates on each bit position of the surrounding expressions
independently, according to this rule: if both input bits are 1, the resulting output is 1,
otherwise the output is 0. Another way of expressing this is:

COPY
0 & 0 == 0
0 & 1 == 0
1 & 0 == 0
1 & 1 == 1
In Arduino, the type int is a 16-bit value, so using & between two int expressions causes 16
simultaneous AND operations to occur. In a code fragment like:

COPY
int a = 92; // in binary: 0000000001011100
int b = 101; // in binary: 0000000001100101
int c = a & b; // result: 0000000001000100, or 68 in decimal.
Each of the 16 bits in a and b are processed by using the bitwise AND, and all 16 resulting
bits are stored in c, resulting in the value 01000100 in binary, which is 68 in decimal.
One of the most common uses of bitwise AND is to select a particular bit (or bits) from an
integer value, often called masking. For example, if you wanted to access the least significant
bit in a variable x, and store the bit in another variable y, you could use the following code:

COPY
int x = 5; // binary: 101
int y = x & 1; // now y == 1
x = 4; // binary: 100
y = x & 1; // now y == 0
Bitwise OR
The bitwise OR operator in C++ is the vertical bar symbol, |. Like the & operator, | operates
independently each bit in its two surrounding integer expressions, but what it does is different
(of course). The bitwise OR of two bits is 1 if either or both of the input bits is 1, otherwise it
is 0. In other words:

COPY
0 | 0 == 0
0 | 1 == 1
1 | 0 == 1
1 | 1 == 1
Here is an example of the bitwise OR used in a snippet of C++ code:

COPY
int a = 92; // in binary: 0000000001011100
int b = 101; // in binary: 0000000001100101
int c = a | b; // result: 0000000001111101, or 125 in decimal.
Bitwise OR is often used to make sure that a given bit is turned on (set to 1) in a given
expression. For example, to copy the bits from a into b, while making sure the lowest bit is
set to 1, use the following code:

COPY
b = a | 1;
Bitwise XOR
There is a somewhat unusual operator in C++ called bitwise exclusive OR, also known as
bitwise XOR. (In English this is usually pronounced "eks-or".) The bitwise XOR operator is
written using the caret symbol ^. This operator is similar to the bitwise OR operator |, except
that it evaluates to 1 for a given position when exactly one of the input bits for that position is
1. If both are 0 or both are 1, the XOR operator evaluates to 0 :

COPY
0 ^ 0 == 0
0 ^ 1 == 1
1 ^ 0 == 1
1 ^ 1 == 0
Another way to look at bitwise XOR is that each bit in the result is a 1 if the input bits are
different, or 0 if they are the same.

Here is a simple code example:

COPY
int x = 12; // binary: 1100
int y = 10; // binary: 1010
int z = x ^ y; // binary: 0110, or decimal 6
The ^ operator is often used to toggle (i.e. change from 0 to 1, or 1 to 0) some of the bits in an
integer expression while leaving others alone. For example:
COPY
y = x ^ 1; // toggle the lowest bit in x, and store the result in y.
Bitwise NOT
The bitwise NOT operator in C++ is the tilde character ~. Unlike & and |, the bitwise NOT
operator is applied to a single operand to its right. Bitwise NOT changes each bit to its
opposite: 0 becomes 1, and 1 becomes 0. For example:

COPY
int a = 103; // binary: 0000000001100111
int b = ~a; // binary: 1111111110011000 = -104
You might be surprised to see a negative number like -104 as the result of this operation. This
is because the highest bit in an int variable is the so-called sign bit. If the highest bit is 1, the
number is interpreted as negative. This encoding of positive and negative numbers is referred
to as two's complement. For more information, see the Wikipedia article on two's
complement.

As an aside, it is interesting to note that for any integer x, ~x is the same as -x-1.

At times, the sign bit in a signed integer expression can cause some unwanted surprises, as
we shall see later.

Bit Shift Operators


There are two bit shift operators in C++: the left shift operator << and the right shift operator
>>. These operators cause the bits in the left operand to be shifted left or right by the number
of positions specified by the right operand. For example:

COPY
int a = 5; // binary: 0000000000000101
int b = a << 3; // binary: 0000000000101000, or 40 in decimal
int c = b >> 3; // binary: 0000000000000101, or back to 5 like we started with
When you shift a value x by y bits (x << y), the leftmost y bits in x are lost, literally shifted
out of existence:

COPY
int a = 5; // binary: 0000000000000101
int b = a << 14; // binary: 0100000000000000 - the first 1 in 101 was discarded
If you are certain that none of the ones in a value are being shifted into oblivion, a simple
way to think of the left-shift operator is that it multiplies the left operand by 2 raised to the
right operand power. For example, to generate powers of 2, the following expressions can be
employed:

COPY

Explain
1 << 0 == 1
1 << 1 == 2
1 << 2 == 4
1 << 3 == 8
...
1 << 8 == 256
1 << 9 == 512
1 << 10 == 1024
...
When you shift x right by y bits (x >> y), and the highest bit in x is a 1, the behavior depends
on the exact data type of x. If x is of type int, the highest bit is the sign bit, determining
whether x is negative or not, as we have discussed above. In that case, the sign bit is copied
into lower bits, for esoteric historical reasons:

COPY
int x = -16; // binary: 1111111111110000
int y = x >> 3; // binary: 1111111111111110
This behavior, called sign extension, is often not the behavior you want. Instead, you may
wish zeros to be shifted in from the left. It turns out that the right shift rules are different for
unsigned int expressions, so you can use a typecast to suppress ones being copied from the
left:

COPY
int x = -16; // binary: 1111111111110000
int y = unsigned(x) >> 3; // binary: 0001111111111110
If you are careful to avoid sign extension, you can use the right-shift operator >> as a way to
divide by powers of 2. For example:

COPY
int x = 1000;
int y = x >> 3; // integer division of 1000 by 8, causing y = 125.
Assignment Operators
Often in programming, you want to operate on the value of a variable x and store the
modified value back into x. In most programming languages, for example, you can increase
the value of a variable x by 7 using the following code:

COPY
x = x + 7; // increase x by 7
Because this kind of thing occurs so frequently in programming, C++ provides a shorthand
notation in the form of specialized assignment operators. The above code fragment can be
written more concisely as:

COPY
x += 7; // increase x by 7
It turns out that bitwise AND, bitwise OR, left shift, and right shift, all have shorthand
assignment operators. Here is an example:

COPY

Explain
int x = 1; // binary: 0000000000000001
x <<= 3; // binary: 0000000000001000
x |= 3; // binary: 0000000000001011 - because 3 is 11 in binary
x &= 1; // binary: 0000000000000001
x ^= 4; // binary: 0000000000000101 - toggle using binary mask 100
x ^= 4; // binary: 0000000000000001 - toggle with mask 100 again
There is no shorthand assignment operator for the bitwise NOT operator ~; if you want to
toggle all the bits in x, you need to do this:

COPY
x = ~x; // toggle all bits in x and store back in x
A word of caution: bitwise operators vs. boolean operators
It is very easy to confuse the bitwise operators in C++ with the boolean operators. For
instance, the bitwise AND operator & is not the same as the boolean AND operator &&, for
two reasons:

They don't calculate numbers the same way. Bitwise & operates independently on each bit in
its operands, whereas && converts both of its operands to a boolean value (true\==1 or false\
==0), then returns either a single true or false value. For example, 4 & 2 == 0, because 4 is
100 in binary and 2 is 010 in binary, and none of the bits are 1 in both integers. However, 4
&& 2 == true, and true numerically is equal to 1. This is because 4 is not 0, and 2 is not 0, so
both are considered as boolean true values.
Bitwise operators always evaluate both of their operands, whereas boolean operators use so-
called short-cut evaluation. This matters only if the operands have side-effects, such as
causing output to occur or modifying the value of something else in memory. Here is an
example of how two similar looking lines of code can have very different behavior:
COPY

Explain
int fred (int x)
{
Serial.print ("fred ");
Serial.println (x, DEC);
return x;
}
COPY
void setup()
{
Serial.begin (9600);
}
COPY

Explain
void loop()
{
delay(1000); // wait 1 second, so output is not flooded with serial data!
int x = fred(0) & fred(1);
}
If you compile and upload this program, and then monitor the serial output from the Arduino
GUI, you will see the following lines of text repeated every second:

COPY
fred 0
fred 1
This is because both fred(0) and fred(1) are called, resulting in the generated output, the
return values 0 and 1 are bitwise-ANDed together, storing 0 in x. If you edit the line

COPY
int x = fred(0) & fred(1);
and replace the bitwise & with its boolean counterpart &&,

COPY
int x = fred(0) && fred(1);
and compile, upload, and run the program again, you may be surprised to see only a single
line of text repeated every second in the serial monitor window:

COPY
fred 0
Why does this happen? This is because boolean && is using a short-cut: if its left operand is
zero (a.k.a. false), it is already certain that the result of the expression will be false, so there is
no need to evaluate the right operand. In other words, the line of code int x = fred(0) &&
fred(1); is identical in meaning to:

COPY

Explain
int x;
if (fred(0) == 0) {
x = false; // stores 0 in x
} else {
if (fred(1) == 0) {
x = false; // stores 0 in x
} else {
x = true; // stores 1 in x
}
}
Clearly, the boolean && is a lot more concise way to express this surprisingly complex piece
of logic.

As with bitwise AND and boolean AND, there are differences between bitwise OR and
boolean OR. The bitwise OR operator | always evaluates both of its operands, whereas the
boolean OR operator || evaluates its right operand only if its left operand is false (zero). Also,
bitwise | operates independently on all of the bits in its operands, whereas boolean || treats
both of its operands as either true (nonzero) or false (zero), and evaluates to either true (if
either operand is nonzero) or false (if both operands are zero).

Putting it all together: common problems solved


Now we start exploring how we can combine the various bitwise operators to perform useful
tasks using C++ syntax in the Arduino environment.

A word about port registers in the Atmega8 microcontroller


Usually when you want to read or write to digital pins in the Atmega8, you use the built-in
functions digitalRead() or digitalWrite() supplied by the Arduino environment. Suppose that
in your setup() function, you wanted to define the digital pins 2 through 13 as output, and
then you wanted pins 11, 12, and 13 to be set HIGH, and all the other pins set LOW. Here is
how one would typically accomplish this:

COPY

Explain
void setup()
{
int pin;
for (pin=2; pin <= 13; ++pin) {
pinMode (pin, OUTPUT);
}
for (pin=2; pin <= 10; ++pin) {
digitalWrite (pin, LOW);
}
for (pin=11; pin <= 13; ++pin) {
digitalWrite (pin, HIGH);
}
}
It turns out there is a way to accomplish the same thing using direct access to Atmega8
hardware ports and bitwise operators:

COPY

Explain
void setup()
{
// set pins 1 (serial transmit) and 2..7 as output,
// but leave pin 0 (serial receive) as input
// (otherwise serial port will stop working!) ...
DDRD = B11111110; // digital pins 7,6,5,4,3,2,1,0
COPY
// set pins 8..13 as output...
DDRB = B00111111; // digital pins -,-,13,12,11,10,9,8
COPY
// Turn off digital output pins 2..7 ...
PORTD &= B00000011; // turns off 2..7, but leaves pins 0 and 1 alone
COPY
// Write simultaneously to pins 8..13...
PORTB = B00111000; // turns on 13,12,11; turns off 10,9,8
}
This code takes advantage of the fact that the control registers DDRD and DDRB each
contain 8 bits that determine whether a given digital pin is output (1) or input (0). The upper
2 bits in DDRB are not used, because there is no such thing is digital pin 14 or 15 on the
Atmega8. Likewise, the port registers PORTB and PORTD contain one bit for the most
recently written value to each digital pin, HIGH (1) or LOW (0).

Generally speaking, doing this sort of thing is not a good idea. Why not? Here are a few
reasons:

The code is much more difficult for you to debug and maintain and is a lot harder for other
people to understand. It only takes a few microseconds for the processor to execute code, but
it might take hours for you to figure out why it isn't working right and fix it! Your time is
valuable, right? But the computer's time is very cheap, measured in the cost of the electricity
you feed it. Usually, it is much better to write code the most obvious way.
The code is less portable. If you use digitalRead() and digitalWrite(), it is much easier to
write code that will run on all of the Atmel microcontrollers, whereas the control and port
registers can be different on each kind of microcontroller.
It is a lot easier to cause unintentional malfunctions with direct port access. Notice how the
line DDRD = B11111110; above mentions that it must leave pin 0 as an input pin. Pin 0 is
the receive line on the serial port. It would be very easy to accidentally cause your serial port
to stop working by changing pin 0 into an output pin! Now that would be very confusing
when you suddenly are unable to receive serial data, wouldn't it?
So you might be saying to yourself, great, why would I ever want to use this stuff then? Here
are some of the positive aspects of direct port access:

If you are running low on program memory, you can use these tricks to make your code
smaller. It requires a lot fewer bytes of compiled code to simultaneously write a bunch of
hardware pins simultaneously via the port registers than it would using a for loop to set each
pin separately. In some cases, this might make the difference between your program fitting in
flash memory or not!
Sometimes you might need to set multiple output pins at exactly the same time. Calling
digitalWrite(10,HIGH); followed by digitalWrite(11,HIGH); will cause pin 10 to go HIGH
several microseconds before pin 11, which may confuse certain time-sensitive external digital
circuits you have hooked up. Alternatively, you could set both pins high at exactly the same
moment in time using PORTB |= B1100;
You may need to be able to turn pins on and off very quickly, meaning within fractions of a
microsecond. If you look at the source code in lib/targets/arduino/wiring.c, you will see that
digitalRead() and digitalWrite() are each about a dozen or so lines of code, which get
compiled into quite a few machine instructions. Each machine instruction requires one clock
cycle at 16MHz, which can add up in time-sensitive applications. Direct port access can do
the same job in a lot fewer clock cycles.
More advanced example: disabling an interrupt
Now let's take what we have learned and start to make sense of some of the weird things you
will sometimes see advanced programmers do in their code. For example, what does it mean
when someone does the following?

COPY
// Disable the interrupt.
GICR &= ~(1 << INT0);
This is an actual code sample from the Arduino 0007 runtime library, in the file lib\targets\
arduino\winterrupts.c. First of all, we need to know what GICR and INT0 mean. It turns out
that GICR is a control register that defines whether certain CPU interrupts are enabled (1) or
disabled (0). If we search through the Arduino standard header files for INT0, we find
various definitions. Depending on what kind of microcontroller you are writing for, you have
either

COPY
#define INT0 6
or

COPY
#define INT0 0
So on some processors, the above line of code will compile to:

COPY
GICR &= ~(1 << 0);
and on others, it will compile to:

COPY
GICR &= ~(1 << 6);
Let us study the latter case, as it is more illustrative. First of all, the value (1 << 6) means that
we shift 1 left by 6 bits, which is the same as 26, or 64. More useful in this context is to see
this value in binary: 01000000. Then, the bitwise NOT operator ~ is applied to this value,
resulting in all the bits being toggled: 10111111. Then the bitwise AND assignment operator
is used, so the code above has the same effect as:

COPY
GICR = GICR & B10111111;
This has the effect of leaving all the bits alone in GICR, except for the second-to-highest bit,
which is turned off.

In the case where INT0 has been defined to 0 for your particular microcontroller, the line of
code would instead be interpreted as:

COPY
GICR = GICR & B11111110;
which turns off the lowest bit in the GICR register but leaves the other bits as they were. This
is an example of how the Arduino environment can support a wide variety of
microcontrollers with a single line of runtime library source code.

Saving memory by packing multiple data items in a single byte


There are many situations where you have a lot of data values, each of which can be either
true or false. An example of this is if you are building your own LED grid and you want to
display symbols on the grid by turning individual LEDs on or off. An example of a 5x7
bitmap for the letter X might look like this:

A simple way to store such an image is using an array of integers. The code for this approach
might look like this:

COPY

Explain
const prog_uint8_t BitMap[5][7] = { // store in program memory to save RAM
{1,1,0,0,0,1,1},
{0,0,1,0,1,0,0},
{0,0,0,1,0,0,0},
{0,0,1,0,1,0,0},
{1,1,0,0,0,1,1}
};
COPY

Explain
void DisplayBitMap()
{
for (byte x=0; x<5; ++x) {
for (byte y=0; y<7; ++y) {
byte data = pgm_read_byte (&BitMap[x][y]); // fetch data from program memory
if (data) {
// turn on the LED at location (x,y)
} else {
// turn off the LED at location (x,y)
}
}
}
}
If this were the only bitmap you had in your program, this would be a simple and effective
solution to the problem. We are using 1 byte of program memory (of which there are about
7K available in the Atmega8) for each pixel in our bitmap, for a total of 35 bytes. This is not
so bad, but what if you wanted a bitmap for each of the 96 printable characters in the ASCII
character set? This would consume 96*35 = 3360 bytes, which would leave a lot less flash
memory for holding your program code.

There is a much more efficient way to store a bitmap. Let us replace the 2-dimensional array
above with a 1-dimensional array of bytes. Each byte contains 8 bits, and we will use the
lowest 7 bits of each to represent the 7 pixels in a column of our 5x7 bitmap:

COPY

Explain
const prog_uint8_t BitMap[5] = { // store in program memory to save RAM
B1100011,
B0010100,
B0001000,
B0010100,
B1100011
};
(Here we are using the predefined binary constants available starting in Arduino 0007.) This
allows us to use 5 bytes for each bitmap instead of 35. But how do we make use of this more
compact data format? Here is the answer: we rewrite the function DisplayBitMap() to access
the individual bits in each byte of the BitMap...

COPY

Explain
void DisplayBitMap()
{
for (byte x=0; x<5; ++x) {
byte data = pgm_read_byte (&BitMap[x]); // fetch data from program memory
for (byte y=0; y<7; ++y) {
if (data & (1<<y)) {
// turn on the LED at location (x,y)
} else {
// turn off the LED at location (x,y)
}
}
}
}
The crucial line to understand is

COPY
if (data & (1<<y)) {
The expression (1<<y) selects a given bit inside data that we want to access. Then using
bitwise AND, data & (1<<y) tests the given bit. If that bit is set, a nonzero value results,
causing the if to see it as being true. Otherwise, if the bit is zero, it is treated as false, so the
else executes.

Quick Reference
In this quick reference, we refer to the bits in a 16-bit integer starting with the least
significant bit as bit 0, and the most significant bit (the sign bit if the integer is signed) as bit
15, as illustrated in this diagram:

bit integer

Whenever you see the variable n, its value is assumed to be 0 through 15.

COPY
y = (x >> n) & 1; // n=0..15. stores nth bit of x in y. y becomes 0 or 1.
COPY
x &= ~(1 << n); // forces nth bit of x to be 0. all other bits left alone.
COPY
x &= (1<<(n+1))-1; // leaves alone the lowest n bits of x; all higher bits set to 0.
COPY
x |= (1 << n); // forces nth bit of x to be 1. all other bits left alone.
COPY
x ^= (1 << n); // toggles nth bit of x. all other bits left alone.
COPY
x = ~x; // toggles ALL the bits in x.
Here is an interesting function that uses both bitwise & and boolean &&. It returns true if and
only if the given 32-bit integer x is a perfect power of 2, i.e., 1, 2, 4, 8, 16, 32, 64, etc. For
example, calling IsPowerOfTwo(64) will return true, but IsPowerOfTwo(65) returns false. To
see how this function works, let us use the number 64 as an example of a power of 2. In
binary, 64 is 1000000. When we subtract 1 from 1000000, we get 0111111. Applying bitwise
&, the result is 0000000. But if we do the same with 65 (binary 1000001), we get 1000001 &
1000000 == 1000000, which is not zero.

COPY
bool IsPowerOfTwo (long x)
{
return (x > 0) && (x & (x-1) == 0);
}
Here is a function that counts how many bits in the 16-bit integer x are 1 and returns the
count:

COPY

Explain
int CountSetBits (int x)
{
int count = 0;
for (int n=0; n<16; ++n) {
if (x & (1<<n)) {
++count;
}
}
return count;
}
Another way is this:

COPY

Explain
int CountSetBits (int x)
{
unsigned int count;
for (count = 0; x; count++)
x &= x - 1;
return count;
}
Various tricks for common bit-oriented operations can be found here.

Multimeter Basics
Learn about different multimeter features, how they function, and how to use this essential
tool.

AuthorJosé Garcia
Last revision08/02/2024
A multimeter is a test tool, mostly used in electronics, that should always be present in the
FabLab of a Maker.
It is a diagnostic tool that allows us, for instance to:

debug circuits,
display the value of resistors,
measure voltage and current in our circuits,
identify conductive/non conductive materials, and much more!
Parts of the Multimeter
There are many different types of multimeters, some with more or less features. The
following image lists the parts that the majority of multimeters have.

Overview of a multimeter
Overview of a multimeter

The display will show various numeric values of the different measurements we take with the
multimeter.
By changing the position of the measurement selector switch, we will be able to configure the
multimeter to measure different parameters.
Depending on the parameters we want to measure, the connection of the terminals should be
done in an appropriate manner.
How to choose a multimeter
It is hard to say exactly which characteristics a multimeter should have, since there are
different needs depending on the background of the user and the intended usage, but let's say
that independently of the level of the user, a multimeter should have:

Voltage reading
Current reading
Resistance reading, from at least 10 Ohm to 1M Ohm
Continuity detection (with acoustic feedback)
Then, depending on the user background, there will be some features that could make the
multimeter easier to use, or make it a more complex tool. Some of these features are:

Autoscale: This feature will configure the data scale of the multimeter to show the readings in
the easiest format possible for the user to understand them. However, this feature may
compromise the accuracy of the readings.
Hold: This feature "freezes" the reading on the screen, so the user can check it out even after
removing the terminal connectors from the measurement points.
Advanced features such as: Frequency counter, capacitance testing, inductance testing, duty
cycle, etc. These features allow us to measure quite advanced properties of different
components and signals in the electronic circuits; but usually a background in electronics is
needed, to makes sense of these readings and to know how to execute the measurements
correctly in the circuits.
How to use a Multimeter
Multimeters have different working modes, depending on what are you interested on
measuring. Let's start by how to use a multimeter to measure voltage, resistance, conductivity
and current.

Reading voltage
This will require to place the measurement selector in the Volts section the black terminal in
the COM and the red terminal in the V|Ω|mA terminal.

Configuration to measure voltage


Configuration to measure voltage

With this configuration, the selected scale should be adjusted based on the measured voltage.
If you want to measure the voltage close to a 9V battery, the scale should be 20.

The scale limits the higher value that can be measured, meaning that if the selector is within
the 2000m, the highest value that can be measured with that scale is 2000mV = 2V.
In order to know what scale to select, you should check what is the approximate value that
you will be measuring, and select the scale according to it:

From 0 to 200mV --> 200m


From 200mV to 2000mV (2V) --> 2000m
From 2V to 20V --> 20V
If you try to measure a higher value than the one specified on the scale, the display will show
"over-value", which is usually shown with the number "1" on the display.

Terminals
Once you have selected the scale to use, it is time to use the terminals:

The black terminal (Common) should be placed in the point of the circuit closer to the ground
"-" terminal of the battery.
The red terminal should be placed in the point you want to know what is the voltage in the
circuit.
The image below shows how to read the voltage falling in an LED. In order to know the
voltage falling on a component, you will need to connect the multimeter in parallel with it.

Reading voltage schematics


Reading voltage schematics

You can see how the black terminal checks the negative terminal of the LED, which is
connected to the negative pole of the battery and the red terminal on the positive terminal of
the LED.

Reading voltage on a circuit


Reading voltage on a circuit

Reading resistance
In order to measure resistance, the measurement selector should be in the Ohm section.

Configuration to measure resistance


Configuration to measure resistance

The scale to measure resistance works exactly as explained in the "Measuring voltage
section".

In order to know the value of a resistor, you need to keep in mind that the measurement must
be done on a resistor that is not connected to any other component! Then, you can make the
reading:

Place each one of the terminals of the multimeter in each one of the terminals of the resistor.

Reading resistance
Reading resistance

Continuity Testing
This feature allows you to know if a material is or is not conductive.
To make this test, you will need to "touch" a material with both terminals of the multimeter,
once you do so, depending on the multimeter you will see:

OL / 0 in the display if the material is not conductive


1 on the display & Beep if the material is conductive
Reading Current
Reading current is a little bit more complex than reading voltage or resistance. In order to
make current with the multimeter, first you will need to connect the red terminal to the
10A(DCA) connector and place the selector in the A section.

Multimeter configured to read current


Multimeter configured to read current

Once the connections are configured, as shown above, and the selector is properly placed you
can measure the current that is flowing on a circuit. Just make sure that the multimeter is
connected in series with the rest of the components of that same circuit.

Reading current schematic


Reading current schematic

The image below shows how to read the current flowing through a circuit with a LED and a
resistor. Here, you can see how the multimeter is connected in series with the resistor and the
LED, as if it was one more component of the circuit.

Reading current

The Arduino Guide to Soldering


Learn the basics of soldering, a fundamental skill every maker should have.

AuthorJosé Bagur
Last revision08/02/2024
Usually, when we work on building electronic circuits projects, we use breadboards,
especially when prototyping. When we have finished the prototyping stage, we often need to
migrate our projects from a breadboard to a dedicated board, like printed circuit boards
(PCBs), to have our project safely and for a long time. It is in these cases when we need to
know how to solder electronic parts or components.

Soldering is a process where two electronic parts or components are joined together by
melting solder around an electrical or/and mechanical connection between those components
using a handheld tool called soldering iron. Solder creates a solid and permanent electrical
and mechanical bond between the electronic components after it cools.

For mastering soldering, we need practice, a lot, but also good tools. Let's first talk about the
essential tools and materials we need to start soldering.

Soldering Tools
Soldering Irons and Soldering Stations
A soldering iron is the fundamental piece of handheld equipment used in the process of
soldering. Soldering irons heat up to melt solder around electrical or mechanical connections;
as it melts, solder flows into the spaces between and around two components. Once bonded,
the solder is left to cool and harden, creating a permanent and conductive join; it can melt
back into liquid form by reheating enough the join. The process of reheating and separating a
previously soldered joint is called desoldering.

Weller WP35 soldering iron (source: Weller®).


Weller WP35 soldering iron (source: Weller®).

A soldering station is a more advanced and professional type of soldering iron with a separate
temperature control unit; soldering irons provide just one fixed heat setting while soldering
stations offer a range of specific temperatures. Soldering stations provide a far greater degree
of accuracy for heat-critical applications.

HAKKO® FX-888D soldering station (source: HAKKO®).


HAKKO® FX-888D soldering station (source: HAKKO®).

15W to 30W pen-style soldering irons are a good start for beginners.

Soldering Iron Tips


Nowadays, most soldering irons have interchangeable and replaceable tips, sometimes also
referred to as bits. There are many different types and variations of soldering tips, each one
used for specific purposes and with particular advantages or disadvantages in its use. The
most common and standard tips used in soldering irons are the conical tip and the chisel tip.
Let's talk about these types of soldering tips:

Conical tip: a fine, pencil-like tip that can deliver heat to smaller areas without affecting its
surroundings. This tip is a standard-shaped bit for general applications, but it is also handy
for delicate and precision electronics.
Chisel tip: a broad and flattened tip well-suited for soldering wires, through-hole components,
surface-mount components, and desoldering.
Conical (left) and chisel (right) soldering tips.
Conical (left) and chisel (right) soldering tips.

Finding the best tip for soldering jobs can be tricky. Conical and chisel tips should be enough
for soldering standard through-hole and surface-mount electronic components for starters.

One of the most significant causes of soldering problems is poor tip maintenance. It is
essential to take good care of your soldering tips to increase their overall longevity and
reduce the need for regular replacement.

Brass and Conventional Sponges


Using a sponge will help keep soldering iron tips clean by removing oxidation (oxidated tips
will get black and not accept solder). Conventional wet sponges work for cleaning soldering
iron tips, but they tend to shorten the lifespan of the tips due to thermal shock. Also, wet
sponges drop, temporarily, the temperature of the tip when wiped.

A better alternative are brass sponges for cleaning soldering tips. Brass sponges removes
debris in tips better; they have a smaller thermal shock and they don't need water as
conventional sponges.

Brass sponge used for cleaning soldering tips.


Brass sponge used for cleaning soldering tips.

Solder
Solder is a metal alloy that melts to create a permanent bond between electrical parts or
components. Solder comes in both lead and lead-free presentations, also in different
diameters; the most common diameters used are 0.8mm and 1.5mm. Inside the solder core a
material known as flux helps improve electrical contact and mechanical strength of solder.

Solder wire commonly used for soldering.


Solder wire commonly used for soldering.
For electronics soldering, the most commonly used solder is lead-free rosin core solder. This
type of solder consists of a tin and a copper alloy. Leaded rosin core solder is also widely
used, but it's becoming less popular due to health concerns with lead.

When using solder, make sure to have proper ventilation and to wash your hands after
soldering.

Helping Hands
A helping hand, also called "third hand," is a device that can assist you while soldering by
holding the parts or components you are trying to solder, leaving your hands free to work.

Helping hand, also called third hand.


Helping hand, also called third hand.

Soldering 101
Now that we know about the essential tools and materials used for soldering, let's get into
soldering. Before we can start, we need to prepare our soldering iron tip by tinning it with
solder, this should be always the first step. Tinning is a process that helps to improve heat
transfer from the soldering iron to the electronic part or component we want to solder; it also
helps to protect the soldering tip against oxidation.

Let's begin by making sure our soldering tip is attached correctly to our soldering iron, then
turn it on and let it heat up. If you use a soldering station, set the temperature to 400° C (or
752° F). When the soldering iron, or soldering station, is heated up and ready:

Wipe the soldering tip with a conventional wet sponge or a brass sponge. The purpose of this
is to clean the tip by removing any present oxidation or debris on it. After cleaning the
soldering tip, we should wait a few seconds to let the soldering tip heat up again.
Touch the solder with the soldering iron tip, apply a small amount of solder on the soldering
tip making sure the solder flows evenly around it.
Remember to tinning the soldering iron tip before and after every soldering session. Tinning
is a good practice that can increase soldering tip life.

Soldering Circuit Boards


Now, let's solder a resistor to a circuit board. For this process, it’s recommended to use a
helping hand or other type of clamp device like a vice. Let's start with mounting the resistor
to the circuit board. Insert the resistor into the holes of the circuit board.

Resistor mounted into circuit board.


Resistor mounted into circuit board.

Then, flip the circuit board and bend its leads outwards 45°.

Resistor leads bended outwards 45°.


Resistor leads bended outwards 45°.

Touch the copper pad and one of the resistors leads simultaneously, hold the soldering iron in
place to heat the joint formed by the pad and the resistor lead for three to four seconds.

Heating the joint for three to four seconds.


Heating the joint for three to four seconds.
Apply solder to the joint while holding the soldering iron on the copper pad and the resistor
lead. Avoid applying solder directly to the soldering tip; the joint should be hot enough to
melt the solder.

When there is enough solder in the joint, remove the soldering iron and let it cool down
naturally. Once cool, snip the extra wire from the resistor lead. Avoid bad joints by blowing
on the solder and not allowing it to cool down naturally. Repeat this process with the other
resistor lead and the rest of the components of the circuit.

Good solder joints are smooth, shiny, and have a volcano-like shape. Good solder joints also
have enough solder to cover the entire joint but not too much to spill it.

Soldering Wires
Working with electric circuits also involves working with wires; let's learn how to solder
them. For soldering wires, it's also recommended to use a helping hand or another type of
clamp device:

Let's start by removing the insulation from the end of the wires we are going to solder. If the
wire is stranded, we must twist the strands with our fingers.
Touch the end of one wire with the soldering tip, hold the soldering iron in place to heat the
wire for three to four seconds.
While holding the soldering iron on the wire, apply the solder until it's fully coated. Repeat
this process on the other wire end.
With the two wires tinned, hold their tinned end on top of each other and heat them with the
soldering iron. This should melt the solder and coat them. If it is needed, apply solder so both
wires are coated evenly.
Remove the soldering iron and let it cool down and harden naturally.
Use heat shrink to cover connections between wires.

Desoldering
What happens if we want to remove a solder joint? Or if we're going to change it to correct?
Or what about removing a component from a circuit board. Solder joints can be removed or
changed easily by reheating and separating them; this is named desoldering. To desolder a
joint, we will need desoldering braid, also known as solder wick.

Using desoldering braid is simple:

Place the desoldering braid on the top of the solder joint to remove.
Heat the soldering braid and the solder joint with the tip of a soldering iron. Start removing
the soldering braid; you will see that solder has been extracted and removed.
Be careful while using a soldering braid because it will get hot.

If you have a lot of solder, using desoldering braid may not be the best option. In this case, a
device called solder sucker is a better option. A solder sucker is a handheld mechanical
vacuum that sucks up hot solder, usually by pressing a button.

Using a solder sucker is also simple:

Press the solder sucker plunger down.


Heat the solder joint with the tip of a soldering iron, then place the tip of the solder sucker on
top of the hot solder joint.
Press the button of the solder sucker to suck solder.
Arduino® Proto Shields
Designing custom circuits with Arduino® boards is easily done using Proto Shields. For
example, The MKR Proto Shield is a prototyping shield designed for the MKR family boards.
This shield easily plugs onto any MKR board using its provided female/male headers and
offers a duplicate breakout for each pin on the board along with many solderable through-
holes on a standard 0.1” (2.54mm) grid.

The Arduino® MKR Proto Shield.


The Arduino® MKR Proto Shield.

Another example is the MKR SD Proto Shield. This shield allows you to easily connect a
microSD card to an MKR family board; in this shield, there's also a small prototyping area
for soldering components.

The Arduino® MKR SD Proto Shield.


The Arduino® MKR SD Proto Shield.

Check out the documentation of the MKR SD Proto Shield for more information, tutorials
and resources.

Liquid Crystal Displays (LCD) with Arduino


Find out how to wire an LCD to an Arduino, and how to use the LiquidCrystal library
through a set of useful examples.

Last revision08/02/2024
This article was revised on 2021/11/18 by Karl Söderby.

The LiquidCrystal library allows you to control LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you can usually tell them by
the 16-pin interface.

Output of the sketch on a 16x2 LCD


Output of the sketch on a 16x2 LCD

The LCDs have a parallel interface, meaning that the microcontroller has to manipulate
several interface pins at once to control the display. The interface consists of the following
pins:

A register select (RS) pin that controls where in the LCD's memory you're writing data to.
You can select either the data register, which holds what goes on the screen, or an instruction
register, which is where the LCD's controller looks for instructions on what to do next.
A Read/Write (R/W) pin that selects reading mode or writing mode
An Enable pin that enables writing to the registers
8 data pins (D0 -D7). The states of these pins (high or low) are the bits that you're writing to a
register when you write, or the values you're reading when you read.
There's also a display contrast pin (Vo), power supply pins (+5V and GND) and LED
Backlight (Bklt+ and BKlt-) pins that you can use to power the LCD, control the display
contrast, and turn on and off the LED backlight, respectively.

The process of controlling the display involves putting the data that form the image of what
you want to display into the data registers, then putting instructions in the instruction register.
The LiquidCrystal Library simplifies this for you so you don't need to know the low-level
instructions.

The Hitachi-compatible LCDs can be controlled in two modes: 4-bit or 8-bit. The 4-bit mode
requires seven I/O pins from the Arduino, while the 8-bit mode requires 11 pins. For
displaying text on the screen, you can do most everything in 4-bit mode, so example shows
how to control a 16x2 LCD in 4-bit mode.
Hardware Required
Arduino Board
LCD Screen (compatible with Hitachi HD44780 driver)
pin headers to solder to the LCD display pins
10k ohm potentiometer
220 ohm resistor
hook-up wires
breadboard
Circuit
Note that this circuit was originally designed for the Arduino UNO. As the Arduino is
communicating with the display using SPI, pin 11 & 12 will change depending on what board
you are using. For example, on a MKR WiFi 1010, the SPI bus is attached to pin 8 & 11.

Before wiring the LCD screen to your Arduino board we suggest to solder a pin header strip
to the 14 (or 16) pin count connector of the LCD screen, as you can see in the image further
up.

To wire your LCD screen to your board, connect the following pins:

LCD RS pin to digital pin 12


LCD Enable pin to digital pin 11
LCD D4 pin to digital pin 5
LCD D5 pin to digital pin 4
LCD D6 pin to digital pin 3
LCD D7 pin to digital pin 2
LCD R/W pin to GND
LCD VSS pin to GND
LCD VCC pin to 5V
LCD LED+ to 5V through a 220 ohm resistor
LCD LED- to GND
Additionally, wire a 10k potentiometer to +5V and GND, with it's wiper (output) to LCD
screens VO pin (pin3).

The circuit (made using Fritzing).


The circuit (made using Fritzing).

Schematic
The schematic (made using Fritzing).
The schematic (made using Fritzing).

Hello World Example


This example sketch prints Hello World! to the LCD and shows the time in seconds since the
Arduino was reset.

COPY

Explain
/*
LiquidCrystal Library - Hello World

Demonstrates the use a 16x2 LCD display. The LiquidCrystal


library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD
and shows the time.

The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* LCD VSS pin to ground
* LCD VCC pin to 5V
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008


by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi

This example code is in the public domain.

https://docs.arduino.cc/learn/electronics/lcd-displays

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

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

void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
lcd.setCursor(0, 1);
// print the number of seconds since reset:
lcd.print(millis() / 1000);
}
Autoscroll Example
This example sketch shows how to use the autoscroll() and noAutoscroll() methods to move
all the text on the display left or right.

autoscroll() moves all the text one space to the left each time a letter is added
noAutoscroll() turns scrolling off
This sketch prints the characters 0 to 9 with autoscroll off, then moves the cursor to the
bottom right, turns autoscroll on, and prints them again.

COPY

Explain
/*

LiquidCrystal Library - Autoscroll

Demonstrates the use a 16x2 LCD display. The LiquidCrystal

library works with all LCD displays that are compatible with the

Hitachi HD44780 driver. There are many of them out there, and you

can usually tell them by the 16-pin interface.

This sketch demonstrates the use of the autoscroll()

and noAutoscroll() functions to make new text scroll or not.

The circuit:

* LCD RS pin to digital pin 12

* LCD Enable pin to digital pin 11

* LCD D4 pin to digital pin 5

* LCD D5 pin to digital pin 4

* LCD D6 pin to digital pin 3

* LCD D7 pin to digital pin 2

* LCD R/W pin to ground

* 10K resistor:

* ends to +5V and ground

* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008

by David A. Mellis
library modified 5 Jul 2009

by Limor Fried (http://www.ladyada.net)

example added 9 Jul 2009

by Tom Igoe

modified 22 Nov 2010

by Tom Igoe

modified 7 Nov 2016

by Arturo Guadalupi

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/LiquidCrystalAutoscroll

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {

// set up the LCD's number of columns and rows:

lcd.begin(16, 2);
}

void loop() {

// set the cursor to (0,0):

lcd.setCursor(0, 0);

// print from 0 to 9:

for (int thisChar = 0; thisChar < 10; thisChar++) {

lcd.print(thisChar);

delay(500);

}
// set the cursor to (16,1):

lcd.setCursor(16, 1);

// set the display to automatically scroll:

lcd.autoscroll();

// print from 0 to 9:

for (int thisChar = 0; thisChar < 10; thisChar++) {

lcd.print(thisChar);

delay(500);

// turn off automatic scrolling

lcd.noAutoscroll();

// clear screen for the next loop:

lcd.clear();
}
Blink Example
This example sketch shows how to use the blink() and noBlink() methods to blink a block-
style cursor.

COPY

Explain
/*

LiquidCrystal Library - Blink

Demonstrates the use a 16x2 LCD display. The LiquidCrystal

library works with all LCD displays that are compatible with the

Hitachi HD44780 driver. There are many of them out there, and you

can usually tell them by the 16-pin interface.

This sketch prints "Hello World!" to the LCD and makes the

cursor block blink.

The circuit:

* LCD RS pin to digital pin 12

* LCD Enable pin to digital pin 11


* LCD D4 pin to digital pin 5

* LCD D5 pin to digital pin 4

* LCD D6 pin to digital pin 3

* LCD D7 pin to digital pin 2

* LCD R/W pin to ground

* 10K resistor:

* ends to +5V and ground

* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008

by David A. Mellis

library modified 5 Jul 2009

by Limor Fried (http://www.ladyada.net)

example added 9 Jul 2009

by Tom Igoe

modified 22 Nov 2010

by Tom Igoe

modified 7 Nov 2016

by Arturo Guadalupi

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/LiquidCrystalBlink

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
// set up the LCD's number of columns and rows:

lcd.begin(16, 2);

// Print a message to the LCD.

lcd.print("hello, world!");
}

void loop() {

// Turn off the blinking cursor:

lcd.noBlink();

delay(3000);

// Turn on the blinking cursor:

lcd.blink();

delay(3000);
}
Cursor
This example sketch shows how to use the cursor() and noCursor() methods to control an
underscore-style cursor.

COPY

Explain
/*

LiquidCrystal Library - Cursor

Demonstrates the use a 16x2 LCD display. The LiquidCrystal

library works with all LCD displays that are compatible with the

Hitachi HD44780 driver. There are many of them out there, and you

can usually tell them by the 16-pin interface.

This sketch prints "Hello World!" to the LCD and

uses the cursor() and noCursor() methods to turn

on and off the cursor.

The circuit:

* LCD RS pin to digital pin 12

* LCD Enable pin to digital pin 11

* LCD D4 pin to digital pin 5


* LCD D5 pin to digital pin 4

* LCD D6 pin to digital pin 3

* LCD D7 pin to digital pin 2

* LCD R/W pin to ground

* 10K resistor:

* ends to +5V and ground

* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008

by David A. Mellis

library modified 5 Jul 2009

by Limor Fried (http://www.ladyada.net)

example added 9 Jul 2009

by Tom Igoe

modified 22 Nov 2010

by Tom Igoe

modified 7 Nov 2016

by Arturo Guadalupi

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/LiquidCrystalCursor

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {

// set up the LCD's number of columns and rows:


lcd.begin(16, 2);

// Print a message to the LCD.

lcd.print("hello, world!");
}

void loop() {

// Turn off the cursor:

lcd.noCursor();

delay(500);

// Turn on the cursor:

lcd.cursor();

delay(500);
}
Display Example
This example sketch shows how to use the display() and noDisplay() methods to turn on and
off the display. The text to be displayed will still be preserved when you use noDisplay() so
it's a quick way to blank the display without losing everything on it.

COPY

Explain
/*
LiquidCrystal Library - display() and noDisplay()

Demonstrates the use a 16x2 LCD display. The LiquidCrystal


library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.

This sketch prints "Hello World!" to the LCD and uses the
display() and noDisplay() functions to turn on and off
the display.

The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008


by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/LiquidCrystalDisplay

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

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

void loop() {
// Turn off the display:
lcd.noDisplay();
delay(500);
// Turn on the display:
lcd.display();
delay(500);
}
Scroll Example
This example sketch shows how to use the scrollDisplayLeft() and scrollDisplayRight()
methods to reverse the direction the text is flowing. It prints "Hello World!", scrolls it
offscreen to the left, then offscreen to the right, then back to home.

COPY

Explain
/*
LiquidCrystal Library - scrollDisplayLeft() and scrollDisplayRight()

Demonstrates the use a 16x2 LCD display. The LiquidCrystal


library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.

This sketch prints "Hello World!" to the LCD and uses the
scrollDisplayLeft() and scrollDisplayRight() methods to scroll
the text.

The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008


by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/LiquidCrystalScroll

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

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

void loop() {
// scroll 13 positions (string length) to the left
// to move it offscreen left:
for (int positionCounter = 0; positionCounter < 13; positionCounter++) {
// scroll one position left:
lcd.scrollDisplayLeft();
// wait a bit:
delay(150);
}

// scroll 29 positions (string length + display length) to the right


// to move it offscreen right:
for (int positionCounter = 0; positionCounter < 29; positionCounter++) {
// scroll one position right:
lcd.scrollDisplayRight();
// wait a bit:
delay(150);
}

// scroll 16 positions (display length + string length) to the left


// to move it back to center:
for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
// scroll one position left:
lcd.scrollDisplayLeft();
// wait a bit:
delay(150);
}

// delay at the end of the full loop:


delay(1000);

}
Serial to Display Example
This example sketch accepts serial input from a host computer and displays it on the LCD. To
use it, upload the sketch, then open the Serial Monitor and type some characters and click
Send. The text will appear on your LCD.

COPY

Explain
/*
LiquidCrystal Library - Serial Input

Demonstrates the use a 16x2 LCD display. The LiquidCrystal


library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.

This sketch displays text sent over the serial port


(e.g. from the Serial Monitor) on an attached LCD.

The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
modified 7 Nov 2016
by Arturo Guadalupi

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/LiquidCrystalSerialDisplay

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// initialize the serial communications:
Serial.begin(9600);
}

void loop() {
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
}
}
}
Set Cursor Example
This example sketch shows how to use the setCursor() method to reposition the cursor. To
move the cursor, just call setCursor() with a row and column position. For example, for a
2x16 display:

COPY
lcd.setCursor(0, 0); // top left
lcd.setCursor(15, 0); // top right
lcd.setCursor(0, 1); // bottom left
lcd.setCursor(15, 1); // bottom right
Here is the full example:

COPY

Explain
/*

LiquidCrystal Library - setCursor

Demonstrates the use a 16x2 LCD display. The LiquidCrystal

library works with all LCD displays that are compatible with the

Hitachi HD44780 driver. There are many of them out there, and you

can usually tell them by the 16-pin interface.

This sketch prints to all the positions of the LCD using the

setCursor() method:

The circuit:

* LCD RS pin to digital pin 12

* LCD Enable pin to digital pin 11

* LCD D4 pin to digital pin 5

* LCD D5 pin to digital pin 4

* LCD D6 pin to digital pin 3

* LCD D7 pin to digital pin 2

* LCD R/W pin to ground

* 10K resistor:

* ends to +5V and ground

* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008

by David A. Mellis

library modified 5 Jul 2009

by Limor Fried (http://www.ladyada.net)

example added 9 Jul 2009


by Tom Igoe

modified 22 Nov 2010

by Tom Igoe

modified 7 Nov 2016

by Arturo Guadalupi

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/LiquidCrystalSetCursor

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// these constants won't change. But you can change the size of
// your LCD using them:

const int numRows = 2;

const int numCols = 16;

void setup() {

// set up the LCD's number of columns and rows:

lcd.begin(numCols, numRows);
}

void loop() {

// loop from ASCII 'a' to ASCII 'z':

for (int thisLetter = 'a'; thisLetter <= 'z'; thisLetter++) {

// loop over the columns:

for (int thisRow = 0; thisRow < numRows; thisRow++) {

// loop over the rows:

for (int thisCol = 0; thisCol < numCols; thisCol++) {

// set the cursor position:


lcd.setCursor(thisCol, thisRow);

// print the letter:

lcd.write(thisLetter);

delay(200);

}
}
Text Direction Example
This example sketch shows how to use the leftToRight() and rightToLeft() methods. These
methods control which way text flows from the cursor.

rightToLeft() causes text to flow to the left from the cursor, as if the display is right-justified.
leftToRight() causes text to flow to the right from the cursor, as if the display is left-justified.
This sketch prints a through l right to left, then m through r left to right, then s through z right
to left again.

COPY

Explain
/*

LiquidCrystal Library - TextDirection

Demonstrates the use a 16x2 LCD display. The LiquidCrystal

library works with all LCD displays that are compatible with the

Hitachi HD44780 driver. There are many of them out there, and you

can usually tell them by the 16-pin interface.

This sketch demonstrates how to use leftToRight() and rightToLeft()

to move the cursor.

The circuit:

* LCD RS pin to digital pin 12

* LCD Enable pin to digital pin 11

* LCD D4 pin to digital pin 5

* LCD D5 pin to digital pin 4

* LCD D6 pin to digital pin 3


* LCD D7 pin to digital pin 2

* LCD R/W pin to ground

* 10K resistor:

* ends to +5V and ground

* wiper to LCD VO pin (pin 3)

Library originally added 18 Apr 2008

by David A. Mellis

library modified 5 Jul 2009

by Limor Fried (http://www.ladyada.net)

example added 9 Jul 2009

by Tom Igoe

modified 22 Nov 2010

by Tom Igoe

modified 7 Nov 2016

by Arturo Guadalupi

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/LiquidCrystalTextDirection

*/

// include the library code:


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the arduino pin number it is connected to

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

int thisChar = 'a';

void setup() {

// set up the LCD's number of columns and rows:

lcd.begin(16, 2);

// turn on the cursor:


lcd.cursor();
}

void loop() {

// reverse directions at 'm':

if (thisChar == 'm') {

// go right for the next letter

lcd.rightToLeft();

// reverse again at 's':

if (thisChar == 's') {

// go left for the next letter

lcd.leftToRight();

// reset at 'z':

if (thisChar > 'z') {

// go to (0,0):

lcd.home();

// start again at 0

thisChar = 'a';

// print the character

lcd.write(thisChar);

// wait a second:

delay(1000);

// increment the letter:

thisChar++;
}
Custom Character
This example demonstrates how to add custom characters on an LCD display.
Note that this example requires an additional potentiometer:

Outer pins connected to 5V and GND.


Inner pin (wiper) connected to A0.
This potentiometer controls the delayTime variable.

COPY

Explain
/*
LiquidCrystal Library - Custom Characters

Demonstrates how to add custom characters on an LCD display.


The LiquidCrystal library works with all LCD displays that are
compatible with the Hitachi HD44780 driver. There are many of
them out there, and you can usually tell them by the 16-pin interface.

This sketch prints "I <heart> Arduino!" and a little dancing man
to the LCD.

The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K potentiometer:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
* 10K poterntiometer on pin A0

created 21 Mar 2011


by Tom Igoe
modified 11 Nov 2013
by Scott Fitzgerald

Arduino and Stepper Motor Configurations


Learn how to control a variety of stepper motors using unipolar / bipolar circuits with
Arduino.

AuthorArduino
Last revision08/02/2024
Stepper motors, due to their unique design, can be controlled to a high degree of accuracy
without any feedback mechanisms. The shaft of a stepper, mounted with a series of magnets,
is controlled by a series of electromagnetic coils that are charged positively and negatively in
a specific sequence, precisely moving it forward or backward in small "steps".

There are two types of steppers, Unipolars and Bipolars, and it is very important to know
which type you are working with. For each of the motors, there is a different circuit. The
example code will control both kinds of motors. See the unipolar and bipolar motor
schematics for information on how to wire up your motor.
The stepper is controlled by with digital pins 8, 9, 10, and 11 for either unipolar or bipolar
motors. The Arduino board will connect to a U2004 Darlington Array if you're using a
unipolar stepper or a SN754410NE H-Bridge if you have a bipolar motor.

Hardware Required
Arduino Board
stepper motor
U2004 Darlington Array (if using a unipolar stepper)
SN754410ne H-Bridge (if using a bipolar stepper)
power supply appropriate for your particular stepper
hook-up wires
breadboard
Circuit
Below you'll find circuits for both unipolar and bipolar steppers. In either case, it is best to
power your stepper motors from an external supply, as they draw too much to be powered
directly from your Arduino board.

Note: Both circuits below are four wire configurations. Two wire configurations will not
work with the code provided.

Unipolar Stepper Circuit and schematic


Unipolar Motor Knob Circuit. Image made using Fritzing.
Unipolar Motor Knob Circuit. Image made using Fritzing.

Unipolar Motor Knob Schematic. Image made using Fritzing.


Unipolar Motor Knob Schematic. Image made using Fritzing.

Bipolar Stepper Circuit and Schematic


Bipolar Motor Knob Circuit. Image made using Fritzing.
Bipolar Motor Knob Circuit. Image made using Fritzing.

Bipolar Motor Knob Schematic. Image made using Fritzing.


Bipolar Motor Knob Schematic. Image made using Fritzing.

Examples
MotorKnob
A stepper motor follows the turns of a potentiometer (or other sensor) on analog input 0.

COPY

Explain
#include <Stepper.h>

// change this to the number of steps on your motor


#define STEPS 100

// create an instance of the stepper class, specifying


// the number of steps of the motor and the pins it's
// attached to
Stepper stepper(STEPS, 8, 9, 10, 11);

// the previous reading from the analog input


int previous = 0;

void setup() {
// set the speed of the motor to 30 RPMs
stepper.setSpeed(30);
}

void loop() {
// get the sensor value
int val = analogRead(0);

// move a number of steps equal to the change in the


// sensor reading
stepper.step(val - previous);

// remember the previous value of the sensor


previous = val;
}
StepperOneRevolution
The motor should revolve one revolution in one direction, then one revolution in the other
direction.

COPY

Explain
#include <Stepper.h>

const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:


Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

void setup() {
// set the speed at 60 rpm:
myStepper.setSpeed(60);
// initialize the serial port:
Serial.begin(9600);
}

void loop() {
// step one revolution in one direction:
Serial.println("clockwise");
myStepper.step(stepsPerRevolution);
delay(500);

// step one revolution in the other direction:


Serial.println("counterclockwise");
myStepper.step(-stepsPerRevolution);
delay(500);
}
StepperOneStepAtATime
The motor will step one step at a time, very slowly. You can use this to test that you've got
the four wires of your stepper wired to the correctpins. If wired correctly, all steps should be
in the same direction.

COPY
Explain
#include <Stepper.h>

const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:


Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

int stepCount = 0; // number of steps the motor has taken

void setup() {
// initialize the serial port:
Serial.begin(9600);
}

void loop() {
// step one step:
myStepper.step(1);
Serial.print("steps:");
Serial.println(stepCount);
stepCount++;
delay(500);
}
StepperSpeedControl
The motor will rotate in a clockwise direction. The higher the potentiometer value, the faster
the motor speed. Because setSpeed() sets the delay between steps, you may notice the motor
is less responsive to changes in the sensor value at low speeds.

COPY

Explain
#include <Stepper.h>

const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:


Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

int stepCount = 0; // number of steps the motor has taken

void setup() {
// nothing to do inside the setup
}

void loop() {
// read the sensor value:
int sensorReading = analogRead(A0);
// map it to a range from 0 to 100:
int motorSpeed = map(sensorReading, 0, 1023, 0, 100);
// set the motor speed:
if (motorSpeed > 0) {
myStepper.setSpeed(motorSpeed);
// step 1/100 of a revolution:
myStepper.step(stepsPerRevolution / 100);
}
}

Servo Motor Basics with Arduino


Learn how to connect and control servo motors with your Arduino board.

AuthorArduino
Last revision08/02/2024
The Servo Library is a great library for controlling servo motors. In this article, you will find
two easy examples that can be used by any Arduino board.

The first example controls the position of an RC (hobby) servo motor with your Arduino and
a potentiometer. The second example sweeps the shaft of an RC servo motor back and forth
across 180 degrees.

You can also visit the Servo GitHub repository to learn more about this library.

Hardware Required
Arduino Board
Servo Motor
10k ohm potentiometer
hook-up wires
capacitors
power supply
Powering Servo Motors
Servo motors have different power requirements depending on their size and the workload
they are experiencing. A common servo motor such as the Feetech Mini Servo Motor
requires between 4.8 - 6 V at 5 – 6 mA when idle. It doesn't take very much energy to stand
still.

But as soon as the motor starts moving, it starts using more energy, and it gets that energy by
pulling more current from the power source.

If it experiences heavier loads such as added weight or an object blocking its movement , it
naturally needs to use even more energy to move the obstacle, and as a result the current
consumption increases. The current consumption of the motor linked above can reach up to
800 mA.

This high current-draw is generally not safe to draw from an Arduino board. To avoid
damaging our board we need to power the servo motor through an external power supply.
Choosing the correct power supply depends on the servo motor you are using, so always
check the specifications. Pay especially close attention to the:

operating voltage range


idle current - consumption when not moving
running current - consumption when moving freely
stall current - consumption under max load or when blocked
To power a 4.8 - 6 V servo you could use a 5 V 1 A AC Adapter, cut the cable, and connect
the wires to the servo using e.g. a breadboard.

Note that USB wall chargers are limited to 500 mA (USB 2.0) or 900 mA (USB 3.0).
If your project needs to move around freely without being attached to a power outlet you can
also choose batteries to power the servo. If you need 5 V exactly you can use two 18650 Li-
Ion batteries together with a step-down converter.

A step-down converter is needed because 18650 Li-Ion batteries will give you around 7.4 V.
The max current depends on the specific battery but most of them are designed to output
above 1A which is enough to power our small servo.

If you are using bigger or more servos make sure to check your power requirements
accordingly.

Capacitors are recommended for powering servo motors. They help stabilize the power
supply, minimize voltage drops, and reduce electrical noise. The specific capacitor values
may vary based on the servo motor's requirements, but including them is good practice for
better performance and reliability.

When using a Feetech Mini Servo Motor we recommend using a 100 µF capacitor.

Capacitor
Capacitor

Because some capacitors are polarised (meaning that they have a direction), you may need to
be careful with how you connect them to your circuit. Make sure to connect them correctly
by checking for markings such as a white stripe, a '+' symbol, or a longer lead. If your
capacitor has these, match the indicators of the capacitor with your circuit (pay attention to
the + and - signs), and be careful not to exceed the voltage limits. This precaution helps
prevent issues like leaks or damage that could harm your circuit.

You can read more about capacitors here.

Circuit
Servo motors have three wires: power, ground, and signal. The power wire is typically red,
and should be connected to positive pole (+) of your power source. The ground wire is
typically black or brown and should be connected to the negative pole (-) of your power
source.

The signal pin is typically yellow or orange and should be connected to PWM pin on the
board. In these examples, it is pin number 9.

Knob Circuit
For the Knob example, wire the potentiometer so that its two outer pins are connected to
power (+5V) and ground, and its middle pin is connected to A0 on the board. Then, connect
the servo motor as shown in the circuit below.

The Knob Circuit.


The Knob Circuit.

Sweep Circuit
For the Sweep example, connect the servo motor as shown in the circuit below.

The Sweep Circuit.


The Sweep Circuit.

Examples
Knob
Controlling a servo position using a potentiometer (variable resistor).

COPY

Explain
#include <Servo.h>

Servo myservo; // create servo object to control a servo

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


int val; // variable to read the value from the analog pin

void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}

void loop() {
val = analogRead(potpin); // reads the value of the potentiometer (value between 0
and 1023)
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and
180)
myservo.write(val); // sets the servo position according to the scaled value
delay(15); // waits for the servo to get there
}
Sweep
Sweeps the shaft of a RC servo motor back and forth across 180 degrees.

COPY

Explain
#include <Servo.h>

Servo myservo; // create servo object to control a servo


// twelve servo objects can be created on most boards

int pos = 0; // variable to store the servo position

void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}

void loop() {
for (pos = 0; pos <= 180; pos += 1) { // 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); // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}

How To Read Arduino Power Trees


Learn how to read the Arduino power trees and to create our own ones.
AuthorAli Jahangiri
Last revision08/02/2024
Why are we Providing the Power Tree?
Arduino provides a wide range of boards, shield and carrier each design to meet a specific
need. This ranges from the classic Arduino UNO serving as a standard entry point to the
world of Arduino to the Arduino Portenta H7 that incorporates features to meet industry-level
demands. The power delivery system is thus designed to take into considerations of you, the
end users of our products. In order to help users, both new and advanced, better understand
the power structure of your board we have developed graphical power trees to provide a high
level understanding that you can see in the relevant datasheets. In this article, we will explore
the concepts of Power Trees and guide you through a representative example. We welcome
any feedback and comments from the Arduino Community to further improve the Power
Trees.

A Look at the Portenta H7 Power Tree


Lets take a look together at one of our power trees. The Portenta H7 was one of the first
products to be bestowed with a graphical power tree.

Portenta H7 Power Tree

To the left, you will see three grey boxes. Each one of these represents a voltage input. In the
case of the Arduino Portenta H7, we can either provide power via the USB-C® cable, the
VIN pin on the high density connector or a battery.

Portenta H7 Input Sources

You can see more information about the precise schematic location and pins in the schematic
diagram and pinout graphics respectively. The Power Tree is there to provide a visual aid to
better understanding the product and some intermediate components may not be displayed. If
in doubt, refer to the schematics or contact us.

We can also see that the USB-C® and the VIN are connected together. Under each grey box,
we can see that the voltage is listed as 5V. This is the nominal value (see the datasheet for the
allowed voltage ranges). In general, you can expect there to be no difference in the operation
between each approach.

A bit further down, we can see another grey component titled VBATT. In this case, we see
two distinct features: first of all, the arrows are bi-directional. Secondly, the voltage (in the
turquoise box underneath it) is lower. While this can be difficult to understand from a text
based table, having this information can be beneficial to the user when trying to understand
the product from a Model-Based Design approach.

For more information about Model-Based Design, check out the Engineering Kit Rev 2 for
hands on projects.

The current specification noted in the diagram tells you about the maximum amount of
current that can be drawn from that specific voltage source. Consequently you can attach any
sensor or actuator, so long as the maximum current draw is not exceeded. A device always
only draws as much current as it needs to operate. However, the case for voltage is different.
As a general rule, the voltage values must match with a low tolerance and it is not possible to
power a 5V sensor via a 3.3V pin or vice versa. Voltages have to match, while the currents
don't have to match (just be lower). That said, connecting a data line from e.g. a 3.3V sensor
to a 5V micro controller input pin may work depending on the defined TTL levels as long as
the communication is unidirectional. If 5V are applied from the 5V micro controller to the
3.3V peripheral, it may destroy it.

In some cases, components can function over a wide voltage range. Consult the datasheet of
the component to find the supported range.

Next, let us take a look at the block representing the MC34PF1550A0EP component.

Portenta H7 Power Management IC

The input of the power component, as stated previously, can come from either the 5V power
source or the battery. The voltage and net of these two (as seen in the schematic view) is
written on the turquoise box on the connecting lines. Recall that since the USB-C® and VIN
voltage inputs are connected (as denoted by the black dot connecting the lines together). The
5V voltage is fed to a LDO that has a maximum current capacity of 2A, producing a 4.5V
rail. LDO stands for a Low Dropout linear regulator. These are a type of linear regulator that
are designed to work when the input voltage is slightly above the output voltage. The output
of this LDO is a voltage rail (shown again in a turquoise box) with a voltage of 4.5V. Given
that this is slightly lower than 5V input, it is important that the input voltage is stable since, if
it drops below 4.7V the stability of the Portenta board may be compromised.

Since all other system voltages go through the noted LDO, the maximum current that can
pass through the PMIC is at most 2A. Losses in subsequent voltage conversion will reduce
the real current available to the user. For further details, please refer to the
MC34PF1550A0EP datasheet.

The generated 4.5V is then available for use by DC-DC converters. Here, DC-DC conversion
refers to switching regulators. Depending on their architecture, switching regulators can
increase (boost) or reduce (buck) the voltage levels. A major benefit compared to linear
regulators is their lower PCB footprint and power consumption. However, they can also be
susceptible to noise.

All official Arduino boards have been designed to reduce the noise level to the minimum,
with the use of premium PCB manufacturing and stringent quality control. Purchasing
counterfeit boards may lead to reduced power quality and loss of functionality.

To the right, we can see components that make use of these generated voltages. Note that in
some cases, components may make use of multiple voltage levels to operate.

Graphical styles
As you may have noticed, each type of component has its own visual style. The input blocks
are grey, with a turquoise label underneath showing the nominal voltage. Interconnecting
power rails are shown with a black dot. The power lines themselves are marked by a
turquoise box with the voltage/net. The power conversion blocks are also grey. Under that,
one or more power conversion sub-components are shown. The conversion type
(LDO/CHRG/DCDC) is in yellow, while the maximum current output is in red. These sub-
components are all right aligned. To the bottom left, a Legend is shown.

Power Tree Components


Power Tree Components

Further Resources
Various IC manufacturers have material for understanding power conversion, including
switch mode power supplies. These can help advanced users better understand power
conversion that you see in the Power Trees included in the Arduino datasheets. See ON
Semiconductor's Switch-Mode Power Supply Reference Manual or the Power Topologies
Handbook by Texas Instruments.

In order to explain complex interactions, conceptual diagrams similar to the Power Tree are
widely used by domain experts to quickly and efficiently convey information. For a survey of
how conceptual diagrams are used in various disciplines, see:

Ma’ayan, Dor, et al. ‘How Domain Experts Create Conceptual Diagrams and Implications for
Tool Design’. Proceedings of the 2020 CHI Conference on Human Factors in Computing
Systems, ACM, 2020
Tippett, Christine D. ‘What Recent Research on Diagrams Suggests about Learning with
Rather than Learning from Visual Representations in Science’. International Journal of
Science Education, vol. 38, no. 5, Mar. 2016
The Engineering Kit Rev2 goes into more detail about how Model-based Design can be used
to develop and understand complex systems.

The Arduino Guide to Low Power Design


Learn the basics of low-power design using Arduino hardware and software.

AuthorTaddy Chung, José Bagur


Last revision08/02/2024
The objective of Low Power is to reduce the device’s power consumption by controlling its
behavior to extend its operation lifetime. Electronic devices fed directly from a power source
usually do not require the implementation of Low Power or similar techniques to extend their
life. On the other hand, it is necessary to save its power consumption to expand its operation
lifetime for the devices running from a power source such as batteries.

The present guide for achieving low power system are applicable for every Arduino boards.
For example, Arm Cortex-M0 32-bit SAMD21 processor based Arduino boards can take
advantage of low-power features. The Arduino SAMD21 boards with wireless protocol with
LoRaWAN® network capability, with module as Murata CMWX1ZZABZ featured from
MKR WAN 1310, can be combined with low power features to operate for an extensive
period. With advanced techniques, such tools as power source guide and self-discharge rates
design applies to every Arduino boards for designing power efficient systems. You can check
out Arduino Documentation Hardware page to find out about Arduino boards.

Low Power Library


To enable the Low Power feature on Arduino boards, we can download the Arduino Low
Power library from the libraries manager in the Arduino IDE. This library enables the low
power features for MKR family boards.

The library can be managed by going under Sketch -> Include Library -> Manage Libraries in
Arduino IDE and searching for "Arduino Low Power" choosing the latest version.
For when board components needs to be updated, it can be managed by going under Tools ->
Board -> Boards Manager and searching for respective Arduino board family.
You can download the different Arduino IDE version through the link below:

Arduino Software Page

To learn more about the Arduino IDE, follow the links below:

Arduino IDE 1

Arduino IDE 2
Low-Power Design Techniques
There are several different options to reduce the power consumption in microcontrollers:

Sleep Mode
External Events
ADC
Stand-by
The Sleep Technique
The best method of enabling low power features is by putting the processor to sleep. Deep
Sleep mode will allow the device to turn off a variety of internal modules to save most power
consumption. The Deep Sleep mode can be set with a timer to wake up after a defined length
of time is achieved. Additionally there is also a Light Sleep mode, which will allow some of
the internal modules to be powered on to keep such required tasks alive. Usually Deep Sleep
mode is applied to save most power consumption, while the Light Sleep mode will help to
keep some settings alive to track state of external modules when it wakes up.

Within these sleep modes, Stand-By and Idle modes provide different levels of configuration
for putting the microcontroller to low power mode. Depending on the devices requirements,
some components or modules may still have to be running when it is in sleep state. Stand-By
mode is one of the lowest power consumption mode for SAMD21 based boards. This will
stop every clock sources of the microcontroller and set the voltage regulators to be in low
power state. Oscillators can be in 3 different states where it stops or run, and run on behalf of
peripheral request. The device will be then in deep sleep while WFI (Wait For Interrupt) is
active. An interrupt or WDT (Watchdog Timer) will be the triggers to wake up the device
from sleep state.

The same goes for Idle mode as Stand-By mode. The Idle mode will still have the peripherals
running while WFI (Wait For Interrupt) is active. However the device will not be in deep
sleep mode, meaning it will have higher power consumption level compared to Stand-By
mode. The clock sources, on other hand, are dependent on software architect whether to leave
it running or turn it off to lower the power consumption. An interrupt or WDT (Watchdog
Timer) will be the triggers to wake up the device from sleep state as same for this present
mode.

External Events for Waking up from Sleep State


The application is not always meant to remain in sleep state after finishing scheduled tasks,
but to have environmental awareness capability for processing desired trigger response
required task. External events are the cause that will make the microprocessor to wake from
sleep state whenever such designed conditions are met. Ordinarily these External Events are
issued by ADC (Analog to Digital Converter), peripherals such as UART, and I/O (Input and
Output) ports available for usage.

Thus whenever it distinguishes the change in the signal, the microprocessor will wake up and
proceed to initialize designed tasks. For example, for sensing the vibration intensity, low or
excessive level or such resources to be quantified as gas components present in the air.

ADC (Analog to Digital Converter) Triggered Wake Up


A triggered response caused by ADC (Analog to Digital Converter) to wake up is considered
part of external event wake-up cases. As it will trigger based on voltage shift recognized
through the analog pin of the board. The change in voltage level can be decoded in many
different ways of meaning, and commonly it can be understood as some device connected via
analog pin is powering off so the voltage will hit low threshold.
While the same connected device can be powered on, so will the voltage hit upper threshold.
Defining how to use this behavior as a wake up signal is the task of the software architect to
manage long battery life while accomplishing desired task.

Power Source Guide & Self-Discharge Rates


The power source guide is to help understand, other than controlling Arduino boards to save
power consumption, it is also important to know the power source itself has its discharging
rate. There is no point of saving power consumption using all these resources and techniques
if the power source itself is self-discharging at higher current than the device’s low power
current.

Batteries will be quoted as a power source as it will power up the device. There are different
batteries with different capacities and self-discharge rates which are not flat. Meaning it will
discharge faster at the beginning. This factor is usually influenced by temperature, which
makes it behave differently depending on the environment it is in. So this must be considered
as a guide and take it into account to design efficient Low Power device.

Batteries like CR2032 possess capacity of 210 mAH with discharging rate of 1% per month.
NiMH AAA batteries possess 900 mAH of higher capacity than CR2032 but discharging rate
of 30% per month; while the AA sized version has 2400 mAH of capacity but same
discharging rate. Li-Ion batteries are 4400 mAH of capacity but 10% discharging rate per
month.

Omnienergy CR2032 Discharge Characteristics at Different Loads

It is clear that there are several types of power sources that can used for the device with
divergent characteristics that can used for design factors. Some more specific design cases
may require strict power source chemical composite requirement, but we will use the capacity
and the discharge rate as main ingredient for designing power efficient devices. As chemical
composite requirement is for safety assurance for the device to be able to stay inside strictly
maintained environment.

Self-Discharging rates can be expressed by the following equation:

Self Discharging Rate Formula

This Self-Discharing rate equation can assist you into knowing the discharge rate in which
the power source will suffer in an hour. This value will let you know then it is a similar
approximate rate as continuously consumed rate.

Several design factors comes in play when building a power efficient device. Here, the power
sources suffer from these conditions so it must be taken into account to design consideration.
This is to avoid risk, as mentioned before, on having higher consumption than the actual
device consumption.

However, it is also important to know the form factor of the power source as it will define the
size of the device and will limit the selection of power sources if the device requires to be
very small. For this, advanced low power techniques might be able to guide you through the
design considerations to fully take advantage of this low power guide.

Low-Power Applications Examples


With following simple examples, you will be able to understand and implement Low Power
mode.

Standard Low Power Example


Hardware Needed: Any SAMD21 Based Arduino Boards (MKR Family)
This is the most simple way of implementing the Low Power mode. It will use the LED as an
indicator for telling if the device is in active state or sleep state. The device will be in sleep
state for 5 seconds.

COPY

Explain
#include "ArduinoLowPower.h"

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
LowPower.sleep(5000);
}
Here we can also change a line of the code to perform Deep Sleep mode of the device.

COPY
//LowPower.sleep(5000);
LowPower.deepSleep(5000);
This will set the device into Deep Sleep mode when the device is powered on. Having this
simple example code it is possible to see that it is written inside the loop function, but this
low power code line can be written inside the setup function.

Bear in mind that the setup function runs in first place, as it is the sector where it configures
the board appropriately before it executes different tasks. So it is always recommended to
design the software structure and later start writing the actual code, which will be helpful for
achieving power efficient device.

External Events Based Low Power Example


Hardware Needed: Any SAMD21 Based Arduino Boards (MKR Family)
Following example demonstrates how a board wakes up every 10 seconds unless it detected
an external event on a desired pin.

COPY

Explain
#include "ArduinoLowPower.h"

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(pin, mode);
LowPower.attachInterruptWakeup(pin, callback, mode);
}

void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
LowPower.sleep(10000);
}

void callback() {
// This function will be called once on device wakeup
// You can do some little operations here (like changing variables which will be used in the
loop)
// Remember to avoid calling delay() and long running functions since this functions
executes in interrupt context
}
Here requires to define LowPower.attachInterruptWakeup(pin, callback, mode) function with
pin of the device to be handled, the design the task inside the callback, and the mode to define
the transition to sense change on the defined pin. The mode can be defined within 3 different
settings: FALLING, RISING, and CHANGE.

Falling mode means when the signal on the defined pin sense is in negative trend; Rising
mode is when the signal is in positive trend; and Change mode is either trends whenever the
defined pin senses any type of shift. For pinMode(pin, mode), the modes are INPUT,
OUTPUT, or INPUT_PULLUP. A defined external event based low power example can be
seen as follows. This example can be found by navigating to Examples -> Arduino Low
Power -> ExternalWakeup.

COPY

Explain
#include "ArduinoLowPower.h"

// Blink sequence number


// Declare it volatile since it's incremented inside an interrupt
volatile int repetitions = 1;

// Pin used to trigger a wakeup


const int pin = 8;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
// Set pin 8 as INPUT_PULLUP to avoid spurious wakeup
pinMode(pin, INPUT_PULLUP);
// Attach a wakeup interrupt on pin 8, calling repetitionsIncrease when the device is woken
up
LowPower.attachInterruptWakeup(pin, repetitionsIncrease, CHANGE);
}

void loop() {
for (int i = 0; i < repetitions; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
// Triggers an infinite sleep (the device will be woken up only by the registered wakeup
sources)
// The power consumption of the chip will drop consistently
LowPower.sleep();
}

void repetitionsIncrease() {
// This function will be called once on device wakeup
// You can do some little operations here (like changing variables which will be used in the
loop)
// Remember to avoid calling delay() and long running functions since this functions
executes in interrupt context
repetitions ++;
}
ADC (Analog to Digital Converter) Based Low Power Example
Hardware Needed: Any SAMD21 Based Arduino Boards (MKR Family)
Modifying a bit of the previous external event based low power example, it is possible to
configure ADC (Analog to Digital Converter) as a wake up source given a defined range of
voltage detection reading. This example can be found by navigating to Examples -> Arduino
Low Power -> AdcWakeup.

COPY

Explain
#include "ArduinoLowPower.h"

// Blink sequence number


// Declare it volatile since it's incremented inside an interrupt
volatile int repetitions = 1;

// Pin used to trigger a wakeup


const int pin = A0;
// How sensitive to be to changes in voltage
const int margin = 10;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(pin, INPUT);
}

void loop() {
for (int i = 0; i < repetitions; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}

// Read the voltage at the ADC pin


int value = analogRead(pin);

// Define a window around that value


uint16_t lo = max(value - margin, 0);
uint16_t hi = min(value + margin, UINT16_MAX);

// Attach an ADC interrupt on pin A0, calling repetitionsIncrease when the voltage is
outside the given range.
// This should be called immediately before LowPower.sleep() because it reconfigures the
ADC internally.
LowPower.attachAdcInterrupt(pin, repetitionsIncrease, ADC_INT_OUTSIDE, lo, hi);

// Triggers an infinite sleep (the device will be woken up only by the registered wakeup
sources)
// The power consumption of the chip will drop consistently
LowPower.sleep();

// Detach the ADC interrupt. This should be called immediately after LowPower.sleep()
because it restores the ADC configuration after waking up.
LowPower.detachAdcInterrupt();
}

void repetitionsIncrease() {
// This function will be called once on device wakeup
// You can do some little operations here (like changing variables which will be used in the
loop)
// Remember to avoid calling delay() and long running functions since this functions
executes in interrupt context
repetitions ++;
}
Getting in more deeper with the previous code, we will be defining the value window in
which the analog pin A0 of the device will operate.

COPY
uint16_t lo = max(value - margin, 0);
uint16_t hi = min(value + margin, UINT16_MAX);
The ADC (Analog to Digital Converter) interrupt configuration is done inside the loop
function so it is possible to reconfigure immediately before the device goes into sleep state.

COPY
LowPower.attachAdcInterrupt(pin, repetitionsIncrease, ADC_INT_OUTSIDE, lo, hi);
After the device wakes up within configured ADC (Analog to Digital Converter) interrupt, it
will detach the ADC interrupt so it restores its ADC configuration.

COPY
LowPower.detachAdcInterrupt();
Callback functions are to be used when the system wakes up from sleep state via configured
interruption. In this function, and as an entire software architecture, usually it is a good
practice to avoid using delay() and long running functions. This is to avoid what is called
Blocking Operation and to be designed in Non-Blocking Operation fashion, which very
helpful for this types of design cases. In this instances, this will help design power efficient
system in parallel being a responsive system.

LoRa Transmitter With Low Power Example


Hardware Needed: MKR WAN 1300/1310 (On-Board Murata Module)
Extended detail and example about LoRa® using MKR WAN 1310 with its Murata Module,
please check Send Data Using LoRa® with MKR WAN 1310

This example shows MKR WAN1300/1310 as a remote transmitter device that sends alive
beacon status message periodically. This is to simulate a device broadcasting beacon data
every certain amount of time and requires extensive operation lifetime. The receiver device
will be stationary as reception tower. The remote transmitter device will have the SAMD21
go into sleep state, but also the On-Board Murata module to remove unnecessary power
consumption.
For more information on the LoRa library, please visit the Arduino LoRa repository on
GitHub.

COPY

Explain
// Low Power Library
#include "ArduinoLowPower.h"

// LoRa Library
#include <SPI.h>
#include <LoRa.h>

// LoRa Packet Content


char* message = "Hello LoRa!";

void setup() {
Serial.begin(9600);
while (!Serial);

// LoRa Setup
Serial.println(F("LoRa Sender"));
if (!LoRa.begin(868E6)) {
Serial.println(F("Starting LoRa failed!"));
while (1);
} else {
Serial.println(F("Starting LoRa Successful!"));
}
}

void loop() {
LoRa_Packet_Sender();
GoToSleep();
}

// LoRa Task
void LoRa_Packet_Sender() {
Serial.print(F("Sending packet: "));
Serial.println(message);

// send packet
LoRa.beginPacket();
LoRa.print(message);
LoRa.endPacket();

// Putting LoRa Module to Sleep


Serial.println(F("LoRa Going in Sleep"));
LoRa.sleep();
}

// Sleep Task
void GoToSleep(){
Serial.println(F("MKR WAN 1310 - Going in Sleep"));
LowPower.deepSleep(20000);
}
It is important to know that the Low Power task applies only to microcontroller. This means
that external modules such as Murata module we used here, found on MKR WAN 1310
board, must be coded in the task separately to make the module go into sleep state.

If external modules such as Murata (LoRa) Module and sensors are to be used, please
remember to put into sleep state before making the MCU go into sleep. Otherwise the device
will not go into complete sleep state and maximum power saving will not be possible. This
includes turning off for example peripheral interfaces such as TWI and SPI.

Simple Low Voltage Detection Example


Hardware Needed: Arduino Board from any Family
This is an example showing how to implement the simplest low voltage detection task. This
will detect when the power source is running out of energy and to avoid the device to
shutdown itself due to no power left. It is a simple task yet requires such parameters to be
used as a reference to be clear, as otherwise it will observe incorrect measurements.
Following example is configured for use with MKR WAN 1310 with direct feed to an analog
pin to be able to extract the battery percentage.

COPY

Explain
/*
Low Power - Low Voltage Detection - SAMD21 Specific Configuration Example
*/

// Manual Power Management


#include "ArduinoLowPower.h"

float voltValue, battery_volt, battery_percentage;


float minimal_voltage = 1800;
float battery_voltage_ref = 3.3;

void setup() {
Serial.begin(57600);
delay(100);

// Low Power Indicator Set


pinMode(LED_BUILTIN, OUTPUT);

// Default Analog Reference of 3.3V


analogReference(AR_DEFAULT);

// Setting up for resolution of 12-Bits


analogReadResolution(12);
}

void loop() {
// Reading from the Battery Pin
voltValue = analogRead(A0);

// Calculate current voltage level


battery_volt = ((voltValue*battery_voltage_ref)/4095)*1000;

// Battery level expressed in percentage


battery_percentage = 100*abs((battery_volt - minimal_voltage)/((battery_voltage_ref*1000)
- minimal_voltage));

Serial.print(F("Battery: "));
Serial.print(battery_percentage);
Serial.println(F(" % "));

if (battery_volt <= minimal_voltage){


//LED Notification for low voltage detection
lowBatteryWarning();
}

delay(2000);

// Going into Low Power for 20 seconds


LowPower.deepSleep(20000);
}

// Low battery indicator


void lowBatteryWarning(){
digitalWrite(LED_BUILTIN, HIGH);
delay (1);
digitalWrite(LED_BUILTIN, LOW);
delay (999);
}
Here are 4 important configurations:

The analogReference() is used to configure the reference voltage for analog input.
The analogReadResolution() is used to determine the resolution of the value returned by
analogRead().
The analogRead() is used to set an analog pin to read the value from.
Last but not least, the respective resolution divider value. For the present example it uses
4095 for 12-Bit resolution applicable for MKR WAN 1310. If it uses different resolution,
such as 10-Bits, you will need to define it to 1023.
If voltage divider is to be used for the application, it is necessary to define and set the resistor
relationship inside the code to be able to obtain correct value.

*For more advanced low voltage detection please see the last section of the presente guide
about Advanced Low-Power Techniques in Arduino*

Advanced Low-Power Techniques in Arduino


Following advanced Low Power techniques are applicable for every Arduino boards as it will
take advantage of the entire board inside out to make sure the power consumption goes low
as much as possible. These methodologies will help you to be creative yet flexible on your
low power system design with any Arduino boards.

Low Frequency & Low Voltage


For more advanced use cases, there are some methods to further reduce power consumption.
Putting the processor at low frequency and at low voltage. For low frequencies, it may
depend the functionality of the device as it requires minimum level of frequency to enable
communication modules as WiFi. Also, it is possible to operate the device at low voltage of
3.3V, helping it to step down the overall power consumption. This configuration can be done
with Arduino IDE before uploading the sketch to the device.

Voltage and Frequency Configuration of the Microcontroller


Voltage and Frequency Configuration of the Microcontroller

The processor usually will be changing the frequency depending on the workloads. This
processor frequency varies as to speed up the compute process in a minimal amount of time.
Some modules such as Wi-Fi and Bluetooth® Low Energy requires minimum frequency
level. Otherwise, operating at even lower frequencies will result in modules not working
correctly, or not run in any instance. At some instances, going further low frequency requires
external crystal oscillator as it will require matching oscillator.

So forcefully lowering the frequency will not be of help as it will scramble the modules or the
operations. While leaving the frequency unrestricted or unlimited also won't help provide
long battery life. It is recommended to set frequency levels depending on the software
architecture to maintain power consumption while accomplishing designed tasks. Frequency
levels can be referenced via datasheet of the board, so it can used to design the software
architecture and improve power consumption.

With the voltage, commonly the boards can defined at 5V or at 3.3V of operating voltage.
This operating voltage usually depends on external components which will be interfaced to
work with the central boards, in which it will be Arduino boards. However, not always the
requirements of external components or such similar cases require high voltage. So in cases
like this, it is possible to set operating voltage of 3.3V. Providing much better chance of
having power efficient device. The power consumption beginning with these 2 factors can
reduce or even halve the overall power consumption.

Power Management On Microcontroller Level


For the most cases, using the library class is sufficient to achieve low power consumption.
However, if the system design requires to turn off things individually inside the
microcontroller, power management mode or register can help you fulfill this requirement.

SAMD21 Microcontroller - Power Reduction Mode


For SAMD21 microcontrollers, found on MKR Family boards, are seen with Power
Reduction Mode.

The Power Reduction mode is tied to Non-Volatile Memory Controller and CTRLB register
is used to control its mode. The Power Reduction Mode bit is set in Status Register
(STATUS.PRM), when the Non-Volatile Memory controller and block is in power reduction
mode. The Set and Clear Power Reduction Mode commands are used to take in and out the
Non-Volatile Memory controller and block. For register table visualization, you can see
following references and the datasheet for more detail.

CTRLB Register of SAMD21 Microcontroller

SLEEPPRM Bit from CTRLB Register of SAMD21 Microcontroller

Atmega328P Microcontroller - Power Reduction Register


The Classic Family and Arduino Nano that uses the Atmega328P microcontrollers are found
with Power Reduction Register.

This Power Reduction Register can turn off several things inside the Microcontroller. It can
cut off TWI, SPI, USART0, timers and counters, and Analog-to-Digital Converter. If
Analog-to-Digital Converter bit is to be turned off, ADCRSA bust be set to Zero as it will
stay frozen in an active state.

Power Reduction Register


Peripherals & Internal Modules
Turning off unnecessary internal modules depending on the designed application is very
helpful in further reducing power consumption. These modules can be SPI, I2C, Serial and
ADC (Analog to Digital Converter). On top of these modules, there are Brown-out Detection
and Watchdog timer.

Peripheral interfaces such as SPI, I2C, Serial communications are used regularly to establish
bridge with sensors. Having the overall design requirement, it will be known that some
peripherals will not be implemented in the application. Instead of leaving peripherals floating,
it is good practice to turn off these peripherals that are not going to be used to save some
power consumption. On top of it, the sensors also have the capability of putting themselves
into low power state if commanded to do so. Via established peripherals, commands can be
sent to turn the sensors into low power state before cutting off peripherals to get into sleep.

ADC (Analog to Digital Converter) can be used as wake up source as previously discussed.
But it can also be turned off to save power consumption if it will not be used as a wakeup
source. This peripherals sometimes drain significant amount of power, so turning off may
help to gain extra power to attain longer battery life.

The Brown-out Detection and Watchdog timer are internal modules which can be manually
controlled, if required, to ahieve even lower power consumption. Brown-out detection usually
is comparison purposes for when the processor requires low voltage detection. The Watchdog
timer is crucial as it monitors the microcontroller operation state.

If the microcontroller ever gets stuck and stops or goes through illegal process, the watchdog
timer will be triggered to reset and put the microcontroller back on track. On the other hand,
this same watchdog timer can be disabled temporarily to save power consumption. This is
always recommended to be implemented after the software is verified to be stable enough.
Otherwise, it won't help reduce power consumption and break the system.

External Devices
If there are external devices such as SD devices and sensors, these can be turned off by
adding Mosfets in between. The MOSFET can help to cut off the power for SD devices
connected to the Arduino board to reduce power consumption if the device ever goes into
deep sleep mode for example. In case of sensors, if it is required to completely save power
consumption, can be cut off with MOSFET. This method is helpful when device periodically
goes into sleep state, so it can save the power consumption to its fullest.

Low-Dropout Regulator
Some designs require voltage regulators for it to work properly. If the design requires the use
of voltage regulator, try to look for Low-Dropout regulators with low Quiescent Current. This
will help the device to be on a much lower power consumption level when it is in sleep state.
These types of details can be found on the datasheets of regulator manufacturers.

Power Budgeting
It is good practice to keep record of power budget of the system. As it provides an overview
and details to analyze how the power distribution is handled throughout the whole design.
This can help to design better power consumption as it might give you information about
possible sleep state timer increase for example.

Power Consumption Measurement Method


With all the methods and tricks to attain low power consumption on Arduino board, you will
also need to measure the power consumption of its system to confirm its correct functionality.
You can use Multimeter Basics in section Reading Current to measure the current and find
the system's actual power consumption.
Low Voltage Detection
The device working correctly its designed tasks and that has low power consumption is
already good overall design. Nonetheless, the device at some point it will run out of power
source no matter how long it can be up and running. Surely, it might even be able to run an
entire year perhaps with the right configuration and code architecture. However, there is no
escape that the device and some point will drop out due to low power level. It is possible to
know the device is being supplied with minimal power capacity before it goes out of
operation, and that is when it detects Low Voltage in the system.

You can use the following battery life calculator to obtain estimated lifetime:
https://www.omnicalculator.com/other/battery-life

For this we will use power management method of avr microcontrollers, in which
Atmega328P are based of and found in Arduino Nano and Classic Family for example. The
low voltage detection method developed by Nick Gammon, Retrolefty, and Coding Badly,
will be combined with that is capable of going into low power state to save power.

COPY

Explain
// Nick Gammon
// Code courtesy of "Coding Badly" and "Retrolefty" from the Arduino forum

#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

const long InternalReferenceVoltage = 1062; // Adjust this value to your board's specific
internal BG voltage

void setup() {
Serial.begin(57600);
delay(100);

// Low Power Indicator Set


pinMode(LED_BUILTIN, OUTPUT);

// Pre-eliminary Low Power


resetWatchdog(); // In Case WDT fires
}

void loop() {
// Tuning on peripherals, timers, and ADC
manual_periph_ctrl(1);

// Voltage Level Detection


Serial.println(getBandgap());
// Low voltage detection at 3V (300)
if (getBandgap() < 300){
//LED Notification for low voltage detection
lowBatteryWarning();

// Turns off peripherals, timers, and ADC


manual_periph_ctrl(0);
}

// Low Level Handler


i2c_switch_off();
Manual_LowPower_Mode(1);
}

// Fixed at 8 second variant - On the contrary IT TURNS EVERYTHING OFF


void Manual_LowPower_Mode(uint8_t multiplier){
delay(70); // Requires at least 68ms of buffer head time for
module booting time
for(int i = 0; i <= multiplier; i++){ // Multiplier for Power Down Tick
Deep_Sleep_Manual();
}
}

/*
* Low Voltage Detection Task
*/
// Nick Gammon
// Code courtesy of "Coding Badly" and "Retrolefty" from the Arduino forum
// results are Vcc * 100
// So for example, 5V would be 500.
int getBandgap(){
// REFS0 : Selects AVcc external reference
// MUX3 MUX2 MUX1 : Selects 1.1V (VBG)
ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
ADCSRA |= bit( ADSC ); // start conversion
while (ADCSRA & bit (ADSC)){
} // wait for conversion to complete
int results = (((InternalReferenceVoltage * 1024) / ADC) + 5) / 10;
return results;
} // end of getBandgap

/*
* Low Power Related Tasks
*/
// Enabling Watchdog Timer
void WatchdogEnable() {
// clear various "reset" flags
MCUSR = 0;
// allow changes, disable reset
WDTCSR = bit (WDCE) | bit (WDE);
// set interrupt mode and an interval
WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // set WDIE, and 8 seconds delay
wdt_reset(); // pat the dog

// disable ADC
ADCSRA = 0;

// ready to sleep
set_sleep_mode (SLEEP_MODE_PWR_DOWN); // Should throw ~0.4mA at best case
noInterrupts();
sleep_enable();
// turn off brown-out enable in software
MCUCR = bit (BODS) | bit (BODSE);
MCUCR = bit (BODS);
interrupts(); // Guarantees next instruction executed
sleep_cpu ();

// cancel sleep as a precaution


sleep_disable();
}

void resetWatchdog (){


// clear various "reset" flags
MCUSR = 0;
// allow changes, disable reset, clear existing interrupt
WDTCSR = bit (WDCE) | bit (WDE) | bit (WDIF);
// set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // set WDIE, and 8 seconds delay
// pat the dog
wdt_reset();
} // end of resetWatchdog

void i2c_switch_off(){
// turn off I2C
TWCR &= ~(bit(TWEN) | bit(TWIE) | bit(TWEA));

// turn off I2C pull-ups


digitalWrite (A4, LOW);
digitalWrite (A5, LOW);
}

// Runs for 8 seconds aprox counting as a cycle


void Deep_Sleep_Manual(){
// CORE State
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
ADCSRA = 0; // turn off ADC
power_all_disable (); // power off ADC, Timer 0 and 1, serial interface

// Interrupts are not counted as ADXL require


noInterrupts (); // timed sequence coming up
resetWatchdog (); // get watchdog ready
sleep_enable (); // ready to sleep
interrupts (); // interrupts are required now
sleep_cpu (); // sleep
sleep_disable (); // precaution
power_all_enable (); // power everything back on

} // end of goToSleep

// Manual Peripheral controller


void manual_periph_ctrl(uint8_t selector){
byte old_ADCSRA = ADCSRA;
// disable ADC
ADCSRA = 0;

if (selector == 0){
power_adc_disable();
power_spi_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
power_twi_disable();

UCSR0B &= ~bit (RXEN0); // disable receiver


UCSR0B &= ~bit (TXEN0); // disable transmitter
}
if (selector >= 1){
power_adc_enable();
power_spi_enable();
power_timer0_enable();
power_timer1_enable();
power_timer2_enable();
power_twi_enable();

UCSR0B |= bit (RXEN0); // enable receiver


UCSR0B |= bit (TXEN0); // enable transmitter
}

ADCSRA = old_ADCSRA;
}

// Low battery indicator


void lowBatteryWarning(){
digitalWrite(LED_BUILTIN, HIGH);
delay (1);
digitalWrite(LED_BUILTIN, LOW);
delay (999);
}
To find internal reference voltage, you can run either scripts. When running following scripts,
measure the AREF pin of the microcontroller with a multimeter and multiply the obtained
valued by 1000 to use it as Internal Reference Voltage.

Using ADMUX register to obtain the value.


COPY

Explain
// Find internal 1.1 reference voltage on AREF pin
void setup ()
{
ADMUX = bit (REFS0) | bit (REFS1);
}

void loop () { }
Using analogReference and analogRead functions to obtain the value.
COPY

Explain
// Find internal 1.1 reference voltage on AREF pin
void setup ()
{
analogReference (INTERNAL);
analogRead (A0); // force voltage reference to be turned on
}

void loop () { }
To read more about the Low Power systems topic In-Depth, you can check the following
link: https://www.gammon.com.au/power

Basics of Potentiometers with Arduino


Learn the fundamentals of how a potentiometers works, about the forms they come in, and
how to use them in your projects.

Last revision08/02/2024
A potentiometer is a simple mechanical device that comes in many different forms. It
provides a variable amount of resistance that changes as you manipulate it. The examples in
this article uses a potentiometer with a twisting shaft, one of the more common versions of a
potentiometer you will find.

By passing voltage through a potentiometer into an analog input on your Arduino, it is


possible to measure the amount of resistance of the potentiometer as an analog value. This
article will showcase use cases of potentiometers, as well as teach you how to connect and
read data from them. One shows how you can use a potentiometer as an input for a color
mixer, and the other shows how to accurately choose colors and how to smoothly fade
between them.

The typical potentiometer will have 3 pins, two power supply pins (+5V and GND), and one
pin that connects to an analog input pin on your Arduino to read the value output.

To learn how to read data from a potentiometer, and display it in the Serial Monitor, visit the
Analog Read Serial example.

Hardware Required
Arduino board
Potentiometer
1x Red, 1x Green, 1x Blue LED
3x 220 Ohm Resistors
Circuit
Potentiometer + Pin to 5V
Potentiometer - Pin to GND
Potentiometer Data Pin to A3
A Red LED connected to pin 9 with a 220 Ohm Resistor
A Green LED connected to pin 10 with a 220 Ohm Resistor
A Blue LED connected to pin 11 with a 220 Ohm Resistor
Complete Circuit
Complete Circuit

Color Mixer Example


This example will show you how a potentiometer can be used as an analog input to mix
colors with great granularity.

COPY

Explain
/*
* Code for making one potentiometer control 3 LEDs, red, grn and blu, or one tri-color LED
* The program cross-fades from red to grn, grn to blu, and blu to red
* Clay Shirky <clay.shirky@nyu.edu>
*/

// INPUT: Potentiometer should be connected to 5V and GND


int potPin = A3; // Potentiometer output connected to analog pin 3
int potVal = 0; // Variable to store the input from the potentiometer

// OUTPUT: Use digital pins 9-11, the Pulse-width Modulation (PWM) pins
// LED's cathodes should be connected to digital GND
int redPin = 9; // Red LED, connected to digital pin 9
int grnPin = 10; // Green LED, connected to digital pin 10
int bluPin = 11; // Blue LED, connected to digital pin 11

// Program variables
int redVal = 0; // Variables to store the values to send to the pins
int grnVal = 0;
int bluVal = 0;

void setup()
{
pinMode(redPin, OUTPUT); // sets the pins as output
pinMode(grnPin, OUTPUT);
pinMode(bluPin, OUTPUT);
}

// Main program
void loop()
{
potVal = analogRead(potPin); // read the potentiometer value at the input pin

if (potVal < 341) // Lowest third of the potentiometer's range (0-340)


{
potVal = (potVal * 3) / 4; // Normalize to 0-255

redVal = 256 - potVal; // Red from full to off


grnVal = potVal; // Green from off to full
bluVal = 1; // Blue off
}
else if (potVal < 682) // Middle third of potentiometer's range (341-681)
{
potVal = ( (potVal-341) * 3) / 4; // Normalize to 0-255

redVal = 1; // Red off


grnVal = 256 - potVal; // Green from full to off
bluVal = potVal; // Blue from off to full
}
else // Upper third of potentiometer"s range (682-1023)
{
potVal = ( (potVal-683) * 3) / 4; // Normalize to 0-255

redVal = potVal; // Red from off to full


grnVal = 1; // Green off
bluVal = 256 - potVal; // Blue from full to off
}
analogWrite(redPin, redVal); // Write values to LED pins
analogWrite(grnPin, grnVal);
analogWrite(bluPin, bluVal);
}
Color Crossfading Example
COPY

Explain
/*
* Code for cross-fading 3 LEDs, red, green and blue (RGB)
* To create fades, you need to do two things:
* 1. Describe the colors you want to be displayed
* 2. List the order you want them to fade in
*
* DESCRIBING A COLOR:
* A color is just an array of three percentages, 0-100,
* controlling the red, green and blue LEDs
*
* Red is the red LED at full, blue and green off
* int red = { 100, 0, 0 }
* Dim white is all three LEDs at 30%
* int dimWhite = {30, 30, 30}
* etc.
*
* Some common colors are provided below, or make your own
*
* LISTING THE ORDER:
* In the main part of the program, you need to list the order
* you want to colors to appear in, e.g.
* crossFade(red);
* crossFade(green);
* crossFade(blue);
*
* Those colors will appear in that order, fading out of
* one color and into the next

Transistor Motor Control


Learn how to control a DC motor with a transistor, using PWM.

Last revision08/02/2024
This article was revised on 2022/01/18 by Karl Söderby.

Motors and transistors are very common electronic components. This article aims to provide
some of the basics, along with a working code example, circuits and schematics.

When a pushbutton connected to digital pin 2 is pressed, the Arduino will control a transistor
via pulse-width modulation (PWM), which will ramp up the motor's speed, then slow it back
down.

About Transistors
The Arduino can only provide 40mA at 5V on its digital pins. Most motors require more
current and/or voltage to operate. A transistor can act as a digital switch, enabling the
Arduino to control loads with higher electrical requirements. The transistor in this example
completes the motor's circuit to ground. This example uses a TIP120, which can switch up to
60V at 5A.
When PWMing a transistor, it's similar to pulsing an LED. The higher the PWM value, the
faster the motor will spin. The lower the value, the slower it will spin.

Transistors have three pins. For Bipolar Junction Transistors (BJT), like the one used used in
this example, the pins are called base, collector, and emitter. A small amount of current on
the base pin closes a circuit between the collector and emitter pins. BJTs come in two
different types, NPN and PNP. The TIP120 is a NPN-type transistor, which means the
collector will connect to the motor, and the emitter will connect to ground.

About Motors
Motors work through a process called induction. When you an put electric charge through
wire, a magnetic field is created. A coiled wire will create a stronger field, as will increased
current. In a DC motor, a coiled wire surrounds the motor's shaft. The generated magnetic
field is pulled and repulsed by magnets inside the motor's body.

When a motor stops, there is the potential for a small amount of current to be generated as the
shaft continues spinning. A diode placed in parallel with the motor leads will keep any
generated electricity from damaging your circuit.

Motors will pull the most current when they start up, or have a load. The stall current is the
amount of current a motor will pull when it is stopped by a force. When a motor is up and
running, it will pull significantly less current.

The voltage rating describes the peak operating voltage for a motor, when it works at
optimum efficiency. Going over or under the motor's rated voltage will, over time, shorten
the motor's life. If you provide less than the rated voltage, the motor will spin more slowly.
Typically, a motor needs about 1/2 its rated voltage to run. If you provide less than that when
starting up, it probably won't begin to move.

Hardware Required
Arduino Board
A momentary switch or button
10k ohm resistor
Breadboard
Hook-up wire
9V DC motor
TIP120 transistor
1N4001 diode
9V battery
Circuit
Transistor Motor Control circuit.
Transistor Motor Control circuit.

First, connect wires for power and ground. In the illustration, the red (power) and black
(ground), connect to the two long vertical rows on the side of the breadboard. This provides
access to the 5 volt supply and ground.

Place the pushbutton on the breadboard, straddling the center. A wire connects digital pin 2 to
one leg of the pushbutton. That same leg of the button connects through a 10-kilohm pull-
down resistor to ground. The leg of the button not connected to the Arduino should be wired
to the 5 volt supply.

Connect pin 9 on the Arduino to the base pin of the TIP120. If you are looking at the
transistor so that the metal tab is facing away from you, the base pin is on the left side of the
transistor. This is the pin that will control open or close. The transistor's collector connects to
one lead of the motor, the emitter to ground.

The other end of the motor connects to the positive lead of the 9V battery. Connect the
battery's ground to the Arduino's ground.

Schematic
Transistor Motor Control schematic.
Transistor Motor Control schematic.

Code Example
Below is the full program for controlling a DC motor with a transistor. Further down this
article, you will find a more detailed explanation.

COPY

Explain
/*
Motor Control with a Transistor

This example shows you how to control a motor's using a transistor.


When a pushbutton on pin 2 is pressed, the Arduino will control a transistor
via PWM, which will slowly ramp up the motor's speed, then slow it down.

The circuit :
* momentary switch with one end connected to 5V, the other end connected
to GND through a 10-kilohm resistor, and digital pin 2.
* TIP120 tranistor, with the Base connected to digital pin 9, the Emitter to ground,
and the Collector to one lead from a 9V DC motor
* a 9V battery, with the ground connected to the Arduino's ground, and the power
connected to the motor
* 1N4001 diode across the motor's leads, with the striped side connected to the 9V

The Arduino can only provide 40mA at 5V on its pins. Most motors require
more current and/or voltage to overcome inertia and run. A transistor
can act as a digital switch, enabling the Arduino to control loads with
higher electrical requirements.

Created on 03 January 2013


by Scott Fitzgerald

https://docs.arduino.cc/learn/electronics/transistor-motor-control

This example code is in the public domain.


*/

// give a name to digital pin 2, which has a pushbutton attached


int pushButton = 2;

// the transistor which controls the motor will be attached to digital pin 9
int motorControl = 9;

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


void setup() {
// make the pushbutton's pin an input:
pinMode(pushButton, INPUT);

// make the transistor's pin an output:


pinMode(motorControl, OUTPUT);
}

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


void loop() {

// read the state of the button and check if it is pressed


if(digitalRead(pushButton) == HIGH){
// ramp up the motor speed
for(int x = 0; x <= 255; x++){
analogWrite(motorControl, x);
delay(50);
}

// ramp down the motor speed


for(int x = 255; x >= 0; x--){
analogWrite(motorControl, x);
delay(50);
}
}

delay(1); // delay in between reads for stability


}
Code Walkthrough
In this section, you will find a detailed walkthrough of the program.

First, create a pair of variables for the pushbutton's state and the motor control pin :

COPY
int pushButton = 2;
int motorControl = 9;
In the setup(), declare these pins as an input and output, respectively :

COPY
void setup() {
pinMode(pushButton, INPUT);
pinMode(motorControl, OUTPUT);
}
Now that your setup has been completed, move into the loop().

COPY
void loop() {
Read the state of the pushbutton and check if it is HIGH. It's possible to make the evaluation
directly in your if() statement like this :

COPY
if(digitalRead(pushButton) == HIGH){
If the button is pressed, ramp up the speed of the motor by increasing the PWM value of the
motorControl pin. Once it has reached full speed, ramp back down:

COPY
Explain
for(int x = 0; x <= 255; x+=5){
analogWrite(motorControl, x);
delay(50);
}

for(int x = 255; x >= 0; x-=5){


analogWrite(motorControl, x);
delay(50);
}
Close the if() statement and add a small delay() before closing the loop().

COPY
}
delay(1);
}

Powering Alternatives for Arduino Boards


Learn more about the power pins and connectors of Arduino® boards in this article, their
main characteristics, and how to use them correctly.

AuthorJosé Bagur, Taddy Chung, Karl Söderby


Last revision08/02/2024
Arduino boards can be powered in several ways; we can use dedicated connectors (USB
ports, barrel jacks or battery connectors) or dedicated pins. One fundamental question that
usually arises when using an Arduino board in real-life applications is what dedicated power
connector or pin we should use. This article will describe the main characteristics and correct
use of power pins and connectors of Arduino boards.

Powering Alternatives
Arduino boards have five options in which they can be powered:

Powering via USB connector

Powering via the onboard barrel jack connector (if available on the board)

Powering via the onboard battery connector (if available on the board)

Powering via the VIN (Voltage In) pin

Powering via the 3V3/5V pin*

*Powering your board via the 3V3/5V pins is not recommended, as it can damage your
board's voltage regulator. Read more here.

This article will examine these alternatives more in-depth.

USB Connector
The most common and easiest way we can power an Arduino board is by using its onboard
USB connector. The USB connector provides a regulated 5V line to power the board's
electronics. However, 5V from the USB connector can also power external components
through the 5V pin that can be found in Arduino boards.

Micro USB connector of the Arduino Nano RP2040 board.


Micro USB connector of the Arduino Nano RP2040 board.
Something important about the USB connection is the current rating of the USB host device.
For example, a USB host device can be a computer; this means that the computer's USB port
is the 5V power source of the Arduino board connected to it. Besides USB ports of
computers, we can also use power banks, for example, as power sources for Arduino boards.
Power banks usually have one or more USB outputs that provide regulated 5V lines at
different current ratings. Arduino boards that run at 5V use the USB-regulated 5V line
directly, boards that run at 3V3 regulate the 5V line from the USB connector to 3V3 using
their onboard voltage regulator. Output current rating from the 5V pin will vary, depending
on the 5V power source.

Current from USB ports of computers is usually limited to 500mA.

Barrel Jack Connector


Some Arduino boards have an onboard barrel jack connector that is used to connect external
power supplies. The Arduino boards with an onboard barrel jack connector are the following:

Arduino UNO Rev3


Arduino UNO WiFi Rev2
Arduino Leonardo
Arduino Mega 2560 Rev3
Arduino Due
Arduino Zero
Arduino boards with onboard barrel jacks are configured with positive polarity; this means a
negative sleeve and a positive pin. Boards with an onboard barreljack use a negative 5.5mm
sleeve and a 2.1mm positive pin

Barrel jack connector of the Arduino Zero board.


Barrel jack connector of the Arduino Zero board.

The voltage line from the barrel jack connector is regulated in Arduino boards using their
onboard voltage regulator; usually, it is first regulated to 5V and then regulated again to 3V3
in most Arduino boards. The recommended voltage and current ratings for external regulated
DC power supplies connected to the barrel jack connector are summarized in the table below:

Board External Power Supply Voltage (V) External Power Supply Current (A)
Arduino UNO Rev3 7-12 1
Arduino UNO WiFi Rev2 7-12 1.5
Arduino Leonardo 7-12 1
Arduino Mega 2560 Rev3 7-12 1
Arduino Due 7-12 1.5
Arduino Zero 5-18 1
Battery Connector
Some Arduino boards have an onboard battery connector to connect a battery to the board
and use it as its primary or secondary power supply. The Arduino boards with an onboard
battery connector are the following:

Arduino Portenta H7
Arduino Nicla Sense ME
Arduino Nicla Vision
Arduino MKR NB 1500
Arduino MKR Vidor 4000
Arduino MKR WiFi 1010
Arduino MKR ZERO
Arduino MKR WAN 1310
Arduino MKR GSM 1400
Pro family boards use a 3-pin, 1.2mm SMD ACH battery connector; MKR family boards use
a 2-pin, 2mm SMD PH battery connector.

Battery connector of the Arduino MKR WAN 1310 board.


Battery connector of the Arduino MKR WAN 1310 board.

The boards mentioned before have an onboard integrated battery charge management circuit.
This circuit integrates the most common battery and power management functions, like a
battery charger, a voltage regulator, and a load switch, all in one.

Arduino boards with an onboard battery connector can work with single cell 3V7 Li-Ion and
Li-polymer batteries.

VIN Pin
The VIN pin in Arduino boards is a power pin with a dual function. This pin can work as a
voltage input for regulated external power supplies that do not use a barrel jack connector.
This pin can also work as a voltage output when an external power supply is connected to the
barrel jack connector present in some Arduino boards. An important consideration is that the
VIN pin is connected directly to the input pin of the onboard voltage regulator on Arduino
boards. Since the VIN pin is directly connected to the voltage regulator, the VIN pin does not
have reverse polarity protection.

Use the VIN pin carefully to avoid damaging your Arduino board since it does not have
reverse polarity protection.

The minimum and maximum voltages that can be applied to the VIN pin are determined by
the onboard voltage regulator on Arduino boards, varying from board to board. Those
voltages are summarized in the table below:

Board VIN Voltage (V)


UNO Mini 5-18
UNO Rev3 7-12
UNO WiFi Rev2 7-12
UNO Rev3 SMD 7-12
Leonardo 7-12
Mega 2560 Rev3 7-12
Due 7-12
Micro 7-12
Zero 5-18
Portenta H7 5
Nicla Sense ME 5
Nano RP2040 Connect 5-18
MKR NB 1500 5-7
MKR GSM 1400 5-7
MKR Vidor 4000 5-7
MKR WiFi 1010 5-7
MKR Zero 5-5.5
MKR1000 WIFI 5-5.5
MKR WAN 1300 5-5.5
MKR WAN 1310 5-7
Nano 7-12
Nano Every 7-18
Nano 33 IoT 5-18
Nano 33 BLE 5-18
Nano 33 BLE Sense 5-18
3V3/5V Pin
3V3 and 5V pins are also power pins with a dual function. They can work as power outputs
since these pins are directly connected to the onboard 3V3 and 5V voltage regulators outputs
(depending on the board). Moreover, 3V3 and 5V pins can also be used as power inputs if no
regulated power supply is connected through the other power inputs (USB port, barrel jack
connector or VIN pin).

Since 3V3 and 5V pins are directly connected to the onboard's 3V3 and 5V voltage regulators
outputs, these pins have no reverse polarity protection. Use them carefully when working as
power inputs to avoid damaging your board's voltage regulator.

Although 3V3 and 5V pins can be used as power inputs, it is not recommended if no power
supply is connected through the USB port, the barrel jack connector, or the VIN pin. 3V3 and
5V pins are connected directly to the onboard voltage regulator's output pin. Suppose the
voltage in the voltage regulator output pin becomes higher than the input voltage of the
voltage regulator. In that case, a large current may flow into the voltage regulator from its
output pin to its input pin. That large current can permanently damage your board's voltage
regulator.

It is safe, but not recommended, to apply a voltage to the 3V3 or 5V pins that are not higher
than the input voltage of the voltage regulators.

The maximum current that can be drawn from the 3V3 and 5V pins when working as power
outputs are summarized below. Notice that these currents can be provided by the 3V3 and 5V
onboard voltage regulators, or from the power source connected to the board:

Board 5V Pin Output Current (A) 3V3 Pin Output Current (A)
UNO Mini 1 0.5
UNO Rev3 1 0.15
UNO WiFi Rev2 1 0.5
UNO Rev3 SMD 1 0.15
Leonardo 1 0.15
Mega 2560 Rev3 0.8 0.05
Micro 1 0.15
Zero 1 0.5
Portenta H7 - 1
Nicla Sense ME* - 0.5
Nano RP2040 Connect - 1
MKR NB 1500 - 0.5
MKR Vidor 4000 1 0.3
MKR WiFi 1010 1 0.5
MKR Zero - 0.5
MKR1000 WIFI - 0.5
MKR WAN 1300 - 0.5
MKR WAN 1310 - 0.5
Nano 0.8 0.15
Nano Every 1 0.5
Nano 33 IoT 1 0.5
Nano 33 BLE - 1
Nano 33 BLE Sense - 1
Choosing a Power Input
Now that we know more about the powering alternatives of Arduino boards, we can answer
that question we made at the beginning of this article about what power connector or pin we
should use. When choosing a power connector or pin for a specific application or project, we
should consider the available power source and the power budget of our application or
project.

A power budget analyzes how much power our application or project requires for its correct
working.

Let's talk about when it is recommended to use each of the options ways in which Arduino
boards can be powered:

USB Connector
This option is often recommended when experimenting with small loads that require 5V; the
current would be constrained by the USB host device where the board is connected.

Barrel Jack Connector


This option is recommended when a regulated power supply with a barrel jack connector is
available. Current is constrained by the regulated power supply and the onboard voltage
regulator.

Battery Connector
This option is recommended for portable projects or projects that need a secondary o backup
power supply. Currently, 3V7 Li-Ion and Li-polymer batteries are supported only; the
battery's capacity constrains current.

VIN Pin
This option is recommended when a regulated power supply without a barrel jack connector
is available. Take into account that using VIN pin should be made carefully since this pin
does not have reverse polarity protection. Current is constrained by the regulated power
supply and the onboard voltage regulator.

3V3/5V Pin
Avoid this option since the risk of damaging the onboard voltage regulator is high. It can be
done safely if the applied voltage to the 3V3 or 5V pins is not higher than the input voltage of
the voltage regulators.

Further Reading and Resources


If you want to learn more about power supplies, check out the following links:

Power supplies are one of the most popular and most needed electronic testing equipment.
Check out more about them in this guide from BK Precision®.
LiPo batteries are everywhere. Check out this guide from Roger's Hobby Center to learn
more about LiPo batteries.

Power Consumption on Arduino Boards


Learn about measuring power consumption on an Arduino board.

AuthorKarl Söderby
Last revision08/02/2024
All electronic devices, including Arduino boards, consume power. The power consumption is
measured in ampere-hours (Ah), and with low-voltage devices, it is typically measured in
mAh.

When creating projects that run on a battery or are power-constrained, taking power
consumption into account can be critical. It will among other things help you decide which
kind of battery you need to use.
In this article, we will demonstrate how you can perform power consumption tests, using a
power profiler. A power profiler is used to measure consumption over a specific time, where
we record several thousand samples. You will find instructions for both the hardware setup,
the software setup, and the actual power consumption tests in this article.

Note that in this article, third-party products are being used.

Hardware & Software Needed


For the power consumption tests in this article, we used the following hardware & software.
Note that there are many alternatives on the market.

nRF Connect for Desktop


Power Profiler Kit II
Arduino board (link to store)
Jumper wires
Measuring Power Consumption
Power consumption measurements are done by connecting a power profiler between your
Arduino board and computer. The power profiler is connected to the computer via USB, and
then to the Arduino board via jumper wires. For power consumption measurements, we
simply use two wires: power and ground. The power cable is connected to your Arduino
board's power pins, and the ground cable goes to one of the GND pins on the board.

When connected, the power profiler can measure the power consumption of your board with
high accuracy. Any power that your board consumes can now be detected, and with a
software tool (such as the nRF Connect for Desktop), we can record power consumption over
time.

So what is it that we are measuring? In very simple terms, all electronic devices draw current,
whether it is small or big. A small LED can for example draw 10 mA (0.01 A), while a servo
motor can draw up towards 1000 mA (1 A). If you have an LED on for an hour that draws 10
mA, we can express it as mAh, which means milli-ampers consumed per hour.

Power Consumption Example


To provide a practical example, let's take the Nano ESP32 and run a simple sketch on the
board, which continuously runs the analogRead() function. Running the test for 60 seconds
recording 100'000 samples, results in an average consumption of 31.05 mA.

Now, if we wanted to power this application using a 300 mAh battery we need to calculate
the time with the following formula:

Formular
Formular

With that information, we can make an educated guess of what type of battery we should get.
For example, a battery with more capacity, let's say 600 mAh, would in theory last for twice
the period.

Note that there are other factors at play, such as the battery's discharge rate and the general
quality of the battery. The above formulas and measurements are to be considered guidelines.

Software Setup
The software setup involves two steps: uploading a sketch and installing nRF Connect for
Desktop.

Upload Sketch
This step is rather straightforward. Upload the sketch that you want to measure the power
consumption of. Below is a minimal sketch that reads an analog pin continuously.

COPY

Explain
void setup() {}

void loop() {
int analog_value = analogRead(A0);
delay(1);
}
Install Desktop App
To measure the power consumption, we are going to use the nRF Connect for Desktop tool.
This is a program that you install on your computer.

Hardware Setup
The profiler we used is the Power Profiler Kit II.

First, disconnect the USB cable from your board. You will be powering the board directly
from the power profiler, so there's no need for the USB cable at this point.
Use the provided cable from the kit, and connect it to your board's GND and power pin,
following the illustration below:
Connect the power profiler to the board.
Connect the power profiler to the board.

Important note! In the software setup, you enable the "Power Output" of the power profiler.
Make sure that the voltage (3.3 V or 5 V) matches the voltage on the power pin of the board.
Applying 5 V to a 3.3 V pin will damage your board.

Power Consumption Test


With the hardware and software set up, let's take a look at how to record the power
consumption of your device.

Open the nRF Desktop App.

Enable the power output, by clicking the "Enable Power Output" option.

Enable power output.


Enable power output.

Select sample period (60 seconds) and number of samples (100k).

Click on "Begin Sampling" to start the power consumption test.

Start sampling.
Start sampling.

During the test, you can see the power consumption in real-time. After 60 seconds (or when
the specified sample period ends), you will have the data, which includes the max and avg
consumption. You can also zoom in to view the data.

Power consumption data.


Power consumption data.
You have now recorded the power consumption of your device. You can note down the
results, export it as a .csv or take a screenshot for future reference.

Example Results
In this section, you will find a number of tests we ran on a set of Arduino boards during
different conditions.

Simple Analog Read


The simple analog read sketch continuously reads an analog pin.

COPY

Explain
void setup() {}

void loop() {
int analog_value = analogRead(A0);
delay(1);
}
In the table below, you can see the results of each board tested with the sketch:

Board Min Max Average


UNO R4 WiFi 82.86 mA 124.04 mA 92.63 mA
GIGA R1 WiFi 51.02 mA 94.08 mA 58.05 mA
Nano ESP32 29.18 mA 46.58 mA 31.05 mA
Arduino Cloud Basic
The Arduino Cloud Basic sketch sends sensor data to the Arduino Cloud and turns on the
built-in LED whenever activated from a dashboard.

COPY

Explain
#include "thingProperties.h"

void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);

// Defined in thingProperties.h
initProperties();

// Connect to Arduino IoT Cloud


ArduinoCloud.begin(ArduinoIoTPreferredConnection);

setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
ArduinoCloud.update();
digitalWrite(LED_BUILTIN, led);
}
/*
Since Led is READ_WRITE variable, onLedChange() is
executed every time a new value is received from IoT Cloud.
*/
void onLedChange() {
Serial.print("Led status changed:");
Serial.println(led);
}
In the table below, you can see the results of each board tested with the sketch:

Board Min Max Average


UNO R4 WiFi 94.07 mA 513.70 mA 140.19 mA
GIGA R1 WiFi 121.00 mA 477.44 mA 139.83 mA
Nano ESP32 36.70 mA 274.19 mA 58.81 mA
Summary
In this guide, we have learned how to use a power profiler to record power consumption data
from an Arduino board. This is an great utility, as it can help you identify the power
requirements of your application, helping your decision in selecting the right power source.

Inter-Integrated Circuit (I2C) Protocol


Allows the communication between devices or sensors connected via Two Wire Interface
Bus.

AuthorNicholas Zambetti, Karl Söderby, Jacob Hylén


Last revision08/02/2024
Introduction
A good way of adding complexity of features to your projects without adding complexity of
wiring, is to make use of the Inter-integrated circuit (I2C) protocol. The I2C protocol is
supported on all Arduino boards. It allows you to connect several peripheral devices, such as
sensors, displays, motor drivers, and so on, with only a few wires. Giving you lots of
flexibility and speeding up your prototyping, without an abundancy of wires. Keep reading to
learn about how it works, how it is implemented into different standards, as well as how to
use the Wire Library to build your own I2C devices.

Overview
This section provides an overview of the topics covered in the article.

What Is I2C?
Arduino I2C Pins
I2C Wiring
Wire Library
Examples
What Is I2C?
The I2C protocol involves using two lines to send and receive data: a serial clock pin (SCL)
that the Arduino Controller board pulses at a regular interval, and a serial data pin (SDA)
over which data is sent between the two devices.

In I2C, there is one controller device, with one or more peripheral devices connected to the
controllers SCL and SDA lines.

As the clock line changes from low to high (known as the rising edge of the clock pulse), a
single bit of information is transferred from the board to the I2C device over the SDA line.
As the clock line keeps pulsing, more and more bits are sent until a sequence of a 7 or 8 bit
address, and a command or data is formed. When this information is sent - bit after bit -, the
called upon device executes the request and transmits it's data back - if required - to the board
over the same line using the clock signal still generated by the Controller on SCL as timing.

Each device in the I2C bus is functionally independent from the controller, but will respond
with information when prompted by the controller.

Because the I2C protocol allows for each enabled device to have it's own unique address, and
as both controller and peripheral devices to take turns communicating over a single line, it is
possible for your Arduino board to communicate (in turn) with many devices, or other
boards, while using just two pins of your microcontroller.

An I2C message on a lower bit-level looks something like this:

An I2C Message
An I2C Message

The controller sends out instructions through the I2C bus on the data pin (SDA), and the
instructions are prefaced with the address, so that only the correct device listens.
Then there is a bit signifying whether the controller wants to read or write.
Every message needs to be acknowledged, to combat unexpected results, once the receiver
has acknowledged the previous information it lets the controller know, so it can move on to
the next set of bits.
8 bits of data
Another acknowledgement bit
8 bits of data
Another acknowledgement bit
But how does the controller and peripherals know where the address, messages, and so on
starts and ends? That's what the SCL wire is for. It synchronises the clock of the controller
with the devices, ensuring that they all move to the next instruction at the same time.

However, you are nearly never going to actually need to consider any of this, in the Arduino
ecosystem we have the Wire library that handles everything for you.

Arduino I2C Pins


Below is a table that lists the different board form factors and what pins are for I2C.

Form factor SDA SCL SDA1 SCL1 SDA2 SCL2


UNO SDA/A4 SCL/A5
Nano A4 A5
MKR D11 D12
GIGA D20 D21 D102 D101 D9 D8
Mega & Due D20 D21
I2C Wiring
Below you'll find a couple ways to wire I2C breakout modules. Which way is best depends
on each module, and your needs.

Breakout Boards
Some brekout board modules let you wire them directly, with bare wires on a breadboard. To
connect a module like this to your Arduino board, connect it as follows:

VCC* - 5V/3V3 pin (depending on breakout module)


GND* - GND
SDA - SDA
SCL - SCL
*Pin name might vary depending on what module, VCC might be named "VIN", "+", etc.
GND might be named "-".

Here's an example of how you might connect a sensor to an UNO R4 WiFi:


Bare I2C Wiring on UNO R4 WiFi
Bare I2C Wiring on UNO R4 WiFi

Qwiic & STEMMA QT


When delving into the market of breakout modules and sensors, you'll find that there are
entire ecosystems, where standards are built around the I2C protocol. Examples of such
standards are Qwiic, developed by Sparkfun, and STEMMA QT, developed by Adafruit.
Both Qwiic and STEMMA QT use a 4-pin JST SH connector for I2C devices, making it
easier for third parties to design hardware with vast compatibility. By having a standardized
connector, you'll know that if you see the word Qwiic or STEMMA QT in association with
an item, that it will work together with an Arduino board with a Qwiic or STEMMA QT
connector, such as the UNO R4 WiFi.

Both Qwiic and STEMMA QT bundle together wires for power, ground, as well as the SDA
and SCL wires for I2C, making it a complete kit, one cable that bundles everything together.

I2C on a Qwiic/STEMMA QT connector with UNO R4 WiFi


I2C on a Qwiic/STEMMA QT connector with UNO R4 WiFi

But what's the difference between the two?

Both Qwiic and STEMMA QT use I2C, and even when inspecting modules using the two
standards up close, it may be difficult to tell what makes them unique from each other. But
there is a difference! And it has some implications on how and for what you may use them.

Qwiic has level shifting and voltage regulation on the controller (but not on the peripherals).
What this means is that Qwiic is 3.3 V logic only. This makes it easier to use, as for the end
user, there is one less thing that can go wrong when designing and assembling your circuit.

STEMMA QT, on the other hand, doesn't have this. This lets you use both 3.3 V and 5 V
logic for modules. This also means that there is one more thing you may need to consider
when creating your circuit, but it also grants some more flexibility in power and logic
requirements.

The pin order for STEMMA QT is designed to match the pin order for Qwiic, enabling cross-
compatibility between the two standards.

Grove
Grove is another connector standard, this one developed by seeed studio. You can find a
plethora of modules with a Grove connector, however only some of them use I2C. There are
no Arduino boards that have a built in Grove connector, however you can use products such
as the MKR connector carrier, Nano Grove Shield, or the Base Shield from the Arduino
Sensor Kit to connect Grove sensors to your Arduino board.

Wire Library
The Wire library is what Arduino uses to communicate with I2C devices. It is included in all
board packages, so you don't need to install it manually in order to use it.

To see the full API for the Wire library, visit its documentation page.

begin() - Initialise the I2C bus


end() - Close the I2C bus
requestFrom()- Request bytes from a peripheral device
beginTransmission() - Begins queueing up a transmission
endTransmission() - Transmit the bytes that have been queued and end the transmission
write() - Writes data from peripheral to controller or vice versa
available() - returns the number of bytes available for retrieval
read() - Reads a byte that was transmitted from a peripheral to a controller.
setClock() - Modify the clock frequency
onReceive() - Register a function to be called when a peripheral receives a transmission
onRequest() - Register a function to be called when a controller requests data
setWireTimeout() - Sets the timeout for transmissions in controller mode
clearWireTimeoutFlag() - Clears the timeout flag
getWireTimeoutFlag() - Checks whether a timeout has occurred since the last time the flag
was cleared.
Derived libraries
When you buy basically any breakout module that makes use of the I2C protocol, they will
come with some library that helps you use the sensor. This library is more often than not built
on top of the Wire library, and uses it under the hood. Adding functionality in order to make,
for example, reading temperature easier.

An example of this is if you want to use Adafruits MCP9808 sensor module, you download
the Adafruit_MCP9808 Library from the IDEs library manager, which enables you to use
functions such as tempsensor.readTempC() in order to read the sensors temperature data by
requesting from the right address, and read the information returned with just a single line
instead of writing the Wire code yourself.

To learn how to install libraries, check out our guide to installing libraries.

Examples
The remainder of this article is a collection of examples that can get you off the ground with
I2C.

Controller Reader
Arduino Boards connected via I2C
Arduino Boards connected via I2C

In some situations, it can be helpful to set up two (or more!) Arduino boards to share
information with each other. In this example, two boards are programmed to communicate
with one another in a Controller Reader/Peripheral Sender configuration via the I2C
synchronous serial protocol. Several functions of Arduino's Wire Library are used to
accomplish this. Arduino 1, the Controller, is programmed to request, and then read, 6 bytes
of data sent from the uniquely addressed Peripheral Arduino. Once that message is received,
it can then be viewed in the Arduino Software (IDE) serial monitor window.

Controller Reader Sketch

COPY

Explain
// Wire Controller Reader
// by Nicholas Zambetti [http://www.zambetti.com](http://www.zambetti.com)

// Demonstrates use of the Wire library


// Reads data from an I2C/TWI peripheral device
// Refer to the "Wire Peripheral Sender" example for use with this
// Created 29 March 2006

// This example code is in the public domain.

#include <Wire.h>

void setup() {
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}

void loop() {
Wire.requestFrom(8, 6); // request 6 bytes from peripheral device #8

while (Wire.available()) { // peripheral may send less than requested


char c = Wire.read(); // receive a byte as character
Serial.print(c); // print the character
}

delay(500);
}
Peripheral Sender Sketch

COPY

Explain
// Wire Peripheral Sender
// by Nicholas Zambetti [http://www.zambetti.com](http://www.zambetti.com)

// Demonstrates use of the Wire library


// Sends data as an I2C/TWI peripheral device
// Refer to the "Wire Master Reader" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

#include <Wire.h>

void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
}

void loop() {
delay(100);
}

// function that executes whenever data is requested by master


// this function is registered as an event, see setup()
void requestEvent() {
Wire.write("hello "); // respond with message of 6 bytes
// as expected by master
}
Controller Writer
Arduino Boards connected via I2C
Arduino Boards connected via I2C

In some situations, it can be helpful to set up two (or more!) Arduino boards to share
information with each other. In this example, two boards are programmed to communicate
with one another in a Controller Writer/Peripheral Receiver configuration via the I2C
synchronous serial protocol. Several functions of Arduino's Wire Library are used to
accomplish this. Arduino 1, the Controller, is programmed to send 6 bytes of data every half
second to a uniquely addressed Peripheral. Once that message is received, it can then be
viewed in the Peripheral board's serial monitor window opened on the USB connected
computer running the Arduino Software (IDE).

Controller Writer Sketch

COPY

Explain
// Wire Master Writer
// by Nicholas Zambetti [http://www.zambetti.com](http://www.zambetti.com)

// Demonstrates use of the Wire library


// Writes data to an I2C/TWI Peripheral device
// Refer to the "Wire Peripheral Receiver" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

#include <Wire.h>

void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;

void loop()
{
Wire.beginTransmission(4); // transmit to device #4
Wire.write("x is "); // sends five bytes
Wire.write(x); // sends one byte
Wire.endTransmission(); // stop transmitting

x++;
delay(500);
}
Peripheral Receiver Sketch

COPY
Explain
// Wire Peripheral Receiver
// by Nicholas Zambetti [http://www.zambetti.com](http://www.zambetti.com)

// Demonstrates use of the Wire library


// Receives data as an I2C/TWI Peripheral device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

#include <Wire.h>

void setup()
{
Wire.begin(4); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}

void loop()
{
delay(100);
}

// function that executes whenever data is received from master


// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
while(1 < Wire.available()) // loop through all but the last
{
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}
Accelerometer
Grove IMU over I2C
Grove IMU over I2C

This code lets you read accelerometer data from a Grove 6-Axis Accelerometer module using
the seeed arduino LSM6DS3 library.

COPY

Explain
#include "LSM6DS3.h"
#include "Wire.h"

//Create instance of Accelerometer class


LSM6DS3 accelerometer(I2C_MODE, 0x6A);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial);

if (accelerometer.begin() != 0) {
Serial.println("LSM6DS3 not found, check your wiring.");
} else {
Serial.println("LSM6DS3 found!");
}
}

void loop() {
//Gyroscope
Serial.print("\nGyroscope:\n");
Serial.print(" X1 = ");
Serial.println(accelerometer.readFloatGyroX(), 4);
Serial.print(" Y1 = ");
Serial.println(accelerometer.readFloatGyroY(), 4);
Serial.print(" Z1 = ");
Serial.println(accelerometer.readFloatGyroZ(), 4);

//Accelerometer
Serial.print("\nAccelerometer:\n");
Serial.print(" X1 = ");
Serial.println(accelerometer.readFloatAccelX(), 4);
Serial.print(" Y1 = ");
Serial.println(accelerometer.readFloatAccelY(), 4);
Serial.print(" Z1 = ");
Serial.println(accelerometer.readFloatAccelZ(), 4);

delay(1000);
}
I2C BMP280
Qwiic BMP280 module
Qwiic BMP280 module

This code example lets you read the temperature over I2C from a BMP280 breakout module
from Adafruit:

COPY

Explain
#include <Wire.h>
#include <Adafruit_BMP280.h>

//Create an instance of the BMP280 sensor


Adafruit_BMP280 bmp;

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

// Start the sensor, and verify that it was found


if (!bmp.begin()) {
Serial.println("Sensor not found");
while (1){}
}

void loop() {
// Read the values
float temperature = bmp.readTemperature();

// Print to the Serial Monitor


Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" C");

Serial.println();
delay(2000);
}
I2C OLED
Grove OLED over I2C
Grove OLED over I2C
This code example draws a version of the Arduino logo on a 128x64 I2C Grove OLED:

COPY

Explain
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(128, 64, &Wire, -1);

// The Arduino Logo in a bitmap format


const uint8_t arduinoLogo[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x30, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0x00, 0x70, 0x00,
0x00,
0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0x80, 0x50, 0x00,
0x00,
0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xe0, 0x40, 0x00,
0x00,
0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x20, 0x00,
0x00,
0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfc, 0x0f, 0xff, 0xe0, 0x07, 0xff, 0xf0, 0x3f, 0xff, 0x80, 0x00,
0x00,
0x00, 0x00, 0x01, 0xff, 0xc0, 0x00, 0xff, 0xf0, 0x0f, 0xff, 0x00, 0x07, 0xff, 0x80, 0x00,
0x00,
0x00, 0x00, 0x03, 0xff, 0x80, 0x00, 0x7f, 0xf8, 0x1f, 0xfc, 0x00, 0x01, 0xff, 0xc0, 0x00,
0x00,
0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x3f, 0xf8, 0x00, 0x00, 0x7f, 0xe0, 0x00,
0x00,
0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x0f, 0xfe, 0x7f, 0xf0, 0x00, 0x00, 0x3f, 0xe0, 0x00,
0x00,
0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xff, 0x7f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x00,
0x00,
0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xf0, 0x00,
0x00,
0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x80, 0x0f, 0x00, 0x0f, 0xf8, 0x00,
0x00,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x0f, 0x80, 0x07, 0xf8, 0x00,
0x00,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0x80, 0x07, 0xf8, 0x00,
0x00,
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x0f, 0x80, 0x07, 0xf8, 0x00,
0x00,
0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00void setup() {
Serial.begin(9600);

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 not found"));
while(1){}
}

display.clearDisplay();

display.drawBitmap(0, 0, arduinoLogo, 128, 64, SSD1306_WHITE);


display.display();

void loop() {
}

Arduino & Serial Peripheral Interface (SPI)


Serial Peripheral Interface (SPI) is a synchronous serial data protocol used by
microcontrollers for communicating with one or more peripheral devices quickly over short
distances.

AuthorArduino
Last revision08/02/2024
This article was revised on 2021/11/18 by Karl Söderby.

Controller/peripheral is formerly known as master/slave. Arduino no longer supports the use


of this terminology. See the table below to understand the new terminology:

Master/Slave (OLD) Controller/Peripheral (NEW)


Master In Slave Out (MISO) Controller In, Peripheral Out (CIPO)
Master Out Slave In (MOSI) Controller Out Peripheral In (COPI)
Slave Select pin (SS) Chip Select Pin (CS)
SPI Library
The SPI Library is included in every Arduino core/platform, so you do not need to install it
externally. You can read more about SPI functions in the links below:
SPI Library
GitHub (ArduinoCore-avr)
Serial Peripheral Interface (SPI)
With an SPI connection there is always one Controller device (usually a microcontroller)
which controls the peripheral devices. Typically there are three lines common to all the
devices:

CIPO (Controller In Peripheral Out) - The Peripheral line for sending data to the Controller
COPI (Controller Out Peripheral In) - The Controller line for sending data to the peripherals
SCK (Serial Clock) - The clock pulses which synchronize data transmission generated by the
Controller and one line specific for every device
CS (Chip Select) - the pin on each device that the Controller can use to enable and disable
specific devices. When a device's Chip Select pin is low, it communicates with the
Controller. When it's high, it ignores the Controller. This allows you to have multiple SPI
devices sharing the same CIPO, COPI, and SCK lines.
To write code for a new SPI device you need to note a few things:

What is the maximum SPI speed your device can use? This is controlled by the first
parameter in SPISettings. If you are using a chip rated at 15 MHz, use 15000000. Arduino
will automatically use the best speed that is equal to or less than the number you use with
SPISettings.
Is data shifted in Most Significant Bit (MSB) or Least Significant Bit (LSB) first? This is
controlled by second SPISettings parameter, either MSBFIRST or LSBFIRST. Most SPI
chips use MSB first data order.
Is the data clock idle when high or low? Are samples on the rising or falling edge of clock
pulses? These modes are controlled by the third parameter in SPISettings.
The SPI standard is loose and each device implements it a little differently. This means you
have to pay special attention to the device's datasheet when writing your code.
Generally speaking, there are four modes of transmission. These modes control whether data
is shifted in and out on the rising or falling edge of the data clock signal (called the clock
phase), and whether the clock is idle when high or low (called the clock polarity). The four
modes combine polarity and phase according to this table:

Mode Clock Polarity (CPOL) Clock Phase (CPHA) Output Edge Data Capture
SPI_MODE0 0 0 Falling Rising
SPI_MODE1 0 1 Rising Falling
SPI_MODE2 1 0 Rising Falling
SPI_MODE3 1 1 Falling Rising
Once you have your SPI parameters, use SPI.beginTransaction() to begin using the SPI port.
The SPI port will be configured with your all of your settings. The simplest and most
efficient way to use SPISettings is directly inside SPI.beginTransaction(). For example:

COPY
SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));
If other libraries use SPI from interrupts, they will be prevented from accessing SPI until you
call SPI.endTransaction(). The SPI settings are applied at the begin of the transaction and
SPI.endTransaction() doesn't change SPI settings. Unless you, or some library, calls
beginTransaction a second time, the setting are maintained. You should attempt to minimize
the time between before you call SPI.endTransaction(), for best compatibility if your program
is used together with other libraries which use SPI.

With most SPI devices, after SPI.beginTransaction(), you will write the Chip Select pin
LOW, call SPI.transfer() any number of times to transfer data, then write the CS pin HIGH,
and finally call SPI.endTransaction().
For more on SPI, see Wikipedia's page on SPI.

Tutorials
Extended SPI Library Usage with the Arduino Due
Introduction to the Serial Peripheral Interface
Digital Potentiometer Control (SPI)
Barometric Pressure Sensor (SPI)

LPWAN (Low-Power Wide-Area Networks) 101


Learn the fundamentals of low-power wide-area networks, and what Arduino hardware can
connect to them.

AuthorJosé Bagur
Last revision08/02/2024
Arduino and Low-Power, Wide-Area Networks.
Arduino and Low-Power, Wide-Area Networks.

The exponential growth of the Internet of Things (IoT) and machine-to-machine (M2M)
communications in the last few years has had an impact on almost every aspect of our daily
lives. It is expected that by 2025 more than 75 billion IoT devices will be connected and
working around the world. But how are these IoT devices connected to the Internet?

Generally speaking, IoT and M2M applications and devices have low-power and low-data
transmission requirements (the data usually comes from sensors). Until recently, the
technologies used for connecting these applications and devices were not the ideal ones for
IoT applications, as shown in in the image below. For example, wireless personal area
networks (WLANs) and Bluetooth® were designed primarily for medium to high-speed data
communication in short-range environments. Wireless cellular networks such as 2G, 3G, 4G,
and 5G, were designed for high-speed data communication in medium-range environments.
These networks are usually employed in voice, data, and video communication. In order to
meet the particular requirements of IoT and M2M applications and devices, something had to
evolve to meet the particular requirements of IoT and M2M applications and devices.

The term LPWAN, which emerged in 2013, stands for low-power wide-area network. This is
a generic term that describes a group of network technologies designed to communicate small
data packets on low transmission data rates wirelessly, over relatively long distances using
lower power than common network technologies (like WLANs or Bluetooth, for example).
Transmission of small packets of data, low-power consumption, and wide-signal coverage are
ideal characteristics for IoT and M2M devices and applications.

Wireless access geographic coverage.


Wireless access geographic coverage.

Types of LPWAN technologies


In recent years, two main categories of LPWAN technologies have emerged: networks based
on non-cellular based technologies and cellular-based networks. These types of technologies
can use licensed or unlicensed frequencies and use proprietary or open standards. Let’s talk
about the major and most widely deployed LPWANs today: Sigfox, LoRaWAN®, NB-IoT
and LTE-M.

Non-cellular-based technologies: Sigfox and LoRaWAN®.


One of the most widely utilized LPWANs today is Sigfox. This proprietary ultra-narrowband
LPWAN technology runs over a network in the 868MHz or 902MHz frequency bands, these
frequency bands are unlicensed Industrial, Scientific, and Medical (ISM) frequency bands.
This network can deliver messages over distances of 30 to 50 km in rural areas, 3 to 10 km in
urban settings and up to 1,000 km in line-of-site applications. Its packet size is limited to 150
messages of 12 bytes per day, with downlink packets limited to four messages of 8 bytes per
day.

LoRa is a physical layer technology that works in unlicensed ISM frequency bands. It´s based
on the chirped spread spectrum (CSS) technique. LoRa is basically a single-hop technology,
which relays the messages received from LoRa sensor nodes to a central server via gateways.
The data transmission rate supported by Lo Ra varies from 300 bps to 50 kbps. To support
LoRa on the Internet, The LoRa Alliance has developed LoRaWAN®, which includes
network and upper layer functionalities. LoRaWAN® provides three classes of end devices to
address the different requirements of a wide range of IoT applications.

Cellular-based technologies: LTE-M and NB-IoT


LTE-M, which stands for Long Term Evolution for Machines, and NB-IoT, which stands for
Narrowband Internet of Things, are wireless telecommunications technologies standards
developed by the 3rd Generation Partnership Project (3GPP), the international standards
group responsible for all major mobile telecommunications standards, including the Global
System for Mobile Communications (GSM) standards and Long Term Evolution (LTE)
standards. Unlike Sigfox and LoRaWAN®, LTE-M and NB-IoT are operated by wireless
network providers.

LTE-M is compatible with existing LTE networks, it provides extended coverage comparable
to LTE networks, coverage for M2M applications similar to 5G networks, and offers a
seamless path towards 5G M2M solution. LTE-M is focused on providing variable data rates
and support for both real-time and non-real time applications. It supports low latency
applications, as well as deferred traffic applications that can operate with latencies in the
range of a few seconds. It has low power requirements and supports operations ranging from
low bandwidth to bandwidth as high as 1Mbps. LTE-M also supports devices with a very
wide range of message sizes.

NB-IoT can coexist with GSM and LTE in the licensed frequency bands of 700MHz,
800MHz, and 900MHz. NB-IoT is designed by optimizing and reducing the functionalities of
LTE so that it can be used for infrequent data transmissions and with low power
requirements. The data rate supported by NB-IoT is 200 kbps for downlink and 20 kbps for
uplink. The maximum payload size for each message is 1600 Bytes.

Applications of LPWAN technologies


LPWANs are commonly used in smart metering, smart lighting, asset monitoring and
tracking, smart cities, precision agriculture, livestock monitoring, energy management,
manufacturing, and industrial IoT deployments. Choosing an LPWAN depends on the
specific application, namely the desired speed, data amounts and area covered.

LPWANs are best suited for applications requiring infrequent uplink message delivery of
smaller messages. Most LPWANs technologies also have downlink capabilities. With lower
power requirements, longer ranges and lower costs than traditional mobile networks,
LPWANs enable a number of M2M and IoT applications, many of which were previously
constrained by budgets and power issues.

Some examples of current LPWAN applications are the following:

Smart metering (connected utility meters: sensors in basements).


Smart parking (connected parking lots: sensors in the ground and basement garages).
Smart waste management (connected municipal trash cans).
Asset tracking (such as countrywide tracking and tracing of cargo carriers like pallet cages,
pallets, and containers).
Connected buildings (sensors in bridges or tunnels measure temperature, humidity and
corrosion and identify vulnerabilities long before visible damage occurs).
Condition monitoring (sensors in construction machinery and vehicles recognize
malfunctions or theft).
Arduino® and LPWAN technologies
The Arduino's MKR family has some alternatives to offer in terms of connectivity to
LPWANs:

LoRaWAN® (MKR WAN 1300/1310)


The MKR WAN 1310
The MKR WAN 1310

The MKR WAN 1310 is a development board for experimenting with either LoRa® or
LoRaWAN®.

It can easily connect to The Things Network, a platform with LoRa® coverage all over the
world. It can also be used for point-to-point connection, where you can easily set up
communication between two MKR WAN boards.

Coverage
If you are planning to connect to The Things Network, you can check out the available
gateways at their LoRa® Gateway map.

You can also opt to set up your own gateway, which you can have several end-devices
connect to (building your own network).

MKRWAN library
To access the Murata CMWX1ZZABZ module onboard the MKR WAN 1300/1310, you can
refer to the MKRWAN library.

LoRa library
To easily set up communication between two MKR WAN 1310 boards, you can refer to the
examples in the LoRa library, credit to Sandeep Mistry.

Documentation
You can visit the official documentation for the MKR WAN boards through the links below:

MKR WAN 1300 documentation page.


MKR WAN 1310 documentation page.
NB-IoT / LTE-M (MKR NB IoT)
The MKR NB 1500
The MKR NB 1500

The MKR NB 1500 is a development board designed for global use, providing connectivity
on LTE's Cat M1/NB1 bands 1, 2, 3, 4, 5, 8, 12, 13, 18, 19, 20, 25, 26, 28.

Operators offering service in that part of the spectrum include: Vodafone, AT&T, T-Mobile
USA, Telstra, and Verizon, among others.

Coverage
NB-IoT and LTE-M coverage includes many regions, such as Europe, North & South
America and large parts of Asia.
The MKR NB 1500 can be configured to connect to either NB-IoT or LTE-M, with the
option of choosing a preferred RAT (Radio Access Technology). It is possible to configure
the modem with a primary and backup network.

To see the full coverage, you can visit the NB-IoT / LTE-M coverage map.

MKR NB Library
To access the uBlox SARA-R410M-02B modem onboard the MKR NB 1500, you can refer
to the MKRNB library.

Documentation
You can visit the official documentation for this board at the MKR NB 1500 documentation
page.

Sigfox (MKR FOX 1200)


The MKR FOX 1200
The MKR FOX 1200

The MKR FOX 1200 is a development board designed for LPWAN solutions using the
Sigfox infrastructure.

Every MKR FOX 1200 comes with a free one-year subscription to Sigfox' data plan, useful
for testing the Sigfox network. Please check the plan’s conditions in terms of messages per
day at the Sigfox website.

Coverage
The Sigfox network exists in different parts of the world, but it is mainly operating within
EU. Other countries that have coverage is USA, Japan, Australia, South Africa, New Zealand
and more.

Note that while there is coverage in countries outside EU, it is limited to certain areas within
the country.

To see the full coverage, you can visit Sigfox's own coverage map.

Sigfox Library
To access the Sigfox transceiver ATA8520, you can refer to the Sigfox library.

Documentation
You can visit the official documentation for this board at the MKR FOX 1200 documentation
page.

GPS NMEA 0183 Messaging Protocol 101


Learn the fundamentals of the GPS NMEA 0183 messaging protocol, and what Arduino®
hardware can work with this type of messaging protocol.

AuthorJosé Bagur
Last revision08/02/2024
With the help of a smartphone, we can know where we are on the earth to a few meters. Our
smartphones can do this with the help of a chip that communicates with a group of satellites
in the sky, collectively known as a Global Navigation Satellite System (GNSS). A GNSS is a
group, or constellation, of 24, or more, satellites working together to provide positioning and
timing services globally under any weather conditions.
While the Global Positioning System (GPS) from the United States is the most widely GNSS
used in the world, other GNSS are also available, including:

BeiDou Navigation Satellite System (BDS) from China.


Navigation Indian Constellation (NavIC) from India.
European Global Navigation System (Galileo) from Europe.
Quasi-Zenith Satellite System (QZSS) from Japan.
Globalnaya Navigazionnaya Sputnikovaya Sistema (GLONASS) from Russia.
A minimum of four satellites from a GNSS are required to compute positions in three
dimensions and the time offset in the receiver clock. This means that accuracy and precision
of position, velocity and time data increases with more satellites.

Typically, "GPS" is used as a general term for the overall equipment and process of using a
GNSS to estimate position.

GPS receivers communicate using several "languages" or protocols, including standard and
non-standard (i.e., proprietary) message formats. In these messaging protocols, information
can be transmitted as binary data (i.e., 1's and 0's) or using the ASCII character encoding.
From all message standards that are use with GPS receivers, the NMEA 0183 is the most
widely used messaging standard.

NMEA is the acronym for the National Marine Electronics Association. This association was
founded in 1957 by electronics dealers to enhance the technology and safety of marine
electronics through installer training and interface standards. The NMEA 0183 messaging
protocol was adopted in 1983 originally for interfacing marine electronics, but its use has
expanded to terrestrial electronics also [3].

The NMEA 0183 is a simple messaging protocol where data in this messaging protocol is
transmitted in ASCII strings or "sentences" from one "talker" to multiple "listeners" at a time.
Another characteristic of the NMEA 0183 messaging protocol is that it uses the RS-422
electrical standard, although it is also compatible with the RS-232 electrical standard [3]. The
serial configuration of the NMEA 0183 messaging protocol is the following:

Baud rate: 4800 bauds.


Data bits: 8.
Parity: none.
Stop bit: none.
NMEA 0183 "talkers" can be, for example, a satellite, a depth sounder, or a compass, while
the "listeners" can be a chart-plotter, a radar or a GPS receiver like the one used in the
Arduino MKR GPS Shield.

Sometimes, the NMEA 0183 messaging protocol is confusing because there is not just one
"sentence"; there are different NMEA 0183 sentences with different capabilities and
purposes, usually what changes in the sentence sis the information they can provide. To
understand the different capabilities, purposes and provided information of these sentences,
let us first understand their structure.

GPS NMEA 0183 Sentences Structure


All NMEA 0183 sentences start with the $ sign and end with a carriage return and a line feed;
each data field in the sentence is separated with a comma:

COPY
$aaaaa,df1,df2,df3*hh<CR><LF>
A 5 character address field always follow the $ sign while hh is a two hexadecimal
checksum. A NMEA 0183 sentence can have a maximum of 80 characters plus a carriage
return and a line feed. Let us examine now a GPS NMEA 0183 example sentence:

COPY
$GPGGA,181908.00,3404.7041778,N,07044.3966270,W,4,13,1.00,495.144,M,29.200,M,0.1
0,0000,*40
In this NMEA 0183 sentence we can identify the following information:

GP defines a GPS position (GL would denote GLONASS).


181908.00 is the timestamp (UTC in hours, minutes, and seconds).
3404.7041778 is the latitude in DDMM.MMMMM format.
N denotes north latitude.
07044.3966270 is the longitude in DDDMM.MMMMM format.
W denotes west longitude.
4 is a quality indicator (precision).
13 is the number of satellites used to define the coordinate.
1.00 is the horizontal dilution of precision (HDOP).
495.144 is the altitude of the GPS antenna.
M is the unit of altitude (meters or feet).
29.200 is the geoidal separation.
M is the unit of the geoidal separation (meters or feet).
1.0 is the age of the correction (if any).
0000 shows the correction station ID (if any).
*40 is a checksum.
$GPGGA is a basic and common NMEA 0183 sentence; alternative and companion NMEA
0183 sentences provide similar or additional information.

Basic structure of a NMEA 0183 sentence.


Basic structure of a NMEA 0183 sentence.

Common GPS NMEA 0183 Sentences


Some common NMEA 0183 messaging protocol sentences that we can find related to GPS
are described in the table below:

Sentence Description
$GPGGA Time, position, fix type data.
$GPGLL Latitude, longitude, UTC time of position fix and status.
$GPGSA GPS receiver operating mode, satellites used in the position solution, DOP
values.
$GPGSV Number of satellites in view, satellite ID numbers, elevation, azimuth, SNR
values.
$GPRMC Time, date, position, course, speed data.
$GPVTG Course, speed information relative to the ground.
Notice that $GPRMC sentence is essential as it provides the recommended minimum
navigation data to be provided by a GNSS receiver.

To extract information related to the position, record at least one of the following NMEA
0183 sentences: $GPGGA, $GPGLL, $GPRMC.

Arduino® and the GPS NMEA 0183 Messaging Protocol


The Arduino's MKR family boards can work with the NMEA 0183 messaging protocol using
the Arduino MKR GPS Shield and the Arduino_MKR GPS library.

The MKR GPS Shield.


The MKR GPS Shield.

The MKR GPS Shield is based on the u-blox SAM-M8Q GNSS module; this module utilizes
concurrent reception of up to three GNSS (GPS, Galileo and GLONASS) and supports both
SBAS and QZSS. It also recognizes multiple constellations simultaneously and provides
outstanding positioning accuracy in scenarios where urban canyon or weak signals are
involved.

The MKR GPS Shield is meant to be used on top of the MKR family boards, but it is also
possible to hook it up to other SAM D-based Arduino boards via its UART or I2C pins (the
Arduino_MKR GPS library can work with both communications protocols).

For more information, you can visit the official documentation of the shield here.

MKR GPS Shield Tutorials


If you want to learn how to use the MKR GPS Shield, check out the tutorials below:

MKR GPS Shield basics tutorial


MKR WAN 1310 with MKR GPS Shield
References
[1] "SAM-M8Q Data Sheet", u-blox.com, 2020. [Online]. Available: https://www.u-
blox.com/en/docs/UBX-16012619. [Accessed: 05- Oct- 2021].
[2] "u-blox 8 / u-blox M8 Receiver Description", u-blox.com, 2021. [Online]. Available:
https://www.u-blox.com/en/docs/UBX-16018358. [Accessed: 05- Oct- 2021].
[3] "NMEA 0183 Interface Standard", NMEA, 2021. [Online]. Available:
https://www.nmea.org/nmea-0183.html. [Accessed: 05- Oct- 2021].

The Arduino Guide to LoRa® and LoRaWAN®


Learn the basics of LoRa® and LoRaWAN® and how to use them with Arduino hardware
and software.

AuthorJosé Bagur, Taddy Chung


Last revision08/02/2024
The Internet of Things (IoT) is often referred to as a collection of objects connected to the
Internet using wireless networks; these connected objects aim to collect and exchange
information from their surroundings. IoT enables a connection between the physical and the
digital worlds; that connection produces a massive amount of data that can be used for the
optimization of resources and to improve the efficiency of existing systems.

By 2025, there will be more than 25 billion IoT devices connected to the Internet.

Many of the existing IoT devices will be connected to the Internet using short-range wireless
networks such as Wi-Fi®, Bluetooth®, ZigBee, Z-Wave®, etc. Cellular connections using
networks such as 2G, 3G, and 4G will also connect IoT devices to the Internet. Still, these
short and medium-range wireless networks are not always suitable for IoT devices since they
were developed for applications where power consumption and battery life are not significant
issues. IoT devices usually have low-power consumption and send and receive low amounts
of data.

Low-Power Wide Area Networks


Low-Power Wide Area Networks (LPWAN) is a group of wireless networks technologies
well suited to the specific needs of IoT devices: low-bandwidth and low-power devices,
usually battery-powered. This type of networks provide low-bit rates over long ranges with a
low-power consumption. LPWAN's can accommodate data packets sizes from 10 bytes to 1
kB at uplink speeds up to 200 kbps; long-range connectivity varies from 2 to 1,000 km
depending on the network technology. Most LPWAN's technologies have a star topology;
this means that each device connects directly to a central access point.

Some of the important use cases for LPWAN's include the following applications:

Smart cities: smart parking, intelligent street lighting.


Supply chain management: asset tracking, condition monitoring.
Smart grids: electricity, water, and gas metering.
Smart agriculture: land condition monitoring, animal tracking, geofencing.
If you want to read more about LPWAN's, check out this article from the Learn section.

Several LPWAN technologies use licensed or unlicensed frequencies and proprietary or open
specifications. LoRa® and its Media Access Control (MAC) layer protocol implementation,
LoRaWAN®, is currently one of the existing LPWAN gaining the most traction to support
IoT devices and services.

Bandwidth vs. range of short distance, cellullar and LPWA networks. Image credits: The
Things Network.
Bandwidth vs. range of short distance, cellullar and LPWA networks. Image credits: The
Things Network.

LoRa® and LoRaWAN®


What are LoRa® and LoRaWAN®?
LoRa® is a wireless modulation technique derived from Chirp Spread Spectrum (CSS)
technology. CSS uses wideband linear frequency modulated chirp pulses to encode
information. LoRa® can operate on the following license-free sub-gigahertz ISM (Industrial,
Scientific, and Medical) bands: 433 MHz, 868 MHz, and 915 MHz. ISM bands are
internationally reserved for industrial, scientific and, medical uses.

LoRa® modulation technique was invented in 2010 by the French startup Cycleo; then, it
was acquired in 2012 by Semtech.

Based on LoRa®, the LoRaWAN® (LoRa for Wide Area Networks) specification extended
the LoRa® physical communication layer into the Internet by adding a MAC layer. The
LoRaWAN® specification is a software layer that defines how devices must use the LoRa,
for example, when they transmit or receive messages. The LoRaWAN specification is open-
source; it has been supported and maintained by the LoRa Alliance® since 2015.

The LoRa Alliance® is an open, nonprofit organization that collaborates and shares
experiences to promote and drive the success of the LoRaWAN® standard as the leading
open global standard for secure IoT LPWAN connectivity.

LoRaWAN® Network Architecture


A typical LoRaWAN® network architecture includes the following essential parts: end-
devices (usually sensors), a base station or gateway, also known as Long Range Relay (LRR),
a network server also known as Long Range Controller (LRC), and the Operation Support
System (OSS) for provisioning and management of the network.

Typical LoRaWAN® network architecture example. Image credits: The Things Network.
Typical LoRaWAN® network architecture example. Image credits: The Things Network.

From the image above, notice there is a fundamental difference between a network server and
a gateway. The network server controls the virtualized MAC layer of the LoRaWAN®
network while gateways are devices pre-integrated with the network server to ease the
LPWAN rollout and provisioning. LoRaWAN® network servers and gateways access can be
public or private.

The Things Network (TTN) is a crowdsourced, open, and decentralized LoRaWAN®


network server. This network is a great way to start testing devices, applications, integrations
and get familiar with LoRaWAN®. To connect to TTN, you will need to be in the range of a
gateway. Check the world map to see if your local community already has a gateway
installed; if not, consider installing one!

LoRaWAN® networks are usually deployed in a star-of-stars topology; this means that
gateways manage data between end-devices and a network server. Gateways are connected to
the central network server via the Internet, while end-devices use LoRa® to send and receive
data to and from the gateways; end-devices are not exclusively tied to a single gateway, end-
devices broadcast information to all the gateways in range. Communication in LoRaWAN®
networks is natively bi-directional, although uplink communication between end-devices and
the central network server is expected to be predominant in the network.

Star networks topologies provide the best relationship between long-range communications,
the number of gateways or base stations in the network, end-devices power consumption, and
battery life.

Star networks present several advantages compared to other network topologies:

Gateways can be added to the network anywhere and anytime without prior planning.
Message delivery is more robust since multiple gateways receive the same data packets
during each uplink.
Data Rates
Communication between end-devices and gateways in LoRaWAN® networks is spread out
on different frequency channels and data rates (communications using different data rates do
not interfere with each other).

LoRa® supports data rates ranging from 300 bps to 5 kbps for a 125 kHz bandwidth.

To maximize the battery life of each end-device and the overall capacity available through
the network, LoRaWAN® uses an Adaptive Data Rate (ADR) mechanism for optimizing
data rates, airtime, and power consumption. ADR controls the following transmission
parameters on end-devices:

Spreading factor: the speed of data transmission. Lower spreading factors mean a higher data
transmission rate.
Bandwidth: the amount of data that can be transmitted from one point to another within the
network.
Transmission power: the energy that the end-device transmitter produces at its output.
The table below shows compares spreading factor, data rate, and time on-air at a bandwidth
of 125 kHz (range is an indicative value, it will depend on the propagation conditions):

Spreading Factor Data Rate Range Time on-Air


SF7 5470 bps 2 km 56 ms
SF8 3125 bps 4 km 100 ms
SF9 1760 bps 6 km 200 ms
SF10 980 bps 8 km 370 ms
SF11 440 bps 11 km 40 ms
SF12 290 bps 14 km 1400 ms
End-devices may transmit on any channel available at any time, using any available data rate,
as long as the following rule is respected:
The end-device changes channel in a pseudo-random fashion for every transmission. The
resulting frequency diversity makes the system more robust against interference.
Also, local regulations must be respected, for example:

In the EU868 band, the end-device must respect the maximum transmit duty cycle relative to
the sub-band used and local regulations (1% for end-devices).
In the US915 band, the end-device must respect the maximum transmit duration (or dwell
time) relative to the sub-band used and local regulations (400ms).
LoRaWAN® network layers. Image credits: Semtech.
LoRaWAN® network layers. Image credits: Semtech.

Regional Parameters
The LoRaWAN® Regional Parameters specification is a companion to the LoRaWAN®
network layer specification. While the LoRaWAN® network layer specification defines the
air interface between a compliant end-device (sensor, actuator, tracker, etc.) and a compliant
network core, the LoRaWAN® Regional Parameters specification defines the adaptation of
the LoRaWAN® network layer specification to comply with the various regulations enforced
throughout the world on the use of various frequency bands of the unlicensed spectrum which
are available.

Also, the LoRaWAN® Regional Parameters specification documents the physical layer
configurations required for the compliant operation of LoRaWAN® Link Layer radios using
various radio frequency modulation techniques.

The idea behind the LoRaWAN® Regional Parameters specification is to create the smallest
number of regional channel plans covering the largest possible number of regulatory regions.
With this, complexity is decreased to implementers as well as the certification cost (end-
device certification is enumerated by network layer, Regional Parameters and channel plan
revision).

LoRaWAN® Regional Parameters specifications do not specify everything. They only cover
a region by specifying the common denominator. For example, the LoRaWAN® Regional
Parameters for Asia only specify a common subset of channels, but there are variations
between regulations in Asian countries. Furthermore, each network server, for example TTN,
is free to select additional parameters, such as additional emission channels.

For more information, you can read the RP002-1.0.2 LoRaWAN® Regional Parameters
document here, we also have a more detailed tutorial about LoRaWAN® Regional
Parameters and Arduino hardware; the tutorial can be found here here

Classes
The LoRaWAN® specification has three different communication profiles between devices
and applications: Class A, Class B, and Class C. Each class serves different application needs
and has optimized requirements for specific purposes. The main difference between the three
classes is latency and power consumption; end-devices can always send uplinks when
needed, but its class will determine when to receive downlinks.

All LoRaWAN devices must implement Class A; Class B, and Class C are extensions of
Class A profile.

Class A: "Aloha"
Class A devices implement a bi-directional communication profile where two short
downlinks follow the end-device uplink transmission receive windows, usually referred to as
RX1 and RX2. If the server does not respond in either RX1 or RX2 windows, the next
opportunity will be after the next uplink transmission. Class A devices are often battery-
powered and spend most of the time in sleep mode; therefore, they have the lowest energy
consumption, keep long intervals between uplinks, and have high downlink latency.

Class A default configuration profile. Image credits: The Things Network.


Class A default configuration profile. Image credits: The Things Network.

Class B: The "Beaconing" Class


Class B devices extend Class A devices by adding scheduled receive windows for downlinks,
and, therefore, they emulate a continuously receiving device by opening receive windows at
fixed time intervals. This class should be implemented when low latency of downlink
communication while keeping the power consumption as low as possible is required.

Class B default configuration profile. Image credits: The Things Network.


Class B default configuration profile. Image credits: The Things Network.

Class C: Continuous Reception


Class C communication profile is used in applications with enough power available, so there
is no need to minimize the time of the reception windows; this is the case of most actuators
(e.g., smart plugs, street lights, electrical meters, etc.) Class C devices always listen for
downlinks messages unless they transmit an uplink message. This behavior results in the
lowest latency between the server and the end-device.

Class C default configuration profile. Image credits: The Things Network.


Class C default configuration profile. Image credits: The Things Network.

Authentication and Security


Authentication and security are also important in LoRaWAN® networks. Any LoRaWAN®
network has a baseline authentication and security framework based on the AES 128
encryption scheme. Compared to other LPWAN's, which rely on a single key for
authentication and encryption, the LoRaWAN® framework separates both. Authentication
and integrity control use a network session key (NwkSKey) while user data encryption uses
an application session key (AppSKey).

NwkSKey and AppSKey are AES-128 root keys specific to the end-device, end-devices
manufacturers, or application owners assigned them.

LoRaWAN® supports two authentication and activation methods: Over-The-Air-Activation


(OTAA) and Activation by Personalization (ABP).

Over-The-Air Activation (OTAA): In this method, end-devices are not initialized for any
particular network; they send a JOIN request to a specific LoRaWAN® network and then
receive a device address and an authorization token from which session keys are derived;
NwkSKey and AppSKey are derived during this procedure from a root AppKey pre-
provisioned in the end-devices by its manufacturer.
Over-The-Air activation process. Image credits: Heath Raftery.
Over-The-Air activation process. Image credits: Heath Raftery.

Activation by Personalization (ABP): In this method, end-devices are personalized to work


with a given LoRaWAN® network. End-devices are pre-provisioned with the NwkSKey and
AppSKey and the 32-bits device network address.
Activation by Personalization process. Image credits: Heath Raftery.
Activation by Personalization process. Image credits: Heath Raftery.
The recommended authentication and activation method is OTAA since it provides a high
level of security; ABP method should be used only for specific situations.

Arduino® and LoRa®


Arduino® brings LoRa® connectivity to your projects with several boards, addons and
libraries.

Arduino® Boards with LoRa® Connectivity


The MKR WAN 1300 and 1310 boards provide you with a practical and cost-effective
solution to applications that require LoRa® connectivity and low-power consumption. The
MKR WAN 1300 and 1310 boards are based on a SAMD21 microcontroller from
Microchip®; they also features a CMCMWX1ZZABZ module from Murata® for LoRa®
connectivity, the ATECC508 cryptoauthentication device for security, and a 2MB SPI Flash
memory for onboard storage.

The Arduino® MKR WAN 1310 board.


The Arduino® MKR WAN 1310 board.

PRO hardware also has LoRa® connectivity. The Arduino® Portenta H7 board can have
LoRa® connectivity with the Portenta Vision Shield - LoRa; this addon board also features a
CMCMWX1ZZABZ module from Murata® for LoRa® connectivity, the same module
present in the MKR 1300 and 1310 boards.

The Arduino Portenta Vision Shield - LoRa.


The Arduino Portenta Vision Shield - LoRa.

The Arduino® Edge Control, a remote monitoring and control solution optimized for outdoor
environments, can expand its wireless connectivity capabilities by adding an MKR WAN
1300 or 1310 board. Edge Control can be positioned anywhere and is well suited for smart
agriculture and other applications that require intelligent control in remote locations.

The Arduino® Edge Control.


The Arduino® Edge Control.

Arduino® Libraries for LoRa® Connectivity


You can use several Arduino libraries with the CMCMWX1ZZABZ LoRa® module from
Murata®; we recommend two: The MKRWAN library, developed by Arduino, and the
Arduino LoRa library, developed by Sandeep Mistry. The MKRWAN and the Arduino LoRa
libraries provide you the APIs to communicate with LoRa® and LoRaWAN networks®.

You can use both libraries in the Arduino IDE, online and offline. If you are using the online
IDE, you don't need to do anything, both libraries are already installed and ready to be used.
If you are using the offline IDE, you must install the libraries manually. Installing libraries
can be done easily by navigating to Tools > Manage Libraries... and then look for MKRWAN
library by Arduino and LoRa by Sandeep Mistry; remember to install the latest version of the
libraries.

Currently, there are two versions of the MKRWAN library; MKRWAN_v2 library is still in
beta.

Example: Sending and Receiving Data to a Network Server


Using Arduino® hardware and software to communicate with LoRa® and LoRaWAN®
networks is simple; let's check out an example. This example uses an MKR WAN 1310 board
and the MKRWAN library to send data to a LoRaWAN® network, in this case, TTN. The
circuit for this example is shown in the image below:
Circuit used in the example.
Circuit used in the example.

Before sending and receiving messages from TTN, you need to register your board first to the
network. For this, you need to know your board's Device EUI. You can get your board's
Device EUI by running the FirstConfiguration example from the MKRWAN library. With
your Device EUI, you can register your board in TTN by creating an account in TTN, adding
an application, and registering your board. This tutorial from TTN explains the process.

Once your device is registered on TTN, you can start sending and receiving data with the
following code:

COPY

Explain
/*
Send and receive data from a LoRaWAN network
This sketch demonstrates how to send and receive data with the MKR WAN 1300/1310
board.
This example code is in the public domain.
*/

#include <MKRWAN.h>
#include "arduino_secrets.h"

LoRaModem modem;

void setup() {
// Serial port initialization
Serial.begin(115200);
while (!Serial);

// LoRa module initialization


// Initialize the modem with your regional band (eg. US915, AS923,...)
if (!modem.begin(EU868)) {
Serial.println("- Failed to start module");
while (1) {}
};

// With the module initialized, we can get its version and device EUI
// Your network server provider requires device EUI information to connect to their network
Serial.print("- Your module version is: ");
Serial.println(modem.version());
Serial.print("- Your device EUI is: ");
Serial.println(modem.deviceEUI());

// Join procedure to the network server


// OTAA method need appEUI and appKey, this information is provided by the network
server
int connected = modem.joinOTAA(appEui, appKey);
if (!connected) {
Serial.println("- Something went wrong; are you indoor? Move near a window and
retry...");
while (1) {}
}

// Set poll interval to 60 secs.


modem.minPollInterval(60);

// NOTE: independent of this setting, the modem will not allow sending more than one
message every 2 minutes
// This is enforced by firmware and can not be changed.
}

void loop() {
Serial.println();
Serial.println("- Enter a message to send to network");
Serial.println("(make sure that end-of-line 'NL' is enabled)");

// Get message from Serial Monitor


while (!Serial.available());
String msg = Serial.readStringUntil('\n');

// Show the sent message to the network in HEX format


Serial.println();
Serial.print("- Sending: " + msg + " - ");
for (unsigned int i = 0; i < msg.length(); i++) {
Serial.print(msg[i] >> 4, HEX);
Serial.print(msg[i] & 0xF, HEX);
Serial.print(" ");
}
Serial.println();

// Check if the message was sent correctly or if there was an error


int err;
modem.beginPacket();
modem.print(msg);
err = modem.endPacket(true);
if (err > 0) {
Serial.println("- Message sent correctly!");
} else {
Serial.println("- Error sending message :(");
Serial.println("(- You may send a limited amount of messages per minute, depending on
the signal strength");
Serial.println("- It may vary from one message every couple of seconds to one message
every minute)");
}

// Wait and check if there's a message sent from the network


delay(1000);
if (!modem.available()) {
Serial.println("- No downlink message received at this time");
return;
}

// If there's a message available, store it


char rcv[64];
int i = 0;
while (modem.available()) {
rcv[i++] = (char)modem.read();
}

// Decode and show the received message from the network


Serial.print("- Received: ");
for (unsigned int j = 0; j < i; j++) {
Serial.print(rcv[j] >> 4, HEX);
Serial.print(rcv[j] & 0xF, HEX);
Serial.print(" ");
}
Serial.println();
}
Check out more detailed tutorials we have about sending data between a MKR WAN board
to TTN and between two MKR WAN boards; the tutorials can be found here.

Further Reading and Resources


LoRa® and LoRaWAN® are pretty extensive but exciting topics to study. If you want to
learn more about these technologies, check out the following links:

The LoRa Alliance® Resource Hub. Here you can access LoRaWAN® technical documents
and Whitepapers from The LoRa Alliance®.
LoRa Developer Portal from Semtech. Here you can find technical papers and user guides as
well as specifications and datasheets from Semtech.
The Things Network documentation. Here you can learn all about LoRaWAN® and The
Things Network!
The Things Academy online course in Udemy. A free online course where you'll learn all
about LoRa® and LoRaWAN®, and get ready to start building your own Low Power Wide
Area Network applications.

1-Wire Protocol
Learn about the communication between devices or sensors using the OneWire protocol.

AuthorArduino Community
Last revision08/02/2024
This article was revised on 2022/09/28 by Hannes Siebeneicher.

Controller/peripheral is formerly known as master/slave. Arduino no longer supports the use


of this terminology. Devices formerly known as master are referred to as controller and
devices formerly known as slaves are referred to as peripheral.

1-Wire communication is a protocol operating through one wire between the controller
device and the peripheral device. This article covers the basics of using the 1-Wire protocol
with an Arduino with the help of the OneWire library. The following sections provide
information about the 1-Wire protocol, interface, power, addressing devices, reading devices
and finally a short glimpse into the library's history.

Latest version
The latest version of the library is on Paul Stoffregen's site.

OneWire is currently maintained by Paul Stoffregen. If you find a bug or have an


improvement (to the library), email paul@pjrc.com. Please be sure you are using the latest
version of OneWire.
Bus is a subclass of the OneWire library. Bus class scans the 1-Wire Bus connected to an
analog pin and stores the ROMs in an array. Several methods are available in the Bus class to
acquire data from different 1-Wire sensors (DS18B20, DS2438).

The 1-Wire Protocol


Dallas Semiconductor (now Maxim) produces a family of devices that are controlled through
a proprietary 1-Wire protocol. There are no fees for programmers using the Dallas 1-Wire
(trademark) drivers.

On a 1-Wire network, which Dallas has dubbed a "MicroLan" (trademark), a single controller
device communicates with one or more 1-Wire peripheral devices over a single data line,
which can also be used to provide power to the peripheral devices. (Devices drawing power
from the 1-wire bus are said to be operating in parasitic power mode.) Tom Boyd's guide to
1-Wire may tell you more than you want to know, but it may also answer questions and
inspire interest.

The 1-Wire temperature sensors have become particularly popular, because they're
inexpensive and easy to use, providing calibrated digital temperature readings directly. They
are more tolerant of long wires between sensor and Arduino. The sample code below
demonstrates how to interface with a 1-Wire device using Jim Studt's OneWire Arduino
library, with the DS18S20 digital thermometer as an example. Many 1-Wire chips can
operate in both parasitic and normal power modes.

1-Wire Interfaces
Dedicated Bus Controller
Dallas/Maxim and a number of other companies manufacture dedicated bus controller for
read/write and management of 1-Wire networks. Most of these are listed here:

http://owfs.org/index.php?page=bus-masters

These devices are specifically designed and optimized to read and write efficiently to 1-Wire
devices and networks. Similar to UART/USART controller, they handle clocked operations
natively with the use of a buffer, offloading the processing load from the host processor (e.g.,
sensor gateway or microcontroller) thereby increasing accuracy . External pull-up resistors
are also often not required.

Many of the chips provide error-handling that specifically deals with loss of signal integrity,
level variation, reflections, and other bus issues that may cause problems, particularly on
large networks. Many of the devices have additional features, and are offered on a large
variety of interfaces. They range in price from $1 to $30.

Another key advantage is support of , a read/write file system with vast device support for 1-
Wire controller that exposes many native functions for a wide variety of 1-Wire device types.

UART/USART controller
Most UART/USARTs are perfectly capable of sustained speeds well in excess of the
15.4kbps required of the 1-Wire bus in standard mode. More important, the clock and
buffering is handled separately, again offloading it from the main process of the
microcontroller or main processor. This implementation is discussed here:
http://www.maximintegrated.com/en/app-notes/index.mvp/id/214.

Bitbanging approaches
Where native buffering/clock management is not available, 1-Wire may be implemented on a
general purpose IO (GPIO) pin, where manual toggle of the pin state is used to emulate a
UART/USART with reconstruction of the signal from the received data. These are typically
much less processor-efficient, and directly impact and are directly impacted by other
processes on the processor shared with other system processes.

On Arduino and other compatible chips, this may be done with the OneWire library.

On single-board computers such as the Raspberry Pi, 1-Wire network read is often possible
using kernel drivers that offer native support. The w1-gpio, w1-gpio-therm, and w1-gpio-
custom kernel mods are included in the most recent distributions of Raspbian and are quite
popular, as they allow interfacing with a subset of 1-Wire device with no additional
hardware. Currently, however, they have limited device support, and have bus size limitations
in software.

Powering OneWire devices


The chip can be powered two ways. One way is the "parasitic" option,meaning that only two
wires need go to the chip. The other may, in some cases, give a more reliable operation
(parasitic often works well), as an extra wire carrying the power for the chip is involved. For
getting started, especially if your chip is within 20 feet of your Arduino, the parasitic option
is probably fine. The code below works for either option.

Parasite power mode


When operating in parasite power mode, only two wires are required: one data wire, and one
ground. In this mode, the power line must be connected to ground, per the datasheet. At the
controller, a 4.7k pull-up resistor must be connected to the 1-wire bus. When the line is in a
"high" state, the device pulls current to charge an internal capacitor.

This current is usually very small, but may go as high as 1.5 mA when doing a temperature
conversion or writing EEPROM. When a peripheral device is performing one of these
operations, the bus controller must keep the bus pulled high to provide power until the
operation is complete; a delay of 750ms is required for a DS18S20 temperature conversion.
The controller can't do anything during this time, like issuing commands to other devices, or
polling for the peripheral's operation to be completed. To support this, the OneWire library
makes it possible to have the bus held high after the data is written.

Normal (external supply) mode


With an external supply, three wires are required: the bus wire, ground, and power. The 4.7k
pull-up resistor is still required on the bus wire. As the bus is free for data transfer, the
microcontroller can continually poll the state of a device doing a conversion. This way, a
conversion request can finish as soon as the device reports being done, as opposed to having
to wait for conversion time (dependent on device function and resolution) in "parasite" power
mode.

Note on resistors:
For larger networks, you can try smaller resistors.
The ATmega328/168 datasheet indicates starting at 1k6 and a number of users have found
smaller to work better on larger networks.

Addressing a 1-Wire device


Each 1-Wire device contains a unique 64-bit 'ROM' address, consisting of an 8-bit family
code, a 48-bit serial number, and an 8-bit CRC. The CRC is used to verify the integrity of the
data. For example, the sample code, below, checks if the device being addressed is a
DS18S20 temperature sensor by checking for its family code, 0x10. To use the sample code
with the newer DS18B20 sensor, you would check for a family code of 0x28, instead, and for
the DS1822 you would check for 0x22.

Single-device commands
Before sending a command to a single peripheral device, the controller must first select that
device using its unique ROM. Subsequent commands will be responded to by the selected
device, if found.

Multiple-device commands
Alternatively, you can address a command to all peripheral devices by issuing a 'Skip ROM'
command (0xCC), instead. It is important to consider the effects of issuing a command to
multiple devices. Sometimes, this may be intended and beneficial. For example, issuing a
Skip ROM followed by a convert T (0x44) would instruct all networked devices that have a
Convert T command to perform a temperature conversion. This can be a time-saving and
efficient way of performing the operations. On the other hand, issuing a Read Scratchpad
(0xBE) command would cause all devices to report Scratchpad data simultaneously. Power
consumption of all devices (for example, during a temperature conversion) is also important
when using a Skip ROM command sequence.

Reading a 1-Wire device


Reading a 1-Wire device requires multiple steps. The details are device-dependent, in that
devices are capable of reporting different measurables. The popular DS18B20, for example,
reads and reports temperature, while a DS2438 reads voltage, current, and temperature.

Two Main Read Process Steps:


Conversion
A command is issued to the device to perform an internal conversion operation. With a
DS18B20, this is the Convert T (0x44) byte command. In the OneWire library, this is issued
as ds.write(0x44), where ds is an instance of the OneWire class. After this command is
issued, the device reads the internal ADC, and when this process is complete, it copies the
data into the Scratchpad registers. The length of this conversion process varies depending on
the resolution and is listed in the device datasheet. a DS18B20 takes from 94 (9-bit
resolution) to 750ms (12-bit resolution) to convert temperature. While the conversion is
taking place, the device may be polled, e.g. using in the ds.read() command in OneWire, to
see if it has successfully performed a conversion.

Read Scratchpad
Once the data has been converted, it is copied into the Scratchpad memory, where it may be
read. Note that the Scratchpad may be read at any time without a conversion command to
recall the most previous reading, as well as the resolution of the device and other device-
dependent configuration options.

Asynchronous vs. Synchronous read/write


The majority of existing code for 1-Wire devices, particularly that written for Arduino, uses a
very basic "Convert, Wait, Read" algorithm, even for multiple devices. This creates several
problems:

Program timing for other functions


Arguably the biggest problem with using the above methodology is that unless threading
measures are undertaken, the device must sit (hang) and wait for the conversion to take place
if a hardcoded wait time is included. This presents a serious problem if other timed processes
exist, and even if they don't -- many programs wait for user input, process data, and perform
many other functions that cannot be put on hold for the time necessary for a temperature
conversion process. As noted, a 12-bit conversion process for a DS18B20 can take as long as
750ms. There is no reason to use the wait method, unless it is desired that the controller does
nothing (at all) until the measurement conversion is complete. It is far more efficient to issue
a conversion command and return later to pick up the measurement with a Read Scratchpad
command once the conversion is complete.
Scaling for Poll Speed with multiple devices
Another major problem with the "Convert, Wait, Read" method is that it scales very poorly,
and for no good reason. All conversion commands can be issued in series (or simultaneously)
by issuing a Skip ROM and then converting the command so the result can then be read back
in succession. See discussion here: http://interfaceinnovations.org/onewireoptimization.html.

Adjustment of wait time to required conversion time


The most efficient and expeditious read of 1-Wire devices explicitly takes the conversion
time of the device being read into account, which is typically a function of read resolution. In
the example below, for example, 1000ms is given, while the datasheet lists 750ms as the
maximum conversion time, and typical conversion takes place in 625ms or less. Most
important, the value should be adjusted for the resolution that is currently being polled. A 9-
bit conversion, for example, will take 94ms or less, and waiting for 1000ms simply does not
make sense. As noted above, the most efficient way to poll is the use a read time slot to poll
the device. This way one can know exactly when the result is ready and pick it up
immediately.

History
In 2007, Jim Studt created the original OneWire library that makes it easy to work with 1-
Wire devices. Jim's original version only worked with arduino-007 and required a large (256-
byte) lookup table to perform CRC calculations. This was later updated to work with arduino-
0008 and later releases. The most recent version eliminates the CRC lookup table and has
been tested under arduino-0010.

The OneWire library had a bug causing an infinite loop when using the search function but
Version 2.0 merges Robin James's improved search function and includes Paul Stoffregen's
improved I/O routines (fixes occasional communication errors), and also has several small
optimizations.

Version 2.1 added compatibility with Arduino 1.0-beta and an improved temperature
example (Paul Stoffregen), DS250x PROM example (Guillermo Lovato), chipKit
compatibility (Jason Dangel), CRC16, convenience functions and DS2408 example (Glenn
Trewitt).

Miles Burton derived its Dallas Temperature Control Library from it as well.

Example code
COPY

Explain
#include <OneWire.h>

// DS18S20 Temperature chip i/o

OneWire ds(10); // on pin 10

void setup(void) {

// initialize inputs/outputs

// start serial port

Serial.begin(9600);
}

void loop(void) {

byte i;

byte present = 0;

byte data[12];

byte addr[8];

ds.reset_search();

if ( !ds.search(addr)) {

Serial.print("No more addresses.\n");

ds.reset_search();

return;

Serial.print("R=");

for( i = 0; i < 8; i++) {

Serial.print(addr[i], HEX);

Serial.print(" ");

if ( OneWire::crc8( addr, 7) != addr[7]) {

Serial.print("CRC is not valid!\n");

return;

if ( addr[0] == 0x10) {

Serial.print("Device is a DS18S20 family device.\n");

else if ( addr[0] == 0x28) {


Serial.print("Device is a DS18B20 family device.\n");

else {

Serial.print("Device family is not recognized: 0x");

Serial.println(addr[0],HEX);

return;

ds.reset();

ds.select(addr);

ds.write(0x44,1); // start conversion, with parasite power on at the end

delay(1000); // maybe 750ms is enough, maybe not

// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();

ds.select(addr);

ds.write(0xBE); // Read Scratchpad

Serial.print("P=");

Serial.print(present,HEX);

Serial.print(" ");

for ( i = 0; i < 9; i++) { // we need 9 bytes

data[i] = ds.read();

Serial.print(data[i], HEX);

Serial.print(" ");

Serial.print(" CRC=");

Serial.print( OneWire::crc8( data, 8), HEX);


Serial.println();

}
Converting HEX to something meaningful (Temperature)
In order to convert the HEX code to a temperature value, first you need to identify if you are
using a DS18S20, or DS18B20 series sensor. The code to read the temperature needs to be
slightly different for the DS18B20 (and DS1822), because it returns a 12-bit temperature
value (0.0625 deg precision), while the DS18S20 and DS1820 return 9-bit values (0.5 deg
precision).

First, you need to define some variables, (put right under loop() above)

COPY
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
Then for a DS18B20 series you will need to add the following code below the
Serial.println();

COPY

Explain
LowByte = data[0];

HighByte = data[1];

TReading = (HighByte << 8) + LowByte;

SignBit = TReading & 0x8000; // test most sig bit

if (SignBit) // negative

TReading = (TReading ^ 0xffff) + 1; // 2's comp

Tc_100 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25

Whole = Tc_100 / 100; // separate off the whole and fractional portions

Fract = Tc_100 % 100;

if (SignBit) // If its negative

Serial.print("-");

Serial.print(Whole);

Serial.print(".");
if (Fract < 10)

Serial.print("0");

Serial.print(Fract);

Serial.print("\n");
This block of code converts the temperature to deg C and prints it to the Serial output.

A Code Snippet for the DS 1820 with 0.5 Degree Resolution


The example shown above works only for the B-type of the DS1820. Below is a code
example that works with the lower resolution DS1820 and with multiple sensors displaying
their values on a LCD. The example is working with Arduino pin 9. Feel free to change that
to an appropriate pin for your use. Pin 1 and 3 of the DS1820 have to be connected to ground!
In the example a 5k resistor is connected from pin 2 of DS1820 to Vcc (+5V). See
LiquidCrystal documentation for connecting the LCD to the Arduino.

COPY

Explain
#include <OneWire.h>

#include <LiquidCrystal.h>

// LCD=======================================================

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

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

#define LCD_WIDTH 20

#define LCD_HEIGHT 2

/* DS18S20 Temperature chip i/o */

OneWire ds(9); // on pin 9

#define MAX_DS1820_SENSORS 2

byte addr[MAX_DS1820_SENSORS][8];

void setup(void)
{

lcd.begin(LCD_WIDTH, LCD_HEIGHT,1);
lcd.setCursor(0,0);

lcd.print("DS1820 Test");

if (!ds.search(addr[0]))

lcd.setCursor(0,0);

lcd.print("No more addresses.");

ds.reset_search();

delay(250);

return;

if ( !ds.search(addr[1]))

lcd.setCursor(0,0);

lcd.print("No more addresses.");

ds.reset_search();

delay(250);

return;

int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;

char buf[20];

void loop(void)

byte i, sensor;

byte present = 0;

byte data[12];

for (sensor=0;sensor<MAX_DS1820_SENSORS;sensor++)
{

if ( OneWire::crc8( addr[sensor], 7) != addr[sensor][7])

lcd.setCursor(0,0);

lcd.print("CRC is not valid");

return;

if ( addr[sensor][0] != 0x10)

lcd.setCursor(0,0);

lcd.print("Device is not a DS18S20 family device.");

return;

ds.reset();

ds.select(addr[sensor]);

ds.write(0x44,1); // start conversion, with parasite power on at the end

delay(1000); // maybe 750ms is enough, maybe not

// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();

ds.select(addr[sensor]);

ds.write(0xBE); // Read Scratchpad

for ( i = 0; i < 9; i++)

{ // we need 9 bytes

data[i] = ds.read();

}
LowByte = data[0];

HighByte = data[1];

TReading = (HighByte << 8) + LowByte;

SignBit = TReading & 0x8000; // test most sig bit

if (SignBit) // negative

TReading = (TReading ^ 0xffff) + 1; // 2's comp

Tc_100 = (TReading*100/2);

Whole = Tc_100 / 100; // separate off the whole and fractional portions

Fract = Tc_100 % 100;

sprintf(buf, "%d:%c%d.%d\337C ",sensor,SignBit ? '-' : '+', Whole, Fract < 10 ? 0 :


Fract);

lcd.setCursor(0,sensor%LCD_HEIGHT);

lcd.print(buf);

Arduino® & Modbus Protocol


Modbus is an open serial communication protocol used for transmitting information over
serial lines between electronic devices.

AuthorHannes Siebeneicher
Last revision08/02/2024
Introduction
This article contains information about the Modbus serial communication protocol and how it
can be used with Arduino hardware. The different elements are highlighted, compatible
libraries and boards are shown together with example code. The following section gives an
overview of Modbus compatible Arduino boards and the libraries to enable Modbus protocol
capability. Depending on the hardware you are using, the libraries might vary. Therefore, it is
always important to check your device specifications.

Modbus compatible hardware


All boards compatible with the MKR 485 Shield and the MKR ETH Shield
All boards compatible with the Ethernet Shield Rev2
Portenta Machine Control
Portenta Max Carrier
Opta™
Libraries
ArduinoRS485
ArduinoModbus
Controller/peripheral is formerly known as master/slave. Arduino no longer supports the use
of this terminology. Devices formerly known as master are referred to as controller and
devices formerly known as slaves are referred to as peripheral.

What is Modbus?
Modbus is an open serial communication protocol used for transmitting information over
serial lines between electronic devices. It was originally published by Modicon (now
Schneider Electric) in 1979. The Modbus protocol is the oldest and by far the most popular
automation protocol in the field of automation process. It enables devices, such as energy
meters or humidity sensors connected to the same network to communicate the results to a
supervisory computer or a Programmable Logic Controller (PLC).

Several versions of the Modbus protocol exist such as Modbus RTU, Modbus ASCII,
Modbus TCP and Modbus Plus. It is based on a controller-peripheral (formerly known as
master-slave) architecture and communication between nodes is achieved with send request
and read response type messages. Modbus communicates over several types of physical
media such as RS-232/RS-485 or Ethernet. The original Modbus interface ran on RS-232
serial communication but most of the later Modbus implementations use RS-485 because it
allows for longer distances, higher speeds and the possibility of multiple devices on a single
multi-drop network. The communication over serial RS-485 physical media works with two-
wire transmit and receive connections.

On interfaces like RS-485 and RS-232, the Modbus messages are sent in plain form over the
network and the network will be dedicated to only Modbus communication. However, if your
network requires multiple heterogeneous devices, TCP/IP over Ethernet based protocol is
recommended. In this case, Modbus and other types of mixed protocols can co-exist in the
same physical interface simultaneously. The main Modbus message structure is peer-to-peer,
but it can also function on point-to-point and multidrop networks. As mentioned, the Modbus
protocol communicates using a controller-peripheral technique in which only one device can
initiate transactions, called queries.

ModbusProtocol

How does Modbus work?


Each Modbus message has the same structure, consisting of four basic elements which are
present in each message. The sequence and order of these elements are the same for all
messages, subsequently allowing for easy content parse. The controller always initiates the
conversation. When a message is sent, the peripheral interprets the message and responds to
it. Modbus sends functions which communicate read and write instructions to the peripheral’s
internal memory registers to configure, monitor and control the peripheral’s inputs and
outputs. Modbus devices typically include a register map outlining where the configuration
input and output data can be written and read. You should always refer peripheral’s register
map of your device to gain a better understanding of its overall operation.

Modbus requests follow a simple structure:


requestFrame

Device Address
Every peripheral device has its own address which it responds to when addressed by the
controller. All other devices ignore the message if the address doesn't match their own.
Device addresses are assigned in the range of 1 - 247, but without additional hardware, the
stable number of devices should be limited to 32 as it could cause instability when attaching
more devices.

Function Code
The Function code tells the peripheral device if it should read or write data from the internal
memory registers. Many of the data types are named from their use in driving relays, for
example, a single-bit physical output is called a coil, and a single-bit physical input is called a
discrete input or a contact. The following functions are supported by the Modbus poll:

01 READ COIL
02 READ DISCRETE INPUT
03 READ HOLDING REGISTERS
04 READ INPUT REGISTERS
05 WRITE SINGLE COIL
06 WRITE SINGLE REGISTER
15 WRITE MULTIPLE COILS
16 WRITE MULTIPLE REGISTERS
Data
The data field contains the requested or send data. In the request form used by the Arduino
Modbus library, the data field requires you to enter the starting registers and register count.

CRC Error Check


CRC stands for Cyclic Redundancy check and is an error detecting code commonly used in
digital networks to detect accidental changes in digital data. CRC’s have their name because
the check (data verification) value is a redundancy (it expands the message without adding
information) and the algorithm is based on cyclic codes. They are simple to implement in
binary hardware, easy to analyse mathematically, and particularly good at detecting common
errors caused by noise in transmission channels.

Two bytes are added to the end of every Modbus message for error detection and every byte
in the message is used to calculate the CRC. The receiving device then also calculates the
CRC and compares it to the CRC from the sending device. If even one bit in the message is
received incorrectly, the CRC’s will be different resulting in an error.

Byte and word ordering


The Modbus specification doesn't define exactly how the data is stored in the registers.
Therefore, some manufacturers implemented Modbus in their equipment to store and transmit
the higher byte first followed by the lower byte. Alternatively, others store and transmit the
lower byte first. Similarly, when registers are combined to represent 32-bit data types, some
devices store the higher 16 bits (high word) in the first register and the remaining low word in
the second while others do the opposite. It doesn't matter which order the bytes or words are
sent in, as long as the receiving device knows which way to expect it. (Schneider Electric,
2022)

Use Modbus with Arduino


Now that you have learned about the basics and functionalities of Modbus, it is time to talk
about how you can use your Arduino to establish Modbus communication across devices.
You can use your Arduino either as a controller or as a peripheral device depending on the
setup. To make your life easier you can use the Arduino Modbus library which allows you to
implement the Modbus protocol over two different types of transport: serial communication
over RS485 with RTU or Ethernet and Wi-Fi communication using the TCP protocol.
Because the Modbus library is dependent on the RS-485 library, you must include both of
them in your code.

A lot of Arduino boards are Modbus compatible especially if you consider Ethernet-type
messages. In case you want to communicate via RS-485, MKR 485 Shields will help you
convert any MKR board into a Modbus compatible device. Check out this tutorial to learn
more about sending data between two MKR 485 Shields.

When using the Modbus library, sending messages is fairly straightforward as you can see in
the exemplary request format function below:

Device Address Function CodeStarting Register Register Count


0x21 INPUT REGISTERS 30107 2
Note that this request form is specific to the Modbus library and only works with boards
compatible with this library. Make sure to check the specifications for the board you are
using!

You have to check the device-specific documentation to attain the correct address, function
code, starting registers and register count. The CRC error check is taken care of by the
Modbus library. The example below shows how to implement the Modbus library in order to
make it easy to understand.

Example
Let's say you have a Modbus-compatible energy meter working with RS-485. In our case, we
use a model from Finder which uses Modbus RTU protocol but you can use a different one.

Take a look at the request frame inside the Finder documentation:

finderRequestFrame

We can see that the device address is 33 (or 0x21).

The function code states 04 which we know that it stands for INPUT REGISTERS (see
Function Code).

The starting register is 00 6B (or 0x6B) but for the Modbus library to work we need to
change it from hexadecimal to decimal. In this example, the starting register is stated as
hexadecimal but if we scroll down further in the documentation we can see that the registers
are written in decimals:

modbusMeasurmentFinder

We can also see that the register for U1 takes up 30107 and 30108 which means that the
register count is 2.

Using the readVoltage() function, defined within the parameters we discussed, will retrieve
the voltage measurement from the Finder energy meter.

Inside you can see how the requestFrom() is being called with Device Address, Function
Code, Starting Register and Register Count as parameters.

COPY

Explain
/**
Dedicated to read voltage information from a Modbus-compatible Finder 7M.24 energy
meter.

@param none
@return Returns obtained voltage information.
*/
float readVoltage() {
float volt = 0.;
// Send reading request over RS485
if (!ModbusRTUClient.requestFrom(0x21, INPUT_REGISTERS, 30107, 2)) {
// Error handling
Serial.print("- Failed to read the voltage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
// Response handler
uint16_t word1 = ModbusRTUClient.read(); // Read word1 from buffer
uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer
uint32_t millivolt = word1 << 16 | word2; // Join word1 and word2 to retrieve voltage
value in millivolts
volt = millivolt/1000.0; // Convert to volts
}

return volt;
}
As this article does not cover all types of Modbus implementation, focusing on Modbus RTU,
the following section includes more references to read about the different implementation
types in more detail.

Bluetooth® Low Energy


Bluetooth® Low Energy is a wireless communication technology designed for short-range
communication between electronic devices.

AuthorHannes Siebeneicher
Last revision08/02/2024
Introduction
Bluetooth® Low Energy®, often referred to as Bluetooth® LE, is a wireless communication
technology designed for short-range data exchange between electronic devices. It emerged as
a response to the need for energy-efficient wireless communication in various applications,
especially those where power consumption is a critical concern.

Unlike its predecessor, Bluetooth® Classic, which is optimized for continuous and relatively
high-data-rate communication, Bluetooth® LE focuses on minimizing energy consumption
while maintaining connectivity. This makes Bluetooth® LE particularly suitable for
applications that require long battery life, such as fitness trackers, healthcare devices, smart
sensors, and Internet of Things (IoT) devices.

The aim of this article is to highlight the basic concepts of Bluetooth® Low Energy and
explain how to use the ArduinoBLE library to create Bluetooth® LE projects with
compatible Arduino boards.

Bluetooth® Supported Boards


Below is a list of all supported Bluetooth® boards:

MKR WiFi 1010


UNO R4 WiFi
Nano 33 BLE
Nano 33 BLE Sense
Nano 33 BLE Sense Rev2
Nano 33 IoT
Nano ESP32
Nano RP2040 Connect
Portenta H7
Portenta H7 Lite Connected
Portenta Machine Control
Nicla Voice
Opta WiFi
GIGA R1 WiFi
Overview
The following section provides an overview of the article. If you want to skip to one
particular section simply click the respective link.

Frequency - What frequency does Bluetooth® LE operate on?


Range - How far does Bluetooth® LE's signal reach?
Central / Peripheral Devices - How do you set up your device?
Advertising / Connection Mode - What different modes are there?
Services and Characteristics - How do you advertise information?
Bluetooth® Classic - How does Bluetooth® LE compare to Bluetooth® Classic?
ArduinoBLE Library - Get quick overview of the ArduinoBLE library
Examples - Try different examples using the ArduinoBLE library
To follow along this article you need a compatible board and the ArduinoBLE library

Harald Blåtand (Bluetooth)


Harald Blåtand was a 10th-century Danish king who ruled from approximately 958 to 986
AD and he originally inspired the name Bluetooth®. He is best known for his role in uniting
various Danish tribes and for his conversion to Christianity, which had a significant impact
on the history of Denmark. His nickname “Blåtand” (translated: Bluetooth®) is believed to
have been inspired by his dead or discolored tooth, which may have appeared blue or black.

Similar to how Harald Blåtand united Denmark the Bluetooth® protocol was meant to unite
various devices and communication protocols.

Technical Specifications
The following parts explore the core concepts and technical specifications of Bluetooth®
Low Energy.

Frequency Bands and Range


Bluetooth® Low Energy operates in the 2.4 GHz ISM (Industrial, Scientific, and Medical)
band, which is commonly used for various wireless technologies. This frequency band is
divided into multiple channels that Bluetooth® devices use for communication.

Range
The range of a Bluetooth® Low Energy connection can vary depending on several factors,
but in typical scenarios, it can extend up to approximately 50 meters (or roughly 164 feet) in
a line-of-sight environment. This range can be affected by several factors:

Obstacles: Physical obstacles such as walls, furniture, and other objects can significantly
reduce the range of a Bluetooth® LE connection. Thick walls and materials like concrete can
be particularly challenging for Bluetooth® LE signals to penetrate.
Interference: As mentioned earlier, the 2.4 GHz band is shared by various wireless devices.
Interference from other devices operating in the same frequency range can impact the range
and reliability of Bluetooth® LE connections.

Antenna Design: The design and quality of the antennas in both the central and peripheral
devices can influence the range. Devices with well-designed antennas tend to have better
coverage.

Orientation: The relative orientation of the central and peripheral devices also affects range.
A clear line of sight between devices typically results in the best range, while obstructed lines
of sight can reduce it.

Central / Peripheral Devices


Bluetooth® Low Energy devices operate using different roles and modes that define how
devices interact with each other.

Central Device: A central device in Bluetooth® LE is typically a more capable device with
features like a higher CPU power, more memory, or a larger battery. Central devices take on
the role of initiating connections to peripheral devices. For example, your smartphone is often
a central device when connecting to Bluetooth® LE peripherals like fitness trackers, smart
sensors or an Arduino board.

Peripheral Device: Peripheral devices are generally resource-constrained compared to central


devices (e.g. an Arduino board compared with your smartphone). Peripheral devices advertise
their presence and data to central devices. Compared to Bluetooth® classic, Bluetooth® LE
devices don't maintain a continuous connection to the central device to save power.

Bluetooth® LE Roles
Bluetooth® LE Roles

Advertising / Connection Mode


Advertising Mode: Advertising mode is primarily used to make a Bluetooth® LE peripheral
device discoverable by other devices, particularly central devices. During advertising mode,
the peripheral device periodically broadcasts advertising packets. These packets contain
information about the peripheral's identity, services, and characteristics. Central devices
continuously scan for these advertising packets to discover nearby peripherals. In advertising
mode, the peripheral device is not actively connected to any central device. It remains in a
low-power state while broadcasting advertising packets. It is "waiting" for a central device to
establish a connection.

Connection Mode: Connection mode is activated once a central device successfully


establishes a connection with a peripheral device. During this mode, devices can exchange
data bi-directionally. Central devices can read data from and write data to the peripheral
device. The connection mode is crucial for ongoing communication between Bluetooth® LE
devices.

Bluetooth® LE Modes

Services and Characteristics


In Bluetooth® LE, services and characteristics are fundamental concepts that organize and
describe the data exchanged between devices. Let's explore these concepts in detail:

Services
In Bluetooth® LE, a service can be thought of as a logical grouping of related data
measurements or functionalities provided by a peripheral device. These data measurements
can represent various aspects of the device's capabilities or the information it collects.

For example, consider a weather monitoring sensor. It might have a service called "Weather
Data" that encompasses measurements like temperature, humidity, and wind speed. Another
service, "Energy Information," could include data related to battery level and energy
consumption.

Characteristics

Within each service, we have characteristics. Characteristics are individual data points or
attributes that provide specific information or measurements.

For instance, in the "Weather Data" service mentioned earlier, characteristics may include
"Temperature," "Humidity," and "Wind Speed." These characteristics continuously record
data and update as new measurements become available.

Similarly, the "Energy Information" service may consist of characteristics like "Battery
Level" and "Energy Consumption."

Unique Universal Identifier(UUIDs):

To distinguish services and characteristics, Bluetooth® LE relies on a unique identifier called


a UUID (Unique Universal Identifier).

A UUID is a 128-bit value that serves as a universally unique name for a service or
characteristic. It acts like a label or identifier that central devices use to identify and
communicate with specific services and characteristics.

UUIDs play a crucial role in Bluetooth® LE communication because they ensure that central
devices can accurately locate and interact with the desired data points on peripheral devices.
They eliminate ambiguity and allow for precise data retrieval and control.

In practical terms, understanding services and characteristics is essential when designing or


interacting with Bluetooth® LE devices. Services provide a high-level organization of data,
while characteristics represent the individual data points within those services. UUIDs act as
the keys that enable central devices to access and utilize the data provided by peripheral
devices.

As you explore Bluetooth® LE further, you'll encounter various predefined services and
characteristics used in common applications. These standardized profiles simplify the
development process, making it easier to create Bluetooth® LE-based projects and
applications.

Profiles

Bluetooth® LE profiles are predefined sets of services and characteristics that standardize
how Bluetooth® LE devices interact with each other. These profiles define the behavior and
capabilities of Bluetooth® LE devices, making it easier for different devices to communicate
seamlessly. Let's delve into Bluetooth® LE profiles:

Defining Bluetooth® LE Profiles


Bluetooth® LE profiles serve as blueprints that specify how data should be organized and
exchanged between devices in a standardized manner. They define the roles, services, and
characteristics that devices can use to communicate effectively.

Each profile is tailored to a specific use case or application, ensuring that devices of different
manufacturers can work together seamlessly when using the same profile.

Common Standard Profiles

Bluetooth® LE includes a range of standard profiles that simplify the development of


Bluetooth® LE applications. Some of the most well-known standard profiles include:

Battery Service: The Battery Service provides information about the battery level of a device.
It typically includes a Battery Level characteristic that central devices can read to monitor the
battery status of a peripheral device, such as a wireless headset or smartwatch.

Heart Rate Service: The Heart Rate Service is commonly used in fitness and health
monitoring applications. It includes characteristics that provide real-time heart rate data,
allowing central devices like smartphones or fitness trackers to monitor a user's heart rate
during exercise.

Generic Access Profile (GAP): While not a service in itself, GAP defines the roles and
procedures for device discovery and connection establishment in Bluetooth® LE. It plays a
vital role in enabling devices to find and connect to each other seamlessly.

You can read more about Bluetooth® profiles here.

Creating Custom Profiles

In addition to standard profiles, developers have the flexibility to create custom profiles
tailored to their specific application needs. These custom profiles define unique services and
characteristics that match the requirements of a particular project.

Using Bluetooth® LE profiles, developers can leverage standardized profiles for common
applications or create custom profiles for specialized projects. This standardized approach
simplifies the development process, enhances interoperability, and allows for the creation of
diverse Bluetooth® LE-based applications, from health monitoring to home automation.

As you explore Bluetooth® LE further, you'll discover a wide range of profiles designed to
support various use cases. These profiles play a crucial role in ensuring that Bluetooth® LE
devices can seamlessly communicate and provide valuable data to central devices.

Bluetooth® Classic
Bluetooth® Low Energy is distinctly different from Bluetooth® Classic. Bluetooth® Classic
operates in a manner similar to a serial port or UART (Universal Asynchronous Receiver-
Transmitter), which is commonly used for point-to-point communication.

Some key differences are:

Power Consumption

Bluetooth® Classic: is designed for continuous, relatively high-data-rate communication. As


a result, it consumes more power, making it less suitable for battery-operated devices with
limited power sources.
Bluetooth® Low Energy: is optimized for energy efficiency. It is specifically designed for
applications where power consumption is a critical consideration, such as fitness trackers, IoT
sensors, and wearable devices. BLE devices can operate for extended periods on small
batteries or even energy harvesting solutions.

Data Transfer Rates

Bluetooth® Classic: offers higher data transfer rates suitable for tasks like streaming audio or
transferring files between devices.

Bluetooth® Low Energy: sacrifices data transfer speed in favor of energy efficiency. It's ideal
for applications that require intermittent or small bursts of data, such as sending sensor
readings or control commands.

Connection Types

Bluetooth® Classic: establishes a continuous and relatively power-hungry connection,


making it suitable for applications requiring real-time, continuous communication.

Bluetooth® Low Energy: supports two primary modes - advertising and connection. In
advertising mode, a BLE peripheral periodically broadcasts its presence but doesn't maintain
a continuous connection, conserving power. When needed, a central device can establish a
connection for data exchange.

ArduinoBLE Library
The ArduinoBLE Library is the main library enabling Bluetooth® Low Energy on
compatible Arduino boards. You must first download and install the ArduinoBLE library. See
our instructions on how to install a library.

In the following section you will find an overview and explanation of the library's most
important methods and how to use them:

BLE.begin() - Initialize the library


Central Device
BLE.scan() - Scan for peripherals

BLE.available() - Check for available peripherals

BLE.scanForUuid("UUID") - Start scanning for peripherals with specific UUID

bleDevice.address() - Check the peripheral's address

bleDevice.localName() - Check the peripheral's name

bleDevice.advertisedServiceUuid() - Check the peripheral's advertised service

bleDevice.connect() - Connect to a Bluetooth® Low Energy device.

BLE.connected() - Check if connection was successful

bleDevice.discoverAttributes() - Discover a peripheral's attributes

BLE.stopScan() - Stop scanning

BLE.disconnect() - Disconnect from a peripheral


Peripheral
BLE.setLocalName(name) - Give your device a name

BLEService newService(service) - Create a service object

Read more about standard services in the Assigned Numbers document.

BLEUnsignedCharCharacteristic customCharacteristic("UUID_here", Properties_here); -


Create characteristic object

BLE.setAdvertisedService(bleService) - Set the advertised service

bleService.addCharacteristic(bleCharacteristic) - Add characteristics to the service

bleCharacteristic.writeValue() - Write the value of the characteristic

BLE.advertise() - Start advertising

These are just a few of the most important methods. You can find more information about all
methods and their details in the ArduinoBLE reference.

Examples
Below you can find examples showing how to send data between two Arduino boards and
how to connect to your Arduino board, reading and writing values using your smartphone.

Remote LED Control


This example can be used with two Bluetooth® LE supported Arduino boards, one with a
button, and the other with an LED. When the button is pressed, it will advertise a
corresponding value (high/low), which will be received by the board with an LED.

Central
This example scans for Bluetooth® Low Energy peripherals with a specific UUID (in this
case another Arduino board), connects to it, and lets you control the built-in LED with a
button connected to pin 4.

The circuit below uses an Arduino UNO R4 WiFi. You can use any of the Bluetooth®
compatible boards from this list.
central
central

Then upload the code found below:

COPY

Explain
#include <ArduinoBLE.h>

// variables for button


const int buttonPin = 4;
int oldButtonState = LOW;

void setup() {
Serial.begin(9600);
while (!Serial);
// configure the button pin as input
pinMode(buttonPin, INPUT);

// initialize the Bluetooth® Low Energy hardware


BLE.begin();

Serial.println("Bluetooth® Low Energy Central - LED control");

// start scanning for peripherals


BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
}

void loop() {
// check if a peripheral has been discovered
BLEDevice peripheral = BLE.available();

if (peripheral) {
// discovered a peripheral, print out address, local name, and advertised service
Serial.print("Found ");
Serial.print(peripheral.address());
Serial.print(" '");
Serial.print(peripheral.localName());
Serial.print("' ");
Serial.print(peripheral.advertisedServiceUuid());
Serial.println();

if (peripheral.localName() != "LED") {
return;
}

// stop scanning
BLE.stopScan();

controlLed(peripheral);

// peripheral disconnected, start scanning again


BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
}
}

void controlLed(BLEDevice peripheral) {


// connect to the peripheral
Serial.println("Connecting ...");

if (peripheral.connect()) {
Serial.println("Connected");
} else {
Serial.println("Failed to connect!");
return;
}

// discover peripheral attributes


Serial.println("Discovering attributes ...");
if (peripheral.discoverAttributes()) {
Serial.println("Attributes discovered");
} else {
Serial.println("Attribute discovery failed!");
peripheral.disconnect();
return;
}

// retrieve the LED characteristic


BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-
d104768a1214");

if (!ledCharacteristic) {
Serial.println("Peripheral does not have LED characteristic!");
peripheral.disconnect();
return;
} else if (!ledCharacteristic.canWrite()) {
Serial.println("Peripheral does not have a writable LED characteristic!");
peripheral.disconnect();
return;
}

while (peripheral.connected()) {
// while the peripheral is connected

// read the button pin


int buttonState = digitalRead(buttonPin);

if (oldButtonState != buttonState) {
// button changed
oldButtonState = buttonState;

if (buttonState) {
Serial.println("button pressed");

// button is pressed, write 0x01 to turn the LED on


ledCharacteristic.writeValue((byte)0x01);
} else {
Serial.println("button released");

// button is released, write 0x00 to turn the LED off


ledCharacteristic.writeValue((byte)0x00);
}
}
}

Serial.println("Peripheral disconnected");
}
Peripheral
This example is the corresponding sketch to the one above, setting up your Arduino board as
peripheral with the correct UUID, advertising a built-in LED characteristic. Since we are only
using the built-in LED you don't need to wire any components.

LED_BUILTIN works on all Arduino boards.


COPY
Explain
#include <ArduinoBLE.h>

BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // Bluetooth® Low


Energy LED Service

// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and
writable by central
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214",
BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
Serial.begin(9600);
while (!Serial);

// set LED pin to output mode


pinMode(ledPin, OUTPUT);

// begin initialization
if (!BLE.begin()) {
Serial.println("starting Bluetooth® Low Energy module failed!");

while (1);
}

// set advertised local name and service UUID:


BLE.setLocalName("LED");
BLE.setAdvertisedService(ledService);

// add the characteristic to the service


ledService.addCharacteristic(switchCharacteristic);

// add service
BLE.addService(ledService);

// set the initial value for the characeristic:


switchCharacteristic.writeValue(0);

// start advertising
BLE.advertise();

Serial.println("BLE LED Peripheral");


}

void loop() {
// listen for Bluetooth® Low Energy peripherals to connect:
BLEDevice central = BLE.central();

// if a central is connected to peripheral:


if (central) {
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
// while the central is still connected to peripheral:
while (central.connected()) {
// if the remote device wrote to the characteristic,
// use the value to control the LED:
if (switchCharacteristic.written()) {
if (switchCharacteristic.value()) { // any value other than 0
Serial.println("LED on");
digitalWrite(ledPin, HIGH); // will turn the LED on
} else { // a 0 value
Serial.println(F("LED off"));
digitalWrite(ledPin, LOW); // will turn the LED off
}
}
}

// when the central disconnects, print it out:


Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
}
}
Control an Arduino with a Smartphone App
This example lets you control the built-in LED on your Arduino board with your smartphone.
We recommend using the LightBlue app available for Android and iOS for connecting to
your board. Once installed upload the code and follow the steps as shown in the image below.

Step 1 - Upload Code

COPY

Explain
#include <ArduinoBLE.h>
BLEService newService("180A"); // creating the service

BLEUnsignedCharCharacteristic randomReading("2A58", BLERead | BLENotify); //


creating the Analog Value characteristic
BLEByteCharacteristic switchChar("2A57", BLERead | BLEWrite); // creating the LED
characteristic

const int ledPin = 2;


long previousMillis = 0;

void setup() {
Serial.begin(9600); // initialize serial communication
while (!Serial); //starts the program if we open the serial monitor.

pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a


central is connected
pinMode(ledPin, OUTPUT); // initialize the built-in LED pin to indicate when a central is
connected

//initialize ArduinoBLE library


if (!BLE.begin()) {
Serial.println("starting Bluetooth® Low Energy failed!");
while (1);
}

BLE.setLocalName("<My Board Name>"); //Setting a name that will appear when scanning
for Bluetooth® devices
BLE.setAdvertisedService(newService);

newService.addCharacteristic(switchChar); //add characteristics to a service


newService.addCharacteristic(randomReading);

BLE.addService(newService); // adding the service

switchChar.writeValue(0); //set initial value for characteristics


randomReading.writeValue(0);

BLE.advertise(); //start advertising the service


Serial.println(" Bluetooth® device active, waiting for connections...");
}

void loop() {

BLEDevice central = BLE.central(); // wait for a Bluetooth® Low Energy central

if (central) { // if a central is connected to the peripheral


Serial.print("Connected to central: ");

Serial.println(central.address()); // print the central's BT address

digitalWrite(LED_BUILTIN, HIGH); // turn on the LED to indicate the connection

// check the battery level every 200ms


// while the central is connected:
while (central.connected()) {
long currentMillis = millis();

if (currentMillis - previousMillis >= 200) { // if 200ms have passed, we check the battery
level
previousMillis = currentMillis;

int randomValue = analogRead(A1);


randomReading.writeValue(randomValue);

if (switchChar.written()) {
if (switchChar.value()) { // any value other than 0
Serial.println("LED on");
digitalWrite(ledPin, HIGH); // will turn the LED on
} else { // a 0 value
Serial.println(F("LED off"));
digitalWrite(ledPin, LOW); // will turn the LED off
}
}

}
}
digitalWrite(LED_BUILTIN, LOW); // when the central disconnects, turn off the LED
Serial.print("Disconnected from central: ");
Serial.println(central.address());
}
}
Step 2 - Run LightBlue App
Control your board using LightBlue
Control your board using LightBlue

Summary
In this article we explored the basics of Bluetooth® Low Energy and how to set it up on your
Arduino board using the ArduinoBLE library. We highlighted the differences between
Bluetooth® LE and Bluetooth® Classic and finally we provided examples showcasing how
you can send data between two Arduino boards or how to use your smartphone to connect to
your Arduino board.

Universal Asynchronous Receiver-Transmitter (UART)


A serial communication protocol for sending serial data over USB or via TX/RX pins.

AuthorHannes Siebeneicher
Last revision08/02/2024
In this article, you will learn the basics of Universal Asynchronous Receiver-Transmitter
(UART), a serial communication protocol that can be used to send data between an Arduino
board and other devices. This is the protocol used when you send data from an Arduino to
your computer, using the classic Serial.print() method.

UART is one of the most used device-to-device (serial) communication protocols. It’s the
protocol used by Arduino boards to communicate with the computer. It allows an
asynchronous serial communication in which the data format and transmission speed are
configurable. It's among the earliest serial protocols and even though it has in many places
been replaced by SPI and I2C it's still widely used for lower-speed and lower-throughput
applications because it is very simple, low-cost and easy to implement.

Communication via UART is enabled by the Serial class, which has a number of methods
available, including reading & writing data.

If you want to jump straight to the examples click here or go to the end of this article.

Overview
Overview
Serial Class
Arduino UART Pins
Technical Specifications
How UART Works
Timing and Synchronization
UART Messages
Serial USB Examples
Basic Print Example
Read
RX/TX Pin Examples
Transmit / Receive Messages
Control Built-in LED
Serial Class
With the Serial class, you can send / receive data to and from your computer over USB, or to
a device connected via the Arduino's RX/TX pins.
When sending data over USB, we use Serial. This data can be viewed in the Serial Monitor in
the Arduino IDE.
When sending data over RX/TX pins, we use Serial1.
The GIGA R1 WiFi, Mega 2560 and Due boards also have Serial2 and Serial3
The Serial class have several methods with some of the essentials being:

begin() - begins serial communication, with a specified baud rate (many examples use either
9600 or 115200).
print() - prints the content to the Serial Monitor.
println() - prints the content to the Serial Monitor, and adds a new line.
available() - checks if serial data is available (if you send a command from the Serial
Monitor).
read() - reads data from the serial port.
write() - writes data to the serial port.
For example, to initialize serial communication on both serial ports, we would write it as:

COPY
Serial.begin(9600); //init communication over USB
Serial1.begin(9600); //communication over RX/TX pins
The Serial class is supported on all Arduino boards.

Arduino UART Pins


The default TX/RX pins on an Arduino board are the D0(RX) and D1(TX) pins. Some boards
have additional serial ports, see table below:

Form Factor RX TX RX1 TX1 RX2 TX2 RX3 TX3


MKR D0 D1
UNO D0 D1
Nano D0 D1
Mega D0 D1 D19 D18 D17 D16 D15 D14
Technical Specifications
How UART Works
UART operates by transmitting data as a series of bits, including a start bit, data bits, an
optional parity bit, and stop bit(s). Unlike parallel communication, where multiple bits are
transmitted simultaneously, UART sends data serially, one bit at a time. As the name reveals
the protocol operates asynchronous which means that it doesn't rely on a shared clock signal.
Instead, it uses predefined baud rates to determine the timing of data bits.

Serial / Parallel Communication


Serial / Parallel Communication

As seen in the image above when using parallel communication an 8-bit message would
require eight cables while serial communication only requires one cable for sending messages
and one for receiving.

Consider that you need to connect a common ground between the devices to define the high
and low signals for UART communication. Without a common ground, devices may not be
able to correctly interpret transmitted data.

Components

The key components of UART include the transmitter, receiver, and baud rate. The
transmitter collects data from a source, formats it into serial bits, and sends it via a TX
(Transmit) pin. The receiver receives it via a RX (Receive) pin, processes incoming serial
data and converts it into parallel data for the host system. The baud rate determines the speed
of data transmission.

Timing and Synchronization


Timing and synchronization are crucial aspects of UART communication. Unlike
synchronous serial communication protocols such as SPI and I2C, UART operates operates
asynchronously, meaning it doesn't rely on a shared clock signal to coordinate data
transmission. Instead, it uses predefined baud rates to determine the timing of data bits.

Baud Rate

The baud rate is a fundamental parameter in UART communication. It defines the speed at
which data is transmitted over the communication channel. The baud rate is specified in bits
per second (bps) and represents the number of bits transmitted in one second. In UART, both
the transmitting and receiving devices must agree on the same baud rate to ensure successful
communication.

The significance of the baud rate lies in its direct influence on the data transfer speed. A
higher baud rate allows for faster data transmission, but it also demands a more precise
timing synchronization between the sender and receiver. On the other hand, a lower baud rate
may be suitable for applications where timing accuracy is less critical, but it results in slower
data transfer. When programming your Arduino common baud rates are 9600, 115200, 4800,
and 57600. In your code, you set the baud rate like so:

COPY
Serial.begin(9600);
Flow Control in UART

UART Flow Control is a method for slow and fast devices to communicate with each other
over UART without the risk of losing data. Consider the case where two units are
communicating over UART. A transmitter T is sending a long stream of bytes to a receiver R.
R is a slower device than T, and R cannot keep up. It needs to either do some processing on
the data or empty some buffers before it can keep receiving data.

R needs to tell T to stop transmitting for a while. This is where flow control comes in. Flow
control provides extra signaling to inform the transmitter that it should stop (pause) or start
(resume) the transmission.

Several forms of flow control exist. For example, hardware flow control uses extra wires,
where the logic level on these wires define whether the transmitter should keep sending data
or stop. With software flow control, special characters are sent over the normal data lines to
start or stop the transmission.

You can read more about UART flow control here.

UART Messages
In UART communication, each data frame is encapsulated by start and stop bits. These bits
serve a vital role in establishing the boundaries of data transmission and ensuring
synchronization between the sender and receiver.

Frame Format

Frame Format
Frame Format
Start Bit

A single start bit is transmitted at the beginning of each UART frame. The primary purpose
of the start bit is to indicate the start of the data transmission and prepare the receiver for data
reception.

The start bit is always logic low (0) for UART communication. This means that the start bit is
transmitted as a voltage level that is lower than the logic high threshold, typically at the
receiver's end.

When the receiver detects a start bit, it knows that a new data frame is beginning, and it
prepares to receive the incoming bits.

Start Bit
Start Bit

Data Bits

Data bits are a fundamental component of UART communication as they carry the actual
information to be transmitted. The number of data bits in a UART frame can vary, but a
common and widely used configuration is 8 bits. However, UART supports various character
sizes, including 7-bit and 6-bit configurations, depending on the specific application
requirements.

Data Bits
Data Bits

Character Size

The character size in UART communication is defined by the number of data bits within a
frame. It's essential to choose the appropriate character size to match the requirements of the
data being transmitted. Here are some common character size configurations:

8-Bit: This is the most prevalent character size in UART communication. It allows for the
transmission of a byte of data, which can represent a wide range of values, including ASCII
characters, numerical values, and more.

7-Bit: In cases where data size needs to be smaller, 7-bit character size is utilized. It's suitable
for applications that require less data overhead and can represent 128 different values.

6-Bit: For even more compact data representation, 6-bit character size can be used. This
configuration provides the ability to represent 64 different values.

Data Encoding

Data bits represent the characters or data using binary encoding, where each bit corresponds
to a power of 2. Each bit within the data byte holds a specific position and weight in the
binary representation. This encoding allows for the transmission of a wide range of
information, making UART versatile for various data types, from simple text characters to
complex binary data.

Data Integrity

The accuracy of data transmission in UART communication relies on the proper


configuration of data bits. It's essential that both the transmitter and receiver agree on the
number of data bits and their encoding. If the configuration is incorrect, data corruption can
occur. For example, if the transmitter sends data as 8-bit characters, but the receiver is
configured to expect 7-bit characters, data may be misinterpreted, leading to errors in the
received information.

Parity

In addition to data bits, UART communication may include a parity bit as part of the data
frame. Parity is an error-checking mechanism that can help detect data transmission errors.
Parity can be set to "odd" or "even," and it ensures that the total number of bits set to logic
"1" in a character is either even or odd, depending on the chosen parity type. The presence of
a parity bit allows the receiver to verify the integrity of the received data. If the number of "1"
bits don't match the expected parity, an error is detected.

Parity Bit
Parity Bit

Stop Bits

One or more stop bits are sent after the data bits within each UART frame. The stop bit(s)
signal the end of the data byte and serve to indicate the conclusion of data transmission. The
most common configuration is to use one stop bit, but in situations where added reliability is
required, two stop bits can be employed.

The polarity of the stop bit(s) can vary, with some systems using a high stop bit and others
using a low stop bit based on the specific UART configuration.

Stop Bits
Stop Bits

Serial USB Examples


To send data between an Arduino and a computer, you will need to the board to a computer
with a USB cable.

Basic Print Example


This example will send the string Hello World! from an Arduino to a computer, using the
Serial.println() function. Data will be sent every one second.

COPY

Explain
void setup(){
Serial.begin(9600); //initialize serial communication at a 9600 baud rate
}

void loop(){
Serial.println("Hello world!");
delay(1000);
}
Serial.print() / Serial.println() is used in almost all Arduino sketches, as you can understand
what goes on in the board, and design programs to provide you information on specific
events.

Read
To send data from a computer to an Arduino (from the Serial Monitor), we can make use of
the Serial.available() and Serial.read() functions. First, we check if there's any data available,
and if so, we read it and print it out.

This example will essentially print out whatever you enter in the Serial Monitor (because we
send the data to the board, but we also print it back).

COPY

Explain
int incomingByte = 0; // for incoming serial data

void setup() {
Serial.begin(9600); //initialize serial communication at a 9600 baud rate
}

void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();

// say what you got:


Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
RX/TX Pin Examples
This section contains some basic UART examples, where you send data between two
Arduino boards. To set it up, connect the TX with RX pins on both boards, following the
circuit below:

Connecting two Arduino boards via UART.


Connecting two Arduino boards via UART.

Transmit / Receive Messages


This example allows you to send messages (strings) back and forth between devices. Upload
the following sketch to both devices:

COPY

Explain
String sendMessage;
String receivedMessage;

void setup() {
Serial.begin(9600); // Initialize the Serial monitor for debugging
Serial1.begin(9600); // Initialize Serial1 for sending data
}

void loop() {
while (Serial1.available() > 0) {
char receivedChar = Serial1.read();
if (receivedChar == '\n') {
Serial.println(receivedMessage); // Print the received message in the Serial monitor
receivedMessage = ""; // Reset the received message
} else {
receivedMessage += receivedChar; // Append characters to the received message
}
}

if (Serial.available() > 0) {
char inputChar = Serial.read();
if (inputChar == '\n') {
Serial1.println(sendMessage); // Send the message through Serial1 with a newline
character
sendMessage = ""; // Reset the message
} else {
sendMessage += inputChar; // Append characters to the message
}
}
}
We start by declaring two String variables for our incoming and outgoing messages.

COPY
String sendMessage;
String receivedMessage;
Inside setup() we initialize both Serial and Serial1 with a baudrate of 9600, establishing a
connection with the computer and the other transmitting Arduino board.

COPY
Serial.begin(9600);
Serial1.begin(9600);
Reading Messages

The core code can be found inside loop(). If a new byte is received, meaning
Serial1.available() is larger than 0 we check the received message.

COPY
while (Serial1.available() > 0) {
...
}
We read a single character from the Serial1 input buffer:

COPY
char receivedChar = Serial1.read();
If a newline character '\n' is encountered, the received message is processed and printed to the
Arduino serial monitor. The receivedMessage is then reset to an empty string to prepare for
the next incoming message.

In programming, the newline character ('\n') is like pressing "Enter" key. It's a special
character that tells the computer, "Move to the next line." In our case we know that a message
is sent after pressing enter which equals the newline character ('n').

COPY
if (receivedChar == '\n') {
Serial.println(receivedMessage);
receivedMessage = "";
}
Send Messages
For sending messages we first check if there are any characters available in the Serial input
buffer. In other words we check if there is any text written inside the serial monitor, in which
case Serial.available() > 0.

COPY
if (Serial.available() > 0) {
...
}
When a newline character '\n' is detected, the message is sent via Serial1. The sendMessage is
then reset to an empty string for the next outgoing message.

COPY

Explain
char inputChar = Serial.read();
if (inputChar == '\n') {
Serial1.println(sendMessage);
sendMessage = "";
}
If the input is not a newline (meaning everything is written on the same line) it's added to the
same message.

COPY
else {
sendMessage += inputChar; // Append characters to the message
}
Control Built-in LED
The following example lets you control the built-in LED by sending UART messages.

Receiver

COPY

Explain
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // set LED pin as output
digitalWrite(LED_BUILTIN, LOW); // switch off LED pin

Serial1.begin(9600); // initialize UART with baud rate of 9600


}
void loop() {
while (Serial1.available() >= 0) {
char receivedData = Serial1.read(); // read one byte from serial buffer and save to
receivedData
if (receivedData == '1') {
digitalWrite(LED_BUILTIN, HIGH); // switch LED On
}
else if (receivedData == '0') {
digitalWrite(LED_BUILTIN, LOW); // switch LED Off
}
}
}
Transmitter
COPY

Explain
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // set LED pin as output
digitalWrite(LED_BUILTIN, LOW); // switch off LED pin

Serial.begin(9600); // initialize serial communication at 9600 bits per second:


Serial1.begin(9600); // initialize UART with baud rate of 9600
}
void loop() {
if (Serial.read() == '1'){
Serial1.println('1');
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("LEDS ON");
}
else if (Serial.read() == '0'){
Serial1.println('0');
digitalWrite(LED_BUILTIN, LOW);
Serial.print("LEDS OFF");
}
}
Receiver

First, we start by setting up our devices setting the built-in LED as OUTPUT and writing an
initial LOW value to it.

COPY
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Inside setup() we initialize the UART connection by calling Serial1 with a baudrate of 9600.

COPY
Serial1.begin(9600);
If a new byte is received, meaning Serial1.available() is larger than 0 we check the received
message.

COPY
while (Serial1.available() > 0) {
...
}
Next, we read the received byte and check if it equals '1'. If the condition is met, we turn on
the built-in LED by writing HIGH.

COPY
char receivedData = Serial1.read(); // read one byte from serial buffer and save to
receivedData
if (receivedData == '1') {
digitalWrite(LED_BUILTIN, HIGH); // switch LED On
}
If the received byte equals '0' we write LOW to the buit-in LED.

COPY
else if (receivedData == '0') {
digitalWrite(LED_BUILTIN, LOW); // switch LED Off
}
Transmitter

First, we start by setting up our devices setting the built-in LED as OUTPUT and writing an
initial LOW value to it.

COPY
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Inside setup() we initialize both Serial and Serial1 with a baudrate of 9600, establishing a
connection with the computer and the other transmitting Arduino board. This is because only
the transmitter needs to be connected to the serial monitor.

COPY
Serial.begin(9600);
Serial1.begin(9600);
Inside loop() we check if the written message inside the IDE serial monitor (Serial) equals '1'
and if so we print the same message to Serial1, turning the built-in LED on.

COPY

Explain
if (Serial.read() == '1'){
Serial1.println('1');
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("LEDS ON");
}
If the written message inside the IDE serial monitor (Serial) equals '0', we print the same
message to Serial1, turning the built-in LED off.

Designing Arduino Nano Hardware


Learn how to create your own custom hardware that is compatible with the Arduino Nano
Family.

AuthorKarl Söderby
Last revision08/02/2024
The Nano Family
The Nano Family

The Arduino Nano Family is a series of boards with a tiny footprint. This guide is dedicated
to you who wants to design your own customized hardware for the Nano Family.

This article aims to provide you with technical information that will aid the design of your
own customized Nano hardware.

Documentation
Each Nano Family board has a dedicated documentation page, see the list below:

Nano
Nano Every
Nano 33 BLE
Nano 33 BLE Sense
Nano 33 IoT
Nano RP2040 Connect
Inside the documentation page, you will find design files such as full pinout, CAD and
Fritzing files. You will also find tutorials and compatible libraries with the respective boards
in this page.

Technical Overview
Dimensions
Nano dimensions.
Nano dimensions.

The following dimensions apply to all of the Nano boards.

Format Measurement
Width 17.76 mm
Length 43.16 mm
Pitch 2.54 mm
Pitch is the space between the pins (e.g. between A1, A2. This specification is important
when choosing header pins.

More detailed blueprints are available for download through the links below (in .svg format):

Nano General Dimensions


Nano Header Dimensions
Nano Pads Dimensions
Feature Comparisons
Below is a comparison between the different Nano Family boards.

Board Nano Nano Every Nano 33 BLE Nano 33 BLE Sense Nano 33 IoT Nano
RP2040 Connect
Processor ATmega328P ATmega4809 nRF52840 nRF52840 SAMD21G18A
RP2040
Radio Module x x NINA-B306 NINA-B306 NINA-W102 NINA-W102
Connectivity x x Bluetooth® Bluetooth® Wi-Fi, Bluetooth® Wi-Fi,
Bluetooth®
Clock Speed 16 Mhz 16 Mhz 64 Mhz 64 Mhz 48 Mhz 133
MHz
Flash Memory 32 KB 48 KB 256 KB 256 KB 264 KB 16 MB
SRAM 2 KB 6 KB 1 MB 1 MB 256 KB 264 KB
EEPROM 1 KB 256 byte x x x x
I/O Voltage 5V 5V 3.3V 3.3V 3.3V 3.3V
There are several embedded sensors on the Nano boards, which can be seen below:

Board Nano Nano Every Nano 33 BLE Nano 33 BLE Sense Nano 33 IoT Nano
RP2040 Connect
IMU x x LSM9DS1 LSM9DS1 LSM6DS3 LSM6DSOX
Microphone x x x MP34DT05 x MP34DT05
Gesture x x x APDS-9960 x x
Light x x x APDS-9960 x x
Color x x x APDS-9960 x x
Pressure x x x LPS22HB x x
Temperature x x x HTS221 x x
Humidity x x x HTS221 x x
Power Considerations
Voltage (3.3V / 5V)
It is important to understand that the Nano family boards operate on different voltage. Any
board with a radio module (Nano 33 BLE, Nano 33 BLE Sense, Nano 33 IoT, Nano RP2040
Connect) operates on 3.3V. The Nano and Nano Every operate on 5V.

As the boards with radio modules operate on 3.3V logic, the 5V pin is connected to headers
via a solder jumper which defaults open. When powering the board via USB, the VIN pin can
be used as a 5V output from the board. This is useful when powering carrier boards requiring
5V and powering the system via USB.

VUSB Pads
The 5V pin is also referred to as "VUSB". The purpose of this pin is to provide direct
connection between USB connector's VUSB (5V) to headers. This can be used to power
devices on a carrier board directly while when using VIN pin this will exhibit a drop due to
the series diodes that prevents VIN to back power the USB. In order to connect VUSB/5V
pin headers, you will need to solder together the VUSB pads on the bottom of the board, as
shown in the image below:

Solder the VUSB pads.


Solder the VUSB pads.

If you solder the VUSB pads, and then power the board via USB, it also enables the 5V pin to
be used. Be very cautious with this, as you risk damaging your board's ICs.

VIN Min/Max
The min/max voltage supply varies between boards. This is important to consider when
choosing the battery source, that you do not exceed the limits to damage the board.

Nano Nano Every Nano 33 BLE Nano 33 BLE Sense Nano 33 IoT Nano RP2040
Connect
7-12V 7-18V 5-18V 5-18V 5-18V 5-18V
Battery Connection
Nano boards can be powered with batteries, but they do not come with a battery charging
circuit or battery protection circuit.

Many LiPo batteries have a built-in protection circuit, but some does not. In short, this means
overdischarge can happen when powering the board with a LiPo battery. See the section
below for more information.

Battery Overdischarge Warning


If you want to connect a battery to a Nano, do so by using the VIN pin but you have to keep
in mind VIN minimum requirements (which means a single cell battery won't be enough).
Since there's no under voltage protection, a LiPo battery without a protection circuit will be
damaged if it is kept connected to the Nano board even after it is completely discharged. It is
thus recommended not to connect a battery directly but rather to use circuits like those in
USB battery packs that provide a stabilized 5V power supply and protect the battery from
undervoltage.

To connect a battery to a Nano board, you will need to use the VIN pin (refer to the VIN min-
max table in the section above).

Nano battery connection.


Nano battery connection.

Pinout
Nano boards largely share the placement of many pins, to make it easy for accessories to be
designed for different Nano boards.

Serial Buses
The Nano Family boards have serial buses attached to the following pins:

Protocol Pins
UART RX,TX
SPI COPI(11), CIPO(12), SCK(13)
I²C SDA(A4), SCL(A5)
The location of these pins are located in the pinout for each board. These are found in the
Resources Section product page of each board.

Carrier Templates
Nano carrier template file.
Nano carrier template file.

In this section, you will find downloadble files that can be used together with various PCB
design programs, such as Altium and Eagle to create your own Nano accessories.

You can either download the connector template, or the solder pads template.

Connector template: empty carrier template with connectors. This is useful if you want to
create a design where you can attach and remove a Nano board easily.
Solder pads template: an empty carrier template with solder pads. This is useful if you want
to create a design where you solder the Nano directly on top of the PCB.
Altium
Below are template files for Altium.

Nano Carrier PCB template (solder pads)


Nano Carrier PCB template (connectors)
Eagle
Below are template files for Eagle.

Nano Carrier PCB template (solder pads)


Nano Carrier PCB template (connectors)
3D Files
The design file(s) below can be used for 3D printing, e.g. enclosures, mounts.

Nano Board Enclosure (.stl)


Nano Board Enclosure (.stp)
Soldering Directly To PCB
All Nano boards can be purchased without headers attached. This makes it possible to solder
it directly to a custom PCB, using the castellated holes on the board.

Castellated holes on a Nano board to the left, solder pads on a PCB to the right.
Castellated holes on a Nano board to the left, solder pads on a PCB to the right.

This method is useful for more robust applications, where the Nano board needs to be
permanently attached.

Do not attempt to solder any Arduino Nano boards shipped in single package using the
reflow soldering method. Since Arduino boards are not shipped in a dry pack, the board may
absorb humidity and is thus unsuitable for reflow process. Boards should always be soldered
manually; in case you're interested in using the reflow soldering process for volume
manufacturing, please contact Arduino PRO.

Nicla Family Form Factor Specification


Our smallest footprint packed with advanced features.

AuthorDario Pennisi
Last revision08/02/2024
This document aims to describe the design philosophy and technical specifications of the
Nicla Form Factor and should be used as a guideline for designing boards and accessories
(shields/carriers) compatible with the form factor.

Nicla Form Factor


The Nicla form factor has been designed to address the needs of industrial applications and
makers for an all-in-one package featuring wireless sensing capabilities. Key focus is given to
collecting and processing data at the edge with minimal power consumption. Nicla boards
integrate application specific sensors and high performance microcontrollers capable of
processing raw data in real time and provide high level measurements to the host board or to
the main application. Nicla boards support programmable I/O voltage ranging between 1.8
and 3.3V whose voltage reference can either be supplied externally or generated internally.

Nicla family has been designed to fulfill the following key needs:

Low Power
integrated sensing with AI capabilities
wireless communication
partial compatibility with MKR form factor
industrial temperature range
Nicla boards are designed for the following three use cases:

Standalone - Nicla boards can be used as a traditional Arduino board on which the user can
load the final application. In this scenario Nicla's microcontroller is executing the whole
application and its interfaces can be used to communicate to external sensors and actuators
ESLOV peripheral - Nicla boards can be connected through the ESLOV connector,
consisting of 5 pins including an I2C bus, power supply and a GPIO. Through this connector
the board can be interfaced with MKR boards directly or, via adapter cables, to other boards
exposing similar interfaces such as QWIIC, STEMMA/STEMMA QT and GROVE. Nicla
boards are provided with a readymade firmware which abstracts sensors and allows reading
high level measurements processed by Nicla main processor.
MKR Shield - Nicla boards can be fitted on a MKR board as a shield. In this scenario MKR
would be running the main application and would communicate with Nicla through I2C as it
would do via ESLOV.
Wireless - Nicla boards can be battery operated and can communicate wirelessly to a central
processor. As in other use case scenarios Nicla would be processing sensor data and provide
high level processed information.
Mechanical Specification
Board Size and Shape
Nicla form factor shape is a square with 900 mils edge length, excluding the protrusions of
connectors which are meant to be passing though a case. Although board is square its shape
and its connectors are asymmetric to prevent connecting the board in the wrong orientation.

Nicla board quotes


Nicla board quotes
In order to create a consistent ecosystem and allow creation of cases usable across all the
family, Nicla form factor fixes the following mechanical positions:

board to board connectors


I/O Headers
debug fins
USER Interface
pushbutton
RGB LED
Board to cable connectors
USB connector
Battery Connector
ESLOV connector
Headers
Nicla header quotes
Nicla header quotes

Fins
Nicla fins quotes
Nicla fins quotes

User Interface
Nicla user interface quotes
Nicla user interface quotes

Connectors
Nicla connector quotes
Nicla connector quotes

Power Supply
Nicla boards can be powered from four different power supply rails:

USB connector
ESLOV connector
Vin pin
Battery
When powered from USB, Vin or ESLOV the board can charge the battery if software is
programmed to allow it. All voltages can be present at the same time without causing any
issue as the three voltages are ORed through diodes. Vin pin is directly connected to the
PMIC whereas the other two pass through diodes, which means that ESLOV connector will
not be able to power external devices and is meant primarily as a peripheral.

Nicla boards provide an on board battery charger for single cell LiPo batteries which have a
programmable charge current depending on the specific board. All boards provide sleep
mode functionality which minimizes current draw from battery, keeping the system off until
the reset button is pressed.

External Interfaces
Headers
Header I/O pins are driven by a bidirectional voltage translator that allows decoupling I/O
Voltage from internal CPU voltage. Header pins are referenced to the VDDIO pin which can
either be generated internally with a programmable voltage or fed externally. Board has two
columns of header+castellated pins that are partially compatible with MKR form factor.
Specifically Nicla boards are designed so that a nicla board can be fitted in the first half of the
MKR connectors.
{/* , aligning it as in figure:

Nicla connection to a MKR board */}

Using this connection it's possible to use Nicla as a shield for MKR or Nicla as a controller
for MKR shields provided the shield doesn't use the missing pins.

Pinout

Pin Name MKR Pin Description


J1-8 ADC1 A0 Analog Capable Pin
J1-7 ADC2 A1 Analog Capable Pin
J1-6 SCLK A2 SPI clock
J1-5 CIPO A3 SPI Controller Input/Peripheral Output
J1-4 COPI A4 SPI Controller Output/Peripheral Input
J1-3 CS A5 SPI Chip Select
J1-2 ADC3 A6 Analog Capable Pin
J1-1 LPIO0 A7 Low Power IO
Pin Name MKR pin Description
J2-9 VIN +5V Input Supply Voltage
J2-8 - VIN No Connection
J2-7 VDDIO +3V3 Header I/O Voltage
J2-6 GND GND Reference Ground
J2-5 LPIO3 RESET Low Power IO
J2-4 LPIO2 D14/TX Low Power IO/UART
J2-3 LPIO1 D13/RX Low Power IO/UART
J2-2 SCL D12/SDA GPIO/I2C SDA, shared with ESLOV
J2-1 SDA D11/SDA GPIO/I2C SCL, shared with ESLOV
Pin Name MKR pin Description
J3-2 VBAT - Battery Positive Terminal
J3-1 NTC - optional NTC Sensor for Battery Overtemperature Protection
Low Power I/Os

As reported in the table above, Nicla boards have a set of Low Power I/Os. These I/Os are
translated through an 8-Bit Bidirectional Voltage-Level Shifter with Auto Direction Sensing
(check TXB0108 datasheet for further info) and powered by VDDIO_EXT. This shifter is
able to convert logic levels from inputs operating at 3.3V or less down to 1.8V (i.e.
microcontroller operating voltage). However, it does not feature directional pins, since each
input and output connected to it can detect and shift signals in either direction independently
and automatically. As a consequence, the nominal behavior of these pins is guaranteed only
when they are connected to a CMOS logic. In the next section, the interaction with Low
Power pins as input or output is described.

Low Power Input Pins

Any input device operating with a voltage less or equal to 3.3V can be connected to the Low
Power pins. The integrated Voltage-Level shifter will automatically detect that an input
device has been connected to the pin and it will guarantee the conversion from 3.3.V to 1.8V,
i.e. microcontroller operating voltage, to properly interface with the Nicla boards.

Low Power Output Pins

Any Low Power device can be directly connected to the Low-Power pins in case it does not
absorb any current. The Voltage-Level shifter will automatically detect that an output device
has been connected to the pin and switch the port accordingly. The output voltage is digital
and its value depends on how VDDIO_EXT has been programmed via software:
VDDIO_EXT can be switched off or switched on either at 1.8V or 3.3V. On the other hand,
if the connected output device needs to absorb current (e.g. LEDs, resistive loads, buzzers
etc.), the user should connect a MOSFET or a buffer to guarantee the required current flow.
A reference schematics showing how to connect an LED to a Low-Power pin through a
MOSFET is reported below.

Reference schematics for LED connection

Fins
Nicla boards have a set of fins interleaved among headers that are mainly for debug and
initial programming. These pins are arranged so that they can easily be contacted by inserting
the board in a 1.27mm/50 mil dual row header that would allow firmly contacting the fins
along with header pins, provided no header has been soldered on it. The functions of each fin
is specific to a board but SWD pins for on board processors have been set up so that they are
consistent across boards.

Pinout

Pin Name Description


P-8 AUX3 Auxiliary Pin 3
P-7 +1V8 Internal 1.8V Supply
P-6 AUX2 Auxiliary Pin 2
P-5 RESET Main MCU Reset Pin
P-4 SWCLK Main MCU SW Debug Clock
P-3 SWDIO Main MCU SW Debug Data
P-2 AUX1 Auxiliary Pin 1
P-1 AUX0 Auxiliary Pin 0
Battery
Battery terminals are available either via a 3 pin connector or via headers. In both cases
supported battery is 1 cell Lithium Polymer. Please check board datasheet for available
charge current options and make sure to never charge the battery at more than the
recommended max limit. If possible use the provided NTC terminal to connect a Negative
Temperature Coefficient resistor to sense battery temperature so that charging can be stopped
in case battery temperature reaches the programmed limit.

Pinout

Pin Name Description


J4-3 GND Battery negative terminal
J4-2 NTC optional NTC sensor for battery overtemperature protection
J4-1 VBAT battery positive terminal
ESLOV
ESLOV is a 5 pin connector available on MKR and Portenta boards and can be used to
connect to a Nicla via cable. Through this connector the board can be interfaced with MKR
and Portenta boards directly or, via adapter cables, to other boards exposing similar interfaces
such as QWIIC, STEMMA/STEMMA QT and GROVE. Nicla boards are provided with a
readymade firmware which abstracts sensors and allows reading high level measurements
processed by the Nicla's main processor.

Pinout

Pin Name Description


J5-5 GND Ground
J5-4 SDA GPIO/I2C SDA, Shared with Headers
J5-3 SCL GPIO/I2C SCL, Shared with Headers
J5-2 INT GPIO Referenced to VDDIO voltage
J5-1 VESLOV ESLOV Supply Input
USB
USB connector consists of a micro USB with the Nicla only capable of acting as a peripheral.
Voltage from this connector can be used to power the board. USB port can be used to
program and debug the board or to expose custom application specific interfaces.

PDM Library
The PDM library allows you to use Pulse-density modulation microphones, found onboard
the Nano RP2040 Connect & Nano 33 BLE Sense boards.

AuthorArduino
Last revision08/02/2024
Overview
The PDM library allows you to use PDM (Pulse-density modulation) microphones, such as
the onboard MP34DT05 on the Arduino Nano 33 BLE Sense.

To use this library:

COPY
#include <PDM.h>
The library takes care of the audio that will be accessible also through the ArduinoSound
library.

Functions
begin()
Description
Initialize the PDM interface.

Syntax
COPY
PDM.begin(channels, sampleRate)
Parameters
channels: the number of channels, 1 for mono, 2 for stereo
sampleRate: the sample rate to use in Hz
Returns
1 on success, 0 on failure

Example
COPY
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
end()
Description
De-initialize the PDM interface.

Syntax
COPY
PDM.end()
Parameters
None
Returns
Nothing

Example
COPY

Explain
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}

//

PDM.end();
available()
Description
Get the number of bytes available for reading from the PDM interface. This is data that has
already arrived and was stored in the PDM receive buffer.

Syntax
COPY
PDM.available()
Parameters
None

Returns
The number of bytes available to read

Example
COPY

Explain
// buffer to read samples into, each sample is 16-bits
short sampleBuffer[256];

// number of samples read


volatile int samplesRead;

//

// query the number of bytes available


int bytesAvailable = PDM.available();

// read into the sample buffer


PDM.read(sampleBuffer, bytesAvailable);
read()
Description
Read data from the PDM into the specified buffer.

Syntax
COPY
PDM.read(buffer, size)
Parameters
buffer: array to store the PDM data into
size: number of bytes to read
Returns
The number of bytes read

Example
COPY

Explain
// buffer to read samples into, each sample is 16-bits
short sampleBuffer[256];

// number of samples read


volatile int samplesRead;

//

// query the number of bytes available


int bytesAvailable = PDM.available();

// read into the sample buffer


Int bytesRead = PDM.read(sampleBuffer, bytesAvailable);

// 16-bit, 2 bytes per sample


samplesRead = bytesRead / 2;
onReceive()
Description
Set the callback function that is called when new PDM data is ready to be read.

Syntax
COPY
PDM.onReceive(callback)
Parameters
callback: function that is called when new PDM data is ready to be read

Returns
Nothing

Example
COPY

Explain
// buffer to read samples into, each sample is 16-bits
short sampleBuffer[256];

// number of samples read


volatile int samplesRead;

//

// configure the data receive callback


PDM.onReceive(onPDMdata);

// initialize PDM with:


// - one channel (mono mode)
// - a 16 kHz sample rate
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}

//

void onPDMdata() {
// query the number of bytes available
int bytesAvailable = PDM.available();

// read into the sample buffer


Int bytesRead = PDM.read(sampleBuffer, bytesAvailable);

// 16-bit, 2 bytes per sample


samplesRead = bytesRead / 2;
}
setGain()
Description
Set the gain value used by the PDM interface.

Syntax
COPY
PDM.setGain(gain)
Parameters
gain: gain value to use, 0 - 255, defaults to 20 if not specified.

Returns
Nothing

Example
COPY

Explain
// optionally set the gain, defaults to 20
PDM.setGain(30);

// initialize PDM with:


// - one channel (mono mode)
// - a 16 kHz sample rate
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
setBufferSize()
Description
Set the buffer size (in bytes) used by the PDM interface. Must be called before
PDM.begin(...), a default buffer size of 512 is used if not called. This is enough to hold 256
16-bit samples.

Syntax
COPY
PDM.setBufferSize(size)
Parameters
size: buffer size to use in bytes

Returns
Nothing

Example
COPY

Explain
PDM.setBufferSize(1024);

// initialize PDM with:


// - one channel (mono mode)
// - a 16 kHz sample rate
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}

I2S Library
Documentation for usage of the I2S (Inter-IC Sound) protocol on SAMD21 boards.

AuthorArduino
Last revision08/02/2024
Overview
This library allows you to use the I2S protocol on SAMD21 based boards (i.e Arduino or
Genuino Zero, MKRZero or MKR1000 Board).

To use this library

COPY
#include <I2S.h>
I2S (Inter-IC Sound), is an electrical serial bus interface standard used for connecting digital
audio devices together. It is used to communicate PCM audio data between integrated circuits
in an electronic device.

An I2S bus that follows the Philips standard is made up of at least three wires:

SCK (Serial Clock): is the clock signal also referred as BCLK (Bit Clock Line);
FS (Frame Select): used to discriminate Right or Left Channel data also referred WS (Word
Select);
SD (Serial Data): the serial data to be transmitted;
As detailed below, the device who generates SCK and WS is the Controller.

The SCK line has a frequency that depends on the sample rate, the number of bits for channel
and the number of channels in the following way:

Frequency = SampleRate x BitsPerChannel x numberOfChannels


In a typical setup, the sender of audio data is called a Transmitter and it transfers data to a
Receiver at the other end. The device that controls the bus clock, SCK, together with the
Word Select - WS - signal is the Controller in the network and in any network just one device
can be Controller at any given time; all the other devices connected are in Peripheral mode.
The Controller can be the Transmitter, or the Receiver, or a standalone controller. The
digitized audio data sample can have a size ranging from 4 bits up to 32.

As a general rule of thumb, the higher the sample rate (kHz) and bits per sample, the better
audio quality (when the digital data is converted back to analog audio sound).

I2S Class
begin()
Description
Initializes the I2S interface with the given parameters to enable communication.

Syntax
COPY
I2S.begin(mode, sampleRate, bitsPerSample); // controller device
I2S.begin(mode, bitsPerSample); // peripheral device
Parameters
mode: one between I2S_PHILIPS_MODE, I2S_RIGHT_JUSTIFIED_MODE or
I2S_LEFT_JUSTIFIED_MODE sampleRate: the desired sample rate in Hz - long
bitsPerSample: the desired bits per sample (i.e 8, 16, 32)

Returns
1 if initialization is ok, 0 otherwise

end()
Description
Disables I2S communication, allowing the I2S pins to be used for general input and output.
To re-enable I2S communication, call I2S.begin().

Syntax
COPY
I2S.end()
Parameters
none

Returns
nothing

available()
Description
Get the number of bytes available for reading from the I2S interface. This is data that has
already arrived and was stored in the I2S receive buffer. available() inherits from the Stream
utility class.

Syntax
COPY
I2S.available()
Parameters
none

Returns
the number of bytes available to read

peek()
Description
Returns the next sample of incoming I2S data without removing it from the internal I2S
buffer. That is, successive calls to peek() will return the same sample, as will the next call to
read(). peek() inherits from the Stream utility class.

Syntax
COPY
I2S.peek()
Parameters
None

Returns
The next sample of incoming I2S data available (or 0 if no data is available)

write()
Description
Writes binary data to the I2S interface. This data is sent as a sample or series of samples.

Syntax
COPY
I2S.write(val) // blocking
I2S.write(buf, len) // not blocking
Parameters
val: a value to send as a single sample

buf: an array to send as a series of samples

len: the length of the buffer

Returns
byte

write() will return the number of bytes written, though reading that number is optional.
availableForWrite()
Description
Get the number of bytes available for writing in the buffer without blocking the write
operation.

Syntax
COPY
I2S.availableForWrite()
Parameters
none

Returns
the number of bytes available to write.

onTransmit(handler)
Description
Registers a function to be called when a block of data has been transmitted.

Parameters
handler: the function to be called when data is sent and return nothing, e.g.: void myHandler()

Returns
None
onReceive(handler)
Description
Registers a function to be called when a block of data has been received.

Parameters
handler: the function to be called when the device receives data and return nothing, e.g.: void
myHandler()

Returns
None

EEPROM Library
Documentation for usage of the EEPROM library. EEPROM is a memory whose values are
kept when the board is powered off.

AuthorArduino
Last revision08/02/2024
The microcontroller on the Arduino and Genuino AVR based board has EEPROM: memory
whose values are kept when the board is turned off (like a tiny hard drive). This library
enables you to read and write those bytes.

The supported micro-controllers on the various Arduino and Genuino boards have different
amounts of EEPROM: 1024 bytes on the ATmega328P, 512 bytes on the ATmega168 and
ATmega8, 4 KB (4096 bytes) on the ATmega1280 and ATmega2560. The Arduino and
Genuino 101 boards have an emulated EEPROM space of 1024 bytes.

To use this library

COPY
#include <EEPROM.h>
Examples
To see a list of examples for the EEPROM library, click the link below:

A Guide to EEPROM
Functions
read()
Description
Reads a byte from the EEPROM. Locations that have never been written to have the value of
255.

Syntax
COPY
EEPROM.read(address)
Parameters
address: the location to read from, starting from 0 (int)

Returns
the value stored in that location (byte)

Example
COPY

Explain
#include <EEPROM.h>
int a = 0;
int value;

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

void loop()
{
value = EEPROM.read(a);

Serial.print(a);
Serial.print("\t");
Serial.print(value);
Serial.println();

a = a + 1;

if (a == 512)
a = 0;

delay(500);
}
write()
Description
Write a byte to the EEPROM.

Syntax
COPY
EEPROM.write(address, value)
Parameters
address: the location to write to, starting from 0 (int)

value: the value to write, from 0 to 255 (byte)

Returns
none

Note: An EEPROM write takes 3.3 ms to complete. The EEPROM memory has a specified
life of 100,000 write/erase cycles, so you may need to be careful about how often you write
to it.

Example
COPY

Explain
#include <EEPROM.h>

void setup()
{
for (int i = 0; i < 255; i++)
EEPROM.write(i, i);
}
void loop()
{
}
update()
Description
Write a byte to the EEPROM. The value is written only if differs from the one already saved
at the same address.

Syntax
COPY
EEPROM.update(address, value)
Parameters
address: the location to write to, starting from 0 (int)

value: the value to write, from 0 to 255 (byte)

Returns
none

Note: An EEPROM write takes 3.3 ms to complete. The EEPROM memory has a specified
life of 100,000 write/erase cycles, so using this function instead of write() can save cycles if
the written data does not change often

Example
COPY

Explain
#include <EEPROM.h>

void setup()
{
for (int i = 0; i < 255; i++) {
// this performs as EEPROM.write(i, i)
EEPROM.update(i, i);
}
for (int i = 0; i < 255; i++) {
// write value "12" to cell 3 only the first time
// will not write the cell the remaining 254 times
EEPROM.update(3, 12);
}
}

void loop()
{
}
get()
Description
Read any data type or object from the EEPROM.

Syntax
COPY
EEPROM.get(address, data)
Parameters
address: the location to read from, starting from 0 (int)
data: the data to read, can be a primitive type (eg. float) or a custom struct

Returns
A reference to the data passed in

Example
COPY

Explain
#include <EEPROM.h>

struct MyObject{
float field1;
byte field2;
char name[10];
};

void setup(){

float f = 0.00f; //Variable to store data read from EEPROM.


int eeAddress = 0; //EEPROM address to start reading from

Serial.begin( 9600 );
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print( "Read float from EEPROM: " );

//Get the float data from the EEPROM at position 'eeAddress'


EEPROM.get( eeAddress, f );
Serial.println( f, 3 ); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid
float.

// get() can be used with custom structures too.


eeAddress = sizeof(float); //Move address to the next byte after float 'f'.
MyObject customVar; //Variable to store custom object read from EEPROM.
EEPROM.get( eeAddress, customVar );

Serial.println( "Read custom object from EEPROM: " );


Serial.println( customVar.field1 );
Serial.println( customVar.field2 );
Serial.println( customVar.name );
}

void loop(){ /* Empty loop */ }


put()
Description
Write any data type or object to the EEPROM.

Syntax
COPY
EEPROM.put(address, data)
Parameters
address: the location to write to, starting from 0 (int)
data: the data to write, can be a primitive type (eg. float) or a custom struct

Returns
A reference to the data passed in

Note: This function uses EEPROM.update() to perform the write, so does not rewrites the
value if it didn't change.

Example
COPY

Explain
#include <EEPROM.h>

struct MyObject {
float field1;
byte field2;
char name[10];
};

void setup() {

Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

float f = 123.456f; //Variable to store in EEPROM.


int eeAddress = 0; //Location we want the data to be put.

//One simple call, with the address first and the object second.
EEPROM.put(eeAddress, f);

Serial.println("Written float data type!");

/** Put is designed for use with custom structures also. **/

//Data to store.
MyObject customVar = {
3.14f,
65,
"Working!"
};

eeAddress += sizeof(float); //Move address to the next byte after float 'f'.

EEPROM.put(eeAddress, customVar);
Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how
you can retrieve the values!");
}

void loop() { /* Empty loop */ }


EEPROM[]
Description
This operator allows using the identifier EEPROM like an array. EEPROM cells can be read
and written directly using this method.

Syntax
COPY
EEPROM[address]
Parameters
address: the location to read/write from, starting from 0 (int)

Returns
A reference to the EEPROM cell

Example
COPY

Explain
#include <EEPROM.h>

void setup(){

unsigned char val;

//Read first EEPROM cell.


val = EEPROM[ 0 ];

//Write first EEPROM cell.


EEPROM[ 0 ] = val;

//Compare contents
if( val == EEPROM[ 0 ] ){
//Do something...
}
}

void loop(){ /* Empty loop */ }


length()
This function returns an unsigned int containing the number of cells in the EEPROM.

Description
This function returns an unsigned int containing the number of cells in the EEPROM.

Syntax
COPY
EEPROM.length()
Returns
Number of cells in the EEPROM as an unsigned int.

SoftwareSerial Library
The SoftwareSerial library allows serial communication on other digital pins of an Arduino
board.

AuthorArduino
Last revision08/02/2024
The SoftwareSerial library allows serial communication on other digital pins of an Arduino
board, using software to replicate the functionality (hence the name "SoftwareSerial"). It is
possible to have multiple software serial ports with speeds up to 115200 bps. A parameter
enables inverted signaling for devices which require that protocol.

The version of SoftwareSerial included in 1.0 and later is based on the NewSoftSerial library
by 'Mikal Hart'.

To use this library:

COPY
#include <SoftwareSerial.h>
Limitations of This Library
SoftwareSerial library has the following known limitations:

It cannot transmit and receive data at the same time.


If using multiple software serial ports, only one can receive data at a time.
Not all pins on the Mega and Mega 2560 boards support change interrupts, so only the
following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10
(64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69). Not all pins on the Leonardo and
Micro boards support change interrupts, so only the following can be used for RX: 8, 9, 10,
11, 14 (MISO), 15 (SCK), 16 (MOSI).
On Arduino or Genuino 101 boards the current maximum RX speed is 57600bps.
On Arduino or Genuino 101 boards RX doesn't work on digital pin 13.
If your project requires simultaneous data flows, see Paul Stoffregen's AltSoftSerial library.

Examples
SoftwareSerial example: sometimes one serial port just isn't enough!
Two port receive: Work with multiple software serial ports.
Methods
SoftwareSerial()
Create an instance of a SoftwareSerial object. Multiple SoftwareSerial objects may be
created, however only one can be active at a given moment.

Syntax
COPY
SoftwareSerial(rxPin, txPin, inverse_logic)
Parameters
rxPin: the pin on which to receive serial data.
txPin: the pin on which to transmit serial data.
inverse_logic: used to invert the sense of incoming bits (the default is normal logic). If set,
SoftwareSerial treats a LOW (0v on the pin, normally) on the RX pin as a 1-bit (the idle
state) and a HIGH (5V on the pin, normally) as a 0-bit. It also affects the way that it writes to
the TX pin. Default value is false.
Returns
None.

Example
COPY

Explain
#include <SoftwareSerial.h>

const byte rxPin = 2;


const byte txPin = 3;
// Set up a new SoftwareSerial object
SoftwareSerial mySerial (rxPin, txPin);
See also
available()
begin()
isListening()
overflow()
peek()
read()
print()
println()
listen()
write()
available()
Get the number of bytes (characters) available for reading from a software serial port. This is
data that has already arrived and stored in the serial receive buffer.

Syntax
COPY
mySerial.available()
Parameters
None.

Returns
The number of bytes available to read.

Example
COPY

Explain
#include <SoftwareSerial.h>

#define rxPin 10
#define txPin 11

// Set up a new SoftwareSerial object


SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);

void setup() {
// Define pin modes for TX and RX
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);

// Set the baud rate for the SoftwareSerial object


mySerial.begin(9600);
}

void loop() {
if (mySerial.available() > 0) {
mySerial.read();
}
}
See also
SoftwareSerial()
begin()
isListening()
overflow()
peek()
read()
print()
println()
listen()
write()
begin()
Sets the speed (baud rate) for the serial communication. Supported baud rates are: 300, 600,
1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250, 38400, 57600, and 115200 bauds.

Syntax
COPY
mySerial.begin(speed)
Parameters
speed: the desired baud rate (long). Supported baud rates are: 300, 600, 1200, 2400, 4800,
9600, 14400, 19200, 28800, 31250, 38400, 57600, and 115200 bauds.
Returns
None.

Example
COPY

Explain
#include <SoftwareSerial.h>

#define rxPin 10
#define txPin 11

// Set up a new SoftwareSerial object


SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);

void setup() {
// Define pin modes for TX and RX
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);

// Set the baud rate for the SoftwareSerial object


mySerial.begin(9600);
}

void loop() {
// ...
}
See also
SoftwareSerial()
available()
isListening()
overflow()
peek()
read()
print()
println()
listen()
write()
isListening()
Tests to see if requested software serial object is actively listening.

Syntax
COPY
mySerial.isListening()
Parameters
None.

Returns
Boolean.

Example
COPY

Explain
#include <SoftwareSerial.h>

// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11
SoftwareSerial portOne(10, 11);

void setup() {
// Set the baud rate for the Serial port
Serial.begin(9600);

// Set the baud rate for the SerialSoftware object


portOne.begin(9600);
}

void loop() {
if (portOne.isListening()) {
Serial.println("portOne is listening!");
}

// ...
See also
SoftwareSerial()
available()
begin()
overflow()
peek()
read()
print()
println()
listen()
write()
overflow()
Tests to see if a SoftwareSerial buffer overflow has occurred. Calling this function clears the
overflow flag, meaning that subsequent calls will return false unless another byte of data has
been received and discarded in the meantime. The SoftwareSerial buffer can hold up to 64
bytes.

Syntax
COPY
mySerial.overflow()
Parameters
None.

Returns
Boolean.

Example
COPY

Explain
#include <SoftwareSerial.h>

// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11
SoftwareSerial portOne(10, 11);

void setup() {
// Set the baud rate for the Serial port
Serial.begin(9600);

// Set the baud rate for the SerialSoftware object


portOne.begin(9600);
}

void loop() {
if (portOne.overflow()) {
Serial.println("portOne overflow!");
}

// ...
See also
SoftwareSerial()
available()
begin()
isListening()
peek()
read()
print()
println()
listen()
write()
peek()
Return a character that was received on the RX pin of the software serial port. Unlike read(),
however, subsequent calls to this function will return the same character. Note that only one
SoftwareSerial object can receive incoming data at a time (select which one with the listen()
function).

Syntax
COPY
mySerial.peek()
Parameters
None.

Returns
The character read or -1 if none is available.

Example
COPY

Explain
#include <SoftwareSerial.h>

// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11
SoftwareSerial mySerial(10, 11);

void setup() {
// Set the baud rate for the SerialSoftware object
mySerial.begin(9600);
}

void loop() {
char c = mySerial.peek();
}
See also
SoftwareSerial()
available()
begin()
isListening()
overflow()
read()
print()
println()
listen()
write()
read()
Return a character that was received on the RX pin of the SoftwareSerial objecto. Note that
only one SoftwareSerial object can receive incoming data at a time (select which one with the
listen() function).

Syntax
COPY
mySerial.read()
Parameters
None.

Returns
The character read or -1 if none is available.

Example
COPY

Explain
#include <SoftwareSerial.h>

// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11
SoftwareSerial mySerial(10, 11);

void setup() {
// Set the baud rate for the SerialSoftware object
mySerial.begin(9600);
}

void loop() {
char c = mySerial.read();
}
See also
SoftwareSerial()
available()
begin()
isListening()
overflow()
peek()
print()
println()
listen()
write()
print()
Prints data to the transmit pin of the SoftwareSerial object. Works the same as the
Serial.print() function.

Syntax
COPY
mySerial.print(val)
Parameters
val: the value to print.
Returns
The number of bytes written (reading this number is optional).

Example
COPY

Explain
#include <SoftwareSerial.h>

// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11
SoftwareSerial mySerial(10, 11);

int analogValue;

void setup() {
// Set the baud rate for the SerialSoftware object
mySerial.begin(9600);
}

void loop() {
// Read the analog value on pin A0
analogValue = analogRead(A0);

// Print analogValue in the Serial Monitor in many formats:


mySerial.print(analogValue); // Print as an ASCII-encoded decimal
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue, DEC); // Print as an ASCII-encoded decimal
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue, HEX); // Print as an ASCII-encoded hexadecimal
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue, OCT); // Print as an ASCII-encoded octal
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue, BIN); // Print as an ASCII-encoded binary
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue/4, BYTE); // Print as a raw byte value (divide the
// value in 4 because analogRead() function returns numbers
// from 0 to 1023, but a byte can only hold values up to 255)

mySerial.print("\t"); // Print a tab character


mySerial.println(); // Print a line feed character

// Pause for 10 milliseconds before the next reading


delay(10);
}
See also
SoftwareSerial()
available()
begin()
isListening()
overflow()
peek()
read()
print()
println()
listen()
write()
println()
Prints data to the transmit pin of the SoftwareSerial object followed by a carriage return and
line feed. Works the same as the Serial.println() function.

Syntax
COPY
mySerial.println(val)
Parameters
val: the value to print.
Returns
The number of bytes written (reading this number is optional).

Example
COPY

Explain
#include <SoftwareSerial.h>

// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11
SoftwareSerial mySerial(10, 11);

int analogValue;

void setup() {
// Set the baud rate for the SerialSoftware object
mySerial.begin(9600);
}
void loop() {
// Read the analog value on pin A0
analogValue = analogRead(A0);

// Print analogValue in the Serial Monitor in many formats:


mySerial.print(analogValue); // Print as an ASCII-encoded decimal
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue, DEC); // Print as an ASCII-encoded decimal
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue, HEX); // Print as an ASCII-encoded hexadecimal
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue, OCT); // Print as an ASCII-encoded octal
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue, BIN); // Print as an ASCII-encoded binary
mySerial.print("\t"); // Print a tab character
mySerial.print(analogValue/4, BYTE); // Print as a raw byte value (divide the
// value in 4 because analogRead() function returns numbers
// from 0 to 1023, but a byte can only hold values up to 255)

mySerial.print("\t"); // Print a tab character


mySerial.println(); // Print a line feed character

// Pause for 10 milliseconds before the next reading


delay(10);
}
See also
SoftwareSerial()
available()
begin()
isListening()
overflow()
peek()
read()
print()
listen()
write()
listen()
Enables the selected SoftwareSerial object to listen. Only one SoftwareSerial object can listen
at a time; data that arrives for other ports will be discarded. Any data already received is
discarded during the call to listen() function (unless the given instance is already listening).

Syntax
COPY
mySerial.listen()
Parameters
None.

Returns
Returns true if it replaces another.

Example
COPY

Explain
#include <SoftwareSerial.h>
// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11
SoftwareSerial portOne(10, 11);

// Set up a new SoftwareSerial object with RX in digital pin 8 and TX in digital pin 9
SoftwareSerial portTwo(8, 9);

void setup() {
// Set the baud rate for the Serial object
Serial.begin(9600);

// Set the baud rate for the SerialSoftware objects


portOne.begin(9600);
portTwo.begin(9600);
}

void loop() {
// Enable SoftwareSerial object to listen
portOne.listen();

if (portOne.isListening()) {
Serial.println("portOne is listening!");
} else {
Serial.println("portOne is not listening!");
}

if (portTwo.isListening()) {
Serial.println("portTwo is listening!");
} else {
Serial.println("portTwo is not listening!");
}
}
See also
SoftwareSerial()
available()
begin()
isListening()
overflow()
peek()
read()
print()
println()
write()
write()
Prints data to the transmit pin of the SoftwareSerial object as raw bytes. Works the same as
the Serial.write()function.

Syntax
COPY
mySerial.write(val)
Parameters
val: the binary value to print.
Returns
The number of bytes written (reading this number is optional).
Example
COPY

Explain
#include <SoftwareSerial.h>

// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11
SoftwareSerial mySerial(10, 11);

void setup() {
// Set the baud rate for the SerialSoftware object
mySerial.begin(9600);
}

void loop() {
// Send a byte with the value 45
mySerial.write(45);

//Send the string “hello” and return the length of the string.
int bytesSent = mySerial.write(“hello”);
}
See also
SoftwareSerial()
available()
begin()
isListening()
overflow()
peek()
read()
print()
println()
listen()

Arduino Style Guide for Writing Content


Learn how to write clear Arduino examples that can be read by beginners and advanced users
alike.

Last revision08/02/2024
This is a guide for writing clear Arduino examples that can be read by beginners and
advanced users alike. You don't have to code this way, but it helps if you want your code to
be clear to all levels of users. This is not a set of hard and fast rules, it's a set of guidelines.
Some of these guidelines might even conflict with each other. Use your judgment on when
they're best followed, and if you're not sure, ask someone who'll be learning from what you
write what makes the most sense. You might also be interested in the Arduino Style Guide
for Creating Libraries.

If you want to contribute with content for the Arduino Documentation website, please find
instructions in the contribution-templates folder in the Arduino Documentation repository.

Writing a tutorial
Most of this is borrowed from various editors over the years, and here is a list of guidelines
that you can follow when writing code.

Write in the active voice.


Write clearly and conversationally, as if the person following your instructions were there in
the room with you.
When giving instruction, write in the second person, so the reader understands that she's the
one who'll be doing it.
Use short, simple, declarative sentences and commands rather than compound sentences. It's
easier for the reader to digest one instruction at a time.
Give directions in no uncertain terms like so:
"Next, you'll read the sensor..."
"Make a variable called thisPin..."
Avoid phrases that add no information. Don't tell the reader that "You want to set the pins",
just tell her "Set the pins."
Use pictures and schematics rather than just schematics alone. Many electronics hobbyists
don't read schematics.
Check your assumptions. Does the reader understand all the concepts you've used in your
tutorial? If not, explain them or link to another tutorial that does.
Explain things conceptually, so the reader has a big picture of what he's going to do. Then lay
out instructions on how to use it step-by-step.
Whenever you use a technical term for the first time, define it. Have someone else check that
you defined all new terms. There are probably one or two that you missed.
Be consistent with the terms you use. If you refer to a component or concept by a new name,
make the relationship to the other name explicit. Don't use two terms interchangeably unless
you tell the reader that they are interchangeable.
Don't use acronyms or abbreviations without spelling them out first.
Make your example do one thing well. Don't combine concepts or functions unless it's a
tutorial about combining concepts.
Writing Example Code
Efficiency is not paramount; readability is.

The most important users of Arduino are beginners and people who don't care about code, but
about getting projects done.

Think generously about people who know less than you about code. Don't think they should
understand some technical concept. They don't, and they're not stupid for not understanding.
Your code should explain itself, or use comments to do the same. If it needs a complex
concept like registers or interrupts or pointers, either explain it or skip it.

When forced to choose between technically simple and technically efficient, choose the
former.

Introduce concepts only when they are useful and try to minimize the number of new
concepts you introduce in each example. For example, at the very beginning, you can explain
simple functions with no variable types other than int, nor for consts to define pin numbers.
On the other hand, in an intermediate example, you might want to introduce peripheral
concepts as they become useful. Concepts like using const ints to define pin numbers,
choosing bytes over ints when you don't need more than 0 - 255, etc. are useful, but not
central to getting started. So use them sparingly, and explain them when they're new to your
lesson plan.

Put your setup() and your loop() at the beginning of the program. They help beginners to get
an overview of the program, since all other functions are called from those two.

Commenting Your Code


Comment every variable or constant declaration with a description of what the variable does.
Comment every code block. Do it before the block if possible, so the reader knows what's
coming
Comment every for loop
Use verbose if statements. For simplicity to the beginning reader, use the block format for
everything, i.e. avoid this:

COPY
if (distance > 10) moveCloser();
Instead, use this:

COPY
if (distance > 10) {
moveCloser();
}
Avoid pointers

Avoid #defines

Variables
Avoid single letter variable names. Make them descriptive.
Avoid variable names like val or pin. Be more descriptive, like buttonState or switchPin.
If you want to define pin names and other quantities which won't change, use const ints.
They're less messy than #defines, yet still give you a way to teach the difference between a
variable and a constant.

Use the wiring/Processing-style variable types, e.g. boolean,char,byte,int,unsigned


int,long,unsigned long,float,double,string,array,void when possible, rather than uint8_t, etc.
The former are explained in the documentation, and less terse names.

Avoid numbering schemes that confuse the user, e.g.:

COPY
pin1 = 2
pin2 = 3
If you need to renumber pins, consider using an array, like this:

COPY
int myPins[] = { 2, 7, 6, 5, 4, 3 };
This allows you to refer to the new pin numbers using the array elements, like this:

COPY
digitalWrite(myPins[1], HIGH); // turns on pin 7
It also allows you to turn all the pins on or off in the sequence you want, like this:

COPY

Explain
for (int thisPin = 0; thisPin < 6; thisPin++) {
digitalWrite(myPins[thisPin], HIGH);
delay(500);
digitalWrite(myPins[thisPin], LOW);
delay(500);
}
Explanation of Code
Here's a good title block:

COPY
/*
Sketch title

Describe what it does in layman's terms. Refer to the components


attached to the various pins.

The circuit:
* list the components attached to each input
* list the components attached to each output

Created day month year


By author's name
Modified day month year
By author's name

http://url/of/online/tutorial.cc

*/
Circuits
For digital input switches, the default is to use a pulldown resistor on the switch rather than a
pullup. That way, the logic of a switch's interaction makes sense to the non-engineer.

Keep your circuits simple. For example, bypass capacitors are handy, but most simple inputs
will work without them. If a component is incidental, explain it later.

Arduino Style Guide for Creating Libraries


Learn how to write library APIs in an Arduino style.

Last revision08/02/2024
This is a style guide to writing library APIs in an Arduino style. Some of these run counter to
professional programming practice. We’re aware of that, but it’s what’s made it possible for
so many beginners to get started with Arduino easily. So please code with these principles in
mind. If you have suggestions on how to make Arduino libraries clearer for that core
audience, please jump in the discussion.

Be kind to the end user. Assume you are writing an API for an intelligent person who has not
programmed before. Come up with a clear mental model of the concept you’re working with,
and the terms and functions you will use.

Match your API to the underlying capabilities. You don’t want to expose implementation
details to the user but you also don’t want an API that suggests an inaccurate mental model of
the possibilities. For example, if there are only a few possible options for a particular setting,
don’t use a function that takes an int, as it implies you can use any value you want.

Organize your public functions around the data and functionality that the user wants. Quite
often, the command set for a particular electronic module is overly complicated for the most
common uses, or can be re-organized around higher level functionality. Think about what the
average person thinks the thing does, and try to organise your API functions around that.
Adafruit's BMP085 library is a good example. The readPressure() function performs all the
necessary steps to get the final pressure. The library wraps this commonly executed series of
functions into a high-level single command which returns the value the user's looking for in a
format she expects. It abstracts away not only the low-level I2C commands, but also the mid-
level temperature and pressure calculations, while still offering those mid-level functions as
public functions for those who want them.
Use full, everyday words. Don’t be terse with your function names or variables. Use
everyday terms instead of technical ones. Pick terms that correspond to popular perception of
the concept at hand. Don’t assume specialized knowledge. For example, this is why we used
analogWrite() rather than pwm(). Abbreviations are acceptable, though, if they’re in common
use or are the primary name for something. For example, “HTML” is relatively common and
“SPI” is effectively the name of that protocol (“serial-peripheral interface” is probably too
long). (“Wire” was probably a mistake, as the protocol it uses is typically called “TWI” or
“I2C”.)

Avoid words that have different meanings to the general public. For example, to
programmers, an error is a notification that something happened. To the general public, errors
are bad things.

When you have to use a domain-specific term, write a sentence or two describing it to the
general public FIRST. You’ll likely come across a better term, and if not, you’ll have started
the documentation on your library.

Document and comment as you go. When writing examples and documentation, follow the
Writing Style Guide

Use the established core libraries and styles.

Use read() to read inputs, and write() to write to outputs, e.g. digitalRead(), analogWrite(),
etc.
Use the Stream and Print classes when dealing with byte streams. If it’s not appropriate, at
least try to use its API as a model. For more on this, see below
For network applications, use the Client and Server classes as the basis.
Use begin() to initialize a library instance, usually with some settings. Use end() to stop it.
Use camel case function names, not underscore. For example, analogRead, not analog_read.
Or myNewFunction, not my_new_function. We've adopted this from Processing.org for
readability's sake.
LONG_CONSTANT_NAMES_FULL_OF_CAPS are hard to read. Try to simplify when
possible, without being terse.

Try to avoid boolean arguments. Instead, consider providing two different functions with
names the describe the differences between them.

Don’t assume knowledge of pointers. Beginning users of C find this the biggest roadblock,
and get very confused by & and *, so whenever you can avoid having them hanging out in
the API, do so. One way is to pass by reference using array notation rather than * notation,
for example.

COPY
void printArray(char* array);
can be replaced by

COPY
void printArray(char[] array);
Though there are some libraries where we pass pointers by using structures like const chars,
avoid anything that requires the user to pass them. For example,rather than:

COPY
foo.readAccel(&x, &y, &z);
use something like this:
COPY
xAxis = adxl.readX();
yAxis = adxl.readY();
zAxis = adxl.readZ();
When using serial communication, allow the user to specify any Stream object, rather than
hard-coding Serial. This will make your library compatible with all serial ports on boards
with multiple (e.g., Mega), and can also use alternate interfaces like SoftwareSerial. The
Stream object can be passed to your library's constructor or to a begin() function (as a
reference, not a pointer). See Firmata 2.3 or XBee 0.4 for examples of each approach.

When writing a library that provides byte-stream communication, inherit Arduino's Stream
class, so your library can be used with all other libraries that accept Stream objects. If
possible, buffer incoming data, so that read() immediately accesses the buffer but does not
wait for more data to arrive. If possible, your write() method should store data to a transmit
buffer, but write() must wait if the buffer does not have enough space to immediately store all
outgoing data. The yield() function should be called while waiting.

Here are a few libraries that are exemplary from Adafruit. She breaks the functions of the
devices down into their high-level activities really well.

https://github.com/adafruit/Adafruit-BMP085-Library
https://github.com/adafruit/DHT-sensor-library
This does a nice job of abstracting from the Wire (I2C) library:
https://github.com/adafruit/RTClib

The text of the Arduino reference is licensed under a Creative Commons Attribution-
ShareAlike 3.0 License. Code samples in the reference are released into the public domain.

Writing a Library for Arduino


Creating libraries to extend the functionality of Arduino. Goes step-by-step through the
process of making a library from a sketch.

Last revision08/02/2024
This document explains how to create a library for Arduino. It starts with a sketch for
flashing Morse code and explains how to convert its functions into a library. This allows
other people to easily use the code that you've written and to easily update it as you improve
the library.

For more information, see the API Style Guide for information on making a good Arduino-
style API for your library.

We start with a sketch that does simple Morse code:

COPY

Explain
int pin = 13;

void setup()
{
pinMode(pin, OUTPUT);
}

void loop()
{
dot(); dot(); dot();
dash(); dash(); dash();
dot(); dot(); dot();
delay(3000);
}

void dot()
{
digitalWrite(pin, HIGH);
delay(250);
digitalWrite(pin, LOW);
delay(250);
}

void dash()
{
digitalWrite(pin, HIGH);
delay(1000);
digitalWrite(pin, LOW);
delay(250);
}
If you run this sketch, it will flash out the code for SOS (a distress call) on pin 13.

The sketch has a few different parts that we'll need to bring into our library. First, of course,
we have the dot() and dash() functions that do the actual blinking. Second, there's the pin
variable which the functions use to determine which pin to use. Finally, there's the call to
pinMode() that initializes the pin as an output.

Let's start turning the sketch into a library!

You need at least two files for a library: a header file (w/ the extension .h) and the source file
(w/ extension .cpp). The header file has definitions for the library: basically a listing of
everything that's inside; while the source file has the actual code. We'll call our library
"Morse", so our header file will be Morse.h. Let's take a look at what goes in it. It might seem
a bit strange at first, but it will make more sense once you see the source file that goes with it.

The core of the header file consists of a line for each function in the library, wrapped up in a
class along with any variables you need:

COPY

Explain
class Morse
{
public:
Morse(int pin);
void begin();
void dot();
void dash();
private:
int _pin;
};
A class is simply a collection of functions and variables that are all kept together in one place.
These functions and variables can be public, meaning that they can be accessed by people
using your library, or private, meaning they can only be accessed from within the class itself.
Each class has a special function known as a constructor, which is used to create an instance
of the class. The constructor has the same name as the class, and no return type.

You need a couple of other things in the header file. One is an #include statement that gives
you access to the standard types and constants of the Arduino language (this is automatically
added to normal sketches, but not to libraries). It looks like this (and goes above the class
definition given previously):

COPY
#include "Arduino.h"
Finally, it's common to wrap the whole header file up in a weird looking construct:

COPY

Explain
#ifndef Morse_h
#define Morse_h

// the #include statement and code go here...

#endif
Basically, this prevents problems if someone accidentally #include's your library twice.

Finally, you usually put a comment at the top of the library with its name, a short description
of what it does, who wrote it, the date, and the license.

Let's take a look at the complete header file:

COPY

Explain
/*
Morse.h - Library for flashing Morse code.
Created by David A. Mellis, November 2, 2007.
Released into the public domain.
*/
#ifndef Morse_h
#define Morse_h

#include "Arduino.h"

class Morse
{
public:
Morse(int pin);
void begin();
void dot();
void dash();
private:
int _pin;
};

#endif
Now let's go through the various parts of the source file, Morse.cpp.
First comes a couple of #include statements. These give the rest of the code access to the
standard Arduino functions, and to the definitions in your header file:

COPY
#include "Arduino.h"
#include "Morse.h"
Then comes the constructor. Again, this explains what should happen when someone creates
an instance of your class. In this case, the user specifies which pin they would like to use. The
constructor records that in a private variable for use in the other functions:

COPY
Morse::Morse(int pin)
{
_pin = pin;
}
There are a couple of strange things in this code. First is the Morse:: before the name of the
function. This says that the function is part of the Morse class. You'll see this again in the
other functions in the class. The second unusual thing is the underscore in the name of our
private variable, _pin. This variable can actually have any name you want, as long as it
matches the definition in the header file. Adding an underscore to the start of the name is a
common convention to make it clear which variables are private, and also to distinguish the
name from that of the argument to the function (pin in this case).

Next, you'll create a begin() function to handle hardware configuration. This will be called
from the setup() function of the sketch. Hardware configuration is done in a dedicated
function instead of the constructor because the hardware has not yet been initialized at the
time the constructor code is executed. In our library, we need to set the pin as an output:

COPY
void Morse::begin()
{
pinMode(_pin, OUTPUT);
}
Then comes the actual code from the sketch that you're turning into a library (finally!). It
looks pretty much the same, except with Morse:: in front of the names of the functions, and
_pin instead of pin:

COPY

Explain
void Morse::dot()
{
digitalWrite(_pin, HIGH);
delay(250);
digitalWrite(_pin, LOW);
delay(250);
}

void Morse::dash()
{
digitalWrite(_pin, HIGH);
delay(1000);
digitalWrite(_pin, LOW);
delay(250);
}
Finally, it's typical to include the comment header at the top of the source file as well. Let's
see the whole thing:

COPY

Explain
/*
Morse.cpp - Library for flashing Morse code.
Created by David A. Mellis, November 2, 2007.
Updated by Jason A. Cox, February 18, 2023.
Released into the public domain.
*/

#include "Arduino.h"
#include "Morse.h"

Morse::Morse(int pin)
{
_pin = pin;
}

void Morse::begin()
{
pinMode(_pin, OUTPUT);
}

void Morse::dot()
{
digitalWrite(_pin, HIGH);
delay(250);
digitalWrite(_pin, LOW);
delay(250);
}

void Morse::dash()
{
digitalWrite(_pin, HIGH);
delay(1000);
digitalWrite(_pin, LOW);
delay(250);
}
And that's all you need (there's some other nice optional stuff, but we'll talk about that later).
Let's see how you use the library.

First, make a Morse directory inside of the libraries sub-directory of your sketchbook
directory. Copy or move the Morse.h and Morse.cpp files into that directory. Now launch the
Arduino environment. If you open the Sketch > Import Library menu, you should see Morse
inside. The library will be compiled with sketches that use it. If the library doesn't seem to
build, make sure that the files really end in .cpp and .h (with no extra .ino, .pde or .txt
extension, for example).

Let's see how we can replicate our old SOS sketch using the new library:

COPY
Explain
#include <Morse.h>

Morse morse(13);

void setup()
{
morse.begin();
}

void loop()
{
morse.dot(); morse.dot(); morse.dot();
morse.dash(); morse.dash(); morse.dash();
morse.dot(); morse.dot(); morse.dot();
delay(3000);
}
There are a few differences from the old sketch (besides the fact that some of the code has
moved to a library).

First, we've added an #include statement to the top of the sketch. This makes the Morse
library available to the sketch and includes it in the code sent to the board. That means if you
no longer need a library in a sketch, you should delete the #include statement to save space.

Second, we now create an instance of the Morse class called morse:

COPY
Morse morse(13);
When this line gets executed (which actually happens even before the setup() function), the
constructor for the Morse class will be called, and passed the argument you've given here (in
this case, just 13).

Notice that our setup() now has a call to morse.begin() which configures the pin that was set
in the constructor.

Finally, to call the dot() and dash() functions, we need to prefix them with morse. - the name
of the instance we want to use. We could have multiple instances of the Morse class, each on
their own pin stored in the _pin private variable of that instance. By calling a function on a
particular instance, we specify which instance's variables should be used during that call to a
function. That is, if we had both:

COPY
Morse morse(13);
Morse morse2(12);
then inside a call to morse2.dot(), _pin would be 12.

If you tried the new sketch, you probably noticed that nothing from our library was
recognized by the environment and highlighted in color. Unfortunately, the Arduino software
can't automatically figure out what you've define in your library (though it would be a nice
feature to have), so you have to give it a little help. To do this, create a file called
keywords.txt in the Morse directory. It should look like this:

COPY
Morse KEYWORD1
begin KEYWORD2
dash KEYWORD2
dot KEYWORD2
Each line has the name of the keyword, followed by a tab (not spaces), followed by the kind
of keyword. Classes should be KEYWORD1 and are colored orange; functions should be
KEYWORD2 and will be brown. You'll have to restart the Arduino environment to get it to
recognize the new keywords.

It's also nice to provide people with an example sketch that uses your library. To do this,
create an examples directory inside the Morse directory. Then, move or copy the directory
containing the sketch (let's call it SOS) we wrote above into the examples directory. (You can
find the sketch using the Sketch > Show Sketch Folder command.) If you restart the Arduino
environment (this is the last time, I promise) - you'll see a Library-Morse item inside the File
> Sketchbook > Examples menu containing your example. You might want to add some
comments that better explain how to use your library.

If you'd like to check out the complete library (with keywords and example), you can
download it: Morse.zip.

If you'd like to make your library available to others in Arduino's Library Manager you will
also have to include a library.properties file. Check out the library specification for more info
on that. For general questions on the Arduino Library Manager, see the FAQ.

If you have any problems or suggestions, please post them to the Software Development
forum.

For more information, see the API Style Guide for information on making a good Arduino-
style API for your library.

You might also like