Chapter 3: How an Arduino Program Works 

The Arduino community calls a program a sketch. This is because the Arduino was originally written for artists, but nonetheless, a sketch is a computer program. We will use both terms without too much regard to formality. When we are discussing concepts general to computers we'll probably use 'program' and when we are referring to a specific Arduino program we might use 'sketch' so be prepared to see it either way.

We define a program (sketch) as a sequence of human readable text statements following the rules of a programming language. This program can be converted to instructions that a computer can follow to do the sorts of things a computer does.

A computer program is converted to a sequence of instructions that a computer understands and those instructions can be uploaded to a computer to make it do what we tell it to do in the program. These programs are converted from human readable text to machine-readable code by a compiler, which is also a computer program. The process is called compiling, though the Arduino community calls it verifying (or verify) and we'll also use it both ways.

  

Chapter 3: How an Arduino Program Works 

The Arduino community calls a program a sketch. This is because the Arduino was originally written for artists, but nonetheless, a sketch is a computer program. We will use both terms without too much regard to formality. When we are discussing concepts general to computers we'll probably use 'program' and when we are referring to a specific Arduino program we might use 'sketch' so be prepared to see it either way.

We define a program (sketch) as a sequence of human readable text statements following the rules of a programming language. This program can be converted to instructions that a computer can follow to do the sorts of things a computer does.

A computer program is converted to a sequence of instructions that a computer understands and those instructions can be uploaded to a computer to make it do what we tell it to do in the program. These programs are converted from human readable text to machine-readable code by a compiler, which is also a computer program. The process is called compiling, though the Arduino community calls it verifying (or verify) and we'll also use it both ways.

How do we write a program?

Let's repeat the above: a program is some text that follows some rules and can be converted into something that we can feed the computer to use to make decisions about what it is to do next. Text, rules, and decisions - we learn the rules, then we write the text, then the computer makes decisions and does something. This is the sequence:

1. We decide what we want the computer to do.

2. We think about how our programming language rules might be used to get the computer to do our bidding.

3. We write a program using the text editor in the Arduino IDE (Integrated Development Environment).

4. The Arduino IDE sends that text to a compiler on our PC that checks our text against some rules and then builds something that can be uploaded to the computer on the Arduino board. The computer on the Arduino accepts the uploaded data and starts making decisions about how the Arduino board processes information and uses the hardware.

Following this list means that in order for us to write a program we are going to have to learn two things: what are the rules we can use and what are the decisions the computer can make? Fortunately we don't have to learn it all at once before we get started playing with them. We will learn bits and pieces in small steps, playing around as much as we like until it starts making sense.

How an Arduino Program is structured

An Arduino program is structured in four parts.

FIRST: Begin with some comments about the program

SECOND: List variables and constants that all the functions may use. Variables are names for memory locations that a computer can use to store information that might change. Constants are numbers that won't change.

THIRD: Run the setup() function to get the system ready to run the loop() function. This is where you perform tasks that you want done once at the beginning of your program.

void setup()

{

  // do things once at the start of the program

}

SIDE NOTE: the '//' tells the compiler that the line is a comment and that it isn't code that needs to be compiled.

FOURTH: Run the loop() function. This is where you run things in a sequence from the top of the loop to the bottom of the loop, and then you start over again at the top, looping until the machine gets turned off.

void loop()
{
  // Do the first thing
  // Do the second thing
  // Do any number of things
  // Do the last thing in the list
  // Go back to the beginning of this list
}

Structure of the Arduino Blink example

 

I have taken the Blink program from the Arduino Examples and added the lines showing each of the four sections.

FIRST: Opening comments:

/*
* Blink
*
* The basic Arduino example. Turns on an LED on for one second,
* then off for one second, and so on... We use pin 13 because,
* depending on your Arduino board, it has either a built-in LED
* or a built-in resistor so that you need only an LED.
*
* http://www.arduino.cc/en/Tutorial/Blink

*/

SECOND: List variables

