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

Intro To Arduino

Uploaded by

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

Intro To Arduino

Uploaded by

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

Home / Learn / What is Arduino?

What is Arduino?
An introduction to what Arduino is, and what it can be used for.

Last revision10/28/2024

Arduino is an open-source electronics platform based on easy-to-use


hardware and software. Arduino boards are able to read inputs - light on a
sensor, a finger on a button, or a Twitter message - and turn it into an
output - activating a motor, turning on an LED, publishing something online.
You can tell your board what to do by sending a set of instructions to the
microcontroller on the board. To do so you use the Arduino programming
language (based on Wiring), and the Arduino Software (IDE), based on
Processing.

Over the years Arduino has been the brain of thousands of projects, from
everyday objects to complex scientific instruments. A worldwide community
of makers - students, hobbyists, artists, programmers, and professionals -
has gathered around this open-source platform, their contributions have
added up to an incredible amount of accessible knowledge that can be of
great help to novices and experts alike.

Arduino was born at the Ivrea Interaction Design Institute as an easy tool
for fast prototyping, aimed at students without a background in electronics
and programming. As soon as it reached a wider community, the Arduino
board started changing to adapt to new needs and challenges,
differentiating its offer from simple 8-bit boards to products for IoT
applications, wearable, 3D printing, and embedded environments.

Why Arduino?
Thanks to its simple and accessible user experience, Arduino has been used
in thousands of different projects and applications. The Arduino software is
easy-to-use for beginners, yet flexible enough for advanced users. It runs
on Mac, Windows, and Linux. Teachers and students use it to build low cost
scientific instruments, to prove chemistry and physics principles, or to get
started with programming and robotics. Designers and architects build
interactive prototypes, musicians and artists use it for installations and to
experiment with new musical instruments. Makers, of course, use it to build
many of the projects exhibited at the Maker Faire, for example. Arduino is a
key tool to learn new things. Anyone - children, hobbyists, artists,
programmers - can start tinkering just following the step by step
instructions of a kit, or sharing ideas online with other members of the
Arduino community.

There are many other microcontrollers and microcontroller platforms


available for physical computing. Parallax Basic Stamp, Netmedia's BX-24,
Phidgets, MIT's Handyboard, and many others offer similar functionality. All
of these tools take the messy details of microcontroller programming and
wrap it up in an easy-to-use package. Arduino also simplifies the process of
working with microcontrollers, but it offers some advantage for teachers,
students, and interested amateurs over other systems:

 Inexpensive - Arduino boards are relatively inexpensive compared to


other microcontroller platforms. The least expensive version of the
Arduino module can be assembled by hand, and even the pre-
assembled Arduino modules cost less than \$50

 Cross-platform - The Arduino Software (IDE) runs on Windows,


Macintosh OSX, and Linux operating systems. Most microcontroller
systems are limited to Windows.

 Simple, clear programming environment - The Arduino Software (IDE)


is easy-to-use for beginners, yet flexible enough for advanced users
to take advantage of as well. For teachers, it's conveniently based on
the Processing programming environment, so students learning to
program in that environment will be familiar with how the Arduino IDE
works.

 Open source and extensible software - The Arduino software is


published as open source tools, available for extension by
experienced programmers. The language can be expanded through
C++ libraries, and people wanting to understand the technical details
can make the leap from Arduino to the AVR C programming language
on which it's based. Similarly, you can add AVR-C code directly into
your Arduino programs if you want to.

Open source and extensible hardware - The plans of the Arduino boards are
published under a Creative Commons license, so experienced circuit
designers can make their own version of the module, extending it and
improving it. Even relatively inexperienced users can build the breadboard
version of the module in order to understand how it works and save money.

How do I use Arduino?


See the getting started guide. If you are looking for inspiration you can find
a great variety of Tutorials on Arduino Project Hub.

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.

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike
4.0 license.
ON THIS PAGE

 Why Arduino?
 How do I use Arduino?

Was this article helpful?

Getting started with Arduino tools


Get to know the different tools that Arduino have, and how to set up your
environment.

AuthorLiam Aljundi
Last revision10/28/2024

Welcome to Arduino! Before you start controlling the world around you,
you'll need to set up the software to program your board.

IDE
An Integrated Development Environment (IDE) is a software that allows you
to write code and upload it to your Arduino hardware. We have our
own [Arduino Software (IDE)]
(https://www.arduino.cc/en/software application available for Windows,
macOS and Linux users. Besides the convenient code editing functions, the
Arduino Software (IDE) is equipped with a list of libraries that provide extra
functionality for use in sketches, making it easier for you to connect
sensors, displays, modules, etc.

Arduino Tools
You can write programs and upload them to your board with the browser
IDE (Arduino Cloud Editor), or the desktop one (Arduino Software IDE).
Another option is to use the Arduino Cloud web platform if you are
interested in creating IoT systems and have a compatible board. Here are
some tips to help you pick the best tool to suit your needs:

1. If you have a reliable Internet connection, you should use the online
IDE (Arduino Cloud Editor). It will allow you to save your sketches in the
Cloud, having them available from any device and backed up. Also, you will
always have the most up-to-date version of the IDE without the need to
install updates or community generated libraries.

2. If you would rather work offline, you should use the latest version of
the desktop IDE (Arduino Software IDE).

3. If you wish to create our very own IoT project, you should use
the Arduino Cloud. It will allow you to track data in real time, trigger remote
devices and build wireless systems.

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike
4.0 license.

ON THIS PAGE

 IDE
 Arduino Tools

Was this article helpful?


Home / Learn / Using the Arduino Software (IDE)

Using the Arduino Software (IDE)


The offline IDE makes it easy to write code and upload it to the board without an
Internet connection.
AuthorLiam Aljundi
Last revision10/28/2024

The Arduino Software (IDE) makes it easy to write code and upload it to the
board offline. We recommend it for users with poor or no internet
connection. This software can be used with any Arduino board.

There are currently two versions of the Arduino IDE, one is the IDE 1.x.x and
the other is IDE 2.x. The IDE 2.x is new major release that is faster and even
more powerful to the IDE 1.x.x. In addition to a more modern editor and a
more responsive interface it includes advanced features to help users with
their coding and debugging.

The following steps can guide you with using the offline IDE (you can
choose either IDE 1.x.x or IDE 2.x):

1. Download and install the Arduino Software IDE:

 Arduino IDE 1.x.x (Windows, Mac OS, Linux, Portable IDE for
Windows and Linux, ChromeOS).
 Arduino IDE 2.x

2. Connect your Arduino board to your device.

3. Open the Arduino Software (IDE).

The Arduino Integrated Development Environment - or Arduino


Software (IDE) - connects to the Arduino boards to upload programs and
communicate with them. Programs written using Arduino Software (IDE) are
called sketches. These sketches are written in the text editor and are
saved with the file extension .ino.

Using the offline IDE 1.x.x


The editor contains the four main areas:
1. A Toolbar with buttons for common functions and a series of menus.
The toolbar buttons allow you to verify and upload programs, create, open,
and save sketches, and open the serial monitor.

2. The message area, gives feedback while saving and exporting and also
displays errors.

3. The text editor for writing your code.

4. The text console displays text output by the Arduino Software (IDE),
including complete error messages and other information.

The bottom right-hand corner of the window displays the configured board
and serial port.

The Arduino Software IDE

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

5. Connect your Arduino or Genuino board to your computer.


6. Now, you need to select the right core & board. This is done by
navigating to Tools > Board > Arduino AVR Boards > Board. Make sure
you select the board that you are using. If you cannot find your board, you
can add it from Tools > Board > Boards Manager.

Selecting a board

7. Now, let's make sure that your board is found by the computer,
by selecting the port. This is simply done by navigating to Tools > Port,
where you select your board from the list.
Selecting the port

8. Let’s try an example: navigate to File > Examples > 01.Basics >
Blink.
Opening an example

9. To upload it to your board, simply click on the arrow in the top left
corner. This process takes a few seconds, and it is important to not
disconnect the board during this process. If the upload is successful, the
message "Done uploading" will appear in the bottom output area.

10. Once the upload is complete, you should then 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.
Congratulations! You have successfully programmed your board to blink
its on-board LED! You can find more information about the Arduino Software
(IDE) 2.x here.

Using the offline IDE 2.x


The editor contains the four main areas:

1. A toolbar with buttons for common functions and a series of menus.


The toolbar buttons allow you to verify and upload programs, create, open,
and save sketches, choose your board and port and open the serial monitor.

2. The Sidebar for regularly used tools. It gives you quick access to board
managers, libraries, debugging your board as well as a search and
replacement tool.

3. The text editor for writing your code.

4. Console controls gives control over the output on the console.

5. The text console displays text output by the Arduino Software (IDE),
including complete error messages and other information.

The bottom right-hand corner of the window displays the configured board
and serial port.
The Arduino Software IDE

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.

2. Now, you need to select the right board & port. This is done from the
toolbar. Make sure you select the board that you are using. If you cannot
find your board, you can add it from the board manager in the sidebar.
Selecting a board & port

3. Let’s try an example: navigate to File > Examples > 01.Basics >
Blink.
Opening an example

4. To upload it to your board, simply click on the arrow in the top left
corner. This process takes a few seconds, and it is important to not
disconnect the board during this process. If the upload is successful, the
message "Done uploading" will appear in the bottom output area.

5. Once the upload is complete, you should see on your board the yellow
LED with the letter 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.
Congratulations! You have successfully programmed your board to blink
its on-board LED! You can find more information about the Arduino Software
(IDE) here.

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord

Using the Arduino Cloud Editor


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

AuthorLiam Aljundi

Last revision10/28/2024

The Arduino Cloud 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 Cloud, 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 Cloud 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 Cloud 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 Cloud 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 Cloud Editor .

Using the online IDE


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

The Arduino Cloud Editor

The Arduino Cloud 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

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.
Congratulations! You have successfully programmed your board to blink
its on-board LED! You can find more information about the Arduino Cloud
Editor here.

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord

License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike
4.0 license.
ON THIS PAGE

 Using the online IDE

Was this article helpful?

Get to know Arduino Libraries


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

AuthorLiam Aljundi

Last revision10/28/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

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

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 library of
your choice, 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 Cloud
Editor) is quite similar to the offline one:

1. Login to the Arduino Cloud.

2. Create or open a sketch.


3. 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.

4. 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.

5. If you can't find a specific library on the list, you can search every
existing library through the search bar. 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).

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord

License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike
4.0 license.
ON THIS PAGE

 Offline IDE
 Online IDE

Was this article helpful?

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 revision10/28/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


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

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

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

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

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

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

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.

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.

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:

Por
Domain
t

mqtts- 888
up.iot.arduino.cc 4

mqtts- 888
sa.iot.arduino.cc 3

844
wss.iot.arduino.cc
3

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.

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord

License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike
4.0 license.
ON THIS PAGE

 Using the Arduino Cloud


o Creating a Thing
o Building the Sketch
o Creating the dashboard
 Network Configuration

Was this article helpful?

Troubleshooting Arduino Sketches


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

AuthorLiam Aljundi
Last revision10/28/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 Cloud 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):

o 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).
o On Linux, it should be /dev/ttyACM0 or similar (for the UNO or
Mega 2560) or /dev/ttyUSB0 or similar (for older boards).
o 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

1sudo usermod -a -G tty yourUserName

2sudo 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


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.

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike
4.0 license.

ON THIS PAGE

 Board & Port


 Drivers
 Troubleshooting Guide
 Forum Support

Was this article helpful?

nstalling additional cores


Learn how to install cores in the Arduino IDE.

Last revision10/28/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.

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.
Now you can find the new board in the Tools > Board menu.
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.

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.
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.

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike
4.0 license.

ON THIS PAGE

 How to install an Arduino core


 How to install a third party core

Was this article helpful?

The Arduino Comic Project


Learn Arduino comic book style! This community project has been translated into
several languages, including Spanish, Chinese & Arabic.

AuthorArduino
Last revision10/28/2024

The Arduino Comic was created by Jody Culkin and published during 2011.
You can download the original , but you can also help out and contribute
translating it to your own language.

The workflow to translate the comic is:


 Download the original comic just to see how it looks like
 Download the original text document , that contains all the strings in
English, it comes both as TXT and DOC file
 Translate all the strings to your own language
 Download the PDF file with the blank boxes
 Edit the PDF file with your graphic tool of choice: InDesign, Illustrator,
Inkscape ... and insert the different strings
 Fill in the Support Contact Form with information that you have
created your comic. You will receive an email with your case number
where you can send the translated strings as well as a PDF with the
final version of the comic (if you want to share your work files it might
also be a nice thing to do)
 Remember to add your name and contact information, we like to give
credit to those that contributed, besides people might want to contact
you with questions

Translations
ARABIC /‫عربي‬

 Translated by: Ahmad Y. Saleh


 Email/url: ahmad.y.saleh@gmail.com
 Arabic PDF Version ‫ملف اللغة العربية‬

Work files:

 Right-to-left SVGs
 Arabic work files
CATALAN / CATALÀ

 Translated by: Antoni Ubieto


 Email/url: antoni DOT ubieto@gmail.om
 BETA Catalan PDF version

Chinese / 中文

 Translated by: Lukas Riad


 Email/url: luksury@gmail.com
 Simplified Mandarin PDF version

DUTCH / NEDERLANDS

 Translated by: Johan Korten / i&i


 Email/url: jksoft.edu@gmail.com
 Dutch PDF version

DEUTSCH / GERMAN

 Translated by: 'Thorben Weber & Kreativität trifft Technik' e.V


 Email/url: tw@kreativitaet-trifft-technik.de
 Online Version
 PDF from PNG (works in all PDF Readers)
 PDF from SVG (more detail - Not viewable in every reader)

Work files: Inkscape SVGs in zip File

DEVNAGARI / देवनागरी

 Translated by: Kaushlendra Singh Sisodia


 Email/url: kaushlendra.sisodia@gmail.com / The IoT Academy
 PDF version

FRENCH / français

 Translated by: Alban Crommer


 Email/url: https://git.interhacker.space/tmplab/arduino-comic-fr
 PDF version

GREEK / ΕΛΛΗΝΙΚΑ
 Translated by: Anna Maragkoudaki
 Email/url: rottyfish@yahoo.com
 Greek PDF version

GUJARATI / ગુજરાતી

 Translated by: Maitreya Deepak Korekar


 Email: korekarmaitreya@gmail.com
 PDF Version

INDONESIAN / BAHASA INDONESIA

 Translated by: Moriano Mordekhai


 Email/url: 'mor.d.khai013@gmail.com '
 Indinesian PDF version

KOREAN / 한국어

 Translated by: kocoafab


 Email/url: webmaster@kocoafab.cc
 Arduino comic 한국어 버전
 translated text file: Arduino comic 한국어 텍스트 .docx

Nepali / नेपाली

 Translated by: Niraj Pradhan


 Email/url: nirajpradhan299@gmail.com
 Nepali PDF version

Persian / ‫فارسی‬

 Translated by: Hossein Ahmadi (‫)حسین احمدی‬


 Email/url: 4hmadi.ho55ein@gmail.com
 Persian PDF version

PORTUGUESE / PORTUGUÊS

 Translated by: Rodrigo Caitano


 Email/url: rodrigocaett@gmail.com
 Comic em Português
 Translated text in .doc format

SONAR BANGLA / সোনার বাংলা


 Translated by: Kaushlendra Singh Sisodia
 Email/url: kaushlendra.sisodia@gmail.com / The IoT Academy
 PDF version

SPANISH / ESPAÑOL

 Translated by: Josemanu (Ardumania.es)


 Email/url: josemescuder@gmail.com
 Comic en Español
 Translated text in .doc format

Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything
wrong, you can edit this page here.

Need support?
Help CenterAsk the Arduino ForumDiscover Arduino Discord
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike
4.0 license.

ON THIS PAGE

 The workflow to translate the comic is:


 Translations

Was this article helpful?

Arduino API
A reference to the Arduino Programming Language.

AuthorKarl Söderby

Last revision10/28/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

Retur
Method & Parameters Description
ns

Reads the state of a digital


int digitalRead(int pin) int
pin.

void digitalWrite(int pin, int Writes a state to a digital Nothin

state) pin. g

void pinMode(int pin, int


Nothin
mode) Define the mode of a pin.
g
*

*Available modes are:

 INPUT

(0)

 OUTPUT

(1)

 INPUT_PULLUP

(2)

 INPUT_PULLDOWN

(3)

 OUTPUT_OPENDRAIN

(4)
Analog I/O

Retur
Method & Parameters Description
ns

Reads the value of an analog pin in a


int analogRead(int pin) int
10-bit resolution (0-1023).*

void analogReadResolution(int Nothin


Sets ADC read resolution in bits.
resolution) g

void analogReference(int Changes the voltage reference for a Nothin

reference) board.** g

void analogWrite(int pin, int Writes a value to a PWM supported pin Nothin

value) in a 8-bit resolution (0-255).** g

void analogWriteResolution(int Nothin


Sets write resolution for a board.
resolution) g

 *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

Retur
Method & Parameters Description
ns

void tone(int pin, int Generates a square wave on specified pin, Nothin

frequency, long duration) with 50% duty cycle. g


Retur
Method & Parameters Description
ns

Stops generation of square wave on the Nothin


void noTone(int pin)
specified pin. g

Reads a pulse (either HIGH or LOW) on a


long pulseIn(int pin, int
pin and returns the length of the pulse (in long
state, long timeout)
microseconds)

long pulseInLong(int pin, int Returns the length of the pulse (in
long
state, long timeout) microseconds)

int shiftIn(int pin, int


Shifts in a byte of data one bit at a time,
clockPin, int bitOrder) byte
and returns the value of the bit read.
*

void shiftOut(int pin, int

clockPin, int bitOrder, byte Nothin


Shifts out a byte of data one bit at a time.
value) g
**

 *The

bitOrder

parameter is either

MSBFIRST

) or

LSBFIRST
(

) (most / least significant bits).

 **The pin used for

shiftOut()

needs to be configured as an

OUTPUT

, using

pinMode()

Time

Retur
Method & Parameters Description
ns

Freezes program execution for specified Nothin


void delay(long milliseconds)
number of milliseconds. g

void delayMicroseconds(int Freezes program execution for specified Nothin

microseconds) number of microseconds. g

Returns milliseconds passed since


long millis() long
program start.

Returns microseconds passed since


long micros() long
program start.
Math

Retur
Method & Parameters Description
ns

Calculates the absolute value


int abs(int value) int
of a number.

Constrains a number to be
int constrain(int value, int min, int max) int
within a range.

long map(long val, long min, long max, Re-maps a number from one
long
long newMin, long newMax) range to another.

Returns the greater of two


int max(int val1, int val2) int
values.

Returns the smaller of two


int min(int val1, int val2) int
values.

double pow(double base, double Raises a base to the power of


double
exponent) an exponent.

Calculates the square of a


int sq(int value) int
number.

Calculates the square root of a


double sqrt(double value) double
number.
Trigonometry

Method & Retur


Description
Parameters ns

Calculates the cosine of an angle in


cos(double angle) double
radians.

Calculates the sine of an angle in


sin(double angle) double
radians.

Calculates the tangent of an angle in


tan(double angle) double
radians.

Characters

Retur
Method & Parameters Description
ns

Checks if the character is an alphabetic


boolean isAlpha(char c) boolean
character.

boolean Checks if the character is an alphanumeric


boolean
isAlphaNumeric(char c) character.

Checks if the character is a 7-bit ASCII


boolean isAscii(char c) boolean
character.

Checks if the character is a control


boolean isControl(char c) boolean
character.

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 boolean


Retur
Method & Parameters Description
ns

character, excluding space.

boolean Checks if the character is a hexadecimal


boolean
isHexadecimalDigit(char c) digit (0-9, A-F, a-f).

Checks if the character is a lowercase


boolean isLowerCase(char c) boolean
alphabetic character.

Checks if the character is a printable


boolean isPrintable(char c) boolean
character, including space.

Checks if the character is a punctuation


boolean isPunct(char c) boolean
character.

Checks if the character is a whitespace


boolean isSpace(char c) boolean
character.

Checks if the character is an uppercase


boolean isUpperCase(char c) boolean
alphabetic character.

Checks if the character is a whitespace


character according to
boolean isWhitespace(char
boolean
c) isSpaceChar()

method.
Random Numbers

Retur
Method & Parameters Description
ns

Generates a pseudo-random number


between 0 and
int random() int
RAND_MAX

void randomSeed(unsigned Nothin


Seeds the random number generator.
long seed) g

Bits and Bytes

Retur
Method & Parameters Description
ns

Gets the value of a specific


boolean bit(int value, int bitNumber) boolean
bit.

Nothin
void bitClear(int &value, int bit) Clears a specific bit.
g

boolean bitRead(int value, int Reads the value of a specific


boolean
bitNumber) bit.

Nothin
void bitSet(int &value, int bit) Sets a specific bit.
g

void bitWrite(int &value, int bit, int Writes a value to a specific Nothin

bitValue) bit. g

byte highByte(int value) Returns the high byte of an byte


Retur
Method & Parameters Description
ns

int

Returns the low byte of an

byte lowByte(int value) int byte

External Interrupts

Retur
Method & Parameters Description
ns

void attachInterrupt(int pin, void Attaches an interrupt to a Nothin

(*function)(void), int mode) specific pin. g

Detaches an interrupt from a Nothin


void detachInterrupt(int pin)
specific pin. g

Interrupts

Method & Retur


Description
Parameters ns

Enables interrupts Nothin


void interrupts()
globally. g

Disables interrupts Nothin


