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.
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?
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
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?
Now we want a procedure blinker
that takes 3 arguments
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.
You have now written procedures that take arguments. There is only one mystery left in our magical incantation.
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.
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