Read The Arduino Inventor's Guide Online
Authors: Unknown
Notice that in this example we changed the duration the
tone()
is played
➏
and the
delay()
➐
to
50
ms. This will allow you to create faster changes in notes. Otherwise, you would only be able to play notes that were half a second long! Finally, you want to make sure that the Arduino only plays a tone when the SoftPot is pressed. To do this, you use the
else()
statement to detect when the SoftPot is not being pressed
➑
and the
noTone()
command to turn the buzzer off.
Now, instead of using a frequency sent from the Serial Monitor, the Arduino uses the raw sensor value from the SoftPot. To play around, simply squeeze the SoftPot between your thumb and index finger, applying pressure at different points along the sensor. As you slide your fingers up and down the SoftPot, you can generate tones from 1 Hz to 1,023 Hz. What do you hear? Does it sound like aliens are landing? Pretty cool—now you have your very own special effects generator! Can you play anything that resembles a song? If not, take a look at the next example.
Now that you have a feel for how the Arduino can make sounds, it’s time to map the sensor readings of the SoftPot to real notes so you can make actual music. You’ll break the sensor up into eight distinct sections (or keys) and map these to an index that you can use to play notes.
Copy the sketch in
Listing 10-3
into the Arduino IDE, and upload it to your device.
LISTING 10-3:
Tiny Electric Piano sketch
//Tiny Electric Piano Example Code
➊
int
frequencies[] = {262, 294, 330, 349, 392, 440, 494, 524};
int
sensorValue;
➋
byte note;
void
setup
()
{
pinMode
(9,
OUTPUT
);
Serial
.
begin
(9600);
}
void
loop
()
{
sensorValue =
analogRead
(A0);
if
(sensorValue > 0)
//if it's a note, play it!
{
//map the key pressed to a note
➌
note =
map
(sensorValue, 0, 1023, 0, 8);
➍
note =
constrain
(note, 0, 7);
Serial
.
print
(sensorValue);
Serial
.
print
(
"\t"
);
Serial
.
println
(
➎
frequencies[note]);
tone
(9,
➏
frequencies[note], 50);
delay
(50);
}
else
{
noTone
(9);
}
}
Let’s look at the code. First, you declare a data structure referred to as an array. An
array
is a kind of variable that represents a list of values rather than just a single value. Arrays can be of any standard data type, including bytes, ints, longs, and floats, and you declare the data type before the array name.
Declaring an array is similar to declaring a variable except that the array name is followed by two square brackets,
[ ]
. When you initialize an array, you define the list inside two curly brackets,
{ }
, and use commas to separate each value:
dataType arrayName
[] = {
val0
,
val1, val2, val3, val4
... };
Listing 10-3
declares an integer (
int
) array named
frequencies[]
that stores a list of eight values for the frequencies of the musical notes
➊
. You can access the values in the array using the index number of the value, placed between square brackets. The first value is referenced as
frequencies[0]
, the second is referenced as
frequencies[1]
, and so on. Notice, as usual, that the index starts at 0 rather than 1, as shown in
Figure 10-11
.
FIGURE 10-11:
The
frequencies[]
array elements
The sketch then declares an index variable named
note
➋
. The array has only eight values, so you can declare this variable as a
byte
since it uses less memory space than an integer. Next, the sketch uses the
map()
function
➌
to translate the raw
sensorValue
reading in the range 0–1,023 to a 0–8 scale.
The
map()
function is a great tool for converting from one range of values to another. You pass it the input value, the range of the input, and the desired range, and it will scale your input value to the desired range, like so:
map
(
inValue
,
inMin
,
inMax
,
outMin
,
outMax
);
The sketch assigns this scaled value to the variable
note
. This will be the index to reference the array. But while the
map()
function scales the 0–1,023 range to a range of 0–8, the
frequencies[]
array actually has only eight values and is indexed from 0 to 7.
We do this because
map()
rounds down when it scales from one range to another range, so to get eight equally spaced values, we actually need to give it nine values. Value 8 is produced only when the input is equal to 1,023. Because value 8 (the ninth value) is not a valid index for the array, we correct this using another command,
constrain()
➍
. This function constrains the value to a range of 0 to 7. Any value that is below 0 is constrained to a minimum value of 0, and any value greater than 7 is constrained to a maximum value of 7. The
constrain()
function is often used in conjunction with
map()
to scale and limit a value.
The
constrain()
function is used like so:
constrain
(
value
,
minValue
,
maxValue
);
Finally, the sketch prints the frequency of the current note being triggered to the Serial Monitor
➎
and uses the
tone()
function
➏
to play the note.
To test it out, press or squeeze the SoftPot. As you move your finger up and down the length of the sensor, you’ll hear the different notes. See what songs you can play.
Now, let’s turn this prototype into a finished piano!
To convert the prototype into a more functional piano, you just need to apply it to a flat surface and mark out the eight keys.
Unfortunately, the pins on this sensor are not long enough or thick enough to simply insert into the male-to-female jumper wires, so if you want to remove it from the breadboard, we suggest that you solder three male-to-male jumper wires from the Inventor’s Kit to the ends of the SoftPot, as shown in
Figure 10-12
. Alternatively, you
can
use male-to-female jumpers, but you’ll need to crimp the ends using a set of needle-nose pliers. If you do this, insert the sensor pins into a set of male-to-female jumper wires and crush the plastic casing around the sensor pins. Make sure that the wires are in contact with the pins of the sensor.
FIGURE 10-12:
Soldering wires to the SoftPot
The SoftPot has adhesive backing designed to be placed flat on a hard surface, so with the wires attached, apply the sensor to any portable hard surface (
Figure 10-13
), like a small piece of cardboard or even the breadboard holder itself.
FIGURE 10-13:
Options for mounting the SoftPot
The SoftPot sensor is 50 mm long (approximately 2 inches). You need to divide the length of the sensor into eight keys, which means each key should be roughly a quarter inch wide. Using a piece of masking tape or a sheet of paper, mark off eight quarter-inch keys, as shown in
Figure 10-14
.
FIGURE 10-14:
Marking off the keys
Next, position the masking tape or paper on top of the SoftPot to give you a guide for playing the notes. The completed keyboard should look like
Figure 10-15
. If you like, you can label the keys with the notes matching the frequencies in your code to help you play from sheet music.
FIGURE 10-15:
The finished Tiny Electric Piano keyboard
In this project, we introduced you to the piezo buzzer and SoftPot. Now that you know how to make some fun sounds, here are a few ideas for taking this project further.
Play around with the code and see what other fun tones you can create. If you want to play a song in a different key or using a different scale, for example, you could change the frequencies in the array.
Table 10-2
shows frequencies you can use to change the key of your piano. C major and G major are the two most common scales used in music. Find some sheet music online or just mess around. Can you play “Twinkle, Twinkle, Little Star” on your new SoftPot piano?