void noInterrupts()
globally. g
Stream

Retur
Method & Parameters Description
ns

Returns the number of bytes available


int available() int
in the serial buffer.

Reads the next byte from the serial


int read() int
buffer.

Waits for the transmission of outgoing Nothin


void flush()
serial data to complete. g

Searches for a target string in the


int find(char *target) int
serial buffer.

int findUntil(char *target, char Searches for a target string until a


int
*terminate) specified termination string is found.

Returns the next byte in the serial


int peek() int
buffer without removing it.

int readBytes(char *buffer, int Reads characters from the serial


int
length) buffer into a buffer.

int readBytesUntil(char Reads characters from the serial

terminator, char *buffer, int buffer into a buffer until a terminator int

length) is found.

Reads characters from the serial

String readString() buffer into a String until a newline String


character is found.
Retur
Method & Parameters Description
ns

Reads characters from the serial


String readStringUntil(char
buffer into a String until a specified String
terminator)
terminator is found.

Reads characters from the serial

int parseInt() buffer and converts them to an int


integer.

Reads characters from the serial


float parseFloat() float
buffer and converts them to a float.

Sets the maximum duration for

find()

findUntil()
void setTimeout(unsigned long Nothin
,
timeout) g
parseInt()

, and

parseFloat()

Serial

Retur
Method & Parameters Description
ns

if(Serial) Checks if the Serial object is available. boolean


Retur
Method & Parameters Description
ns

Returns the number of bytes available


int available() int
for reading.

Returns the number of bytes available


int availableForWrite() int
for writing.

void begin(unsigned long Initializes the Serial communication


void
baudrate) with the specified baud rate.

void end() Ends the Serial communication. void

Searches for a target string in the


int find(char *target) int
serial buffer.

int findUntil(char *target, char Searches for a target string until a


int
*terminate) specified termination string is found.

Waits for the transmission of outgoing


void flush() void
serial data to complete.

Reads characters from the serial buffer


float parseFloat() float
and converts them to a float.

Reads characters from the serial buffer


int parseInt() int
and converts them to an integer.

Returns the next byte in the serial


int peek() int
buffer without removing it.

size_t print() Prints data to the serial port. size_t


Retur
Method & Parameters Description
ns

Prints data to the serial port followed


size_t println() size_t
by a newline character.

Reads the next byte from the serial


int read() int
buffer.

int readBytes(char *buffer, size_t Reads characters from the serial buffer
int
length) into a buffer.

int readBytesUntil(char Reads characters from the serial buffer

terminator, char *buffer, size_t into a buffer until a terminator is int

length) found.

Reads characters from the serial buffer

String readString() into a String until a newline character String


is found.

Reads characters from the serial buffer


String readStringUntil(char
into a String until a specified String
terminator)
terminator is found.

void setTimeout(unsigned long Sets the maximum duration for void

timeout)
find()

findUntil()

parseInt()

, and
Retur
Method & Parameters Description
ns

parseFloat()

size_t write(uint8_t) Writes a byte to the serial port. size_t

Called when data is available in the


void serialEvent() void
serial buffer.

SPI

Method & Parameters Description Returns

Creates an SPISettings object


SPISettings(uint32_t clock, uint8_t SPISetting
with the specified clock, bit order,
bitOrder, uint8_t dataMode) s
and data mode.

void begin() Initializes the SPI library. void

void beginTransaction(SPISettings Begins an SPI transaction with


void
settings) the specified settings.

void endTransaction() Ends the current SPI transaction. void

void end() Ends the SPI library. void

Sets the bit order (MSBFIRST or


void setBitOrder(uint8_t bitOrder) void
LSBFIRST) for SPI communication.

Sets the clock divider for SPI


void setClockDivider(uint8_t divider) void
communication.
Method & Parameters Description Returns

void setDataMode(uint8_t Sets the data mode for SPI


void
dataMode) communication.

byte transfer(byte value) Transfers a byte over SPI. byte

void usingInterrupt(int Specifies which interrupt to use


void
interruptNumber) for SPI transactions.

I2C (Wire)

Retur
Method & Parameters Description
ns

void begin() Initializes the Wire library. void

void end() Ends the Wire library. void

Requests data from a slave device with


int requestFrom(int address,
the specified address and quantity of int
int quantity)
bytes.

void beginTransmission(int Begins a transmission to the slave device


void
address) with the specified address.

Ends the transmission and returns the


int endTransmission() int
status.

size_t write(uint8_t data) Writes a byte to the I2C bus. size_t

Returns the number of bytes available for


int available() int
reading.
Retur
Method & Parameters Description
ns

int read() Reads a byte from the I2C bus. int

void setClock(uint32_t
Sets the I2C clock frequency. void
frequency)

void onReceive(void Sets a function to be called when data is


void
(*function)(int)) received by the slave.

void onRequest(void Sets a function to be called when the


void
(*function)(void)) master requests data from the slave.

void setWireTimeout(uint32_t
Sets the timeout for I2C operations. void
timeout)

void clearWireTimeoutFlag() Clears the timeout flag. void

bool getWireTimeoutFlag() Returns the timeout flag status. bool

Variables

Enums

Enum
Enumeration Description
Type

PinStatus HIGH / LOW Logical HIGH and LOW values (

and

0
Enum
Enumeration Description
Type

).

Constants for specifying pin modes (


INPUT
0
/
,
OUTPUT
1
/
,
INPUT_PULLUP
PinMode 2
/
,
INPUT_PULLDOWN
3
/
,
OUTPUT_OPENDRAI
4
N
).

Constant representing the built-in LED


LED_BUILTIN
pin.*

Boolean constants for true and false (

true / false and

).
Conversion

Method &
Description
Parameter

Type casting to unsigned


(unsigned int)
int.

Type casting to unsigned


(unsigned long)
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 &
Description
Parameter

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.


Method &
Description
Parameter

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.

Sequence of characters (not a primitive


string
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 &
Description
Parameter

const Qualifier to define constants.

Not a specific keyword; refers to variable


scope
scope.

static Qualifier to declare static variables.

volatile Qualifier to declare volatile variables.

Utilities

Method &
Description
Parameter

PROGMEM Qualifier to store data in program memory.

Operator to determine the size of a data type or


sizeof()
variable.

Structure

Sketch

Method &
Description
Parameter

Main function for continuous code


void loop()
execution.
Method &
Description
Parameter

Initialization function, called once at


void setup()
startup.

Control Structure

Method &
Description
Parameter

break Exits a loop or switch statement.

continue Skips the rest of a loop iteration.

Executes a block of code repeatedly while a specified


do...while
condition is true.

else Part of the if-else statement.

Creates a loop with a specified initialization, condition, and


for
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 &
Description
Parameter

#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
Single line comment.
comment)

; (semicolon) Statement terminator.

Block of code, often used with control


{} (curly braces)
structures.

Arithmetic Operators

Method &
Description
Parameter

Modulo operator for finding the remainder of a


% (remainder)
division.

* (multiplication) Multiplication operator.

+ (addition) Addition operator.

- (subtraction) Subtraction operator.

/ (division) Division operator.

= (assignment Assignment operator.


Method &
Description
Parameter

operator)

Comparison Operators

Method &
Description
Parameter

!= (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 Checks if the left value is less than or equal to the right

to) 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 Checks if the left value is greater than or equal to the

equal to) right value.

Boolean Operators

Method &
Description
Parameter

Inverts the logical value, true becomes false and vice


! (logical not)
versa.

&& (logical and) Logical AND operator, returns true if both operands are
Method &
Description
Parameter

true.

Logical OR operator, returns true if at least one operand is


(logical or)
true.

Pointer Access Operators

Method &
Description
Parameter

Returns the memory address of a


& (reference operator)
variable.

* (dereference Accesses the value pointed to by a

operator) pointer.

Bitwise Operators

Method &
Description
Parameter

& (bitwise and) Performs bitwise AND operation.

<< (bitshift left) Shifts bits to the left.

>> (bitshift right) Shifts bits to the right.

Performs bitwise XOR (exclusive OR)


^ (bitwise xor)
operation.

\| (bitwise or) Performs bitwise OR operation.


Method &
Description
Parameter

~ (bitwise not) Inverts all bits.

Compound Operators

Method &
Description
Parameter

%= (compound Performs a modulo operation and assigns the result to the

remainder) left operand.

&= (compound Performs a bitwise AND operation and assigns the result

bitwise and) to the left operand.

*= (compound Multiplies the left operand by the right operand and

multiplication) assigns the result to the left operand.

++ (increment) Increments the value of the operand by 1.

+= (compound Adds the right operand to the left operand and assigns the

addition) result to the left operand.

-- (decrement) Decrements the value of the operand by 1.

-= (compound Subtracts the right operand from the left operand and

subtraction) assigns the result to the left operand.

/= (compound Divides the left operand by the right operand and assigns

division) the result to the left operand.


Method &
Description
Parameter

^= (compound Performs a bitwise XOR operation and assigns the result

bitwise xor) to the left operand.

\|= (compound Performs a bitwise OR operation and assigns the result to

bitwise or) the left operand.

Using Variables in Sketches


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

Last revision10/28/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

1int pin = 13;

2int pin2 = pin;

3pin = 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

1int pin = 13;

2void setup()

3{

4pinMode(pin, OUTPUT);

5}

6void loop()

7{

8digitalWrite(pin, HIGH);

9}

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

1int pin = 13;

2void setup()

3{

4pin = 12;

5pinMode(pin, OUTPUT);

6}

7void loop()

8{

9digitalWrite(pin, HIGH);

10}
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

1void setup()

2{

3int pin = 13;

4pinMode(pin, OUTPUT);

5digitalWrite(pin, HIGH);

6}

In this case, the variable pin can only be used inside the setup() function. If
you try to do something like this:

Copy

1void loop()

2{

3digitalWrite(pin, LOW); // wrong: pin is not in scope here.

4}

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 revision10/28/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

To "call" our simple multiply function, we pass it parameters of the


datatype that it is expecting:

Copy

1void loop(){

2int i = 2;

3int j = 3;

4int k;

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


7}

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

1void setup(){

2 Serial.begin(9600);

3}

5void loop() {

6 int i = 2;

7 int j = 3;

8 int k;

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

11 Serial.println(k);

12 delay(500);

13}

14

15int myMultiplyFunction(int x, int y){

16 int result;

17 result = x * y;

18 return result;

19}
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

1int ReadSens_and_Condition(){

2 int i;

3 int sval = 0;

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

6 sval = sval + analogRead(0); // sensor on analog pin 0

7 }

9 sval = sval / 5; // average

10 sval = sval / 4; // scale to 8 bits (0 - 255)

11 sval = 255 - sval; // invert output

12 return sval;

13}

To call our function we just assign it to a variable.

Copy

1int sens;

3sens = 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 revision10/28/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

1/*

3 * Blink

5*

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

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

10

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


12

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

14

15 *

16

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

18

19 */

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

1int 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

1void setup()

2{

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


5}

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
1digitalWrite(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

1delay(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 revision10/28/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:

Prefi
Description
x

Wire, for all combinatorial signals, for example wDATA. Typically defined
w
with wire directive

Reg, for all sequential signals, for example rSHIFTER. Typically defined
r
with reg directive

Input, for all input signals in module declaration, for example iCLK.
i
Typically defined with input directive

Output, for all output signals in module declaration, for example oREAD.
o
Typically defined with output directive

Bidirectional, for all inout signals in module declaration, for example


b
bSDA. Typically defined with inout directive

Parameter, for all parameters that can be used to parametrize block, for
p
example pCHANNELS. Typically defined with param directive

c Constant, for all definitions which are constant or are derived values and
Prefi
Description
x

can't be directly used to parametrize the block. For example


cCHANNEL_BITS. Typically defined with localparam directive

Enumerated, for all the possible constant values used by one or more
e 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:

Directio Directio Widt


Signal Description
n n h

Controlle Periphera
r l
Directio Directio Widt
Signal Description
n n h

Register address, width


ADDRESS O I var.
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

Optional signal to flag which


BYTE_ENABLE O I 4 bytes of the 32 bit word are
actually going to be written

Optional signal to flag the


peripheral is busy. Read and
WAIT_REQUES
I O 1 write strobes will be considered
T
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.

Directio Directio Widt


Signal Description
n n h

Controlle Periphera
r l

Number of sequential
BURST_COUNT O I var.
operations to perform

Peripheral uses this signal to


flag when data is being
provided to controller. Can be
asserted with any delay and
READ_DATAVALI
I O 1 there is no guarantee on
D
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

1module COUNTER #(

2pWIDTH=8

3) (

4input iCLK,
5input iRESET,

6output reg [pWIDTH-1:0] oCOUNTER

7);

8endmodule

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

1module COUNTER #(

2pWIDTH=8

3) (

4input iCLK,

5input iRESET,

6output [pWIDTH-1:0] oCOUNTER

7);

8always @(posedge iCLK)

9begin

10if (iRESET) begin

11oCOUNTER<=0;

12end else begin

13oCOUNTER<= oCOUNTER+1;

14end

15end
16endmodule

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

1module COUNTER #(

2pWIDTH=8

3) (

4input iCLK,

5input iRESET,

6output [pWIDTH-1:0] oCOUNTER

7);

8reg [pWIDTH-1:0] rCOUNTER;

9always @(posedge iCLK)

10begin

11if (iRESET) begin

12rCOUNTER<=0;

13end else begin


14rCOUNTER<= rCOUNTER+1;

15end

16end

17assign oCOUNTER=rCOUNTER;

18endmodule

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

1module COUNTER #(

2pWIDTH=8

3) (

4input iCLK,

5input iRESET,
6output [pWIDTH-1:0] oCOUNTER

7);

8reg [pWIDTH-1:0] rCOUNTER;

9wire [pWIDTH-1:0] wNEXT_COUNTER;

10assign wNEXT_COUNTER = rCOUNTER+1;

11assign oCOUNTER = rCOUNTER;

12always @(posedge iCLK)

13begin

14if (iRESET) begin

15rCOUNTER<=0;

16end else begin

17rCOUNTER<= wNEXT_COUNTER;

18end

19end

20endmodule

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

1reg [pWIDTH-1:0] rCOUNT_UP, rCOUNT_DOWN;

2always @(posedge iCLK)

3begin

4if (iRESET) begin

5rCOUNT_UP<=0;

6rCOUNT_DOWN<=0;

7end else begin

8rCOUNT_UP<= rCOUNT_UP+1;

9rCOUNT_DOWN<= rCOUNT_DOWN-1;

10end

11end

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

1module PULSE_GEN #(

2pWIDTH=8,

3pHIGH_COUNT=240,

4pLOW_COUNT=40

5) (

6input iCLK,

7input iRESET,

8input iPULSE_REQ,

9output reg oPULSE

10);

11reg [pWIDTH-1:0] rCOUNTER;

12enum reg [1:0] {

13eST_IDLE,

14eST_PULSE_HIGH,

15eST_PULSE_LOW

16} rSTATE;

17always @(posedge iCLK)

18begin

19if (iRESET) begin

20rSTATE<=eST_IDLE;
21end else begin

22case (rSTATE)

23eST_IDLE: begin

24if (iPULSE_REQ) begin

25rSTATE<= eST_PULSE_HIGH;

26oPULSE<= 1;

27rCOUNTER <= pHIGH_COUNT-1;

28end

29end

30eST_PULSE_HIGH: begin

31rCOUNTER<= rCOUNTER-1;

32if (rCOUNTER==0) begin

33rSTATE<= eST_PULSE_LOW;

34oPULSE<= 0;

35rCOUNTER<= pLOW_COUNT-1;

36end

37end

38eST_PULSE_LOW: begin

39rCOUNTER<= rCOUNTER-1;

40if (rCOUNTER==0) begin

41rSTATE<= eST_IDLE;

42end

43end

44endcase

45end
46end

47endmodule

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

1module PWM #(
2parameter pCHANNELS=16,

3parameter pPRESCALER_BITS=32,

4parameter pMATCH_BITS=32

5)

6(

7input iCLK,

8input iRESET,

9input [$clog2(2*pCHANNELS+2)-1:0] iADDRESS,

10input [31:0] iWRITE_DATA,

11input iWRITE,

12output reg [pCHANNELS-1:0] oPWM

13);

14// register declaration

15reg [pPRESCALER_BITS-1:0] rPRESCALER_CNT;

16reg [pPRESCALER_BITS-1:0] rPRESCALER_MAX;

17reg [pMATCH_BITS-1:0] rPERIOD_CNT;

18reg [pMATCH_BITS-1:0] rPERIOD_MAX;

19reg [pMATCH_BITS-1:0] rMATCH_H [pCHANNELS-1:0];

20reg [pMATCH_BITS-1:0] rMATCH_L [pCHANNELS-1:0];

21reg rTICK;

22integer i;

23always @(posedge iCLK)

24begin

25// logic to interface with bus.

26// register map is as follows:


27// 0: prescaler value

28// 1: PWM period

29// even registers >=2: value at which PWM output is set high

30// odd registers >=2: value at which PWM output is set low

31if (iWRITE) begin

32// the following statement is executed only if address is >=2. case on


iADDRESS[0]

33// selects if address is odd (iADDRESS[0]=1) or even (iADDRESS[0]=0)

34if (iADDRESS>=2) case (iADDRESS[0])

350: rMATCH_H[iADDRESS[CLogB2(pCHANNELS):1]-1]<= iWRITE_DATA;

361: rMATCH_L[iADDRESS[CLogB2(pCHANNELS):1]-1]<= iWRITE_DATA;

37endcase

38else begin

39// we get here if iADDRESS<2

40case (iADDRESS[0])

410: rPRESCALER_MAX<=iWRITE_DATA;

421: rPERIOD_MAX<=iWRITE_DATA;

43endcase

44end

45end

46// prescaler is always incrementing

47rPRESCALER_CNT<=rPRESCALER_CNT+1;

48rTICK<=0;

49if (rPRESCALER_CNT>= rPRESCALER_MAX) begin

50// if prescaler is equal or greater than the max value


51// we reset it and set the tick flag which will trigger the rest of the logic

52// note that tick lasts only one clock cycle as it is reset by the rTICK<= 0
above

53rPRESCALER_CNT<=0;

54rTICK <=1;

55end

56if (rTICK) begin

57// we get here each time rPRESCALER_CNT is reset. from here we


increment the PWM

58// counter which is then clocked at a lower frequency.

59rPERIOD_CNT<=rPERIOD_CNT+1;

60if (rPERIOD_CNT>=rPERIOD_MAX) begin

61// and of course we reset the counter when we reach the max period.

62rPERIOD_CNT<=0;

63end

64end

65// this block implements the parallel comparators that actually generate
the PWM outputs

66// the for loop actually generates an array of logic that compares the
counter with

67// the high and low match values for each channel and set the output
accordingly.

68for (i=0;i<pCHANNELS;i=i+1) begin

69if (rMATCH_H[i]==rPERIOD_CNT)

70oPWM[i] <=1;

71if (rMATCH_L[i]==rPERIOD_CNT)

72oPWM[i] <=0;
73end

74end

75endmodule

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

1module QUAD_ENCODER #(

2pENCODERS=2,

3pENCODER_PRECISION=32

4)(

5input iCLK,

6input iRESET,

7// AVALON PERIPHERAL INTERFACE

8input [$clog2(pENCODERS)-1:0] iAVL_ADDRESS,

9input iAVL_READ,

10output reg [31:0] oAVL_READ_DATA,

11// ENCODER INPUTS

12input [pENCODERS-1:0] iENCODER_A,

13input [pENCODERS-1:0] iENCODER_B

14);

15// bidimensional arrays containing encoder input states at 4 different


points in time

16// the first two delay taps are used to synchronize inputs with the internal
clocks

17// while the other two are used to compare two points in time of those
signals.

18reg [3:0][pENCODERS-1:0] rRESYNC_ENCODER_A,rRESYNC_ENCODER_B;

19// bidimensional arrays containing the counters for each channel


20reg [pENCODERS-1:0][pENCODER_PRECISION-1:0] rSTEPS;

21// encoder decrementing

22// A __----____----__

23// B ____----____----

24// ENABLE __-_-_-_-_-_-_-_

25// DIR __---_---_---_--

26//

27// encoder incrementing

28// A ____----____----

29// B __----____----__

30// ENABLE __-_-_-_-_-_-_-_

31// DIR ___-___-___-___-

32wire [pENCODERS-1:0] wENABLE =


rRESYNC_ENCODER_A[2]^rRESYNC_ENCODER_A[3]^rRESYNC_ENCODER_B[2
]^rRESYNC_ENCODER_B[3];

33wire [pENCODERS-1:0] wDIRECTION =


rRESYNC_ENCODER_A[2]^rRESYNC_ENCODER_B[3];

34integer i;

35initial rSTEPS <=0;

36always @(posedge iCLK)

37begin

38if (iRESET) begin

39rSTEPS<=0;

40rRESYNC_ENCODER_A<=0;

41rRESYNC_ENCODER_B<=0;

42end
43else begin

44// implement shift registers for each channel. since arrays are packed we
can treat that as a monodimensional array

45// and by adding inputs at the bottom we are effectively shifting data by
one bit

46rRESYNC_ENCODER_A<={rRESYNC_ENCODER_A,iENCODER_A};

47rRESYNC_ENCODER_B<={rRESYNC_ENCODER_B,iENCODER_B};

48for (i=0;i<pENCODERS;i=i+1)

49begin

50// if strobe is high..

51if (wENABLE[i])

52// increment or decrement based on direction

53rSTEPS[i] <= rSTEPS[i]+ ((wDIRECTION[i]) ? 1 : -1);

54end

55// if PERIPHERAL interface is being read...

56if (iAVL_READ)

57begin

58// return the value of the counter indexed by the address

59oAVL_READ_DATA<= rSTEPS[iAVL_ADDRESS];

60end

61end

62end

63endmodule

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 revision10/28/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.

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.

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:

Microcontrol Architectur
Board Family
ler e

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

ATSAMD21G1 Von
Zero Arm® Cortex®-M0+
8 Neumann

Arm® Cortex®-
Portenta H7 STM32H747 Harvard
M4/M7

Nicla Sense ME nRF52832 Arm® Cortex®-M4 Harvard


Microcontrol Architectur
Board Family
ler e

Nano RP2040 Von


RP2040 Arm® Cortex®-M0+
Connect Neumann

ATSAMD21G1 Von
MKR FOX 1200 Arm® Cortex®-M0+
8 Neumann

ATSAMD21G1 Von
MKR NB 1500 Arm® Cortex®-M0+
8 Neumann

ATSAMD21G1 Von
MKR Vidor 4000 Arm® Cortex®-M0+
8 Neumann

ATSAMD21G1 Von
MKR WiFi 1010 Arm® Cortex®-M0+
8 Neumann

ATSAMD21G1 Von
MKR Zero Arm® Cortex®-M0+
8 Neumann

ATSAMW25H1 Von
MKR1000 WIFI Arm® Cortex®-M0+
8 Neumann

ATSAMD21G1 Von
MKR WAN 1300 Arm® Cortex®-M0+
8 Neumann

ATSAMD21G1 Von
MKR WAN 1310 Arm® Cortex®-M0+
8 Neumann
Microcontrol Architectur
Board Family
ler e

Nano ATmega328P AVR Harvard

Nano Every ATmega4809 AVR Harvard

ATSAMD21G1 Von
Nano 33 IoT Arm® Cortex®-M0+
8 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.

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.

The ARM-based microcontroller's memory is organized into the following


sections within the address type mentioned previously:

 Virtual address:
o Kernel code and data
o Application code and data

 Physical address:
o ROM
o RAM
o Flash
o Peripherals

The following table summarizes a specific Arduino® board's memory


allocation:

Microcontrol Architect Flas SRA EEPRO


Board Family
ler ure h M M

UNO Mini ATmega328P AVR Harvard 32kB 2kB 1kB


Microcontrol Architect Flas SRA EEPRO
Board Family
ler ure h M M

UNO Rev3 ATmega328P AVR Harvard 32kB 2kB 1kB

UNO WiFi
ATmega4809 AVR Harvard 48kB 6kB 256B
Rev2

UNO Rev3
ATmega328P AVR Harvard 32kB 2kB 1kB
SMD

Leonardo ATmega32u4 AVR Harvard 32kB 2.5kB 1kB

Mega 2560 256k


ATmega2560 AVR Harvard 8kB 4kB
Rev3 B

Micro ATmega32u4 AVR Harvard 32kB 2.5kB 1kB

Arm®
ATSAMD21G1 Von 256k
Zero Cortex® 32kB -
8 Neumann B
-M0+

Portenta H7
Arm®
(basic
STM32H747 Cortex® Harvard 16MB 8MB -
configuration
-M4/M7
)

Arm®
Nicla Sense 512k
nRF52832 Cortex® Harvard 64kB -
ME B
-M4
Microcontrol Architect Flas SRA EEPRO
Board Family
ler ure h M M

Arm®
Nano RP2040 Von 264k
RP2040 Cortex® - -
Connect Neumann B
-M0+

Arm®
MKR FOX ATSAMD21G1 Von 256k
Cortex® 32kB -
1200 8 Neumann B
-M0+

Arm®
ATSAMD21G1 Von 256k
MKR NB 1500 Cortex® 32kB -
8 Neumann B
-M0+

Arm®
MKR Vidor ATSAMD21G1 Von 256k
Cortex® 32kB -
4000 8 Neumann B
-M0+

Arm®
MKR WiFi ATSAMD21G1 Von 256k
Cortex® 32kB -
1010 8 Neumann B
-M0+

Arm®
ATSAMD21G1 Von 256k
MKR Zero Cortex® 32kB -
8 Neumann B
-M0+

Arm®
MKR1000 ATSAMW25H1 Von 256k
Cortex® 32kB -
WIFI 8 Neumann B
-M0+
Microcontrol Architect Flas SRA EEPRO
Board Family
ler ure h M M

Arm®
MKR WAN ATSAMD21G1 Von 256k
Cortex® 32kB -
1300 8 Neumann B
-M0+

Arm®
MKR WAN ATSAMD21G1 Von 256k
Cortex® 32kB -
1310 8 Neumann B
-M0+

Nano ATmega328P AVR Harvard 32kB 2kB 1kB

Nano Every ATmega4809 AVR Harvard 48kB 6kB 256B

Arm®
ATSAMD21G1 Von 256k
Nano 33 IoT Cortex® 32kB -
8 Neumann B
-M0+

Arm®
256k
Nano 33 BLE nRF52840 Cortex® Harvard 1MB -
B
-M4

Arm®
Nano 33 BLE 256k
nRF52840 Cortex® Harvard 1MB -
Sense B
-M4

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

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

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

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

1void display_freeram() {

2 Serial.print(F("- SRAM left: "));

3 Serial.println(freeRam());
4}

6int freeRam() {

7 extern int __heap_start,*__brkval;

8 int v;

9 return (int)&v - (__brkval == 0

10 ? (int)&__heap_start : (int) __brkval);

11}

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

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


2

3void display_freeram(){

4 Serial.print(F("- SRAM left: "));

5 Serial.println(freeRam());

6}

8int freeRam() {

9 char top;

10 return &top - reinterpret_cast<char*>(sbrk(0));

11}

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

1#include <EEPROM.h>

3void setup() {

4}
5

6void loop {

7 // Write data into an specific address of the EEPROM memory

8 EEPROM.write(address, value);

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

11 EEPROM.read(address);

12}

Also, it is possible to clear the entire EEPROM memory by setting it to 0, as


shown in the code below:

Copy

1#include <EEPROM.h>

3void setup() {

4}

6void loop {

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

8 // Clear EEPROM memory

9 EEPROM.write(i, 0);

10

11}

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

1Serial.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

1#include <avr/pgmspace.h>

3// Basic PROGMEM structure

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

6// Storing an unsigned, 16-bit, integer

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

9// Storing a char in PROGMEM

10const 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

1static const int Variable = Data;


The usage differs in different levels summarized as following:

 Namespace Level
o 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
o If it is declared within

static

, any type of applicable data that is to be managed will be between


function calls.

 Class Level
o 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:


o 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):


o 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:
o 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.
o 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

1// String_Variable is an String type variable

2// Alloc_Size is the memory to be pre-allocated in number of Bytes with


unsigned int type

3String_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

1#define SERIAL_TX_BUFFER_SIZE 64

3#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:

Byte
Type Range of Values
Length

boolean 1 Limited to logic true and false

char 1 -128 to 127

unsigned
1 0 to 255
char

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

-2,147,483,648 to
long 4
2,147,483,647

unsigned
4 0 to 4,294,967,295
long

-3.4028235E+38 to
float 4
3.4028235E+38

-3.4028235E+38 to
double 4
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 revision10/28/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 are 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

1/*

2 * EEPROM Clear

3*
4 * Sets all of the bytes of the EEPROM to 0.

5 * Please see eeprom_iteration for a more in depth

6 * look at how to traverse the EEPROM.

7*

8 * This example code is in the public domain.

9 */

10

11#include <EEPROM.h>

12

13void setup() {

14 // initialize the LED pin as an output.

15 pinMode(13, OUTPUT);

16

17 /***

18 Iterate through each byte of the EEPROM storage.

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

20 - Arduino Duemilanove: 512 B EEPROM storage.

21 - Arduino Uno: 1 kB EEPROM storage.

22 - Arduino Mega: 4 kB EEPROM storage.

23 Rather than hard-coding the length, you should use the pre-provided
length function.

24 This will make your code portable to all AVR processors.

25 ***/

26

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


28 EEPROM.write(i, 0);

29 }

30

31 // turn the LED on when we're done

32 digitalWrite(13, HIGH);

33}

34

35void loop() {

36 /** Empty loop. **/

37}

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

1/***

3 Written by Christopher Andrews.

5 CRC algorithm generated by pycrc, MIT licence (


https://github.com/tpircher/pycrc ).

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


corrupted.
8

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

10

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

12

13***/

14

15#include <Arduino.h>

16#include <EEPROM.h>

17

18void setup() {

19

20 //Start serial

21

22 Serial.begin(9600);

23

24 while (!Serial) {

25

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

27

28 }

29

30 //Print length of data to run CRC on.

31
32 Serial.print("EEPROM length: ");

33

34 Serial.println(EEPROM.length());

35

36 //Print the result of calling eeprom_crc()

37

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

39

40 Serial.println(eeprom_crc(), HEX);

41

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

43}

44

45void loop() {

46

47 /* Empty loop */

48}

49

50unsigned long eeprom_crc(void) {

51

52 const unsigned long crc_table[16] = {

53

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

55

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


57

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

59

60 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c

61

62 };

63

64 unsigned long crc = ~0L;

65

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

67

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

69

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

71

72 crc = ~crc;

73

74 }

75

76 return crc;

77}

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

1/***

3 eeprom_get example.

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

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

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

10

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

12

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

14

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

16

17 loaded.

18

19 Written by Christopher Andrews 2015

20

21 Released under MIT licence.

22
23***/

24

25#include <EEPROM.h>

26

27void setup() {

28

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

30

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

32

33 Serial.begin(9600);

34

35 while (!Serial) {

36

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

38

39 }

40

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

42

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

44

45 EEPROM.get(eeAddress, f);

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

48

49 /***

50

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

52

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

54

55 ***/

56

57 /***

58

59 Get can be used with custom structures too.

60

61 I have separated this into an extra function.

62

63 ***/

64

65 secondTest(); //Run the next test.

66}

67

68struct MyObject {

69

70 float field1;
71

72 byte field2;

73

74 char name[10];

75};

76

77void secondTest() {

78

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

80

81 MyObject customVar; //Variable to store custom object read from


EEPROM.

82

83 EEPROM.get(eeAddress, customVar);

84

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

86

87 Serial.println(customVar.field1);

88

89 Serial.println(customVar.field2);

90

91 Serial.println(customVar.name);

92}

93

94void loop() {
95

96 /* Empty loop */

97}

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 source of code snippets to
be used elsewhere.

Copy

1/***

3 eeprom_iteration example.

5 A set of example snippets highlighting the

7 simplest methods for traversing the EEPROM.

9 Running this sketch is not necessary, this is

10

11 simply highlighting certain programming methods.

12

13 Written by Christopher Andrews 2015

14

15 Released under MIT licence.


16

17***/

18

19#include <EEPROM.h>

20

21void setup() {

22

23 /***

24

25 Iterate the EEPROM using a for loop.

26

27 ***/

28

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

30

31 //Add one to each cell in the EEPROM

32

33 EEPROM[ index ] += 1;

34

35 }

36

37 /***

38

39 Iterate the EEPROM using a while loop.

40
41 ***/

42

43 int index = 0;

44

45 while (index < EEPROM.length()) {

46

47 //Add one to each cell in the EEPROM

48

49 EEPROM[ index ] += 1;

50

51 index++;

52

53 }

54

55 /***

56

57 Iterate the EEPROM using a do-while loop.

58

59 ***/

60

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

62

63 do {

64

65 //Add one to each cell in the EEPROM


66

67 EEPROM[ idx ] += 1;

68

69 idx++;

70

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

72

73} //End of setup function.

74

75void 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

1/***

3 eeprom_put example.

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

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

8
9 example sketch eeprom_get.

10

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

12

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

14

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

16

17 different.

18

19 Written by Christopher Andrews 2015

20

21 Released under MIT licence.

22

23***/

24

25#include <EEPROM.h>

26

27struct MyObject {

28

29 float field1;

30

31 byte field2;

32

33 char name[10];
34};

35

