Introduction to the Arduino guide series

The basics of Arduino programming: program structure, functions, variables, operators

In this lesson, we discuss the basics of Arduino programming to help you understand the basic concepts of the Arduino language: the structure, the functions, the variables and the operators.

On the second-last lesson of our 7-lesson introduction course on the Arduino, we’re going to discuss the basics of Arduino programming.

In the previous lesson, you learned about the power of the libraries that are part of the Arduino ecosystem, and how these libraries can help turbo-boost your productivity. 

Just like a builder needs to know how to use the brick and other components that are used in building a new house, similarly, you will need to know how to use and extend the libraries.

Even more important, you will need to know how to write your own code.

The combination of

  1. understanding the basics of programming,
  2. understanding the basics of electronics,
  3. and understanding how to use the shared work of others,

will make it possible for you to create amazing things.

This is what this (and the next and last lesson) is about: helping you understand the basic concepts in programming the Arduino.

The Arduino language

The Arduino language is C++.

Most of the time, people will use a small subset of C++, which looks a lot like C. If you are familiar with Java, then you will find C++ easy to work with and to recognize. If you have never programmed before, do not worry, and do not be afraid. In the next few paragraphs, you will learn everything you need to get started.

The most important “high level” characteristic of C++ is that it is object-oriented. In such a language, an object is a construct that combines functional code (the code that does things like calculations and memory operations), with “state” (the results of such calculations, or simply values, stored in variables).

Object orientation made programming much more productive in most types of applications when compared with earlier paradigms because it allowed programmers to use abstractions to create complicated programs.

For example, you could model an Ethernet adaptor as an object that contains attributes (like its IP and MAC addresses) and functionality (like asking a DHCP server for network configuration details). Programming with objects became the most common paradigm in programming, and most modern languages, like Java, Ruby, and Python, have been influenced heavily by C++.

Much of the sketch code you will be writing and reading will be referencing libraries containing definitions for objects (these definitions are called “classes”). Your original code, to a large extent, will consist of “glue” code and customizations. This way, you can be productive almost right away by learning a small subset of C++.

The code that makes up your sketch must be compiled into the machine code that the microcontroller on the Arduino can understand. This compilation is done by a special program, the compiler. The Arduino IDE ships with an open-source C++, so you don’t have to worry about the details. Imagine: every time you click the “Upload” button, the IDE starts up the compiler, which converts your human-readable code into ones and zeros, and then sends it to the microcontroller via the USB cable.

As every useful programming language, C++ is made up of various keywords and constructs. There are conditionals, functions, operators, variables, constructors, data structures, and many other things.

In this lesson, you will learn about the structure of an Arduino program, functions, and variables. Take a bit of time to consolidate this new knowledge, because next, you will complete this series with the last lesson in which you will learn how to program your Arduino to make decisions, and interact with the outside world.

Let’s take the most important of those things to examine them one at a time.

The structure of an Arduino sketch

The simplest possible Arduino sketch is this (click here to see the Gist for this sketch):

void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}

This code contains two functions in it.

The first one is setup(). Anything you put in this function will be executed by the Arduino just once when the program starts.

The second one is loop(). Once the Arduino finishes with the code in the setup() function, it will move into a loop(), and it will continue running it in a loop, again and again, until you reset it or cut off the power.

Notice that both setup() and loop() have open and close parenthesis? Functions can receive parameters, which is a way by which the program can pass data between its different functions. The setup and loop functions don’t have any parameters passed to them. If you add anything within the parenthesis, you will cause the compiler to print out a compilation error and stop the compilation process.

Every single sketch you write will have these two functions in it, even if you don’t use them.

In fact, if you remove one of them, the compiler again will produce an error message. These are two of the few expectations of the Arduino language.

These two functions are required, but you can also make your own. Let’s look at this next.

Custom functions

A function is merely a group of instructions with a name. The Arduino IDE expects that the setup() and loop() functions will be in your sketch, but you can make your own. Group instructions inside functions is a good way of organizing your sketches, especially as they tend to get bigger in size and complexity as you become a more confident programmer.

To create a function, you need a definition and the code that goes inside the curly brackets.