int ledPin = 13; // LED connected to digital pin 

 

THIRD: Things to do once at the beginning

void setup() // run once, when the sketch starts{
    pinMode(ledPin, OUTPUT); // sets the digital pin as output
}

 

FOURTH: Do things in a loop

void loop() // run over and over again
{
   digitalWrite(ledPin, HIGH); // sets the LED on
   delay(1000); // waits for a second
   digitalWrite(ledPin, LOW); // sets the LED off
   delay(1000); // waits for a second
}

 

In the January article we saw how to take the example program Blink, load it in the Arduino IDE, compile it, and upload it to the Arduino board. You can locate this program in the Arduino IDE menu: File\Examples\Digital\Blink. Now would be a good time to repeat that lesson: click on the Blink example then follow the instructions from Chapter 1 to compile and upload.

And if it doesn't compile?

We write a software program using tools that allow us to create these computer instructions in some human comprehensible form, like text files that use words and symbols available on a keyboard. Our text file (source code) must follow a set of rules that are provided for a specific programming language, and then we must submit that file to some compiler software that will then do one of two things: compile it or refuse and give you hints about what went wrong that provide a guide to making the source file more palatable to the compiler.

 

We will intentionally make a mistake in the blink example to generate an error by deleting the last H in the parameter HIGH in the digitalWrite function. The compiler can find HIGH, but it can't find HIG so it stops the compilation and generates an error as shown in Figure 1.

 

 

Figure 1: Error

 

The process of finding errors in a program is called debugging. In the example given, debugging, in this case, is easy since the Arduino IDE tells you what the problem is and even shows you where it is located. The error message was: "'HIG' was not declared in this scope" and the line with the error was highlighted in orange. The message may be somewhat cryptic at this point in your learning since we haven't discussed what 'declared' or 'scope' mean, but by pointing out that the 'HIG' was giving the compiler problems you can easily guess that it is the culprit and if you don't already know that the only valid second parameters for the pinMode function are HIGH or LOW, you can highlight the digitalWrite function as shown in Figure 2 and then open the help menu and click on Find in Reference.

 

Figure 2: Find in reference

 

This will open the page for digitalWrite where as you can see in Figure 3, the values for the second parameter are HIGH and LOW.

 

Figure 3: Found in reference

 

If we add back the 'H' then the program will compile. While this example was easy, program debugging often isn't so easy since the error messages may be quite cryptic. When it isn't entirely clear what is going on, it is probably best to refer to code that you know works and has a similar line in it so that you can see what you might be doing differently. If you still can't figure it out, then it is time to go on the Internet and ask the question on a forum (more on that process later).

 

We have been using some terms that we haven't yet defined (like function, int, and void). We'll do that a lot in our study of the Arduino since there is just too much to introduce everything in a perfect order all at once. We'll get to those terms below.

 

Learning the programming language rules and concepts

Arduino is, among other things, a programming language. But one of the first things to learn about the Arduino language is that underlying it is the C and C++ programming languages. What Arduino does is to provide a novice-friendly buffer that hides some standard C and C++ requirements and adds some pre-written functions that help the novice use the Arduino board. [They also provide many libraries of functions and many working projects to use as examples.] You don't need to know a thing about C or C++ in order to use Arduino or this text. Since the Arduino keeps it simple, you can often just look at existing code to get an intuitive feel for what is going on and pick up many the rules by osmosis. Of course as you grow in this process and want to do more complex things you'll also want to learn more about the rules. Let's first introduce some rules for a programming concept: the variable.

What is a variable?

As we learned earlier in this chapter, variables are programming elements that can take different values. When we define variables we must tell the compiler what type of a variable it is. To a compiler the variable type indicates the amount of data that must be stored. For instance, a variable with a char type can store any number from 0 to 255, and an int type can store any number from 0 to 65535. In C we define our variables either at the beginning of a code module (usually a file) outside of any function for it to be available to any function in that module, or we define the variable within a function for it to be available only to statements within the function. For example:

 