36void setup() {

37

38 Serial.begin(9600);

39

40 while (!Serial) {

41

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

43

44 }

45

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

47

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

49

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

51

52 EEPROM.put(eeAddress, f);

53

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

55

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

57

58 //Data to store.
59

60 MyObject customVar = {

61

62 3.14f,

63

64 65,

65

66 "Working!"

67

68 };

69

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

71

72 EEPROM.put(eeAddress, customVar);

73

74 Serial.print("Written custom data type! \n\nView the example sketch


eeprom_get to see how you can retrieve the values!");

75}

76

77void loop() {

78

79 /* Empty loop */

80}

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

1/*

2 * EEPROM Read

3*

4 * Reads the value of each byte of the EEPROM and prints it

5 * to the computer.

6 * This example code is in the public domain.

7 */

9#include <EEPROM.h>

10

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

12int address = 0;

13byte value;

14

15void setup() {

16 // initialize serial and wait for port to open:

17 Serial.begin(9600);

18 while (!Serial) {

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

20 }
21}

22

23void loop() {

24 // read a byte from the current address of the EEPROM

25 value = EEPROM.read(address);

26

27 Serial.print(address);

28 Serial.print("\t");

29 Serial.print(value, DEC);

30 Serial.println();

31

32 /***

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

34

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

36 - Arduino Duemilanove: 512 B EEPROM storage.

37 - Arduino Uno: 1 kB EEPROM storage.

38 - Arduino Mega: 4 kB EEPROM storage.

39

40 Rather than hard-coding the length, you should use the pre-provided
length function.

41 This will make your code portable to all AVR processors.

42 ***/

43 address = address + 1;

44 if (address == EEPROM.length()) {
45 address = 0;

46 }

47

48 /***

49 As the EEPROM sizes are powers of two, wrapping (preventing overflow)


of an

50 EEPROM address is also doable by a bitwise and of the length - 1.

51

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

53 ***/

54

55 delay(500);

56}

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

1/***

2 EEPROM Update method

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

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


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

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

9 which would reduce the life span of the EEPROM unnecessarily.

10

11 Released using MIT licence.

12 ***/

13

14#include <EEPROM.h>

15

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

17int address = 0;

18

19void setup() {

20 /** Empty setup **/

21}

22

23void loop() {

24 /***

25 need to divide by 4 because analog inputs range from

26 0 to 1023 and each byte of the EEPROM can only hold a

27 value from 0 to 255.

28 ***/

29 int val = analogRead(0) / 4;


30

31 /***

32 Update the particular EEPROM cell.

33 these values will remain there when the board is

34 turned off.

35 ***/

36 EEPROM.update(address, val);

37

38 /***

39 The function EEPROM.update(address, val) is equivalent to the


following:

40

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

42 EEPROM.write(address, val);

43 }

44 ***/

45

46

47 /***

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

49

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

51 - Arduino Duemilanove: 512 B EEPROM storage.

52 - Arduino Uno: 1 kB EEPROM storage.

53 - Arduino Mega: 4 kB EEPROM storage.


54

55 Rather than hard-coding the length, you should use the pre-provided
length function.

56 This will make your code portable to all AVR processors.

57 ***/

58 address = address + 1;

59 if (address == EEPROM.length()) {

60 address = 0;

61 }

62

63 /***

64 As the EEPROM sizes are powers of two, wrapping (preventing overflow)


of an

65 EEPROM address is also doable by a bitwise and of the length - 1.

66

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

68 ***/

69

70 delay(100);

71}

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

1/*

3 * EEPROM Write

5*

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

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

10

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

12

13 */

14

15#include <EEPROM.h>

16

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

18int addr = 0;

19

20void setup() {

21

22 /** Empty setup. **/

23}
24

25void loop() {

26

27 /***

28

29 Need to divide by 4 because analog inputs range from

30

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 revision10/28/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.

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

1/*
2 SD card read/write

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

5 The circuit:

6 SD card attached to SPI bus as follows:

7 ** MOSI - pin 11

8 ** MISO - pin 12

9 ** CLK - pin 13

10 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

11

12 created Nov 2010

13 by David A. Mellis

14 modified 9 Apr 2012

15 by Tom Igoe

16

17 This example code is in the public domain.

18

19*/

20

21#include <SPI.h>

22#include <SD.h>

23

24File myFile;

25
26void setup() {

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

28 Serial.begin(9600);

29 while (!Serial) {

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

31 }

32

33

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

35

36 if (!SD.begin(4)) {

37 Serial.println("initialization failed!");

38 while (1);

39 }

40 Serial.println("initialization done.");

41

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

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

44 myFile = SD.open("test.txt", FILE_WRITE);

45

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

47 if (myFile) {

48 Serial.print("Writing to test.txt...");

49 myFile.println("testing 1, 2, 3.");

50 // close the file:


51 myFile.close();

52 Serial.println("done.");

53 } else {

54 // if the file didn't open, print an error:

55 Serial.println("error opening test.txt");

56 }

57

58 // re-open the file for reading:

59 myFile = SD.open("test.txt");

60 if (myFile) {

61 Serial.println("test.txt:");

62

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

64 while (myFile.available()) {

65 Serial.write(myFile.read());

66 }

67 // close the file:

68 myFile.close();

69 } else {

70 // if the file didn't open, print an error:

71 Serial.println("error opening test.txt");

72 }

73}

74

75void loop() {
76 // nothing happens after setup

77}

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

1/*

3 SD card test

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

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

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

10

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

12

13 The circuit:

14

15 SD card attached to SPI bus as follows:

16

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

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

20

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

22

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

24

25 Pin 10 used here for consistency with other Arduino examples

26

27 created 28 Mar 2011

28

29 by Limor Fried

30

31 modified 24 July 2020

32

33 by Tom Igoe

34

35*/

36// include the SD library:

37#include <SPI.h>

38#include <SD.h>

39

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

41

42Sd2Card card;

43
44SdVolume volume;

45

46SdFile root;

47

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

49// Default SPI on Uno and Nano: pin 10

50// Arduino Ethernet shield: pin 4

51// Adafruit SD shields and modules: pin 10

52// Sparkfun SD shield: pin 8

53// MKRZero SD: SDCARD_SS_PIN

54

55const int chipSelect = 10;

56

57void setup() {

58

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

60

61 Serial.begin(9600);

62

63 while (!Serial) {

64

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

66

67 }

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

70

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

72

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

74

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

76

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

78

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

80

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

82

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

84

85 while (1);

86

87 } else {

88

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

90

91 }

92
93 // print the type of card

94

95 Serial.println();

96

97 Serial.print("Card type: ");

98

99 switch (card.type()) {

100

101 case SD_CARD_TYPE_SD1:

102

103 Serial.println("SD1");

104

105 break;

106

107 case SD_CARD_TYPE_SD2:

108

109 Serial.println("SD2");

110

111 break;

112

113 case SD_CARD_TYPE_SDHC:

114

115 Serial.println("SDHC");

116

117 break;
118

119 default:

120

121 Serial.println("Unknown");

122

123 }

124

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


FAT32

126

127 if (!volume.init(card)) {

128

129 Serial.println("Could not find FAT16/FAT32 partition.\nMake sure


you've formatted the card");

130

131 while (1);

132

133 }

134

135 Serial.print("Clusters: ");

136

137 Serial.println(volume.clusterCount());

138

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

140

141 Serial.println(volume.blocksPerCluster());
142

143 Serial.print("Total Blocks: ");

144

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

146

147 Serial.println();

148

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

150

151 uint32_t volumesize;

152

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

154

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

156

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


blocks

158

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

160

161 volumesize /= 2; // SD card blocks are always 512 bytes


(2 blocks are 1KB)

162

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

164

165 Serial.println(volumesize);
166

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

168

169 volumesize /= 1024;

170

171 Serial.println(volumesize);

172

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

174

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

176

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

178

179 root.openRoot(volume);

180

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

182

183 root.ls(LS_R | LS_DATE | LS_SIZE);

184

185 root.close();

186}

187

188void loop(void) {

189}
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

1/*

3 SD card file dump

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

7 SD library and send it over the serial port.

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

10
11 The circuit:

12

13 SD card attached to SPI bus as follows:

14

15 ** SDO - pin 11

16

17 ** SDI - pin 12

18

19 ** CLK - pin 13

20

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

22

23 Pin 10 used here for consistency with other Arduino examples

24

25 (for MKRZero SD: SDCARD_SS_PIN)

26

27 created 22 December 2010

28

29 by Limor Fried

30

31 modified 9 Apr 2012

32

33 by Tom Igoe

34

35 This example code is in the public domain.


36

37*/

38#include <SD.h>

39

40const int chipSelect = 10;

41

42void setup() {

43

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

45

46 Serial.begin(9600);

47

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

49

50 while (!Serial);

51

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

53

54 if (!SD.begin(chipSelect)) {

55

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

57

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

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

61

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

63

64 Serial.println("Note: press reset or reopen this serial monitor after fixing


your issue!");

65

66 while (true);

67

68 }

69

70 Serial.println("initialization done.");

71

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

73

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

75

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

77

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

79

80 if (dataFile) {

81

82 while (dataFile.available()) {

83
84 Serial.write(dataFile.read());

85

86 }

87

88 dataFile.close();

89

90 }

91

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

93

94 else {

95

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

97

98 }

99}

100

101void loop() {

102}

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

1/*

3 SD card basic file example

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

7 The circuit. Pin numbers reflect the default

9 SPI pins for Uno and Nano models:

10

11 SD card attached to SPI bus as follows:

12

13 ** SDO - pin 11

14

15 ** SDI - pin 12

16

17 ** CLK - pin 13
18

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

20

21 Pin 10 used here for consistency with other Arduino examples

22

23 (for MKRZero SD: SDCARD_SS_PIN)

24

25 created Nov 2010

26

27 by David A. Mellis

28

29 modified 24 July 2020

30

31 by Tom Igoe

32

33 This example code is in the public domain.

34

35*/

36#include <SD.h>

37

38const int chipSelect = 10;

39

40File myFile;

41

42void setup() {
43

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

45

46 Serial.begin(9600);

47

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

49while (!Serial);

50

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

52

53 if (!SD.begin(10)) {

54

55 Serial.println("initialization failed!");

56

57 while (1);

58

59 }

60

61 Serial.println("initialization done.");

62

63 if (SD.exists("example.txt")) {

64

65 Serial.println("example.txt exists.");

66
67 } else {

68

69 Serial.println("example.txt doesn't exist.");

70

71 }

72

73 // open a new file and immediately close it:

74

75 Serial.println("Creating example.txt...");

76

77 myFile = SD.open("example.txt", FILE_WRITE);

78

79 myFile.close();

80

81 // Check to see if the file exists:

82

83 if (SD.exists("example.txt")) {

84

85 Serial.println("example.txt exists.");

86

87 } else {

88

89 Serial.println("example.txt doesn't exist.");

90

91 }
92

93 // delete the file:

94

95 Serial.println("Removing example.txt...");

96

97 SD.remove("example.txt");

98

99 if (SD.exists("example.txt")) {

100

101 Serial.println("example.txt exists.");

102

103 } else {

104

105 Serial.println("example.txt doesn't exist.");

106

107 }

108}

109

110void loop() {

111

112 // nothing happens after setup finishes.

113}

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

1/*

3 Listfiles

5 This example shows how print out the files in a

7 directory on a SD card.Pin numbers reflect the default

9 SPI pins for Uno and Nano models

10

11 The circuit:

12

13 SD card attached to SPI bus as follows:

14

15 ** SDO - pin 11

16
17 ** SDI - pin 12

18

19 ** CLK - pin 13

20

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

22

23 Pin 10 used here for consistency with other Arduino examples

24

25 (for MKRZero SD: SDCARD_SS_PIN)

26

27 created Nov 2010

28

29 by David A. Mellis

Bit Masks with Arduino


Bit masks are used to access specific bits in a byte of data.

AuthorArduino

Last revision10/28/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

1x: 10001101

3 y: 01010111

5x & 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

1x: 10001101

3 y: 01010111

5x | y: 11011111

The Left Shift (

<<
) operator will shift a value to the left the specified number of times. For example:

Copy

1y = 1010

3 x = y << 1

4
5yields: 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

1y = 1010

3 x = y >> 1

5yields: 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

1byte transmit = 7; //define our transmit pin

2byte data = 170; //value to transmit, binary 10101010

3byte mask = 1; //our bitmask

4byte bitDelay = 100;

6void setup()

7{

9 pinMode(transmit,OUTPUT);
10}

11

12void loop()

13{

14

15 for (mask = 00000001; mask>0; mask <<= 1) { //iterate through bit


mask

16

17 if (data & mask){ // if bitwise AND resolves to true

18

19 digitalWrite(transmit,HIGH); // send 1

20

21 }

22

23 else{ //if bitwise and resolves to false

24

25 digitalWrite(transmit,LOW); // send 0

26

27 }

28

29 delayMicroseconds(bitDelay); //delay

30

31 }

32}
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

100000001

2& 10101010

4 ________

6 00000000

And our output pin gets set to 0. Second time through the loop the mask =
00000010, so our operation looks like:

Copy

100000010

2& 10101010

4 ________

6 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 revision10/28/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

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

1#include <math.h> // requires an Atmega168 chip

3#define outpin 8 // audio out to speaker or amp

4int ptime;

5int k, x, dur, freq, t;

6int i, j;

9float ps; // variable for pow pitchShift routine

10

11float noteval;

12

13// note values for two octave scale

14// divide them by powers of two to generate other octaves

15float A = 14080;

16float AS = 14917.2;

17float B = 15804.3;

18float C = 16744;
19float CS = 17739.7;

20float D = 18794.5;

21float DS = 19912.1;

22float E = 21096.2;

23float F = 22350.6;

24float FS = 23679.6;

25float G = 25087.7;

26float GS = 26579.5;

27float A2 = 28160;

28float A2S = 29834.5;

29float B2 = 31608.5;

30float C2 = 33488.1;

31float C2S = 35479.4;

32float D2 = 37589.1;

33float D2S = 39824.3;

34float E2 = 42192.3;

35float F2 = 44701.2;

36float F2S = 47359.3;

37float G2 = 50175.4;

38float G2S = 53159;

39float A3 = 56320;

40

41//octaves - corresponds to piano octaves

42float oct8 = 4;

43float oct7 = 8;
44float oct6 = 16;

45float oct5 = 32;

46float oct4 = 64;

47float oct3 = 128;

48float oct2 = 256;

49float oct1 = 512;

50float oct0 = 1024;

51

52//rhythm values

53int wh = 1024;

54int h = 512;

55int dq = 448;

56int q = 256;

57int qt = 170;

58int de = 192;

59int e = 128;

60int et = 85;

61int dsx = 96;

62int sx = 64;

63int thx = 32;

64

65// major scale just for demo, hack this

66

67float majScale[] = {

68 A, B, CS, D, E, FS, GS, A2, B2, C2S, D2, E2, F2S, G2S, A3};
69

70void setup() {

71 Serial.begin(9600);

72}

73

74

75void loop(){

76 for(i= 0; i<=11; i++){

77 ps = (float)i / 12; // choose new transpose interval every loop

78 for(x= 0; x<=15; x++){

79 noteval = (majScale[x] / oct4) * pow(2,ps); // transpose scale up 12


tones

80// pow function generates transposition

81// eliminate " * pow(2,ps) " to cut out transpose routine

82

83 dur = 100;

84 freqout((int)noteval, dur);

85

86 delay(10);

87 }

88 }

89}

90

91void freqout(int freq, int t) // freq in hz, t in ms

92{
93 int hperiod; //calculate 1/2 period in us

94 long cycles, i;

95 pinMode(outpin, OUTPUT); // turn on output pin

96

97 hperiod = (500000 / freq) - 7; // subtract 7 us to make up for


digitalWrite overhead

98

99 cycles = ((long)freq * (long)t) / 1000; // calculate cycles

100 // Serial.print(freq);

101 // Serial.print((char)9); // ascii 9 is tab - you have to coerce it


to a char to work

102 // Serial.print(hperiod);

103 // Serial.print((char)9);

104 // Serial.println(cycles);

105

106 for (i=0; i<= cycles; i++){ // play note for t ms

107 digitalWrite(outpin, HIGH);

108 delayMicroseconds(hperiod);

109 digitalWrite(outpin, LOW);

110 delayMicroseconds(hperiod - 1); // - 1 to make up for digitaWrite


overhead

111 }

112pinMode(outpin, INPUT); // shut off pin to avoid noise from other


operations

113

114}
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

1float EIGHTH = 1;

2 float QUARTER = 2;

3 float DOTTED_QUARTER =3;

4 float HALF = 4;

5 float ETERNITY =-1;

6 float TEMPO = 150;

8 float majScale[] = {

9 A,QUARTER, B,QUARTER, CS,QUARTER, D,QUARTER, E,QUARTER,


FS,QUARTER, GS,QUARTER, A2,QUARTER, B2,QUARTER,

10 C2S,QUARTER, D2,QUARTER, E2,QUARTER, F2S,QUARTER,


G2S,QUARTER, A3,QUARTER, REST,ETERNITY

11 };

12

13 float odeToJoy[] = {

14 F2S,QUARTER, F2S,QUARTER, G2,QUARTER, A3,QUARTER, A3,QUARTER,


G2,QUARTER, F2S,QUARTER, E2,QUARTER, D2,QUARTER,

15 D2,QUARTER, E2,QUARTER, F2S,QUARTER, F2S,DOTTED_QUARTER,


E2,EIGHTH, E2,HALF, F2S,QUARTER, F2S,QUARTER, G2,QUARTER,

16 A3,QUARTER, A3,QUARTER,G2,QUARTER, F2S,QUARTER, E2,QUARTER,


D2,QUARTER, D2,QUARTER, E2,QUARTER, F2S,QUARTER,
E2,DOTTED_QUARTER,
17 D2,EIGHTH, D2,HALF, E2,QUARTER, E2,QUARTER, F2S,QUARTER,
D2,QUARTER, E2,QUARTER, F2S,EIGHTH, G2,EIGHTH, F2S,QUARTER,
D2,QUARTER,

18 E2,QUARTER, F2S,EIGHTH, G2,EIGHTH, F2S,QUARTER, E2,QUARTER,


D2,QUARTER, E2,QUARTER, A,QUARTER, REST,ETERNITY

19 };

20

21 void play(float song[]) {

22 for(x= 0; x<10000; x=x+2) {

23 noteval = (song[x] / 64);

24 dur = TEMPO * song[x+1];

25 if(dur < 0) {

26 break;

27 freqout((int)noteval, dur);

28 delay(10);

29 }

30 }

31 }

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

1///////////////////////////////////////

2// Smoothstep Interpolation Example //

3///////////////////////////////////////

5// Dan Thompson 2009

6//

7// Inpired by the code and chat on this site.

8// https://sol.gfxile.net/interpolation/

9//

10// Use this code at your own risk.

11//

12// This sketch was written with motion controlled timelapse photography
13// in mind. I have tried to make it generic enough to understand the
smoothstep

14// concept so that one might adapt this powerful formula in other areas as
well.

15//

16// For the full tutorial visit https://danthompsonsblog.blogspot.com/

17//

18// Usage:

19// 1. Upload the sketch to the Arduino.

20// 2. Click on the Serial monitor to see some visual feed back of the
SMOOTHSTEP function.

21// 3. Scroll through the print out to see the SMOOTHSTEP curve.

22// 4. Play with the code and adapt it to your needs! ;)

23

24#define SMOOTHSTEP(x) ((x) _ (x) _ (3 - 2 \* (x))) //SMOOTHSTEP


expression.

25

26int j = 0; //Just an Iterator.

27int i = 0; //Just another Iterator.

28float A = 0.0; //Input Min Value

29float B = 100.0; //Input Max Value

30float N = 100.0; //Input number of steps for transition

31float X; //final smoothstepped value

32float v; //smoothstep expression variable

33

34void setup() {

35Serial.begin(9600); //establish serial connection for debugging


36}

37

38void loop()

39{

40if (j < N) // Keep looping until we hit the pre-defined max number

41// of steps

42{

43v = j / N; // Iteration divided by the number of steps.

44v = SMOOTHSTEP(v); // Run the smoothstep expression on v.

45X = (B _ v) + (A _ (1 - v)); // Run the linear interpolation expression using


the current

46//smoothstep result.

47for ( i=0; i < X ; i++) // This loop could the relevant code for each time
your

48//motor steps.

49{

50Serial.print("1"); //Prints the number "1" for each step.

51 }

52Serial.print(" "); //Puts a space between each line of steps and their

53//corresponding float value

54Serial.println(X); // prints the soothstepped value

55Serial.println("CLICK!!!"); // this could be where you trigger your timelapse


shutter

56j++; // Increments j by 1.

57}

58}
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

1#include <stdint.h>

2#include <avr/interrupt.h>

3#include <avr/io.h>

4#include <avr/pgmspace.h>

6#define SAMPLE_RATE 8000

8/*
9* The audio data needs to be unsigned, 8-bit, 8000 Hz, and small enough

10* to fit in flash. 10000-13000 samples is about the limit.

11*

12* sounddata.h should look like this:

13* const int sounddata_length=10000;

14* const unsigned char sounddata_data[] PROGMEM = { ..... };

15*

16* You can use wav2c from GBA CSS:

17* https://thieumsweb.free.fr/english/gbacss.html

18* Then add "PROGMEM" in the right place. I hacked it up to dump the
samples

19* as unsigned rather than signed, but it shouldn't matter.

20*

21* https://musicthing.blogspot.com/2005/05/tiny-music-makers-pt-4-mac-
startup.html

22* mplayer -ao pcm macstartup.mp3

23* sox audiodump.wav -v 1.32 -c 1 -r 8000 -u -1 macstartup-8000.wav

24* sox macstartup-8000.wav macstartup-cut.wav trim 0 10000s

25* wav2c macstartup-cut.wav sounddata.h sounddata

26*

27* (starfox) nb. under sox 12.18 (distributed in CentOS 5), i needed to run

28* the following command to convert my wav file to the appropriate format:

29* sox audiodump.wav -c 1 -r 8000 -u -b macstartup-8000.wav

30*/

31

32#include "sounddata.h"
33

34int ledPin = 13;

35int speakerPin = 11; // Can be either 3 or 11, two PWM outputs connected
to Timer 2

36volatile uint16_t sample;

37byte lastSample;

38

39

40void stopPlayback()

41{

42 // Disable playback per-sample interrupt.

43 TIMSK1 &= ~_BV(OCIE1A);

44

45 // Disable the per-sample timer completely.

46 TCCR1B &= ~_BV(CS10);

47

48 // Disable the PWM timer.

49 TCCR2B &= ~_BV(CS10);

50

51 digitalWrite(speakerPin, LOW);

52}

53

54// This is called at 8000 Hz to load the next sample.

55ISR(TIMER1_COMPA_vect) {

56 if (sample >= sounddata_length) {


57 if (sample == sounddata_length + lastSample) {

58 stopPlayback();

59 }

60 else {

61 if(speakerPin==11){

62 // Ramp down to zero to reduce the click at the end of playback.

63 OCR2A = sounddata_length + lastSample - sample;

64 } else {

65 OCR2B = sounddata_length + lastSample - sample;

66 }

67 }

68 }

69 else {

70 if(speakerPin==11){

71 OCR2A = pgm_read_byte(&sounddata_data[sample]);

72 } else {

73 OCR2B = pgm_read_byte(&sounddata_data[sample]);

74 }

75 }

76

77 ++sample;

78}

79

80void startPlayback()

81{
82 pinMode(speakerPin, OUTPUT);

83

84 // Set up Timer 2 to do pulse width modulation on the speaker

85 // pin.

86

87 // Use internal clock (datasheet p.160)

88 ASSR &= ~(_BV(EXCLK) | _BV(AS2));

89

90 // Set fast PWM mode (p.157)

91 TCCR2A |= _BV(WGM21) | _BV(WGM20);

92 TCCR2B &= ~_BV(WGM22);

93

94 if(speakerPin==11){

95 // Do non-inverting PWM on pin OC2A (p.155)

96 // On the Arduino this is pin 11.

97 TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);

98 TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));

99 // No prescaler (p.158)

100 TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

101

102 // Set initial pulse width to the first sample.

103 OCR2A = pgm_read_byte(&sounddata_data[0]);

104 } else {

105 // Do non-inverting PWM on pin OC2B (p.155)

106 // On the Arduino this is pin 3.


107 TCCR2A = (TCCR2A | _BV(COM2B1)) & ~_BV(COM2B0);

108 TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0));

109 // No prescaler (p.158)

110 TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

111

112 // Set initial pulse width to the first sample.

113 OCR2B = pgm_read_byte(&sounddata_data[0]);

114 }

115

116

117

118

119

120 // Set up Timer 1 to send a sample every interrupt.

121

122 cli();

123

124 // Set CTC mode (Clear Timer on Compare Match) (p.133)

125 // Have to set OCR1A *after*, otherwise it gets reset to 0!

126 TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);

127 TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

128

129 // No prescaler (p.134)

130 TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

131
132 // Set the compare register (OCR1A).

133 // OCR1A is a 16-bit register, so we have to do this with

134 // interrupts disabled to be safe.

135 OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000

136

137 // Enable interrupt when TCNT1 == OCR1A (p.136)

138 TIMSK1 |= _BV(OCIE1A);

139

140 lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);

141 sample = 0;

142 sei();

143}

144

145

146void setup()

147{

148 pinMode(ledPin, OUTPUT);

149 digitalWrite(ledPin, HIGH);

150 startPlayback();

151}

152

153void loop()

154{

155 while (true);

156}
The above sketch also requires the

sounddata.h
file which you can find below:

Copy

1// sounddata sound made by wav2c

2// (wav2c modified to use unsigned samples)

4/_ const int sounddata_sampleRate=8000; _/

5const int sounddata_length=10000;

7const unsigned char sounddata_data[] PROGMEM = {

8128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128,

9128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128,

10128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128,

11128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128,

12128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128,

13128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128,

14128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128,

15128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128,

16128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128,
17128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
129, 127, 129, 128, 127, 133,

18117, 109, 125, 121, 116, 132, 140, 126, 114, 114, 116, 120, 114, 93, 73,
66, 76, 116, 142, 129,

19128, 129, 120, 119, 118, 104, 87, 123, 181, 194, 196, 198, 189, 176, 160,
162, 172, 164, 164, 183,

20197, 188, 168, 167, 170, 165, 185, 209, 206, 196, 196, 199, 185, 162,
156, 167, 176, 173, 170, 166,

21151, 142, 140, 134, 130, 127, 113, 86, 67, 66, 69, 75, 73, 75, 86, 90, 91,
84, 65, 48,

2241, 30, 26, 56, 91, 88, 72, 70, 73, 82, 89, 73, 57, 60, 74, 89, 92, 77, 63,
60,

2353, 47, 56, 64, 63, 61, 56, 54, 52, 36, 16, 22, 51, 66, 67, 70, 76, 88, 99,
92,

2477, 74, 85, 100, 106, 97, 83, 85, 96, 108, 133, 160, 164, 144, 113, 96, 91,
82, 74, 76,

2589, 97, 97, 97, 82, 54, 40, 41, 41, 43, 56, 74, 78, 64, 55, 64, 72, 72, 84,
102,

26108, 116, 126, 127, 124, 127, 134, 134, 138, 148, 152, 156, 164, 165,
169, 171, 160, 156, 157, 152,

27151, 145, 133, 136, 153, 166, 165, 163, 165, 161, 156, 158, 155, 147,
148, 160, 185, 209, 215, 220,

28220, 204, 200, 208, 205, 200, 202, 209, 214, 213, 205, 198, 194, 194,
203, 219, 231, 235, 230, 219,

29200, 184, 177, 170, 170, 177, 172, 164, 163, 158, 156, 160, 163, 161,
142, 116, 103, 96, 89, 93,

30101, 105, 111, 116, 120, 110, 89, 80, 78, 75, 73, 80, 93, 91, 77, 69, 70,
77, 91, 98,

3189, 87, 93, 95, 95, 94, 97, 96, 91, 94, 99, 100, 101, 95, 83, 78, 79, 71, 56,
41,

3237, 53, 64, 63, 72, 82, 83, 82, 80, 73, 67, 69, 69, 66, 68, 79, 99, 121, 143,
165,
33180, 174, 148, 131, 122, 112, 115, 120, 121, 126, 122, 108, 87, 72, 71,
73, 79, 81, 83, 86,

3483, 77, 70, 71, 85, 100, 112, 118, 130, 146, 154, 166, 174, 172, 172, 161,
147, 146, 153, 157,

35161, 165, 168, 170, 162, 138, 122, 121, 121, 123, 128, 138, 151, 161,
165, 161, 153, 150, 149, 147,

36136, 129, 140, 150, 156, 176, 194, 193, 179, 168, 167, 174, 185, 188,
181, 174, 164, 156, 156, 155,

37163, 185, 210, 224, 229, 235, 233, 215, 195, 176, 168, 170, 171, 168,
162, 162, 163, 165, 174, 181,

38184, 172, 151, 135, 125, 125, 132, 138, 139, 139, 139, 133, 121, 116,
117, 115, 104, 94, 94, 94,

3992, 90, 82, 70, 64, 69, 77, 82, 87, 85, 85, 92, 97, 105, 112, 108, 103, 107,
116, 122,

40121, 115, 101, 87, 80, 71, 67, 72, 70, 68, 78, 82, 78, 78, 79, 81, 79, 68,
59, 57,

4153, 60, 83, 106, 125, 146, 174, 192, 188, 186, 180, 161, 155, 157, 158,
156, 152, 148, 131, 117,

42111, 100, 97, 101, 104, 107, 110, 113, 112, 108, 106, 108, 122, 130, 141,
164, 175, 180, 185, 186,

43186, 182, 174, 167, 155, 150, 154, 155, 143, 132, 136, 139, 127, 114,
108, 107, 104, 103, 114, 120,

44124, 131, 134, 132, 123, 115, 109, 101, 108, 130, 144, 154, 161, 171,
184, 184, 171, 155, 147, 155,

45165, 165, 151, 142, 144, 136, 137, 152, 158, 162, 177, 200, 209, 206,
201, 181, 163, 159, 154, 154,

46151, 146, 161, 176, 170, 168, 175, 181, 176, 160, 148, 141, 138, 140,
140, 139, 140, 148, 155, 152,

47146, 135, 123, 111, 103, 110, 113, 100, 81, 62, 55, 52, 40, 33, 38, 60, 86,
95, 99, 106,

48111, 113, 105, 91, 87, 94, 101, 106, 103, 90, 76, 67, 63, 68, 72, 68, 63,
58, 68, 86,
4982, 68, 60, 56, 53, 45, 37, 40, 58, 77, 92, 110, 128, 149, 169, 174, 161,
151, 144, 139,

50142, 146, 146, 147, 142, 132, 129, 127, 116, 99, 94, 103, 113, 119, 122,
128, 133, 128, 119, 118,

51132, 160, 193, 215, 221, 222, 226, 224, 217, 211, 200, 181, 166, 158,
152, 148, 139, 125, 118, 118,

52119, 122, 123, 123, 124, 126, 127, 124, 127, 141, 143, 131, 118, 107,
110, 127, 146, 159, 163, 165,

53166, 164, 164, 160, 146, 131, 124, 135, 147, 145, 140, 138, 130, 124,
130, 136, 145, 163, 177, 182,

54181, 179, 177, 169, 159, 154, 155, 165, 176, 184, 195, 195, 183, 173,
163, 156, 158, 160, 159, 165,

55171, 164, 154, 154, 159, 167, 170, 167, 157, 141, 128, 120, 115, 111,
102, 95, 87, 64, 50, 49,

5645, 54, 77, 101, 123, 136, 139, 136, 128, 119, 112, 105, 101, 110, 123,
112, 94, 88, 78, 72,

5783, 89, 80, 69, 65, 57, 58, 64, 59, 53, 39, 16, 18, 36, 46, 66, 92, 107, 119,
135,

58145, 150, 160, 158, 147, 145, 144, 150, 160, 153, 150, 150, 140, 128,
120, 116, 104, 91, 88, 90,

59106, 123, 123, 123, 114, 100, 105, 119, 142, 181, 211, 222, 220, 214,
208, 204, 201, 186, 171, 166,

60162, 154, 138, 128, 120, 101, 93, 94, 103, 119, 117, 109, 109, 112, 119,
121, 121, 124, 122, 119,

61117, 124, 142, 158, 174, 183, 173, 168, 165, 149, 135, 132, 126, 119,
124, 127, 125, 133, 126, 111,

62116, 123, 127, 135, 145, 157, 167, 174, 176, 177, 182, 181, 184, 194,
194, 198, 213, 219, 219, 219,

63206, 184, 164, 153, 154, 163, 166, 162, 165, 164, 154, 154, 160, 161,
165, 166, 158, 146, 140, 130,

64122, 121, 109, 95, 89, 74, 61, 65, 74, 88, 110, 132, 149, 159, 149, 124,
107, 99, 91, 92,
6598, 101, 101, 90, 81, 84, 86, 82, 82, 80, 68, 58, 56, 53, 47, 42, 37, 35, 35,
30,

6628, 31, 40, 56, 74, 91, 99, 98, 101, 110, 114, 111, 110, 119, 127, 133,
140, 139, 128, 118,

67116, 109, 94, 87, 83, 79, 89, 110, 119, 116, 117, 117, 114, 117, 116, 119,
137, 164, 191, 204,

68192, 180, 180, 175, 161, 152, 149, 139, 128, 122, 111, 98, 89, 88, 93, 97,
94, 98, 104, 101,

69107, 119, 117, 121, 140, 152, 157, 164, 165, 171, 183, 190, 194, 191,
182, 172, 166, 154, 137, 132,

70134, 134, 138, 141, 130, 120, 123, 123, 120, 117, 109, 110, 125, 150,
168, 164, 163, 179, 196, 210,

71218, 220, 224, 227, 230, 238, 237, 218, 205, 202, 194, 189, 188, 184,
181, 181, 182, 174, 162, 161,

72168, 181, 194, 187, 176, 170, 156, 151, 143, 127, 125, 125, 116, 103, 94,
95, 107, 124, 145, 161,

73159, 151, 153, 145, 123, 106, 95, 85, 82, 86, 87, 78, 74, 79, 79, 73, 64,
58, 62, 62,

7464, 59, 43, 41, 53, 59, 57, 51, 47, 49, 71, 99, 107, 105, 98, 87, 93, 109,
117, 114,

75110, 113, 120, 132, 136, 131, 129, 123, 112, 105, 97, 95, 103, 115, 123,
125, 130, 140, 145, 145,

76137, 134, 142, 147, 157, 176, 187, 183, 171, 157, 142, 132, 132, 133,
131, 127, 111, 92, 84, 83,

7781, 72, 63, 60, 69, 90, 112, 122, 115, 112, 124, 131, 135, 144, 145, 149,
161, 174, 184, 181,

78171, 160, 148, 143, 138, 127, 119, 119, 126, 130, 120, 107, 100, 99, 104,
109, 105, 95, 95, 106,

79121, 138, 149, 158, 165, 170, 183, 200, 214, 227, 233, 236, 236, 225,
214, 206, 194, 188, 181, 173,

80174, 175, 176, 174, 164, 159, 159, 153, 149, 150, 154, 166, 172, 160,
146, 136, 130, 131, 127, 112,
8196, 91, 97, 107, 117, 125, 125, 120, 119, 120, 119, 112, 96, 80, 70, 65,
67, 69, 63, 63,

8261, 48, 41, 46, 58, 73, 84, 91, 90, 85, 88, 88, 84, 79, 74, 84, 94, 99, 116,
128,

83122, 111, 104, 99, 96, 101, 117, 128, 127, 124, 130, 139, 139, 138, 133,
115, 105, 115, 131, 141,

84147, 149, 147, 149, 159, 162, 159, 158, 155, 156, 160, 162, 168, 168,
163, 166, 168, 148, 121, 118,

85128, 127, 127, 124, 108, 93, 85, 76, 67, 56, 58, 82, 102, 108, 122, 137,
135, 131, 134, 133,

86135, 145, 158, 165, 166, 167, 161, 152, 151, 147, 140, 128, 117, 116,
116, 113, 117, 115, 108, 105,

87105, 99, 91, 98, 112, 115, 120, 133, 145, 158, 171, 182, 188, 190, 201,
222, 235, 239, 241, 245,

88239, 230, 224, 214, 196, 178, 176, 183, 191, 200, 199, 189, 175, 159,
148, 140, 135, 150, 173, 185,

89185, 178, 157, 135, 125, 115, 104, 101, 102, 100, 95, 93, 91, 81, 73, 74,
80, 87, 77, 72,

9072, 56, 45, 47, 45, 42, 39, 37, 27, 16, 24, 54, 82, 92, 91, 94, 92, 88, 84,
75,

9173, 80, 93, 113, 127, 129, 117, 107, 100, 90, 85, 82, 83, 101, 122, 134,
139, 141, 137, 130,

92126, 116, 108, 120, 145, 168, 176, 173, 165, 151, 142, 144, 146, 149,
150, 155, 163, 158, 152, 144,

93136, 140, 142, 136, 132, 126, 123, 122, 118, 120, 120, 115, 115, 108, 91,
82, 85, 98, 120, 144,

94163, 171, 156, 138, 134, 129, 123, 128, 140, 155, 166, 169, 157, 140,
132, 125, 121, 121, 115, 110,

95115, 113, 101, 92, 87, 83, 83, 86, 85, 81, 88, 106, 120, 127, 126, 121,
126, 144, 161, 167,

96166, 173, 196, 217, 224, 226, 220, 211, 213, 217, 208, 200, 197, 187,
184, 190, 194, 198, 199, 186,
97174, 167, 160, 160, 173, 188, 198, 206, 200, 181, 169, 152, 130, 119,
110, 110, 125, 126, 115, 102,

9883, 68, 66, 72, 75, 79, 75, 61, 51, 49, 43, 38, 40, 41, 35, 32, 39, 48, 59,
72,

9987, 98, 91, 87, 92, 84, 71, 66, 73, 91, 110, 123, 127, 113, 95, 88, 82, 76,
76, 84,

10096, 109, 119, 123, 129, 127, 119, 121, 122, 126, 139, 148, 162, 173,
169, 158, 142, 127, 121, 121,

101124, 125, 134, 149, 154, 158, 145, 119, 114, 119, 119, 128, 140, 142,
138, 130, 123, 125, 128, 125,

102128, 137, 141, 147, 157, 156, 149, 158, 174, 171, 153, 139, 127, 123,
130, 136, 151, 166, 166, 158,

103144, 130, 122, 113, 110, 115, 119, 122, 122, 112, 96, 85, 82, 79, 82, 95,
108, 112, 107, 103,

104111, 126, 125, 113, 118, 129, 136, 149, 162, 173, 184, 194, 198, 186,
179, 191, 197, 190, 190, 198,

105201, 193, 187, 185, 188, 197, 202, 206, 212, 213, 207, 198, 191, 193,
203, 203, 191, 178, 160, 137,

106123, 116, 112, 120, 129, 122, 103, 88, 80, 63, 47, 46, 56, 65, 54, 41, 42,
45, 46, 47,

10754, 64, 60, 61, 77, 79, 73, 90, 111, 109, 98, 100, 102, 93, 88, 95, 116,
137, 141, 140,

108137, 122, 104, 97, 99, 101, 106, 110, 115, 127, 130, 129, 139, 148, 146,
143, 147, 144, 139, 149,

109168, 172, 155, 139, 129, 117, 107, 110, 121, 133, 144, 153, 154, 138,
118, 103, 94, 96, 112, 136,

110150, 143, 129, 125, 129, 133, 145, 158, 156, 149, 151, 156, 160, 162,
160, 153, 143, 131, 117, 107,

111107, 110, 113, 123, 134, 131, 118, 111, 112, 104, 90, 99, 118, 121, 123,
131, 121, 104, 101, 112,

112127, 132, 127, 126, 128, 125, 118, 125, 133, 123, 111, 107, 113, 124,
133, 150, 170, 179, 181, 183,
113184, 180, 176, 182, 188, 193, 198, 205, 213, 211, 209, 215, 222, 226,
225, 228, 232, 224, 204, 190,

114192, 199, 196, 193, 186, 168, 151, 136, 126, 125, 126, 123, 112, 95, 77,
64, 53, 40, 32, 34,

11543, 47, 44, 40, 42, 48, 50, 48, 51, 50, 47, 52, 57, 63, 75, 81, 88, 95, 96,
98,

11697, 88, 89, 111, 137, 148, 149, 144, 125, 109, 101, 101, 109, 120, 123,
124, 135, 142, 143, 153,

117160, 156, 152, 148, 141, 135, 131, 128, 129, 126, 113, 105, 108, 101,
88, 91, 99, 104, 114, 118,

118116, 114, 98, 78, 78, 91, 101, 119, 134, 135, 134, 135, 142, 157, 162,
155, 150, 147, 140, 140,

119151, 154, 145, 133, 119, 115, 116, 102, 91, 99, 106, 106, 109, 104, 92,
89, 87, 82, 85, 91,

120102, 123, 134, 131, 129, 121, 116, 126, 133, 132, 127, 121, 113, 114,
121, 124, 123, 118, 110, 113,

121119, 114, 117, 137, 153, 158, 160, 159, 158, 158, 156, 152, 154, 163,
176, 193, 210, 213, 206, 205,

122209, 214, 223, 226, 220, 217, 209, 199, 198, 192, 182, 178, 178, 174,
161, 151, 153, 150, 145, 136,

123119, 104, 86, 68, 60, 49, 44, 52, 61, 68, 69, 58, 52, 56, 57, 57, 60, 56,
49, 51,

12459, 69, 74, 80, 95, 115, 130, 134, 133, 134, 134, 145, 168, 173, 168,
168, 162, 149, 145, 147,

125154, 168, 178, 183, 184, 174, 166, 168, 175, 174, 160, 154, 152, 138,
131, 133, 126, 111, 100, 94,

12697, 93, 86, 97, 105, 101, 102, 107, 108, 102, 92, 87, 89, 97, 117, 149,
170, 162, 148, 150,

127159, 168, 176, 176, 165, 147, 133, 131, 137, 138, 130, 122, 119, 117,
114, 110, 104, 104, 107, 101,

12896, 91, 82, 81, 83, 79, 82, 100, 122, 141, 147, 140, 132, 121, 113, 119,
125, 122, 111, 103,
129108, 113, 117, 124, 120, 116, 119, 117, 128, 142, 141, 148, 159, 161,
163, 169, 171, 171, 176, 183,

130186, 181, 187, 202, 205, 198, 192, 192, 193, 195, 203, 204, 191, 184,
182, 179, 189, 195, 185, 180,

131176, 165, 159, 161, 162, 155, 142, 130, 121, 104, 78, 66, 65, 46, 34, 51,
65, 66, 62, 48,

13235, 34, 36, 35, 42, 49, 49, 53, 57, 57, 66, 76, 84, 95, 109, 120, 130, 137,
129, 122,

133133, 143, 148, 152, 152, 157, 165, 164, 168, 183, 186, 181, 188, 189,
176, 171, 173, 173, 165, 149,

134140, 139, 139, 134, 127, 118, 95, 78, 82, 82, 75, 76, 69, 64, 78, 90, 85,
80, 79, 83,

13598, 117, 131, 145, 153, 153, 153, 151, 151, 155, 157, 152, 146, 146,
141, 133, 136, 134, 125, 123,

136121, 123, 136, 137, 117, 102, 94, 84, 90, 98, 87, 82, 93, 104, 108, 115,
130, 138, 135, 128,

137125, 122, 114, 113, 112, 101, 99, 107, 109, 110, 114, 117, 113, 103,
102, 118, 141, 151, 146, 144,

138151, 165, 181, 181, 176, 181, 179, 177, 185, 190, 188, 185, 182, 174,
172, 175, 172, 177, 185, 187,

139187, 183, 181, 192, 203, 202, 185, 175, 188, 200, 200, 190, 175, 162,
152, 146, 141, 128, 112, 104,

14094, 76, 69, 77, 78, 73, 63, 51, 36, 24, 28, 39, 47, 54, 55, 54, 59, 67, 74,
74,

14173, 86, 103, 113, 121, 126, 125, 127, 136, 142, 145, 155, 169, 183, 185,
178, 170, 166, 172, 183,

142190, 187, 172, 166, 172, 167, 161, 158, 145, 134, 126, 115, 108, 94, 74,
66, 67, 63, 58, 61,

14362, 65, 74, 73, 66, 69, 85, 103, 117, 131, 137, 139, 148, 152, 146, 138,
138, 144, 140, 133,

144140, 150, 140, 128, 129, 124, 116, 118, 121, 124, 128, 128, 116, 96, 86,
91, 105, 116, 115, 117,
145127, 128, 130, 140, 147, 145, 138, 123, 118, 126, 125, 112, 102, 101,
106, 112, 110, 112, 113, 102,

14692, 93, 102, 117, 141, 164, 165, 155, 161, 173, 176, 178, 181, 192, 198,
188, 181, 185, 183, 172,

147165, 159, 158, 164, 163, 158, 164, 171, 169, 164, 164, 176, 190, 194,
185, 173, 169, 179, 189, 186,

148179, 169, 157, 141, 127, 126, 124, 109, 93, 80, 74, 78, 77, 65, 46, 33,
32, 34, 33, 38,

14951, 62, 58, 52, 59, 68, 69, 68, 79, 96, 109, 117, 120, 127, 134, 139, 148,
148, 152, 175,

150191, 190, 190, 191, 183, 166, 160, 171, 189, 199, 189, 169, 157, 161,
171, 173, 166, 155, 144, 129,

151112, 107, 107, 96, 86, 88, 86, 83, 82, 83, 89, 88, 89, 96, 95, 106, 133,
152, 149, 130,

152123, 127, 122, 123, 131, 132, 132, 130, 124, 120, 120, 121, 123, 123,
123, 128, 132, 131, 132, 130,

153118, 103, 97, 113, 142, 163, 164, 149, 132, 127, 133, 142, 146, 146,
137, 116, 102, 103, 103, 97,

15495, 96, 100, 108, 106, 98, 97, 94, 87, 80, 82, 102, 138, 167, 171, 159,
151, 154, 168, 183,

155189, 188, 188, 182, 172, 168, 169, 166, 154, 148, 153, 156, 155, 154,
159, 170, 169, 156, 151, 167,

156193, 208, 199, 177, 169, 177, 188, 193, 191, 183, 170, 155, 139, 120,
110, 105, 96, 89, 83, 75,

15771, 60, 42, 32, 28, 22, 21, 30, 51, 71, 70, 53, 42, 42, 51, 63, 75, 95, 116,
127,

158128, 125, 132, 145, 153, 163, 171, 176, 184, 193, 196, 190, 183, 174,
159, 157, 173, 185, 183, 170,

159160, 165, 177, 184, 176, 157, 139, 125, 107, 96, 97, 97, 98, 100, 95, 93,
97, 99, 103, 100,

16089, 89, 98, 113, 137, 148, 145, 129, 106, 97, 96, 97, 102, 108, 118, 124,
119, 112, 110, 110,
161116, 126, 125, 125, 139, 151, 153, 150, 137, 126, 128, 138, 156, 168,
169, 159, 150, 145, 141, 141,

162145, 140, 125, 109, 95, 88, 86, 86, 92, 96, 97, 99, 99, 97, 92, 80, 67, 73,
96, 117,

163139, 157, 162, 164, 160, 158, 164, 167, 169, 172, 171, 167, 160, 154,
148, 144, 142, 142, 146, 151,

164153, 160, 172, 172, 168, 172, 173, 179, 192, 192, 188, 186, 178, 182,
193, 194, 194, 185, 169, 152,

165133, 115, 98, 86, 84, 80, 73, 67, 56, 43, 37, 31, 24, 27, 32, 34, 51, 68,
65, 56,

16654, 57, 63, 74, 91, 106, 123, 141, 154, 164, 170, 170, 173, 186, 193,
193, 199, 200, 196, 187,

167172, 163, 158, 155, 167, 174, 168, 166, 166, 165, 174, 180, 167, 151,
143, 131, 115, 111, 110, 106,

168106, 116, 126, 129, 122, 111, 104, 95, 85, 95, 113, 117, 122, 125, 116,
102, 86, 76, 79, 85,

16986, 88, 93, 93, 95, 101, 98, 99, 109, 115, 120, 130, 136, 138, 140, 144,
147, 148, 146, 144,

170153, 160, 159, 155, 146, 138, 137, 135, 127, 118, 112, 105, 97, 93, 87,
79, 83, 97, 100, 90,

17187, 91, 83, 63, 62, 78, 90, 113, 150, 172, 169, 159, 153, 154, 160, 165,
166, 162, 158, 156,

172156, 157, 154, 155, 161, 162, 162, 169, 169, 168, 175, 178, 180, 194,
205, 202, 197, 199, 198, 188,

173178, 182, 202, 210, 190, 168, 158, 141, 123, 118, 110, 91, 77, 76, 70,
56, 51, 50, 40, 30,

17428, 32, 33, 34, 50, 64, 62, 69, 80, 75, 78, 94, 105, 121, 147, 175, 196,
198, 197, 206,

175214, 217, 218, 216, 210, 199, 191, 175, 160, 165, 172, 165, 164, 171,
172, 165, 158, 157, 161, 158,

176152, 151, 142, 124, 117, 118, 115, 122, 141, 154, 148, 131, 120, 112,
105, 102, 108, 112, 104, 100,
177105, 104, 98, 89, 76, 61, 53, 58, 62, 56, 56, 66, 72, 81, 98, 105, 101,
107, 125, 134,

178135, 135, 134, 136, 139, 142, 141, 138, 140, 143, 139, 128, 118, 114,
108, 101, 101, 106, 103, 89,

17975, 66, 61, 67, 83, 95, 94, 87, 76, 61, 49, 51, 62, 72, 89, 115, 139, 149,
146, 141,

180139, 139, 141, 139, 131, 129, 132, 138, 143, 148, 156, 163, 164, 166,
174, 178, 172, 170, 178, 194,

181217, 227, 220, 217, 225, 229, 225, 219, 213, 209, 204, 200, 194, 181,
169, 153, 132, 121, 110, 100,

18298, 100, 103, 94, 74, 59, 53, 49, 47, 47, 51, 57, 73, 93, 98, 94, 91, 95,
105, 118,

183141, 166, 183, 189, 192, 200, 200, 204, 214, 209, 204, 197, 181, 174,
165, 156, 160, 158, 151, 153,

184156, 155, 158, 157, 156, 164, 165, 163, 163, 151, 139, 140, 141, 145,
151, 155, 158, 160, 162, 151,

185127, 111, 112, 114, 110, 100, 90, 90, 98, 100, 94, 84, 70, 59, 50, 45, 47,
51, 59, 76,

18690, 104, 112, 111, 114, 131, 155, 165, 155, 145, 141, 141, 146, 140,
125, 124, 129, 126, 116, 110,

187106, 98, 90, 85, 82, 82, 78, 64, 47, 43, 51, 59, 65, 77, 90, 89, 73, 58, 57,
70,

18887, 94, 92, 106, 127, 138, 142, 137, 133, 135, 131, 123, 117, 115, 120,
126, 130, 139, 146, 147,

189148, 152, 156, 164, 168, 166, 181, 209, 230, 231, 222, 225, 236, 237,
231, 220, 210, 204, 196, 188,

190174, 156, 143, 130, 114, 101, 91, 80, 69, 68, 74, 77, 73, 59, 47, 46, 49,
55, 57, 56,

19163, 88, 113, 119, 120, 128, 131, 137, 153, 166, 179, 189, 193, 199, 200,
198, 200, 198, 191, 183,

192174, 165, 156, 156, 158, 151, 143, 147, 153, 155, 155, 150, 147, 162,
180, 186, 177, 159, 152, 155,
193153, 152, 154, 149, 146, 160, 159, 135, 120, 112, 110, 113, 107, 97, 85,
77, 84, 94, 88, 70,

19461, 59, 52, 51, 53, 48, 56, 94, 130, 138, 134, 129, 134, 150, 162, 168,
164, 151, 145, 144,

195137, 132, 128, 126, 129, 127, 129, 130, 115, 102, 95, 80, 74, 82, 82, 72,
61, 59, 61, 62,

19674, 99, 113, 106, 92, 85, 84, 86, 91, 96, 99, 110, 129, 138, 140, 140,
138, 137, 133, 124,

197120, 121, 126, 134, 140, 137, 136, 147, 161, 171, 176, 174, 170, 189,
221, 237, 238, 236, 232, 231,

198231, 232, 228, 216, 201, 190, 179, 164, 155, 150, 131, 111, 101, 90, 82,
72, 64, 68, 74, 75,

19976, 71, 61, 54, 49, 50, 54, 58, 78, 116, 136, 137, 132, 130, 134, 140,
153, 170, 175, 185,

200197, 202, 209, 210, 197, 185, 184, 181, 171, 161, 154, 151, 147, 143,
141, 144, 151, 156, 160, 173,

201190, 200, 205, 197, 180, 174, 169, 164, 165, 160, 152, 154, 155, 154,
149, 137, 122, 106, 94, 90,

20286, 80, 67, 56, 64, 72, 66, 57, 48, 40, 35, 34, 46, 70, 87, 99, 118, 129,
126, 129,

203135, 143, 149, 147, 147, 141, 129, 127, 132, 131, 121, 111, 120, 133,
132, 129, 121, 105, 90, 80,

20481, 91, 93, 85, 82, 88, 98, 109, 117, 122, 118, 112, 114, 111, 99, 101,
102, 87, 78, 90,

205113, 133, 140, 136, 128, 117, 109, 109, 109, 108, 113, 123, 131, 132,
135, 141, 148, 160, 171, 178,

206186, 196, 207, 213, 219, 225, 217, 207, 209, 214, 207, 188, 181, 180,
167, 155, 151, 138, 110, 87,

20780, 77, 68, 64, 65, 68, 71, 71, 69, 67, 62, 59, 64, 68, 61, 58, 78, 107,
130, 145,

208145, 139, 141, 145, 151, 164, 181, 196, 205, 212, 214, 205, 191, 181,
181, 187, 191, 183, 166, 156,
209155, 154, 143, 141, 157, 175, 188, 199, 205, 206, 202, 191, 181, 170,
162, 164, 167, 155, 140, 143,

210147, 142, 136, 122, 100, 83, 77, 83, 89, 79, 58, 47, 52, 61, 63, 53, 45,
47, 51, 59,

21171, 75, 75, 84, 97, 105, 107, 107, 112, 121, 129, 134, 138, 137, 124,
116, 118, 116, 105, 99,

212112, 134, 149, 145, 129, 116, 103, 99, 109, 118, 118, 115, 121, 129,
129, 128, 123, 114, 113, 114,

213115, 120, 117, 107, 106, 107, 104, 104, 115, 125, 127, 125, 121, 123,
125, 119, 116, 113, 110, 124,

214147, 152, 151, 165, 173, 173, 188, 202, 203, 203, 210, 217, 221, 220,
208, 199, 204, 208, 202, 196,

215186, 176, 164, 147, 129, 111, 93, 81, 74, 70, 63, 56, 55, 57, 70, 78, 74,
67, 61, 55,

21655, 58, 59, 55, 59, 85, 115, 130, 139, 148, 149, 153, 170, 182, 183, 185,
188, 189, 188, 190,

217195, 188, 181, 185, 188, 180, 168, 160, 163, 168, 161, 161, 179, 190,
194, 199, 200, 198, 195, 192,

218177, 158, 155, 158, 157, 151, 140, 134, 132, 122, 105, 94, 85, 80, 87,
94, 91, 81, 63, 49,

21955, 69, 78, 77, 72, 75, 90, 101, 100, 87, 74, 73, 87, 106, 111, 107, 110,
114, 117, 126,

220132, 122, 105, 92, 92, 99, 99, 95, 106, 122, 125, 128, 126, 112, 113,
135, 144, 134, 123, 119,

221119, 119, 117, 110, 106, 106, 103, 104, 114, 122, 127, 122, 112, 109,
106, 108, 117, 116, 113, 124,

222132, 131, 134, 136, 126, 114, 108, 122, 152, 170, 167, 164, 173, 184,
184, 182, 182, 189, 202, 210,

223212, 209, 202, 203, 208, 205, 200, 196, 188, 175, 163, 158, 151, 131,
104, 82, 74, 72, 70, 68,

22467, 71, 80, 83, 79, 70, 64, 58, 52, 51, 54, 60, 74, 89, 104, 127, 151, 156,
150, 161,
225179, 178, 164, 159, 168, 181, 189, 190, 190, 187, 181, 182, 187, 191,
195, 198, 193, 177, 166, 177,

226195, 196, 186, 184, 189, 187, 182, 185, 189, 178, 158, 143, 140, 139,
130, 119, 112, 106, 96, 86,

22785, 91, 96, 95, 87, 74, 64, 69, 81, 82, 78, 82, 91, 92, 92, 97, 97, 88, 73,
66,

22878, 99, 112, 118, 118, 109, 104, 111, 116, 113, 110, 107, 103, 99, 93,
96, 104, 106, 113, 125,

229128, 128, 135, 143, 145, 135, 120, 111, 108, 106, 104, 100, 96, 94, 97,
104, 109, 115, 117, 114,

230114, 107, 98, 105, 116, 115, 114, 122, 122, 114, 113, 121, 126, 118,
112, 121, 136, 146, 151, 159,

231172, 175, 166, 165, 175, 185, 190, 196, 203, 198, 192, 195, 195, 190,
186, 185, 181, 171, 160, 156,

232155, 141, 109, 86, 77, 74, 78, 83, 83, 83, 82, 83, 82, 77, 70, 66, 61, 54,
53, 67,

23384, 93, 103, 120, 133, 143, 154, 164, 173, 173, 156, 150, 162, 174, 178,
180, 180, 179, 179, 185,

234195, 199, 197, 196, 189, 184, 190, 204, 203, 186, 177, 183, 187, 186,
187, 191, 194, 187, 167, 147,

235136, 133, 130, 125, 121, 116, 108, 101, 95, 90, 89, 87, 85, 86, 90, 100,
100, 83, 79, 93,

236100, 93, 85, 80, 81, 83, 80, 80, 90, 98, 100, 106, 108, 108, 108, 107,
106, 109, 113, 108,

237100, 95, 92, 98, 103, 102, 115, 138, 146, 146, 145, 143, 150, 150, 131,
108, 94, 91, 95, 101,

238103, 104, 104, 94, 88, 93, 96, 99, 104, 104, 105, 115, 119, 108, 107,
117, 122, 116, 111, 125,

239147, 152, 143, 130, 129, 140, 152, 165, 173, 173, 172, 173, 176, 180,
189, 193, 189, 181, 179, 190,

240199, 190, 181, 177, 165, 149, 138, 132, 133, 128, 107, 88, 81, 84, 86,
83, 79, 77, 78, 76,
24168, 62, 56, 47, 40, 39, 53, 81, 98, 95, 104, 125, 143, 156, 163, 170, 176,
171, 162, 156,

242150, 156, 167, 169, 172, 179, 186, 192, 192, 182, 173, 175, 179, 176,
179, 188, 187, 182, 183, 189,

243197, 196, 185, 181, 182, 181, 175, 161, 147, 141, 133, 122, 122, 125,
114, 106, 100, 85, 77, 84,

24492, 89, 81, 82, 88, 89, 87, 91, 93, 77, 65, 66, 65, 70, 83, 84, 85, 95, 99,
102,

245111, 112, 108, 102, 96, 95, 94, 93, 89, 83, 79, 89, 104, 120, 139, 152,
154, 150, 149, 150,

246150, 151, 132, 104, 94, 91, 93, 107, 116, 107, 91, 83, 88, 94, 96, 95, 95,
95, 99, 113,

247128, 129, 131, 140, 139, 133, 138, 153, 163, 162, 156, 153, 158, 165,
170, 171, 174, 183, 186, 184,

248188, 190, 188, 185, 177, 174, 179, 187, 199, 201, 191, 180, 170, 157,
142, 135, 135, 127, 114, 112,

249117, 114, 100, 84, 82, 84, 77, 70, 64, 55, 47, 43, 38, 40, 53, 74, 94, 103,
115, 143,

250161, 162, 165, 165, 167, 178, 176, 161, 158, 168, 175, 181, 188, 192,
193, 186, 174, 173, 180, 181,

251176, 173, 171, 179, 194, 198, 196, 201, 203, 198, 190, 189, 197, 195,
180, 168, 158, 148, 139, 127,

252119, 121, 119, 113, 105, 88, 84, 98, 97, 80, 71, 80, 96, 102, 93, 82, 79,
76, 65, 61,

25371, 82, 85, 88, 94, 101, 105, 104, 100, 100, 96, 87, 81, 73, 71, 78, 76,
63, 59, 75,

254104, 124, 124, 127, 140, 147, 143, 134, 127, 128, 124, 107, 91, 87, 92,
101, 105, 98, 85, 82,

25581, 74, 76, 83, 85, 86, 86, 91, 109, 127, 131, 129, 134, 138, 140, 151,
161, 167, 175, 170,

256163, 169, 175, 178, 183, 183, 178, 181, 189, 187, 185, 189, 187, 178,
171, 178, 194, 198, 188, 172,
257156, 145, 141, 138, 129, 122, 123, 121, 120, 116, 106, 103, 99, 89, 81,
71, 57, 50, 51, 48,

25846, 51, 61, 80, 100, 110, 113, 124, 137, 148, 161, 166, 166, 171, 169,
157, 155, 160, 166, 175,

259184, 186, 180, 174, 168, 162, 159, 159, 157, 155, 159, 171, 184, 190,
195, 201, 201, 196, 191, 187,

260188, 185, 173, 161, 152, 146, 140, 132, 125, 127, 124, 109, 93, 80, 77,
86, 90, 85, 82, 87,

26188, 78, 67, 64, 69, 72, 72, 80, 91, 98, 102, 103, 103, 105, 112, 117, 115,
110, 98, 88,

26280, 67, 70, 84, 85, 75, 74, 83, 102, 119, 121, 126, 141, 142, 132, 124,
120, 123, 121, 109,

263103, 105, 108, 113, 114, 106, 96, 88, 82, 76, 76, 84, 90, 94, 103, 114,
126, 137, 135, 126,

264128, 142, 154, 161, 168, 175, 173, 162, 159, 164, 169, 178, 187, 189,
192, 188, 178, 170, 164, 164,

265171, 181, 183, 179, 178, 176, 163, 148, 140, 139, 134, 126, 118, 109,
108, 112, 115, 115, 110, 102,

26695, 86, 79, 75, 69, 66, 62, 58, 62, 65, 72, 83, 89, 96, 106, 116, 129, 141,
151, 156,

267161, 168, 173, 172, 164, 162, 169, 180, 190, 194, 193, 187, 175, 167,
156, 147, 160, 174, 181, 193,

268200, 202, 204, 203, 201, 196, 187, 182, 179, 177, 175, 169, 160, 150,
138, 135, 135, 135, 131, 116,

269102, 92, 85, 90, 103, 106, 99, 93, 90, 86, 84, 78, 78, 85, 89, 96, 102,
106, 107, 104,

270105, 115, 120, 123, 130, 127, 109, 95, 93, 90, 86, 84, 89, 88, 82, 90,
101, 108, 118, 124,

271124, 121, 118, 119, 118, 122, 128, 122, 110, 106, 108, 107, 103, 99, 93,
87, 84, 85, 83, 78,

27280, 85, 93, 107, 114, 121, 134, 138, 138, 141, 149, 159, 164, 170, 175,
172, 176, 189, 192, 190,
273193, 194, 193, 187, 178, 169, 164, 169, 177, 181, 181, 182, 175, 161,
150, 144, 138, 129, 121, 117,

274111, 103, 98, 95, 96, 101, 97, 89, 83, 83, 79, 71, 65, 63, 61, 57, 55, 55,
54, 61,

27568, 73, 87, 105, 119, 127, 129, 132, 142, 159, 168, 162, 155, 151, 155,
161, 165, 171, 175, 170,

276162, 156, 151, 152, 161, 167, 170, 179, 188, 191, 197, 200, 195, 185,
178, 179, 181, 185, 188, 182,

277172, 161, 150, 144, 136, 129, 124, 117, 107, 99, 97, 101, 109, 108, 100,
96, 94, 91, 92, 90,

27886, 89, 97, 99, 97, 99, 100, 99, 99, 104, 114, 122, 126, 123, 111, 100,
96, 94, 85, 76,

27975, 77, 79, 90, 108, 117, 124, 129, 129, 128, 128, 129, 128, 129, 137,
136, 119, 100, 90, 88,

28087, 89, 93, 97, 99, 100, 89, 72, 70, 84, 97, 105, 107, 110, 122, 132, 133,
135, 149, 160,

281159, 162, 171, 180, 185, 186, 189, 193, 194, 190, 184, 176, 169, 167,
163, 159, 163, 169, 172, 171,

282165, 153, 148, 149, 139, 129, 122, 114, 109, 106, 106, 113, 112, 102,
93, 89, 93, 100, 100, 97,

28399, 94, 79, 60, 48, 53, 64, 72, 81, 91, 103, 118, 124, 121, 124, 133, 145,
159, 167, 165,

284159, 153, 156, 162, 169, 182, 188, 187, 183, 177, 171, 163, 158, 169,
181, 183, 185, 186, 186, 192,

285194, 188, 183, 183, 182, 180, 176, 168, 160, 161, 156, 142, 139, 135,
123, 125, 127, 121, 114, 104,

28698, 97, 95, 101, 102, 88, 81, 87, 87, 83, 79, 79, 81, 83, 90, 95, 94, 100,
109, 113,

287112, 112, 113, 112, 107, 94, 75, 56, 51, 68, 83, 95, 108, 119, 125, 128,
132, 137, 135, 129,

288125, 131, 137, 127, 109, 102, 93, 78, 80, 95, 106, 113, 111, 99, 85, 78,
81, 89, 94, 96,
289101, 109, 119, 133, 146, 150, 148, 149, 154, 163, 175, 177, 172, 175,
186, 196, 201, 193, 183, 183,

290179, 170, 161, 151, 147, 148, 149, 151, 147, 138, 133, 127, 121, 115,
109, 104, 106, 115, 121, 113,

291102, 98, 101, 106, 104, 103, 105, 104, 104, 100, 87, 69, 57, 58, 68, 76,
92, 110, 113, 112,

292119, 120, 122, 132, 141, 147, 156, 160, 156, 157, 169, 181, 188, 197,
205, 210, 214, 207, 191, 181,

293173, 171, 181, 188, 187, 192, 195, 191, 189, 187, 183, 179, 176, 174,
175, 171, 160, 155, 152, 148,

294143, 137, 136, 141, 148, 144, 127, 114, 111, 110, 111, 109, 104, 97, 84,
76, 83, 85, 75, 76,

29581, 84, 92, 91, 87, 91, 98, 105, 115, 123, 119, 107, 96, 84, 71, 63, 68,
79, 84, 92,

296110, 125, 130, 126, 124, 127, 126, 125, 122, 124, 131, 123, 107, 94, 81,
74, 77, 86, 97, 102,

297103, 101, 94, 82, 75, 74, 79, 88, 100, 114, 121, 125, 132, 135, 134, 142,
150, 158, 167, 169,

298171, 173, 177, 191, 204, 203, 196, 191, 191, 185, 167, 153, 150, 152,
151, 153, 149, 135, 120, 112,

299115, 115, 113, 122, 130, 130, 130, 130, 125, 119, 116, 113, 110, 118,
127, 121, 110, 107, 96, 74,

30067, 73, 73, 76, 89, 99, 98, 92, 96, 108, 109, 106, 115, 127, 135, 144,
154, 159, 156, 163,

301188, 211, 215, 208, 205, 205, 200, 191, 188, 193, 192, 189, 187, 180,
175, 174, 177, 179, 174, 166,

302161, 161, 165, 162, 150, 140, 135, 134, 144, 157, 159, 154, 147, 146,
143, 126, 117, 118, 114, 110,

303107, 99, 82, 70, 72, 71, 63, 61, 69, 83, 89, 85, 86, 85, 80, 86, 104, 113,
105, 91,

30474, 63, 62, 61, 67, 77, 83, 96, 108, 106, 104, 107, 114, 124, 133, 134,
128, 121, 113, 103,
30592, 82, 73, 70, 79, 93, 102, 100, 92, 91, 92, 84, 78, 79, 85, 94, 102, 115,
121, 122,

306135, 145, 137, 132, 141, 151, 160, 171, 178, 183, 187, 193, 207, 219,
218, 212, 202, 194, 189, 175,

307159, 158, 156, 154, 152, 133, 110, 104, 105, 112, 126, 132, 132, 141,
144, 136, 126, 120, 122, 124,

308128, 140, 145, 134, 116, 103, 94, 82, 75, 82, 92, 99, 102, 100, 95, 92,
99, 112, 116, 110,

309109, 118, 126, 132, 142, 153, 163, 180, 199, 210, 211, 210, 212, 213,
212, 203, 193, 190, 191, 193,

310193, 186, 177, 174, 177, 185, 184, 171, 159, 153, 154, 155, 148, 141,
137, 138, 154, 177, 186, 183,

311178, 170, 153, 134, 124, 121, 125, 128, 121, 105, 80, 65, 61, 58, 57, 57,
62, 72, 79, 81,

31278, 73, 74, 85, 99, 102, 90, 72, 61, 59, 59, 59, 68, 81, 94, 95, 83, 87, 98,
105,

313121, 129, 121, 110, 98, 93, 88, 79, 72, 66, 63, 71, 85, 93, 92, 91, 93, 90,
83, 76,

31481, 89, 95, 114, 133, 138, 138, 133, 127, 132, 131, 126, 133, 145, 158,
168, 168, 162, 171, 195,

315219, 230, 226, 217, 207, 198, 190, 174, 158, 155, 159, 162, 151, 131,
116, 110, 118, 140, 153, 149,

316143, 140, 139, 134, 131, 131, 130, 139, 146, 137, 129, 123, 112, 101,
91, 81, 80, 88, 95, 98,

31792, 84, 86, 91, 90, 96, 99, 92, 88, 96, 114, 132, 144, 149, 159, 184, 204,
210, 217, 219,

318213, 204, 192, 183, 182, 188, 198, 205, 205, 198, 191, 184, 178, 175,
170, 156, 145, 143, 145, 143,

319134, 124, 130, 158, 196, 214, 207, 194, 182, 170, 162, 152, 137, 136,
143, 138, 121, 96, 77, 69,

32063, 63, 69, 68, 62, 66, 77, 77, 70, 68, 71, 87, 104, 102, 89, 78, 68, 69,
78, 74,
32171, 80, 85, 86, 92, 98, 106, 114, 113, 109, 107, 104, 99, 97, 91, 80, 71,
66, 65, 76,

32287, 87, 86, 86, 84, 79, 72, 71, 79, 89, 112, 136, 145, 146, 141, 130, 122,
122, 126, 119,

323112, 119, 132, 140, 143, 151, 168, 189, 217, 230, 217, 200, 189, 184,
180, 169, 157, 148, 147, 152,

324150, 140, 133, 134, 141, 152, 159, 155, 149, 151, 154, 149, 141, 137,
142, 149, 151, 143, 132, 126,

325119, 111, 101, 89, 86, 88, 88, 89, 84, 84, 98, 105, 101, 97, 99, 106, 113,
124, 134, 140,

326148, 165, 179, 189, 200, 207, 205, 199, 194, 193, 191, 192, 195, 196,
199, 205, 201, 194, 191, 181,

327165, 158, 158, 153, 143, 132, 126, 127, 133, 146, 166, 181, 199, 212,
200, 177, 161, 155, 154, 149,

328136, 121, 119, 123, 116, 104, 87, 71, 69, 67, 65, 65, 57, 51, 58, 62, 62,
70, 81, 87,

32993, 100, 104, 102, 91, 83, 80, 76, 73, 72, 74, 80, 82, 87, 100, 106, 104,
104, 109, 108,

330100, 93, 84, 70, 64, 67, 70, 66, 67, 70, 70, 68, 61, 55, 60, 79, 97, 99,
105, 119,

331127, 133, 138, 131, 123, 122, 122, 115, 104, 101, 114, 130, 141, 155,
171, 189, 205, 209, 201, 182,

332162, 156, 159, 159, 155, 140, 132, 143, 150, 153, 155, 143, 138, 148,
156, 156, 144, 135, 137, 140,

333142, 146, 147, 152, 158, 152, 136, 121, 110, 101, 93, 85, 81, 75, 66, 71,
81, 87, 100, 109,

334110, 115, 133, 147, 139, 129, 133, 143, 161, 176, 176, 183, 198, 206,
209, 210, 208, 207, 205, 198,

335196, 195, 192, 196, 198, 193, 186, 176, 164, 156, 158, 163, 157, 145,
140, 153, 179, 193, 192, 194,

336205, 211, 200, 181, 168, 157, 147, 139, 129, 120, 117, 117, 107, 90, 82,
79, 72, 68, 64, 56,
33746, 40, 42, 53, 71, 86, 89, 91, 106, 125, 127, 115, 102, 91, 85, 79, 70,
66, 68, 78,

33890, 95, 102, 113, 115, 114, 117, 116, 109, 99, 90, 88, 84, 73, 64, 58, 62,
73, 82, 87,

33982, 73, 79, 88, 86, 84, 90, 101, 109, 107, 105, 115, 121, 121, 126, 128,
119, 112, 119, 139,

340154, 162, 168, 171, 181, 192, 185, 175, 170, 161, 160, 165, 160, 152,
147, 149, 158, 156, 149, 149,

341148, 142, 138, 138, 142, 149, 157, 165, 167, 163, 154, 149, 149, 147,
142, 132, 119, 103, 85, 70,

34265, 64, 63, 72, 87, 90, 93, 106, 119, 133, 138, 137, 141, 142, 144, 152,
159, 167, 171, 174,

343181, 194, 204, 202, 193, 185, 179, 176, 174, 172, 173, 173, 166, 158,
153, 154, 159, 165, 171, 172,

344168, 166, 172, 185, 193, 194, 195, 193, 193, 201, 208, 205, 193, 177,
162, 147, 126, 109, 104, 104,

345101, 90, 74, 67, 67, 62, 55, 50, 51, 67, 87, 96, 103, 102, 96, 98, 106,
116, 125, 121,

346110, 98, 87, 78, 75, 77, 80, 84, 87, 88, 96, 110, 120, 120, 113, 110, 115,
116, 104, 91,

34783, 74, 72, 80, 85, 90, 99, 96, 80, 74, 74, 74, 74, 70, 66, 76, 93, 96, 93,
95,

34898, 105, 113, 117, 124, 131, 131, 137, 147, 152, 157, 163, 171, 184,
196, 196, 187, 179, 174, 169,

349161, 146, 138, 144, 150, 143, 137, 139, 137, 139, 146, 147, 155, 167,
167, 163, 156, 147, 145, 146,

350143, 139, 139, 128, 109, 99, 90, 74, 65, 63, 67, 83, 97, 96, 93, 101, 115,
124, 131, 137,

351150, 164, 169, 174, 178, 172, 167, 164, 165, 180, 194, 189, 179, 174,
165, 157, 155, 153, 145, 147,

352158, 158, 151, 150, 153, 164, 170, 165, 171, 185, 187, 187, 192, 195,
193, 193, 206, 220, 223, 210,
353187, 169, 153, 132, 114, 98, 82, 79, 84, 76, 61, 54, 50, 51, 59, 62, 76,
100, 114, 114,

354105, 100, 101, 104, 105, 104, 111, 113, 104, 99, 94, 82, 71, 63, 57, 59,
73, 86, 92, 96,

35599, 102, 104, 105, 112, 120, 116, 107, 96, 85, 79, 77, 84, 89, 88, 88, 84,
75, 68, 67,

35666, 65, 67, 74, 93, 104, 91, 81, 79, 85, 101, 110, 121, 138, 147, 150,
155, 159, 165, 178,

357188, 192, 196, 196, 189, 187, 182, 170, 157, 147, 142, 144, 156, 161,
157, 155, 155, 156, 159, 154,

358152, 162, 175, 178, 174, 165, 159, 152, 141, 138, 144, 148, 141, 123,
104, 89, 73, 66, 73, 83,

35997, 112, 113, 109, 110, 116, 127, 145, 164, 177, 184, 184, 179, 171,
160, 153, 160, 170, 173, 177,

360175, 162, 157, 163, 161, 155, 153, 153, 159, 159, 147, 145, 153, 157,
156, 157, 164, 173, 182, 195,

361205, 207, 209, 215, 219, 211, 201, 197, 185, 169, 153, 129, 104, 85, 77,
80, 86, 88, 79, 65,

36255, 50, 47, 54, 76, 102, 115, 116, 111, 106, 103, 99, 93, 92, 100, 105,
99, 92, 79, 62,

36353, 49, 52, 62, 74, 86, 86, 81, 85, 94, 101, 106, 108, 108, 105, 101, 96,
92, 89, 84,

36479, 82, 89, 89, 84, 78, 70, 66, 63, 58, 63, 72, 77, 79, 74, 71, 76, 86, 95,
98,

365105, 123, 144, 164, 179, 181, 183, 187, 181, 178, 180, 184, 191, 188,
174, 167, 161, 155, 153, 153,

366160, 168, 163, 157, 154, 150, 145, 137, 139, 156, 175, 182, 178, 171,
167, 162, 160, 156, 150, 149,

367144, 130, 110, 95, 88, 88, 94, 100, 116, 133, 127, 115, 114, 121, 133,
143, 153, 168, 180, 185,

368178, 169, 167, 164, 163, 167, 166, 170, 180, 180, 179, 184, 185, 176,
165, 153, 150, 158, 159, 154,
369153, 158, 162, 156, 151, 163, 181, 201, 217, 225, 226, 221, 210, 199,
187, 180, 174, 161, 141, 119,

370103, 93, 87, 84, 84, 84, 76, 60, 44, 33, 30, 30, 45, 74, 98, 113, 113, 98,
89, 89,

37192, 95, 93, 90, 88, 81, 73, 71, 72, 72, 75, 78, 75, 78, 87, 92, 95, 103,
106, 99,

37291, 95, 98, 94, 96, 97, 97, 98, 101, 102, 94, 86, 82, 78, 79, 81, 77, 69,
65, 65,

37369, 76, 81, 84, 84, 86, 95, 98, 103, 127, 153, 169, 186, 196, 194, 189,
183, 175, 171, 179,

374184, 181, 181, 180, 169, 157, 153, 156, 155, 151, 149, 150, 146, 141,
137, 129, 125, 140, 154, 161,

375169, 172, 176, 185, 183, 173, 160, 145, 132, 121, 111, 107, 104, 103,
113, 126, 125, 115, 108, 103,

376106, 115, 123, 131, 141, 153, 161, 164, 167, 168, 164, 161, 166, 174,
179, 184, 193, 193, 190, 193,

377190, 175, 159, 148, 142, 147, 160, 168, 170, 165, 155, 143, 143, 161,
172, 182, 210, 227, 220, 213,

378211, 206, 193, 181, 171, 157, 147, 138, 126, 116, 104, 87, 76, 68, 62,
53, 42, 33, 30, 34,

37953, 84, 101, 98, 92, 88, 85, 91, 103, 105, 95, 86, 80, 83, 85, 81, 75, 74,
81, 91,

38090, 88, 93, 96, 96, 98, 100, 95, 91, 95, 93, 86, 93, 101, 105, 113, 115,
112, 103, 87,

38179, 81, 79, 76, 72, 61, 56, 58, 64, 71, 74, 74, 76, 80, 85, 94, 114, 140,
148, 146,

382165, 187, 187, 182, 184, 186, 187, 191, 200, 201, 186, 173, 169, 161,
156, 155, 151, 149, 153, 152,

383146, 141, 133, 123, 122, 138, 157, 162, 168, 182, 188, 184, 182, 179,
165, 144, 133, 134, 127, 119,

384119, 121, 128, 126, 113, 103, 93, 86, 87, 99, 117, 127, 138, 154, 156,
145, 141, 147, 157, 167,
385179, 190, 193, 193, 193, 189, 181, 175, 170, 160, 151, 142, 134, 137,
153, 165, 158, 148, 145, 137,

386132, 145, 160, 172, 194, 213, 219, 217, 211, 202, 189, 179, 180, 181,
170, 156, 140, 122, 105, 87,

38767, 58, 57, 44, 29, 27, 31, 37, 52, 75, 85, 81, 85, 91, 92, 96, 106, 112,
102, 92,

38898, 102, 93, 84, 83, 90, 99, 110, 119, 115, 106, 100, 91, 83, 87, 93, 93,
96, 97, 96,

389102, 108, 110, 114, 115, 116, 113, 101, 97, 101, 92, 83, 77, 68, 63, 66,
67, 68, 73, 76,

39073, 75, 86, 94, 102, 117, 128, 137, 162, 188, 196, 195, 192, 191, 190,
185, 189, 193, 185, 178,

391170, 158, 152, 151, 151, 150, 149, 145, 139, 133, 129, 130, 136, 148,
162, 172, 181, 185, 185, 185,

392183, 181, 174, 158, 150, 147, 135, 124, 118, 114, 115, 118, 115, 104,
90, 78, 72, 80, 98, 111,

393125, 140, 144, 144, 155, 168, 175, 184, 193, 199, 202, 199, 199, 198,
188, 178, 173, 164, 153, 145,

394144, 149, 153, 155, 154, 150, 144, 134, 128, 136, 151, 169, 198, 221,
226, 224, 212, 198, 192, 190,

395195, 201, 190, 167, 142, 120, 101, 84, 73, 66, 55, 39, 29, 31, 36, 39, 46,
63, 78, 89,

39696, 98, 100, 102, 104, 107, 104, 102, 107, 103, 90, 82, 84, 90, 103, 115,
114, 108, 96, 84,

39782, 75, 70, 74, 80, 85, 88, 96, 112, 119, 120, 123, 120, 114, 108, 104,
107, 106, 94, 78,

39865, 64, 66, 62, 62, 64, 63, 64, 65, 65, 63, 58, 68, 89, 103, 116, 146, 179,
189, 185,

399184, 186, 184, 186, 192, 193, 187, 172, 157, 154, 152, 147, 145, 144,
141, 138, 137, 137, 132, 127,

400137, 155, 163, 167, 176, 186, 183, 175, 171, 164, 158, 155, 151, 150,
146, 135, 121, 112, 114, 117,
401111, 98, 85, 77, 75, 74, 79, 90, 105, 123, 136, 147, 162, 179, 193, 199,
200, 199, 199, 200,

402200, 200, 194, 184, 173, 164, 155, 151, 155, 156, 145, 141, 148, 144,
129, 115, 118, 131, 137, 156,

403195, 222, 226, 222, 211, 200, 201, 208, 214, 212, 197, 176, 153, 128,
102, 82, 70, 64, 53, 40,

40439, 43, 41, 37, 41, 57, 75, 87, 90, 96, 109, 113, 107, 105, 108, 112, 113,
114, 111, 105,

405101, 104, 117, 120, 113, 109, 96, 78, 72, 72, 71, 73, 73, 75, 90, 109,
120, 124, 126, 128,

406121, 107, 102, 108, 111, 109, 105, 95, 79, 68, 65, 62, 61, 60, 60, 63, 62,
56, 52, 50,

40753, 65, 83, 108, 140, 167, 180, 192, 201, 194, 189, 194, 200, 204, 196,
179, 168, 161, 157, 151,

408144, 145, 144, 140, 145, 154, 156, 154, 157, 163, 166, 175, 184, 188,
190, 185, 174, 162, 157, 159,

409165, 172, 170, 157, 138, 122, 123, 123, 107, 95, 92, 83, 73, 71, 80, 89,
97, 114, 140, 164,

410178, 186, 196, 203, 200, 196, 198, 199, 195, 194, 196, 191, 182, 174,
173, 170, 161, 152, 140, 126,

411119, 117, 116, 115, 114, 118, 127, 144, 177, 207, 220, 228, 226, 212,
206, 212, 212, 205, 193, 169,

412145, 126, 103, 81, 64, 53, 49, 51, 51, 46, 43, 37, 38, 48, 57, 68, 84, 94,
99, 100,

41396, 96, 105, 115, 127, 138, 136, 129, 125, 123, 123, 120, 110, 97, 83,
71, 62, 60, 63, 70,

41485, 96, 99, 105, 112, 115, 115, 106, 95, 96, 102, 102, 102, 103, 100, 89,
79, 75, 66, 56,

41553, 51, 47, 39, 35, 35, 36, 39, 50, 61, 72, 96, 130, 161, 184, 197, 198,
194, 191, 186,

416183, 185, 186, 183, 181, 175, 165, 156, 155, 158, 159, 162, 166, 167,
165, 163, 165, 166, 165, 172,
417181, 175, 168, 165, 159, 156, 161, 171, 178, 178, 172, 157, 140, 131,
123, 113, 109, 106, 92, 78,

41870, 70, 82, 104, 126, 139, 145, 156, 172, 181, 185, 185, 188, 192, 191,
189, 187, 183, 184, 185,

419188, 193, 189, 169, 145, 127, 113, 102, 100, 109, 115, 115, 120, 130,
140, 158, 184, 207, 225, 233,

420233, 227, 214, 200, 192, 189, 176, 155, 135, 115, 95, 78, 64, 59, 61, 54,
44, 41, 40, 40,

42143, 46, 51, 64, 81, 91, 97, 101, 106, 112, 122, 133, 137, 137, 133, 128,
131, 130, 126, 124,

422113, 96, 81, 63, 49, 49, 60, 80, 99, 104, 98, 93, 95, 96, 91, 91, 101, 110,
116, 119,

423116, 110, 101, 96, 96, 95, 86, 68, 52, 43, 38, 35, 33, 31, 36, 46, 55, 67,
75, 83,

424110, 144, 163, 174, 181, 178, 176, 172, 165, 169, 176, 178, 182, 184,
182, 176, 169, 168, 173, 174,

425171, 169, 167, 165, 172, 178, 169, 165, 170, 169, 161, 157, 157, 159,
167, 174, 172, 159, 150, 148,

426143, 132, 129, 135, 133, 122, 114, 104, 86, 85, 100, 117, 136, 148, 146,
147, 158, 168, 179, 186,

427186, 188, 194, 193, 184, 179, 186, 197, 198, 193, 189, 173, 146, 123,
107, 96, 96, 112, 131, 142,

428151, 160, 153, 147, 162, 185, 207, 218, 217, 207, 196, 185, 170, 154,
143, 131, 116, 103, 94, 84,

42975, 70, 64, 53, 44, 44, 51, 53, 56, 62, 65, 75, 92, 103, 105, 102, 103,
106, 110, 119,

430123, 117, 117, 120, 116, 111, 116, 116, 104, 90, 74, 53, 41, 46, 61, 74,
87, 97, 92, 83,

43184, 91, 99, 109, 120, 127, 130, 127, 118, 114, 113, 108, 100, 94, 88, 75,
58, 46, 39, 31,

43224, 35, 54, 62, 71, 83, 83, 87, 116, 148, 164, 176, 181, 173, 168, 168,
167, 173, 188, 196,
433191, 185, 187, 195, 196, 189, 185, 179, 174, 177, 184, 190, 193, 189,
172, 156, 157, 161, 157, 155,

434155, 151, 150, 150, 149, 148, 145, 138, 131, 130, 138, 149, 151, 139,
122, 106, 97, 103, 110, 115,

435130, 147, 145, 141, 158, 183, 188, 183, 177, 171, 172, 175, 177, 185,
190, 189, 184, 178, 174, 166,

436151, 133, 123, 124, 130, 143, 159, 168, 171, 170, 164, 157, 162, 183,
203, 207, 202, 191, 179, 169,

437151, 134, 125, 111, 93, 85, 84, 83, 78, 69, 60, 57, 60, 62, 61, 63, 74, 83,
88, 92,

43897, 108, 113, 106, 100, 99, 95, 97, 108, 113, 111, 110, 106, 96, 89, 89,
84, 70, 58, 49,

43945, 53, 60, 68, 84, 93, 95, 97, 100, 108, 116, 119, 121, 123, 121, 114,
108, 111, 111, 99,

44085, 75, 72, 70, 61, 50, 40, 30, 30, 38, 46, 58, 73, 82, 91, 103, 119, 143,
161, 165,

441167, 171, 169, 163, 168, 179, 184, 186, 183, 176, 178, 181, 176, 172,
178, 185, 185, 181, 181, 187,

442191, 188, 181, 170, 163, 162, 159, 160, 163, 154, 139, 127, 130, 142,
149, 146, 138, 134, 139, 146,

443145, 134, 128, 126, 123, 118, 115, 122, 142, 157, 163, 166, 171, 178,
181, 178, 173, 172, 172, 167,

444170, 185, 188, 173, 158, 152, 155, 157, 151, 140, 133, 134, 141, 144,
145, 155, 175, 187, 186, 177,

445177, 189, 196, 193, 190, 183, 167, 146, 127, 115, 110, 107, 98, 90, 87,
82, 71, 64, 66, 75,

44683, 81, 79, 83, 93, 107, 114, 106, 100, 107, 110, 109, 110, 106, 101, 96,
92, 96, 99, 91,

44780, 71, 63, 61, 63, 61, 59, 60, 61, 57, 52, 61, 88, 116, 126, 121, 115,
118, 123, 130,

448136, 131, 123, 120, 114, 111, 109, 98, 85, 77, 72, 65, 54, 43, 34, 28, 28,
35, 45, 63,
44987, 105, 113, 112, 117, 141, 164, 170, 171, 169, 162, 161, 164, 164,
166, 168, 169, 169, 168, 166,

450164, 167, 175, 178, 173, 172, 174, 181, 192, 190, 180, 172, 167, 164,
158, 154, 151, 145, 139, 131,

451129, 134, 132, 124, 128, 136, 135, 136, 137, 129, 125, 131, 137, 138,
132, 133, 154, 172, 172, 169,

452172, 174, 174, 180, 185, 186, 187, 184, 180, 183, 181, 171, 167, 164,
159, 154, 144, 134, 136, 140,

453138, 140, 142, 151, 178, 194, 191, 185, 180, 186, 194, 189, 181, 171,
155, 137, 123, 116, 112, 112,

454111, 102, 93, 85, 77, 72, 71, 78, 86, 84, 86, 104, 121, 123, 113, 100, 94,
98, 105, 107,

455105, 100, 96, 93, 86, 79, 78, 72, 58, 52, 54, 57, 65, 69, 65, 62, 60, 60,
62, 70,

45692, 112, 111, 106, 114, 126, 131, 130, 130, 128, 123, 121, 121, 122,
119, 110, 99, 85, 72, 63,

45754, 44, 34, 27, 31, 43, 57, 71, 94, 112, 112, 109, 111, 128, 147, 148,
147, 153, 155, 154,

458150, 150, 154, 157, 157, 160, 167, 168, 166, 171, 176, 171, 163, 161,
167, 178, 193, 196, 184, 175,

459166, 163, 166, 162, 156, 149, 137, 126, 121, 125, 132, 138, 137, 132,
132, 137, 144, 146, 139, 138,

460143, 146, 148, 150, 157, 167, 164, 158, 159, 166, 176, 182, 188, 193,
196, 198, 198, 197, 195, 184,

461169, 160, 155, 149, 151, 156, 150, 140, 137, 138, 142, 147, 164, 183,
187, 181, 173, 169, 171, 165,

462153, 148, 142, 130, 118, 112, 116, 119, 115, 111, 108, 99, 87, 80, 78,
80, 84, 98, 114, 120,

463125, 125, 113, 103, 98, 94, 102, 107, 102, 102, 103, 94, 78, 66, 67, 70,
66, 61, 55, 56,

46470, 80, 80, 76, 67, 62, 58, 53, 69, 92, 101, 113, 123, 122, 123, 127, 131,
133, 133, 132,
465129, 130, 130, 123, 109, 92, 76, 63, 55, 52, 48, 43, 46, 60, 71, 76, 95,
110, 105, 95,

46689, 94, 112, 120, 124, 137, 146, 144, 137, 133, 139, 146, 153, 160, 167,
169, 166, 165, 171, 170,

467164, 166, 170, 172, 176, 181, 181, 177, 171, 165, 163, 157, 145, 134,
132, 133, 125, 119, 131, 145,

468145, 142, 142, 139, 139, 145, 150, 152, 155, 161, 159, 152, 156, 167,
173, 175, 174, 170, 175, 181,

469185, 191, 199, 205, 203, 191, 182, 177, 172, 169, 164, 161, 165, 167,
163, 156, 154, 158, 157, 154,

470158, 168, 175, 172, 163, 155, 156, 158, 151, 145, 143, 137, 127, 119,
115, 117, 125, 127, 113, 96,

47184, 81, 85, 88, 98, 123, 133, 125, 125, 128, 121, 111, 98, 90, 92, 94, 92,
87, 87, 91,

47285, 73, 66, 61, 61, 60, 55, 50, 49, 58, 66, 61, 51, 46, 46, 47, 54, 74, 99,
115,

473116, 116, 120, 121, 119, 120, 124, 130, 132, 127, 117, 108, 108, 107,
93, 77, 65, 61, 59, 54,

47459, 75, 83, 85, 91, 96, 94, 92, 91, 88, 93, 115, 134, 135, 131, 136, 142,
141, 138, 140,

475149, 158, 161, 158, 153, 159, 171, 169, 166, 174, 178, 172, 171, 174,
177, 177, 168, 156, 147, 137,

476131, 130, 126, 128, 137, 143, 138, 132, 135, 141, 141, 133, 131, 138,
145, 148, 150, 156, 165, 169,

477169, 174, 181, 185, 184, 175, 169, 175, 182, 184, 185, 189, 191, 186,
178, 171, 167, 171, 176, 176,

478171, 173, 179, 175, 172, 176, 173, 170, 172, 174, 176, 181, 182, 173,
162, 156, 154, 154, 145, 134,

479134, 134, 128, 119, 115, 114, 106, 96, 89, 85, 87, 98, 117, 135, 139,
134, 134, 135, 135, 127,

480112, 102, 95, 94, 99, 101, 97, 95, 95, 90, 82, 68, 52, 46, 45, 40, 35, 42,
50, 47,
48144, 47, 45, 46, 65, 91, 106, 115, 124, 123, 117, 115, 118, 117, 122, 126,
122, 120, 122, 119,

482110, 100, 90, 78, 68, 63, 57, 53, 62, 79, 86, 87, 93, 97, 96, 93, 88, 86,
93, 112,

483130, 130, 126, 129, 136, 143, 148, 147, 144, 143, 142, 150, 159, 162,
168, 170, 171, 174, 174, 170,

484169, 174, 178, 177, 175, 167, 152, 145, 141, 130, 133, 148, 156, 155,
151, 141, 134, 134, 129, 121,

485121, 127, 130, 136, 149, 166, 178, 184, 193, 195, 192, 191, 184, 174,
172, 175, 180, 183, 184, 181,

486178, 179, 172, 163, 163, 170, 172, 169, 168, 172, 171, 168, 167, 169,
167, 162, 162, 165, 170, 174,

487174, 168, 155, 145, 141, 137, 126, 115, 117, 125, 125, 118, 108, 100,
91, 79, 74, 79, 90, 109,

488128, 140, 146, 149, 153, 147, 134, 127, 118, 107, 105, 109, 112, 107,
98, 96, 94, 84, 72, 57,

48943, 36, 30, 22, 21, 25, 30, 40, 46, 42, 48, 70, 91, 104, 113, 126, 136,
132, 128, 127,

490126, 126, 126, 129, 137, 138, 132, 125, 113, 102, 92, 77, 67, 57, 52, 62,
72, 80, 89, 90,

49193, 95, 87, 89, 99, 99, 98, 110, 123, 129, 127, 125, 127, 133, 137, 137,
140, 148, 151, 152,

492156, 157, 158, 165, 172, 172, 166, 162, 166, 170, 166, 162, 162, 157,
152, 149, 145, 146, 147, 152,

493162, 164, 157, 150, 140, 129, 120, 112, 105, 108, 123, 145, 163, 170,
177, 186, 192, 195, 192, 189,

494187, 182, 181, 181, 181, 188, 191, 189, 189, 182, 173, 174, 176, 176,
177, 178, 174, 165, 160, 163,

495167, 164, 158, 157, 162, 165, 160, 155, 153, 142, 133, 137, 140, 132,
124, 116, 110, 109, 108, 106,

496102, 97, 91, 87, 83, 85, 94, 114, 135, 145, 146, 144, 142, 140, 130, 119,
115, 113, 112, 109,
497106, 108, 103, 91, 87, 80, 67, 54, 42, 29, 18, 9, 5, 13, 27, 38, 48, 54, 56,
68,

49891, 110, 117, 119, 121, 123, 129, 134, 135, 138, 144, 144, 144, 142,
133, 120, 105, 92, 83, 72,

49962, 58, 57, 61, 70, 78, 83, 92, 99, 101, 104, 107, 106, 107, 111, 119,
129, 135, 135, 131,

500129, 132, 133, 134, 136, 142, 149, 150, 149, 150, 153, 161, 169, 169,
163, 157, 157, 159, 156, 152,

501155, 160, 161, 164, 169, 170, 172, 172, 173, 173, 166, 152, 137, 128,
119, 109, 109, 121, 134, 145,

502156, 160, 161, 166, 174, 184, 191, 189, 186, 185, 178, 173, 182, 193,
203, 204, 198, 197, 196, 192,

503187, 182, 180, 177, 175, 173, 168, 166, 169, 171, 170, 169, 168, 165,
154, 143, 134, 128, 126, 130,

504133, 130, 124, 113, 101, 101, 102, 98, 98, 98, 97, 96, 99, 104, 108, 119,
131, 134, 132, 130,

505132, 135, 131, 123, 121, 121, 117, 110, 105, 99, 95, 89, 85, 81, 69, 55,
43, 29, 17, 12,

50616, 26, 33, 42, 55, 61, 67, 77, 91, 107, 118, 120, 125, 128, 130, 134,
140, 145, 146, 143,

507142, 136, 124, 111, 96, 80, 69, 62, 59, 57, 52, 50, 56, 65, 74, 86, 96,
109, 116,

508};

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

