Experiment 7

The Magical Incantation Explained

When we first introduced procedures we said to treat the void and () as a magical incantation to define procedures. And our gloss of something like

void blink5()

was something like this is how to blink5.

Now it is time to dissect the incantation.

Arguments

Suppose we wanted procedures to blink the led a certain number of times. We could have

int led = 13;
wait = 200;

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

void blink(){
    digitalWrite(led, HIGH);
    delay(wait);
    digitalWrite(led, LOW);
    delay(wait);
}

void blink2(){
    digitalWrite(led, HIGH);
    delay(wait);
    digitalWrite(led, LOW);
    delay(wait);
    digitalWrite(led, HIGH);
    delay(wait);
    digitalWrite(led, LOW);
    delay(wait);
}

void blink3(){
    digitalWrite(led, HIGH);
    delay(wait);
    digitalWrite(led, LOW);
    delay(wait);
    digitalWrite(led, HIGH);
    delay(wait);
    digitalWrite(led, LOW);
    delay(wait);
    digitalWrite(led, HIGH);
    delay(wait);
    digitalWrite(led, LOW);
    delay(wait);
}

void loop(){
    blink();
    delay(wait * 3);
    blink2();
    delay(wait * 3);
    blink3();
    delay(wait * 3);
}

We can be a bit clever and shorten that code to:

int led = 13;
wait = 200;

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

void blink(){
    digitalWrite(led, HIGH);
    delay(wait);
    digitalWrite(led, LOW);
    delay(wait);
}

void blink2(){
    blink();
    blink();
}

void blink3(){
    blink();
    blink();
    blink();
}

void loop(){
    blink();
    delay(wait * 3);
    blink2();
    delay(wait * 3);
    blink3();
    delay(wait * 3);
}

But wouldn’t it be great if we could just tell blink how many times to blink instead of having all those specialized blink procedures. For that we can use an argument. Procedures can take zero, one, or more arguments. So far, we have been using procedures with zero arguments. That is what the empty parentheses represent, both when we define a procedure

void blink(); // define a procedure blink that takes no arguments.

and when we use a procedure:

void loop(){
    blink();          // call blink with no arguments
    delay(wait * 3);
    blink2();         // call blink2 with no arguments;
    delay(wait * 3);
    blink3();         // call blink3 with no arguments;
    delay(wait * 3);
}

Now we are going to create a function called blink that will take one argument, which is the number of times to blink. To use it is simple, we just give the number in the parentheses:

void loop(){
    blink(1);          // call blink with the argument 1
    delay(wait * 3);
    blink(2);         // call blink with the argument 2;
    delay(wait * 3);
    blink(3);         // call blink with the argument 3;
    delay(wait * 3);
}

When we define the procedure blink we need to specify that it takes an argument that will be an integer. As with variables we can name the argument anything we want. In this case, let’s name it num:

void blink(int num){
    ...
}

Now we can use the argument num within the procedure just like we can use a variable. Just to keep things simple, let’s just print the number to the serial monitor. Here is the complete program:


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

}

void blink(int num){
    Serial.print("calling blink with the argument ");
    Serial.println(num);
}

void loop(){
    blink(5);
    delay(1000);
    blink(10);
    delay(1000);
    blink(3);
    delay(1000);
}

When we load that code into the Arduino we will see displayed in the serial monitor

calling blink with argument 5
calling blink with argument 10
calling blink with argument 3

printed repeatedly.

You may have noticed that we used:

Serial.print("calling blink with the argument ");

instead of

Serial.println("calling blink with the argument ");

Serial.print doesn’t move the cursor to the next line so we have the text calling blink with the argument and the number printed on the same line.

That’s all lovely, but what we really wanted blink to do was blink an led a certain number of times. Can you revise it so it blinks the led, num times?

Multiple Arguments

Let’s say we want a procedure that not only specifies how many times to blink but also which led to blink. So something like:

void blinkLed(redLed, 3);

which says to blink the redLed three times. Now we have a procedure with two arguments. We can define it with

void blinkLed(int led, int num){
    ...
}

The full program is

int redLed = 13;
int blueLed = 3;
int greenLed = 4;

