Building Our Own Functions

If you haven't finished the puzzles on the previous page, please take a minute to work on them. Programming a computer is about figuring out how to make the computer do what you want it to do. Actually practicing that is how you will learn.

In our examples so far, we have only had two functions -- the mandatory functions setup() and loop(). But we can make our own functions, and call them. This is a way to make a program that has a lot of repetition get much shorter. It also makes programs easier to read.

If we wanted our program to send SOS out in Morse code on the red LED, we could use a program like this one.

Let's look at the parts of that program one by one. After the setup() function, we see the line:

enum { DOT_PAUSE = 200 };

This creates a named constant, called DOT_PAUSE, that has the value 200. Anywhere we might want a value of 200 (say in a delay() function), we could instead use the constant DOT_PAUSE. Why would we want to do that? Well, in this case, it means that if we want to send out our Morse code more slowly, so that someone who doesn't know Morse yet has time to look up each letter on a cheat sheet, we could just change DOT_PAUSE to a larger number, say 500, and now all the pauses in the program would be longer. Just by making one simple change, instead of having to find all the values of 200 in the program, and change each one. Doing it the hard way is error-prone. There might be a value 200 that has some other use, and we might change it by accident, because it looked the same as the delay between dots.

The next line looks like this:

enum { DASH_PAUSE = 3 * DOT_PAUSE };

It makes a named constant DASH_PAUSE, which is three times longer than DOT_PAUSE. The asterisk (*) is the symbol most of the computer languages used in this book use for multiplication. That is because the letter 'x' is a normal letter in many words, and we want to avoid using words for arithmetic operations like multiplication.

The next two lines set up the pauses between letters and words:

enum { LETTER_PAUSE = 4 * DOT_PAUSE };

enum { WORD_PAUSE = 2000 };

Now we come to the first new function in the program:

void
dot()
{
  digitalWrite( 13, HIGH );
  delay( DOT_PAUSE );
  digitalWrite( 13, LOW );
  delay( DOT_PAUSE );
}

The dot() function turns the LED on, pauses, turns it off, and pauses again. That is how we send a Morse code dot.

The next function sends a dash. Note that the LED is on for a bit longer than it was for a dot:

void
dash()
{
  digitalWrite( 13, HIGH );
  delay( DASH_PAUSE );
  digitalWrite( 13, LOW );
  delay( DOT_PAUSE ); 
}

Now we have a function that sends the letter 's' in Morse code:

void
send_s()
{
  dot();
  dot();
  dot();
  delay( LETTER_PAUSE );
}

It calls dot() three times, and pauses. The next function sends the letter 'o' by sending three dashes and pausing:

void
send_o()
{
  dash();
  dash();
  dash();
  delay( LETTER_PAUSE );
}

Now we have everything we need to send the word SOS out in Morse code on the red LED:

void
send_SOS()
{
  send_s();
  send_o();
  send_s();
}

The loop() function is now just two lines long:

void
loop()
{
  send_SOS();
  delay( WORD_PAUSE ); 
}

Now copy and paste the program into the IDE and click on the Upload button to compile it and send it to the Nano.

So what good is flashing SOS on the red LED going to do anyone?

Well, suppose we wrote a program to water our potted plant every day for us, so we could work on more important things. The program would make the Nano control a valve that let water leak out of a bucket when it sensed that the soil in the pot was dry. But what should it do if the bucket of water is empty? The program needs a way to tell us that it needs help. It could send out an SOS on the only thing it has to catch our attention -- a red LED.

Later we will give out Nano many other ways to communicate, such as printing words on a LCD screen, making a speaker beep, or even talk. But sometimes all you have is an LED to use for communication.