1/* Rick Roll Code

2AUTHOR: Samantha Lagestee

3Copyright 2017 samilagestee at gmail dot com

5 This program is free software: you can redistribute it and/or

6 modify it under the terms of the GNU General Public License as

7 published by the Free Software Foundation, either version 3 of

8 the License, or (at your option) any later version.

10 DISCLAIMER: The song "Never Gonna Give You Up" by Rick Astley

11 is not the creative property of the author. This code simply

12 plays a Piezo buzzer rendition of the song.

13

14*/

15

16#define a3f 208 // 208 Hz

17#define b3f 233 // 233 Hz

18#define b3 247 // 247 Hz

19#define c4 261 // 261 Hz MIDDLE C

20#define c4s 277 // 277 Hz

21#define e4f 311 // 311 Hz

22#define f4 349 // 349 Hz

23#define a4f 415 // 415 Hz


24#define b4f 466 // 466 Hz

25#define b4 493 // 493 Hz

26#define c5 523 // 523 Hz

27#define c5s 554 // 554 Hz

28#define e5f 622 // 622 Hz

29#define f5 698 // 698 Hz

30#define f5s 740 // 740 Hz

31#define a5f 831 // 831 Hz

32

33#define rest -1

34

35// change these pins according to your setup

36int piezo = 8;