// Module start

 char myChar;

 void myFunction(){

int myInt;

  // statements

}

// Module end

 

This example defines the char type variable myChar that can be used by any function in the module and the int type variable myInt that can be used only by statements in the myFunction function.

 

What is a function?

We have been using the word 'function' which has a special meaning in our programming. It refers to a block of software that can be used by referring to the function name followed by parentheses containing a list of information that can be used by the function. For the Arduino, an example of a function is the line shown in Figure 4 with the function: pinMode(13, OUTPUT). The function name is 'pinMode' and it will use the information given between the parenthesis which in this case is the number '13' and the word 'OUTPUT' separated by a comma. When the program uses the pinMode(13, OUTPUT) function, the computer will call a block of software from a library of Arduino functions. This unseen-by-you software will use the '13' and 'OUTPUT' to set the Arduino pin 13 to output voltage signals, meaning the program can set the voltage on pin 13 to 5-volts or 0-volts (ground). Since this pin is also connected to an LED on the Arduino, then setting the pinMode to output lets us provide the LED with +5 volts to turn it on or set it to 0 volts (ground) to turn the LED off. After setting the mode for the pin, we can then use the digitalWrite function to control the voltage. By writing the digitalWrite(13,HIGH); statement in your program, the Arduino will provide 5-volts to the LED shown in Figure 1 and cause it to light up. Adding the statement digitalWrite(13,LOW); causes it to set the voltage to 0 thus turning the LED off

 

Figure 4: pinMode

 

How does an Arduino Program Flow?

We already looked a bit a how a program works, but let's look again from a different angle (we'll use a picture this time) to reinforce the important concept of program flow.

 

Figure 5: Program flow

 

An Arduino program has a minimum of two functions: setup() and loop(). Neither of these functions take parameters in the parentheses. As shown in Figure 5, the setup() function runs once and is used to set up the Arduino. The second function, loop() will run each statement in a loop: a sequence beginning at the top and when it has run the last statement it will go back to the top of the list and run through them again looping through them continuously. In Figure 5 we see that we use pinMode to setup pins 12 and 13 as outputs and that we use the library functions digitalWrite and delay in the loop to put 5-volts on each pin, wait a second, put 0-volts on each pin, wait a second and then go back to the top of the loop to repeat the sequence until the Arduino is turned off.

 

We saw above how Arduino software flows for a program that does something very simple. But most programs do things that are much more complex, and programming languages provide tools for controlling the flow of the program (controlling the execution sequence of the functions). For example you might want to control the flow of a program so that the LED turns on and off once a second forever as we've seen with the Blink example, or you may want the program to only turn the LED on and off ten times. Let's look at some of the core concepts involved.

 

The 'while' flow control statement

In the Blink program from the Arduino Examples directory we saw how to blink an LED in one-second intervals forever. But what if we want blink the LED 5 times and then stop blinking? For this we will need to use a variable to contain the data for the number of times to blink. And we will use the C control flow statement while to loop through a block of code and repeat action of that block the number of times indicated by the variable.This is easier to understand looking at the code than talking about it so:

 

void loop() {
  // define the count variable and set it to 5
  char myCount = 5;

  // run the following while count is greater than 0
  while(myCount){       
     digitalWrite(13, HIGH);    // set the LED on
     delay(1000);                  // wait for a second
     digitalWrite(13, LOW);    // set the LED off
     delay(1000);                 // wait for a second
     myCount = myCount - 1; // decrement the count
   }

   while(1);
}

 

We start the loop function by defining a variable 'myCount' with char variable type and we set the value of that variable to 5 using the equate operator '='. Next we create a block of code that looks like a function but isn't. We write while(count){ then the code to run while count is true meaning that count is not equal to zero. The while(count) block begins with an open brace: { and ends with a close brace: } which is the way we create a block of code in C. It doesn't matter much to the while control flow statement, the C code will run whatever is in the block and then return to the while(expression) and check it to see if the expression is still true, if it is true it runs the block again and then rechecks, repeating the process until the expression becomes not true (equal to 0). In our example, the expression is myCount and it starts out as 5 and then at the end of the while(myCount) block, the count is decremented meaning that the value of myCount is decreased by 1 so that the first time through count becomes 4 and when the program returns to the while(myCount) statement it sees that myCount is 4 which isn't 0, so it repeats the block making myCount equal 3 and repeats for 2, 1, and 0. But when the program returns to the while(myCount) this time it sees that myCount is 0 which is by definition false and the program exits the while loop.

One interesting thing about the while control flow statement is that it can be used to stop a program and have it spin its wheels forever using:

while(1);

The C program evaluates the expression and sees that it is true so it does what the statement tells it to do between the closing parenthesis ')' and the semicolon ';' - which is nothing. It then reruns the statement and examines the while(expression) statement and sees that it is true - you get the picture? And, yes there are times you want to do this, like when you want to have a program stop. In Lab 1 we will use while to blink the LED 5 times then do nothing after that.

Another way to stop the loop

We can also cause this program to terminate by defining the myCount = 5; variable outside any function:

  
// declare myCount outside a functon
char myCount = 5;
  
void loop() {
  // run the following while count is greater than 0
  while(myCount){       
     digitalWrite(13, HIGH);     // set the LED on
     delay(1000);                   // wait for a second
     digitalWrite(13, LOW);     // set the LED off
     delay(1000);                  // wait for a second
     myCount = myCount - 1; // decrement the count
   }
}
Now when the myCount is decremented to 0 and the while(myCount) becomes false the loop() function returns to the top, checks the while(myCount) sees it is false, skips over the contained block, returns to the top and keeps repeating this process until you turn off the computer. In programming we will often see that there are many different ways to do the exact same task and sometimes there is no clear winner as to which might be the best way.

The 'for' flow control statement

We could have accomplished the same task: blink the LED on and off 5 times using the for control flow statement. The rules for this statement can get somewhat complex, but we will only use it in the form that let us do a block of code for a specific number of counts:

for(count = 0; myCount < 5; myCount++) { // run the following 5 times

This statement uses three math operators used in three statements within the parenthesis that follows 'for': the '=' (equate operator), the '<' (less-than operator), and the '++' (post-increment operator). We've seen that = sets the variable on the left of the operator to the value of the variable or constant on the right - for 'myCount < 5' case it is the constant 5. The < operator lets the second statement: count < 5 evaluate if myCount is in fact less than 5 - it asks 'is it true that myCount is less than 5?' and if that is true then the following block of code (code between the { and }) is allowed to run. But before the block of code is run, the third statement in the parenthesis adds 1 to the myCount. So the first time the statement is run by the program, the count is set to 0 in the first statement, the truth of the statement: count < 5 is judged (it is true), then in the third statement myCount is incremented so that it becomes equal to 1. Now the block of code is run by the program to blink the LEDs and the program returns to the for statement, but this time it doesn't set myCount to 0 in the first statement - that is only done for the first pass through the block. It checks the second statement and sees that it is true that myCount which is now 1 is less than 5, in the third statement it increments myCount so that it now equals 2, and it runs the block of code blinking the LED again. And so forth until myCount has been incremented to equal 5 and the 'myCount < 5;' statement is false so the program does not run the block again, but jumps over it and runs what ever statements follow. [In our case this is for(;;) and as with while(1) the (;;) is always true so the program stops blinking the LED and spins its wheels forever.]

void loop() {
  int i;

  for(i = 0; i < 5; i ++) {     // run the following 5 times
    digitalWrite(13, HIGH);   // set the LED on
    delay(250);                   // wait for a second
    digitalWrite(13, LOW);    // set the LED off
    delay(250);                   // wait for a second
  }
  
  for(;;); // Spin your wheels forever
}

You might well ask why are there two different ways to do the same thing - while loops and for loops - and the answer is that there are more advanced cases that we will see later where one or the other while or for has an advantage. In Lab 2 we will use for to blink the LED 5 times then do nothing after that. Now let's take some time to do some hands on lab exercises to reinforce and expand on what we've learned so far.

Lab 1: Counting

 

Parts Required:

1 Arduino

1 Arduino Proto Shield

 

Time required: 10 minutes

Check off when complete:

  Open the Blink program

  Delete the content of the loop() function by highlighting the code with the mouse cursor right button pressed, then press the left mouse button and select 'Cut' as shown in Figure 6.

 

Figure 6: Delete the contents of loop

 

  Type into the loop() function the code shown below and in Figure 7:
 
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;

void setup(){
  pinMode(led,OUTPUT);
}

void loop()
{
  int i;
 
  for(i = 0; i < 5; i ++) {     // run the following 5 times
    digitalWrite(13, HIGH);   // set the LED on
    delay(250);                   // wait for a second
    digitalWrite(13, LOW);   // set the LED off
    delay(250);                   // wait for a second
  }
 
  for(;;); // Spin your wheels forever
}

 

Figure 7: Figure - Blink modified to count

 

  Compile and upload the program and verify that the LED blinks 5 times and stops.

  Beneath the int i; statement write char myCount = 10;

  In the loop() function for statement substitute myCount for the 5 as shown below:

int i;

char myCount = 10;

for(i = 0; i < myCount; i ++) {  // run the following myCount times

  Compile and upload the program and verify that the LED blinks 10 times and stops.

 

Lab 2: Timing

We have used the delay(250) function in several of our examples. The 250 is for 250 ms (milliseconds), (there are 1000 ms in a second so 250 ms is a quarter of a second), but it can be any number of ms up to the maximum allowed type for the delay parameter which is that of an 'unsigned long'. For the Arduino an unsigned long can have values from 0 to 4,294,967,295 and that is a lot of milliseconds. In this lab we will see how to use the delay function to time the blinking of an LED.

 

Parts Required:

1 Arduino

1 Arduino Proto Shield

Part 1 - Blink Timing

Sometimes we want to control the timing of events. In the original blink program we controlled the LED on and off times with the delay() function by setting the number of millisecond to 1000 (one second). What happens if we shorten that interval?

 

Time required: 5 minutes

Check off when complete:

  Open the Blink example program and change the 1000 to 500.

  Run the program and note that the LEDs are blinking faster.

If we continue to reduce the number of milliseconds the LED will appear to blink faster and faster, but at some point when lowering that delay value it will blink so fast that we can no longer perceive that it is blinking. Our eye tells us that the LED is on continuously. This phenomenon is called Persistence of Vision (POV). Lets do an experiment to see how fast we need to blink an LED to make our eyes think it is on continuously.

 

Time required: 15 minutes

Check off when complete:

  Open the blink program and change the 1000 to 100.

  Run the program and note that the LEDs are blinking faster.

  Change the milliseconds from 1000 to 1.

  Run the program and note that the LED appears to be on continuously.

  Bracket the millisecond value until you find the highest value that causes the LED to appear to be on continuously to you.

  If you are in a class, compare this value to the value other students have found.

 

Part 2 - Dimming the LED

You can turn the LEDs on and off at different intervals, for instance you could turn them on for 100 millisceonds and off for 1000 milliseconds, which would make the LED appear to flash on momentarily then be off for a second. You can use this and POV to control the perceived brightness of the LED.

 

Time required: 15 minutes

Check off when complete:

  Set the delay() off time to the value you determined above in the POV experiment. (In my case this was 13 milliseconds).

  Set the delay() on time to 1 milliseconds, then verify and upload the program.

  Note that the LED appears dimmer than in the original experiment.

  Set the delay() on time to 1/2 of your original POV value and notice that the LED appears brighter than the 1ms blink rate.

  Play with the on and off times and observe the effects.

 

What we are seeing is that the LED is being turned on and off too fast to see it blink but we are leaving it off longer than we are leaving it on so less total light is being seen.

The following is an example program that will dim LED 13 on the Arduino

  
/*
 Dimmer - uses the delay() function to dim the LED
 */
 
int onTime = 20;
int offTime = 0;

// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}

// the loop routine runs over and over again forever:
void loop() {
  int i;
  
  for(i=0;i<5;i++)
  {
    digitalWrite(led, HIGH);  
    delay(onTime);               
    digitalWrite(led, LOW);    
    delay(offTime);               
  }
  
  // change the on and off counts
  if(onTime < 20) onTime++; // increment onTime
  else onTime = 0; // reset to 0
  if(offTime > 0 ) offTime--; // decrement offTime
  else offTime = 20; // reset to 20
} 

Please note that this helps demonstrate the delay() function but it is not the best way to dim LEDs on the Arduino. We will get to that in Chapter 5 where we will look at using the timer/counter peripheral to dim an LED.

Part 3 - Emergency Flasher

The example used in this lab comes from a contribution (thanks Rvw) to the arduinoclassroom.com forum posted at:

http://arduinoclassroom.com/index.php/forum/chapter-1/19-tweaked-myblinky

 

Time required: 15 minutes

Check off when complete:

  Open the Arduino IDE

  Delete the content of the loop() and type in the following code:

/* 
MyBlink3
Turn on an LED on for .05 seconds, then off for .05 seconds 
three times in a row and then pauses for one second. This gives 
an emergency flasher effect.
*/

// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;

// the setup routine runs once when you press reset.
void setup() {
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH); // turn the LED on 
  delay(50); // wait for .05 seconds
  digitalWrite(led, LOW); // turn the LED
  delay(50); // wait for .05 seconds
  digitalWrite(led, HIGH);
  delay(50);
  digitalWrite(led, LOW);
  delay(50);
  digitalWrite(led, HIGH);
  delay(50);
  digitalWrite(led, LOW);
  delay(1000); // wait for one second
}
  Play around with the delays and LED sequences to see how your changes affect the visual output.

 

Lab 3: Two LEDs - Railroad crossing

You may have seen how the lights at some railroad crossings blink in opposition to each other: one is on while the other is off. We can do this with two LEDs.

 

Parts Required:

1 Arduino

1 Arduino Proto Shield

2 Red LEDs

2 1000 ohm Resistors

2 jumper wires

 

Time Required: 20 minutes

Check off when complete:

  Unplug your Arduino from the USB (and battery if one is used) to make sure the power is off before building the circuit.

  Follow the illustration in Figures 8 and 9 and add the two LEDs and resistors to the breadboard.

  Note that the LEDs have their long legs to the bottom of the resistors and the short legs are connected to ground.

  Based on what you learned about how to blink a single LED, spend some time to think about how you might blink two LEDs. Now think about how you might blink two LEDs so that one is off while the other is on.

  Plug the USB cable into the Arduino.

  Open the Blink example program and change it so that the LEDs on pins 12 and 11 blink in an alternating pattern at 1/2 second on and 1/2 second off.

 

You may very well have figured out how to do this on your own, but whether you did or not, the following modification of the Blink program shows one way to accomplish the task:

Figure 8: Two LEDs

 

 

Figure 9: Two LEDs Schematic

 
void setup() {
   pinMode(12, OUTPUT); // initialize pin 12 as output 
   pinMode(11, OUTPUT); // initialize pin 11 as output 
} 

void loop() { 
     digitalWrite(12, HIGH); // set the LED on 
     digitalWrite(11, LOW); // set the LED on 
     delay(500); // wait for 1/2 a second 
     digitalWrite(12, LOW); // set the LED off 
     digitalWrite(11, HIGH); // set the LED on 
     delay(500); // wait for 1/2 a second
}

This is a simple modification to what we have already learned. We only have to set one LED HIGH (turned on) and the other LED LOW (turned off).