The definition is made up of at least:

  • a return type
  • a name
  • a list of parameters

Here’s an example


int do_a_calc(int a, int b)
{
  int c = a + b;
  return c;
}

The return type here is int in the first line. It tells the compiler that when this function finishes its work, it will return an integer value to the caller (the function that called it).

The name (also known as the “identifier”) of the function is do_a_calc. You can name your functions anything you like as long as you don’t use a reserved word (that is, a word that the Arduino language already uses), it has no spaces or other special characters like %$ and #. You can’t use a number as the first character. If in doubt, remember only to use letters, numbers, and the underscore in your function names.

In the first line of the body, we create a new variable, c, of type integer (int). We add a and b and then assign the result to c.

And finally, in the second line of the body of the function, we return the value stored in c to the caller of do_a_calc.

Let’s say that you would like to call do_a_calc from your setup function. Here’s a complete example showing how to do that:


void setup()
{
  // put your setup code here, to run once:
  int a = do_a_calc(1,2);
}

void loop()
{
  // put your main code here, to run repeatedly:
}

int do_a_calc(int a, int b)
{
  int c = a + b;
  return c;
}

In the setup() function, the second line defines a new variable, a. In the same line, it calls the function do_a_calc, and passes integers 1 and 2 to it. The do_a_calc function calculates the sum of the two numbers and returns the value 3 to the caller, which is the second line of the setup() function. Then, the value 3 is stored in variable a, and the setup() function ends.

There’s a couple of things to notice and remember.

Comments

Any line that starts with // or multiple lines that start with /* and finish with */ contain comments.

Comments are ignored by the compiler. They are meant to be read by the programmer.

Comments are used to explain the functionality of code or leave notes to other programmers (or to self).

Scope

In the setup() function, there is a definition of a variable with an identifier a. In function do_a_calc, there is also a definition of a variable with the same identifier (it makes no difference that this definition is in the function definition line).

Having variables with the same name is not a problem as long as they are not in the same scope. A scope is defined by the curly brackets. Any variable between an open and close curly bracket is said to be within that scope. If there is a variable with the same name defined within another scope, then there is no conflict.

Be careful when you choose a name for your variables. Problems with scopes can cause headaches: you may expect that a variable is accessible at a particular part of your sketch, only to realize that it is out of scope.

Also, be careful to use good descriptive names for your variables. If you want to use a variable to hold the number of a pin, call it something like:


int digital_pin = 1;
instead of
int p = 1;

You will thank yourself later.

Variables

Programs are useful when they process data. Processing data is what programs do, all the time. Programs will either get some data to process from a user (perhaps via a keypad). From a sensor (like a thermistor that measures temperature), the network (like a remote database), a local file system (like an SD Card), a local memory (like an EEPROM), and so many other places.

Regardless of the place where your program gets its data from, it must store them in memory to work with it. To do this, we use variables. A variable is a programming construct that associates a memory location with a name (an identifier). Instead of using the address of the memory location in our program, we use an easy to remember a name. You have already met a variable. In the earlier section on custom functions, we defined a bunch of variables, ab and c, that each holds an integer.

Variables can hold different kinds of data other than integers. The Arduino language (which, remember, is C++) has built-in support for a few of them (only the most frequently used and useful are listed here):

C++ Keyword

Size

Description

boolean

1 byte

Holds only two possible values, true or false, even though it occupies a byte in memory.

char

1 byte

Holds a number from -127 to 127. Because it is marked as a “char,” the compiler will try to match it to a character from the ASCII table of characters.

byte

1 byte

Can hold numbers from 0 to 255.

int

2 byte

Can hold numbers from -32768 to 32767.

unsigned int

2 byte

Can hold numbers from 0-65535

word

2 byte

Same as the “unsigned int.” People often use “word” for simplicity and clarity.

long

4 byte

Can hold numbers from -2,147,483,648 to 2,147,483,647.

unsigned long

4 byte

Can hold numbers from 0-4,294,967,295

float

4 byte