37int led = 9;

38

39volatile int beatlength = 100; // determines tempo

40float beatseparationconstant = 0.3;

41

42int a; // part index

43int b; // song index

44int c; // lyric index

45

46boolean flag; // play/pause

47

48// Parts 1 and 2 (Intro)


49

50int song1_intro_melody[] =

51{c5s, e5f, e5f, f5, a5f, f5s, f5, e5f, c5s, e5f, rest, a4f, a4f};

52

53int song1_intro_rhythmn[] =

54{6, 10, 6, 6, 1, 1, 1, 1, 6, 10, 4, 2, 10};

55

56// Parts 3 or 5 (Verse 1)

57

58int song1_verse1_melody[] =

59{ rest, c4s, c4s, c4s, c4s, e4f, rest, c4, b3f, a3f,

60rest, b3f, b3f, c4, c4s, a3f, a4f, a4f, e4f,

61rest, b3f, b3f, c4, c4s, b3f, c4s, e4f, rest, c4, b3f, b3f, a3f,

62rest, b3f, b3f, c4, c4s, a3f, a3f, e4f, e4f, e4f, f4, e4f,

63c4s, e4f, f4, c4s, e4f, e4f, e4f, f4, e4f, a3f,

64rest, b3f, c4, c4s, a3f, rest, e4f, f4, e4f

65};

