Custom functions can be used just like built-in Arduino functions and meth- ods. For example, the square_number() function could be used this way:
void setup() {
Serial.begin(9600);
long mySquare = square_number(5); Serial.println(mySquare);
}
long square_number(int value) {
return value * value; }
void loop() {
//Nothing to do here }
You could even use the output of the function as a function parameter in an- other function like Serial.println() as in the next example:
void setup() {
Serial.begin(9600);
//Send the output of square_number() as a parameter to //println()
Serial.println(square_number(5)); }
long square_number(int value) {
return value * value; }
void loop() {
//Nothing to do here }
39
As you can see, functions are useful in organizing code into discrete blocks. Ideally, good functions are generic enough to be utilized in other projects al- though it will not always practical to do so.
Listing 2.7 demonstrates how functions could be used to create a more robust and useful sketch. This sketch will print the octave and note name asso- ciated with a Music Instrument Digital Interface (MIDI) note number. You can interact with the sketch by entering values in the Serial Monitor window. Before looking at source code, consider the logic of the sketch in pseudo-code:
• Ask the user to enter a MIDI note value • If the user has entered a number:
o Determine the octave
o Determine the note number (0–11)
o Convert the note number to text description o Print the results
o Ask the user to enter another number
At the heart of the sketch are two convenience functions. The first func- tions returns the octave designation of a MIDI note, and the second function returns the note number (a value from 0 to 11) representing the chromatic notes from C to B.
int getOctave(int midi_note) {
//Calculate the octave of the midi note return (midi_note / 12)-1;
}
int getNoteNumber(int midi_note) {
//Calculate the midi note value (0-11) return midi_note % 12;
}
A third function, getNoteName() returns a text representation of the note based on its MIDI note number. The function does this by using a switch statement to evaluate the value returned by getNoteNumber(). Also note that the function compares the result returned by getNoteNumber() to an enumeration that is initialized at the top of the sketch. The values could have been “hard-coded” into this example, but the enumeration makes the logic of the sketch easier to follow and maintain. We will talk about strings and character arrays later in the chap- ter, but bear in mind that this syntax is a common way to return a string literal (a block of text) from a function.
char const *getNoteName(int midi_note) {
//Get note number (0-11)
int note = getNoteNumber(midi_note);
//Use a switch statement to determine note name. This //could also be done with if statements.
40
switch(note) {
//Note: each case returns so break keyword is not //needed here
case C: return "C"; case Db: return "Db"; case D: return "D"; case Eb: return "Eb"; case E: return "E"; case F: return "F"; case Gb: return "Gb"; case G: return "G"; case Ab: return "Ab"; case A: return "A"; case Bb: return "Bb"; case B: return "B";
default: return "Unknown"; }
}
A final function, printNoteInfo(), is used to print note information to the Serial Monitor. The function takes the note value, octave, and text description as pa- rameters and formats the output to the Serial Monitor.
void printNoteInfo(int value, int octave, char const * note_ name)
{
//Print information about the note:
Serial.print("Value: "); Serial.println(value); Serial.print("Octave: "); Serial.println(octave); Serial.print("Note: "); Serial.println(note_name); Serial.println("=========================");
}
Although this sketch could have been written without functions, it is easy to see that functions simplify the underlying logic. In fact, only a few lines of code are required in the main loop() to complete the sketch:
void loop() {
if (Serial.available() > 0) {
//Read the incoming byte. int value = Serial.parseInt(); //Print note information.
printNoteInfo(value, getOctave(value), getNoteName (value));
//Prompt the user to enter another number: Serial.println("Enter a MIDI note number: "); }
41
The sketch is shown in its entirety in Listing 2.7
//An enumeration is a convenient way to refer to note numbers. //In this case, C = 0, Db = 1, and so on
enum{C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B}; void setup()
{
Serial.begin(9600);
Serial.println("Enter a MIDI note number: "); }
void loop() {
if (Serial.available() > 0) {
//Read the incoming byte. int value = Serial.parseInt(); //Print note information.
printNoteInfo(value, getOctave(value), getNoteName (value));
//Prompt the user to enter another number: Serial.println("Enter a MIDI note number: "); }
}
int getOctave(int midi_note) {
//Calculate the octave of the midi note return (midi_note / 12) -1;
}
int getNoteNumber(int midi_note) {
//Calculate the midi note value (0-11) return midi_note % 12;
}
char const *getNoteName(int midi_note) {
//Get note number (0-11)
int note = getNoteNumber(midi_note);
//Use a switch statement to determine note name. This //could also be done with a series of "if" statements. switch(note)
{
//Note: each case returns so break keyword is not //needed here
case C: return "C"; case Db: return "Db"; case D: return "D"; case Eb: return "Eb"; case E: return "E"; case F: return "F"; case Gb: return "Gb";
42
case G: return "G"; case Ab: return "Ab"; case A: return "A"; case Bb: return "Bb"; case B: return "B"; default: return "Unknown"; }
}
void printNoteInfo(int value, int octave, char const * note_ name)
{
//Print information about the note:
Serial.print("Value: "); Serial.println(value); Serial.print("Octave: "); Serial.println(octave); Serial.print("Note: "); Serial.println(note_name); Serial.println("=========================");
}
Listing 2.7 Midi Note Explorer
Sample output from the sketch is shown below:
Enter a MIDI note number: Value: 60
Octave: 4 Note: C
========================= Enter a MIDI note number: Value: 31
Octave: 1 Note: G
========================= Enter a MIDI note number: Value: 49
Octave: 3 Note: Db
=========================