Can hold numbers from -3.4028235E38 to 3.4028235E38. Notice that this number contains a decimal point. Only use float if you have no other choice. The ATMEGA CPU does not have the hardware to deal with floats, so the compiler has to add a lot of code to make it possible for your sketch to use them, making your sketch larger and slower.

string - char array

-

A way to store multiple characters as an array of chars. C++ also offers a String object that you can use instead that provides more flexibility when working with strings in exchange for higher memory use.

array

-

A structure that can hold multiple data of the same type.

To create a variable, you need a valid name and a type. Just like with functions, a valid name is one that contains numbers, letters, and an underscore starts with a letter and is not reserved. Here is an example:

byte sensor_A_value;

This line defines a variable named sensor_A_value, which will hold a single byte in memory. You can store a value in it like this:

sensor_A_value = 196;

You can print out this value to the serial monitor like this:

Serial.print(sensor_A_value);

The serial monitor is a feature of the Arduino IDE that allows you to get a text from the Arduino displayed on your screen. More about this later, here I want to show you how to retrieve the value stored in a variable. Just call its name. Also, remember the earlier discussion about scope: the variable has to be within scope when it is called.

Another beautiful thing about a variable is that you can change the value stored in it. You can take a new reading from the sensor and update the variable like this:

sensor_A_value = 201;

No problem, the old value is gone, and the new value is stored.

Constants

If there is a value that will not be changing in your sketch, you can mark it as a constant.

Constants have benefits regarding memory and processing speed, and it is a good habit to use these.

You can declare a constant like this:

const int sensor_pin = 1;

Here, you define the name of the variable sensor_pin, mark it as constant, and set it to 1. If you try to change the value later, you will get a compiler error message, and your program will not even get uploaded to the Arduino.

Operators

Operators are special functions that operate one or more pieces of data.

Most people are familiar with the basic arithmetic functions, = (assignment), +, -, * and /, But there are a lot more.

For example, here are the most commonly used operators:

Operator

Function

Example

%

Modulo operator. It returns the remainder of a division.

5%2=1

+=, -=, *=, /=

Compound operator. It performs an operation on the current value of a variable.

int a = 5;
a+= 2;

This will result in a containing 7 (the original 5 plus a 2 from the addition operation).

++, --

Increment and decrement by 1.

int a = 5;
a++;

This will result in a becoming 6.

==, !=, <, >, <=, >=

Comparison operators. Will return a boolean (true or false) depending on the comparison result.

  • == → equality

  • != → un-equality

  • < → less than

  • > → greater than

  • <= → less or equal than

  • >= → greater or equal than

int a = 5;
int b = 6;
boolean c = a == b;

This will result in variable c contains a false boolean value.

!, &&, ||

Logical operators. The “!” operator will invert a boolean value.

! → NOT (invert) of a boolean value

&& → AND of two booleans

|| → OR of two booleans

boolean a = true;
boolean b = true;
boolean c = false;

boolean x = !a; // x → false
boolean y = b && c; // y → false
boolean z = b || c; // z → true

There are more than these. If you want to work at the bit level, for example, and manipulate individual bits within a byte (useful for things like shift registers), you can use bitwise operators. But this is something you can pick up and learn later.

Ok, that is enough for one lesson.

I hope that now, you have a clear understanding of these fundamental concepts in programming: the structure of an Arduino program, functions, variables, and operators. Just with what you have learned so far, you can write very interesting simple programs.

But the real fun begins when your program can make decisions, and when these programs can sense and control the environment. You will learn about these capabilities in tomorrow’s lesson.

There’s only one lesson left in this series, in which you will learn about Loops, conditions, objects, inputs & outputs. Would you like to continue?

New to the Arduino?

Arduino Step by Step Getting Started is our most popular course for beginners.

This course is packed with high-quality video, mini-projects, and everything you need to learn Arduino from the ground up. We'll help you get started and at every step with top-notch instruction and our super-helpful course discussion space.

We publish fresh content each week. Read how-to's on Arduino, ESP32, KiCad, Node-RED, drones and more. Listen to interviews. Learn about new tech with our comprehensive reviews. Get discount offers for our courses and books. Interact with our community. One email per week, no spam; unsubscribe at any time

Image
{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}