66

67int song1_verse1_rhythmn[] =

68{ 2, 1, 1, 1, 1, 2, 1, 1, 1, 5,

691, 1, 1, 1, 3, 1, 2, 1, 5,

701, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3,

711, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 4,

725, 1, 1, 1, 1, 1, 1, 1, 2, 2,

732, 1, 1, 1, 3, 1, 1, 1, 3
74};

75

76char\* lyrics_verse1[] =

77{ "We're ", "no ", "strangers ", "", "to ", "love ", "", "\r\n",

78"You ", "know ", "the ", "rules ", "and ", "so ", "do ", "I\r\n",

79"A ", "full ", "commitment's ", "", "", "what ", "I'm ", "thinking ", "", "of", "\r\
n",

80"You ", "wouldn't ", "", "get ", "this ", "from ", "any ", "", "other ", "", "guy\r\
n",

81"I ", "just ", "wanna ", "", "tell ", "you ", "how ", "I'm ", "feeling", "\r\n",

82"Gotta ", "", "make ", "you ", "understand", "", "\r\n"

83};

84

85// Parts 4 or 6 (Chorus)

86

87int song1_chorus_melody[] =

88{ b4f, b4f, a4f, a4f,

89f5, f5, e5f, b4f, b4f, a4f, a4f, e5f, e5f, c5s, c5, b4f,

90c5s, c5s, c5s, c5s,

91c5s, e5f, c5, b4f, a4f, a4f, a4f, e5f, c5s,

92b4f, b4f, a4f, a4f,

93f5, f5, e5f, b4f, b4f, a4f, a4f, a5f, c5, c5s, c5, b4f,

94c5s, c5s, c5s, c5s,

95c5s, e5f, c5, b4f, a4f, rest, a4f, e5f, c5s, rest

96};

97
98int song1_chorus_rhythmn[] =

99{ 1, 1, 1, 1,

1003, 3, 6, 1, 1, 1, 1, 3, 3, 3, 1, 2,

1011, 1, 1, 1,

1023, 3, 3, 1, 2, 2, 2, 4, 8,

1031, 1, 1, 1,

1043, 3, 6, 1, 1, 1, 1, 3, 3, 3, 1, 2,

1051, 1, 1, 1,

1063, 3, 3, 1, 2, 2, 2, 4, 8, 4

107};

108

109char* lyrics_chorus[] =

110{ "Never ", "", "gonna ", "", "give ", "you ", "up\r\n",

111"Never ", "", "gonna ", "", "let ", "you ", "down", "", "\r\n",

112"Never ", "", "gonna ", "", "run ", "around ", "", "", "", "and ", "desert ", "",
"you\r\n",

113"Never ", "", "gonna ", "", "make ", "you ", "cry\r\n",

114"Never ", "", "gonna ", "", "say ", "goodbye ", "", "", "\r\n",

115"Never ", "", "gonna ", "", "tell ", "a ", "lie ", "", "", "and ", "hurt ", "you\r\
n"

116};

117

118void setup()

119{

120 pinMode(piezo, OUTPUT);

121 pinMode(led, OUTPUT);


122 digitalWrite(led, LOW);

123 Serial.begin(9600);

124 flag = true;

125 a = 4;

126 b = 0;

127 c = 0;

128}

129

130void loop()

131{

132 // edit code here to define play conditions

133 /*

134 if (CONDITION 1) { // play

135 flag = true;

136 }

137 else if (CONDITION2) { // pause

138 flag = false;

139 }

140 */

141

142 // play next step in song

143 if (flag == true) {

144 play();

145 }

146}
147

148void play() {

149 int notelength;

150 if (a == 1 || a == 2) { // Intro

151 // intro

152 notelength = beatlength * song1_intro_rhythmn[b];

153 if (song1_intro_melody[b] > 0) { // if not a rest, play note

154 digitalWrite(led, HIGH);

155 tone(piezo, song1_intro_melody[b], notelength);

156 }

157

158 b++;

159 if (b >= sizeof(song1_intro_melody) / sizeof(int)) {

160 a++;

161 b = 0;

162 c = 0;

163 }

164 } else if (a == 3 || a == 5) { // Verse 1

165 // verse

166 notelength = beatlength * 2 * song1_verse1_rhythmn[b];

167 if (song1_verse1_melody[b] > 0) {

168 digitalWrite(led, HIGH);

169 Serial.print(lyrics_verse1[c]);

170 tone(piezo, song1_verse1_melody[b], notelength);

171 c++;
172 }

173 b++;

174 if (b >= sizeof(song1_verse1_melody) / sizeof(int)) {

175 a++;

176 b = 0;

177 c = 0;

178 }

179 } else if (a == 4 || a == 6) { //chorus

180 // chorus

181 notelength = beatlength * song1_chorus_rhythmn[b];

182 if (song1_chorus_melody[b] > 0) {

183 digitalWrite(led, HIGH);

184 Serial.print(lyrics_chorus[c]);

185 tone(piezo, song1_chorus_melody[b], notelength);

186 c++;

187 }

188

189 b++;

190 if (b >= sizeof(song1_chorus_melody) / sizeof(int)) {

191 Serial.println("");

192 a++;

193 b = 0;

194 c = 0;

195 }

196 }
197

198 delay(notelength); // necessary because piezo is on independent timer

199 noTone(piezo);

200 digitalWrite(led, LOW);

201 delay(notelength * beatseparationconstant); // create separation


between notes

202 if (a == 7) { // loop back around to beginning of song

203 a = 1;

204 }

205}

MusicalAlgoFun
This is a simple song with the Arduino created by Alexandre Quessy in
2006.

Code

Copy

1/\*

3- Au Clair de la Lune with an Arduino and a PC speaker.

4- The calculation of the tones is made following the mathematical

5- operation:

6-

7- timeUpDown = 1/(2 * toneFrequency) = period / 2

8- )c( Copyleft AlexandreQuessy 2006 http://alexandre.quessy.net


9- Inspired from D. Cuartielles's
http://www.arduino.cc/en/Tutorial/PlayMelody

10 \*/

11

12int ledPin = 9;

13int speakerOut = 8;

14

15/_ 2 octavas :: semitones. 0 = do, 2 = re, etc. _/

16/_ MIDI notes from 48 to 71. Indices here are from 0 to 23. _/

17

18int timeUpDown[] = {3822, 3606, 3404, 3214, 3032, 2862,

192702, 2550, 2406, 2272, 2144, 2024,

201911, 1803, 1702, 1607, 1516, 1431,

211351, 1275, 1203, 1136, 1072, 1012};

22/_ our song. Each number is a (MIDI note - 48) on a beat. _/

23

24byte song[] = {12,12,12,14, 16,16,14,14, 12,16,14,14, 12,12,12,12,

2514,14,14,14, 9,9,9,9, 14,12,11,9, 7,7,7,7};

26// do do do re mi re do mi re re do...

27

28byte beat = 0;

29int MAXCOUNT = 32;

30float TEMPO_SECONDS = 0.2;

31byte statePin = LOW;

32byte period = 0;
33int i, timeUp;

34

35void setup() {

36pinMode(ledPin, OUTPUT);

37pinMode(speakerOut, OUTPUT);

38}

39

40void loop() {

41digitalWrite(speakerOut, LOW);

42 for (beat = 0; beat < MAXCOUNT; beat++) {

43statePin = !statePin;

44digitalWrite(ledPin, statePin);

45

46 timeUp = timeUpDown[song[beat]];

47

48 period = ((1000000 / timeUp) / 2) * TEMPO_SECONDS;

49 for (i = 0; i < period; i++) {

50 digitalWrite(speakerOut, HIGH);

51 delayMicroseconds(timeUp);

52 digitalWrite(speakerOut, LOW);

53 delayMicroseconds(timeUp);

54 }

55 /* Uncomment this if you want notes to be discrete */

56 /* delay(50); */

57
58}

59digitalWrite(speakerOut, LOW);

60delay(1000);

61}

Improved version

Copy

1/\*

3- Square wave tune with an Arduino and a PC speaker.

4- The calculation of the tones is made following the mathematical

5- operation:

6-

7- timeUpDown = 1/(2 \* toneFrequency) = period / 2

8- )c( Copyleft 2009 Daniel Gimpelevich

9- Inspired from AlexandreQuessy's


https://playground.arduino.cc/Code/MusicalAlgoFun

10 \*/

11

12const byte ledPin = 13;

13const byte speakerOut = 11; /_ This makes a standard old PC speaker


connector fit nicely over the pins. _/

14

15/_ 10.5 octaves :: semitones. 60 = do, 62 = re, etc. _/

16/_ MIDI notes from 0, or C(-1), to 127, or G9. _/

17/_ Rests are note number -1. _/


18

19unsigned int timeUpDown[128];

20

21/_ our song. Each number pair is a MIDI note and a note symbol. _/

22/_ Symbols are 1 for whole, -1 for dotted whole, 2 for half, _/

23/_ -2 for dotted half, 4 for quarter, -4 for dotted quarter, etc. _/

24

25const byte BPM = 120;

26const char song[] = {

2764,4,64,4,65,4,67,4, 67,4,65,4,64,4,62,4,

2860,4,60,4,62,4,64,4, 64,-4,62,8,62,2,

2964,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 revision10/28/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

10 & 0 == 0

2 0 & 1 == 0

3 1 & 0 == 0

4 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

1int a = 92; // in binary: 0000000001011100

2 int b = 101; // in binary: 0000000001100101

3 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

1int x = 5; // binary: 101

2 int y = x & 1; // now y == 1

3 x = 4; // binary: 100

4 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

10 | 0 == 0

2 0 | 1 == 1

3 1 | 0 == 1

4 1 | 1 == 1

Here is an example of the bitwise OR used in a snippet of C++ code:


Copy

1int a = 92; // in binary: 0000000001011100

2 int b = 101; // in binary: 0000000001100101

3 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

1b = 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

10 ^ 0 == 0

2 0 ^ 1 == 1

3 1 ^ 0 == 1

4 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

1int x = 12; // binary: 1100

2 int y = 10; // binary: 1010

3 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

1y = 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

1int a = 103; // binary: 0000000001100111

2 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

1int a = 5; // binary: 0000000000000101

2 int b = a << 3; // binary: 0000000000101000, or 40 in decimal

3 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

1int a = 5; // binary: 0000000000000101

2 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

11 << 0 == 1

2 1 << 1 == 2

3 1 << 2 == 4

4 1 << 3 == 8

5 ...

6 1 << 8 == 256

7 1 << 9 == 512

8 1 << 10 == 1024

9 ...

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

1int x = -16; // binary: 1111111111110000

2 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

1int x = -16; // binary: 1111111111110000

2 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

1int x = 1000;

2 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

1x = 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

1x += 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

1int x = 1; // binary: 0000000000000001

2 x <<= 3; // binary: 0000000000001000

3 x |= 3; // binary: 0000000000001011 - because 3 is 11 in binary

4 x &= 1; // binary: 0000000000000001

5 x ^= 4; // binary: 0000000000000101 - toggle using binary mask 100

6 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

1x = ~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

. 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

1int fred (int x)

2 {

3 Serial.print ("fred ");

4 Serial.println (x, DEC);

5 return x;

6 }

Copy

1void setup()

2 {

3 Serial.begin (9600);

4 }

Copy

1void loop()
2 {

3 delay(1000); // wait 1 second, so output is not flooded with serial


data!

4 int x = fred(0) & fred(1);

5 }

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

1fred 0

2 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

1int x = fred(0) & fred(1);

and replace the bitwise

&
with its boolean counterpart
&&
,

Copy

1int 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

1fred 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

1int x;

2 if (fred(0) == 0) {

3 x = false; // stores 0 in x

4 } else {

5 if (fred(1) == 0) {

6 x = false; // stores 0 in x

7 } else {

8 x = true; // stores 1 in x

9 }

10 }

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

1void setup()

2 {

3 int pin;

4 for (pin=2; pin <= 13; ++pin) {


5 pinMode (pin, OUTPUT);

6 }

7 for (pin=2; pin <= 10; ++pin) {

8 digitalWrite (pin, LOW);

9 }

10 for (pin=11; pin <= 13; ++pin) {

11 digitalWrite (pin, HIGH);

12 }

13 }

It turns out there is a way to accomplish the same thing using direct access
to Atmega8 hardware ports and bitwise operators:

Copy

1void setup()

2 {

3 // set pins 1 (serial transmit) and 2..7 as output,

4 // but leave pin 0 (serial receive) as input

5 // (otherwise serial port will stop working!) ...

6 DDRD = B11111110; // digital pins 7,6,5,4,3,2,1,0

Copy

1// set pins 8..13 as output...

2 DDRB = B00111111; // digital pins -,-,13,12,11,10,9,8

Copy

1// Turn off digital output pins 2..7 ...

2 PORTD &= B00000011; // turns off 2..7, but leaves pins 0 and 1 alone

Copy
1// Write simultaneously to pins 8..13...

2 PORTB = B00111000; // turns on 13,12,11; turns off 10,9,8

3 }

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

1// Disable the interrupt.

2 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

1#define INT0 6

or

Copy

1#define INT0 0

So on some processors, the above line of code will compile to:

Copy

1GICR &= ~(1 << 0);

and on others, it will compile to:

Copy

1GICR &= ~(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

1GICR = 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

1GICR = 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

1const prog_uint8_t BitMap[5][7] = { // store in program memory to save


RAM

2 {1,1,0,0,0,1,1},

3 {0,0,1,0,1,0,0},

4 {0,0,0,1,0,0,0},

5 {0,0,1,0,1,0,0},

6 {1,1,0,0,0,1,1}

7 };

Copy

1void DisplayBitMap()

2 {

3 for (byte x=0; x<5; ++x) {

4 for (byte y=0; y<7; ++y) {

5 byte data = pgm_read_byte (&BitMap[x][y]); // fetch data from


program memory

6 if (data) {

7 // turn on the LED at location (x,y)


8 } else {

9 // turn off the LED at location (x,y)

10 }

11 }

12 }

13 }

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

1const prog_uint8_t BitMap[5] = { // store in program memory to save RAM

2 B1100011,

3 B0010100,

4 B0001000,

5 B0010100,

6 B1100011

7 };
(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

1void DisplayBitMap()

2 {

3 for (byte x=0; x<5; ++x) {

4 byte data = pgm_read_byte (&BitMap[x]); // fetch data from


program memory

5 for (byte y=0; y<7; ++y) {

6 if (data & (1<<y)) {

7 // turn on the LED at location (x,y)

8 } else {

9 // turn off the LED at location (x,y)

10 }

11 }

12 }

13 }

The crucial line to understand is

Copy

1if (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:

Whenever you see the variable

n
, its value is assumed to be 0 through 15.

Copy

1y = (x >> n) & 1; // n=0..15. stores nth bit of x in y. y becomes 0 or 1.

Copy

1x &= ~(1 << n); // forces nth bit of x to be 0. all other bits left alone.

Copy

1x &= (1<<(n+1))-1; // leaves alone the lowest n bits of x; all higher bits
set to 0.

Copy

1x |= (1 << n); // forces nth bit of x to be 1. all other bits left alone.

Copy
1x ^= (1 << n); // toggles nth bit of x. all other bits left alone.

Copy

1x = ~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

1bool IsPowerOfTwo (long x)

2 {

3 return (x > 0) && (x & (x-1) == 0);

4 }

Here is a function that counts how many bits in the 16-bit integer

x
are 1 and returns the count:

Copy

1int CountSetBits (int x)

2 {

3 int count = 0;

4 for (int n=0; n<16; ++n) {

5 if (x & (1<<n)) {

6 ++count;

7 }

8 }

9 return count;

10 }

Another way is this:

Copy

1int CountSetBits (int x)

2 {

3 unsigned int count;

4 for (count = 0; x; count++)

5 x &= x - 1;

6 return count;

7 }

Various tricks for common bit-oriented operations can be found here.

You might also like