void setup() {
  pinMode(redLed, OUTPUT);
  pinMode(blueLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  Serial.begin(9600);
}


void blinkLed(int led, int num){
  Serial.print("Blink the led connected to pin ");
  Serial.print(led);
  Serial.print(", ");
  Serial.print(num);
  Serial.println(" times");
}

void loop() {
  blinkLed(redLed, 5);
  delay(1000);
  blinkLed(blueLed, 10);
  delay(1000);
  blinkLed(greenLed, 3);
  delay(1000);

}

This prints repeatedly:

Blink the led connected to pin 13, 5 times
Blink the led connected to pin 3, 10 times
Blink the led connected to pin 4, 3 times

Remix 2: You guessed it

Instead of printing


Blink the led connected to pin 13, 5 times

can you construct a circuit and revise the code so it blinks the correct led the correct number of times?

Remix 3: Blinker

Now we want a procedure blinker that takes 3 arguments

  • the led to blink
  • how many times
  • the length of the delay

So for example.


blinker(blueLed, 3, 200);
blinker(redLed, 2, 400);

would blink the blue led three times, 200 milliseconds on and 200 milliseconds off then it would blink the redLed twice at the slower speed of 400 ms on and 400 off.

Congratulations

You have now written procedures that take arguments. There is only one mystery left in our magical incantation.

Returning a value

Sometimes we want a procedure to return a value. For example, suppose we want a procedure to add two numbers:

add(2,3);
add(10,5);

and we would like add to return the sum. The void in the incantation

void blink5(){
    ...
}

specifies that the procedure does not return a value. If we want the procedure add to return the sum, we would specify that it returns an integer:

int add(int num1, int num2){
    ...
}

Within the procedure we need to specify what to return:

int add(int num1, int num2){
    int sum = num1 + num2;
    return(sum);
}

A complete program might be:

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

int add(int num1, int num2){
    int sum = num1 + num2;
    return(sum);
}

void loop(){
    int sum1 = add(3, 4);
    int sum2 = add(5, 5);
    // for fun let's multiple those together and print the result
    Serial.println(sum1 * sum2);
    delay(1000);
}

which should print 70 repeatedly.

Let’s say we only want to print the result exactly once. We know loop runs repeatedly so we need to move our code somewhere that only runs once.

setup runs only once so let’s move it there:

void setup(){
    Serial.begin(9600);
    int sum1 = add(3, 4);
    int sum2 = add(5, 5);
    // for fun let's multiple those together and print the result
    Serial.println(sum1 * sum2);
    delay(1000);
}

int add(int num1, int num2){
    int sum = num1 + num2;
    return(sum);
}

void loop(){

}

Sweet! That may come in handy later.

Remix 4: blinkest

Suppose we want to do something like the following:

`

int redLed = 13;
int blueLed = 3;
int wait = 200;

void setup() {
  pinMode(redLed, OUTPUT);
  pinMode(blueLed, OUTPUT);
  Serial.begin(9600);
}

 // TBD


void loop() {
  blinka("red");
  blinka("red");
  blinka("blue");
  blinka("blue");
}

In this version, instead of the variable names redLed and blueLed we have a String representing the color. “red” for example. In this case we might want a procedure to match the string “red” to the correct pin and return that value. Let’s call that function lookup:

int lookup(String color){
    if (color == "red"){
        return redLed;
    }
    else { //it must be blue
        return blueLed;
    }
}

The complete program might look like:

int redLed = 13;
int blueLed = 3;
int wait = 200;

void setup() {
  pinMode(redLed, OUTPUT);
  pinMode(blueLed, OUTPUT);
  Serial.begin(9600);
}

 int lookup(String color){
    if (color == "red"){
        return redLed;
    }
    else { //it must be blue
        return blueLed;
    }
}

void blinka(String theColor){
    int led = lookup(theColor);
    digitalWrite(led, HIGH);
    delay(wait);
    digitalWrite(led, LOW);
    delay(wait);
}

void loop() {
  blinka("red");
  blinka("red");
  blinka("blue");
  blinka("blue");
}

Can you write code for blinkest that specifies a string representing a color (red, blue, or green) and how many times to blink that led. For example,

void loop() {
  blinkest("red", 1);
  blinkest("blue", 2);
  blinkest("green", 3);
}

Should

  • blink the red led once (200 ms on and 200 off) then wait one second.
  • blink the blue led twice (200 ms on and 200 off) then wait one second.
  • blink the green led three times (200 ms on and 200 off) then wait one second.

Previous section:
Next section: