Arduino hardware hacking: Part 3

Code

In our previous two tutorials (see here and here), we created a Simon-type game using the Arduino, a hardware platform for simple, and not so simple, electronics projects.

We placed three buttons and three LEDs on to something called a breadboard, and wrote a small program that would send a random sequence to the LEDs, which the player would then need to replicate by pressing the buttons in the same order. Each time you got the sequence correct, the sequence would be extended by one and repeated. The further into the random sequence you got, the higher you scored.

In this, part three, we're going to build on what we already created and add another important feature - sound! So, get the hardware out, make some coffee, and prepare for some hardware hacking fun...

Adding sound to our project is actually very easy, and it has a dramatic effect on the playability of the game. If you purchased a starter pack of components with your Arduino kit, there's a good chance that the kit included some kind if Piezo element. These are usually small, black and circular (about the same size as the average coat button), with a small hole in the top. They can be used to generate sound, as well simple sound capture, which is why they're usually included in starter kits.

If you don't have a Piezo element to hand, don't worry - neither did we. Rather than go out and buy one, we cannibalised an old PC case and removed the speaker, soldering two wires to the connection points on the edge of the magnet that drives the speaker (you might even be able to remove the speaker with the wires attached). Any small speaker should do, and you'd be surprised how many electronic components include one. If you have something broken lying around, take a look inside.

We got our speaker for free, but they are available for next to nothing from your local hardware store.

We got our speaker for free, but they are available for next to nothing from your local hardware store.

Sound and vision

When the speaker is connected to the Arduino, we're going to use sound to mirror the sequence of the LEDs, so that each flash of light is accompanied by a note. In this way, the random sequence of LEDs that light up will now be generating a melody at the same time, and all the player has to do is imitate the LED sequence/melody on the three buttons.

Even if you're not interested in the Simon game we're creating, you can use what you learn here without embedding it within a bigger project. Sound on the Arduino will just work, and there all kinds of applications we can think of where sound would be a useful addition.

Sound generation

There are many different ways to generate sound with the Arduino, all varying in complexity. We're going to use the absolute simplest, a method that's crudely known as 'bit banging'. Bit banging will enable us to generate notes of different pitch, but it won't give us much else - just a raw beep of a certain duration. Don't be put off - the sound is actually quite pleasant, and will be familiar to anyone who grew up in the 1980s. Our sound will be very similar to that generated by the original Simon game and many other electronic devices, including the typical 'beep' you get when you turn your computer on. Presumably this is because the method we've chosen has been the simplest and cheapest way to generate sound for some time, and you don't need any audio-specific hardware other than the speaker.

If you're interested in sound and want to try something a little more ambitious, other sound generation methods can use a digital/analogue converter for the recreation of samples and real sound, and there are several Arduino projects that attempt to recreate the various discrete components you find in a synthesizer, including the oscillators, filters and envelopes, as well as tying it all together with MIDI. If you're interested in any of these applications, the Arduino website has plenty more information.

Beep beep...

But all we want is a beep. To show you how easy it is, attach the positive connection on your speaker to the 9V power connector on the Arduino (you should find small plus and minus signs on the speaker's circuit board to indicate polarity). Next, connect the negative cable to digital pin 9 on the Arduino, and that's all the wiring you need. If you've still got the Simon-type game from the previous tutorials wired up, these two connections should fit alongside the wires going to and from the LEDs and buttons on the breadboard. We now need to write the code to create a sound.

Like having bits of wire and LEDs lying bare on your desk? So do we - Arduino is great fun!

Like having bits of wire and LEDs lying bare on your desk? So do we - Arduino is great fun!

The basic principle is very similar to switching the LEDs on and off, at least as far as the programming is concerned. That's why this is called bit bashing. We first set the pin mode of the connector attached to the speaker, then send a HIGH and LOW signal to the same connector, sending a digital signal down the wire to the speaker, resulting in a tiny click as the coil on the speaker jerks briefly in response to the signal. If you were to draw the movement on a piece of paper, you'd see that the speaker had generated a single cycle of a square waveform - a sharp 'on' slope with a momentary peak followed by a sharp 'off' slope. Now, if we send many more of these small signals to the speaker, generating plenty more square wave cycles, the cumulative effect of the coil and cone jumping backward and forward is that a tone is generated, with the pitch governed by the number of cycles we can fit into a second.

Circuit diagram

One thing that was missing from our previous tutorials was an easier way to explain the layout of the circuit. It's difficult to describe how everything holds together using text in any project that's more complex than an LED or two. We had meant to include a circuit diagram to help with this, but ran out of space. Fortunately, a reader has come to our rescue. Stewart Watkiss sent us his own circuit diagram for the project, which we've printed here, and added a speaker to reflect the changes in this tutorial.

If you've not seen a circuit diagram since you were at school, they're actually very easy to understand, and make the job of constructing the circuit much easier. You can see the various output connections from the Arduino board, and how these are attached to the resistors (shown with their resistance values of 1 kilohms). The other symbols are for the switches and LEDs. Switches are shown as a momentary break in the circuit, while the LEDs are the inverted triangles with the arrows showing the light emission moving away from the element. The only other device is the speaker, which should be easy enough to spot.

Arduino circuit diagram
Arduino circuit diagram key

... beep beep, yeah!

Enough theory - let's make some noise. Open a new Arduino project with the Arduino IDE (or a text editor if you prefer), and type the following at the top of the file:

#define note_len 200000
int speakerOut = 9;
void setup() { 
  pinMode(speakerOut, OUTPUT);
}

These lines are telling the Arduino hardware exactly how we're going to use the pins on the board. We now need to add the code to generate the sound. To do that, just add the following function:

void playTone(int note) {
  long elapsed_time = 0;
  while (elapsed_time  < note_len) {
      digitalWrite(speakerOut,HIGH);
      delayMicroseconds(note / 2);
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(note / 2);
      elapsed_time += (note);
   }                                 
}

In the 'while' loop, the digital pulse is sent to the speaker using the digitalWrite functions - HIGH for on, and LOW for off. There is a delay after each digitalWrite implemented using the delayMicroseconds function. As its name implies, this pauses the execution of the program for the number of microseconds indicated by the number between the brackets. In our case, we've assigned this number to a variable called 'note' because it's the value of this delay that creates pitch in the sound. The less the delay, the faster the pulse will be sent to the speaker and the higher the pitch. We then add the length of all these delays together to the elapsed_time variable so that we can work out how long the sound has been playing, and when the note has been playing for the duration held in note_len we exit the while loop.

To create a sound, we now move to the final function - loop. In the loop function that the Arduino constantly runs through, we can call the playTone function to create the sound:

void loop() {
   playTone (3830);
}

Put it into the game

Now that we've run over the basics of how to generate sound with the Arduino and a cheap speaker, we need to apply what we've learned to the game we created. The first step is to copy the playTone function from our previous example into the game source code. We're going to use this in exactly the same way, calling the function when we want to create a sound.

To go along with the new function, we also need to add the same pinMode line to the setup function, as well as make sure the note_len and speakerOut definitions are copied to the top of the file. We're also going to add some more #define statements for the notes that various delays in the playTone function will play. Doing this helps us to avoid using the raw numbers for the delay value as we did in the loop() function, and as we've only got three buttons, we only need three tones:

#define  play_c     3830
#define  play_d     3400
#define  play_e     3038 

We took the delay values from the Arduino website, where someone has already worked out which delays produce which note. We can now use the fixed variables play_c, play_d and play_e as the arguments in our playTone function to generate the correct tone we want, and this is what we need to add next - create a sound when the corresponding LED is lit up, and we can do this from playSequence - the same function that lights the LEDs. Jumping into the middle of this function, you might remember that we used a case statement that would light the correct LED according to which value was held in the current position of the array. We can simply add the playTone command in each case to play a tone when the LED is lit:

switch (rand_array[i]) {
      case 0:
        digitalWrite(ledPin1, HIGH);
        playTone(play_c);
        break;
      case 1:
        digitalWrite(ledPin2, HIGH);
        playTone(play_d);
        break;  
      case 2:
        digitalWrite(ledPin3, HIGH);
        playTone(play_e);
        break;         
}

You can see that we've chosen three different notes to play with the three different LEDs, and these should play as the sequence unfolds on the lights for the player to copy.

All the sounds in the project are generated from the playTone function.

All the sounds in the project are generated from the playTone function.

Now that playback is sorted out, we now need to add the same functionality to the input section of code, so that as the player presses the button, the speaker creates the corresponding sound. Previously we created a function called readButtons to handle the input, and instead of splitting each button press into a 'case' statement, we used a nested 'if', and we just need to add the correct playTone functions here:

    if (val1==LOW){
      playTone(c);
      return 0;
    } else if (val2==LOW) {
      playTone(d);
      return 1;
    } else if (val3==LOW) {
      playTone(e);
      return 2;
    }

Now our program will play a note when it detects a button press. The only thing to be careful of is that you match the same tone to the playback and input sections of the program, otherwise the player will get a different note to the one they were expecting when they press a button.

That's all there is to the basic sound functionality. The only other addition you might want to consider in the sound category is the use of sound for feedback - a sound for when you get the sequence right, and a sound for when you get the sequence wrong. As you might remember, we already have two functions that deal with those circumstances - flashSuccess and flashFailure, both of which were omitted from the previous source code because of lack of space. You might want to add a suitably disparaging sound to the failure function, so that the player can hear they've made a mistake. It might be something as simple as a long low tone using something like the following:

playTone(8000);
playTone(8000);

But you equally might want to create something a little more jarring. Sounds generated by the speaker don't have to be melodic, and you can create a real cacophony by rapidly sending notes to the speaker. Our playTone function has a hard-wired delay, and we need to change this if we want rapidly altering sounds. The answer is to add anther function variable for the duration of the note. This is simply changed by changing the playTone function to the following:

void playTone(int note, long note_len )

We also need to change the #define note_len 200000 statement at the beginning of the source code to #define duration 200000 so that there's no mixup in variable names. After you've made these two changes, you now need to make sure that every time playTone is called, a duration is provided. For example:

playTone(play_c, duration);

You now have greater control over the length of sounds that the speaker generates, and you quickly follow one note with another. Here's how we used this to replace the flashFailure function with a terrible error sound rather than a bank of flashing lights:

void flashFailure(){ 
  for (int i=0; i<=10; i++){
    playTone (play_c, 10000);
    playTone (play_d, 10000);
    playTone (play_e, 10000);
  }
}

This is a simple loop that plays through the three notes very quickly, creating a kind of laser gun battle sound that clearly informs the player they've made an error while trying to recreate the sequence. We found that with the addition of sound, we don't really need to use the success function now that the failure function is so obvious. Remove flashSuccess(); from void loop() to see what we mean. The game becomes more intuitive to play, and you can recreate the button sequence much more quickly without having to wait for the success notification each time. With the addition of sound, the whole project now feels much more satisfying, and while the bleeps make the game slightly easier, it means that you can go further into the sequence - especially if you have a good memory for sound.

Multimeters

As you start playing with the Arduino a little more, one device you might find particularly useful is a Multimeter. They're the electronic engineer's equivalent to a programmer's debugging tool, and they can be invaluable when trying to figure out why your project isn't working and where things might be going wrong.

They're also an excellent educational tool, and they can help you to see exactly what's going on and where in your own circuits. The other good thing about a multimeter is that they can be extremely cheap, especially for the hobbyist, with basic models costing less than £10. Most share the same operating modes and functionality, with a central circular dial used to select the function, and a digital display used for output. They can be used to measure voltage, as well as work out the value of a resistor, but their most useful function for small Arduino projects is called 'continuity'.

This is where you test whether two components or sections of the circuit are connected by introducing a small voltage from the multimeter. For this reason, the Arduino must be disconnected from the power supply - as must any other circuit you test - and the continuity test will produce a sound as long as adequate voltage is getting from one sensor to another. You can usually find the function by looking for a crotchet or speaker symbol on the function dial. The continuity test is the best way to check that your wiring works, before you move on to testing components separately.

Multimeters come in many different shapes and sizes, but most use a central dial to select the function and a digital display to show the reading.

Multimeters come in many different shapes and sizes, but most use a central dial to select the function and a digital display to show the reading.

First published in Linux Format

First published in Linux Format magazine

You should follow us on Identi.ca or Twitter


Your comments

Thank you - Excellent Tutorial

Always great tutorials

Love the articles, but not a match for real world projects

Don't take the not a match too hard. Microcontroller articles rock and learning them is a skill worth having.

But in real world automation projects I sat and thought terribly hard about the capabilities to price ratio. These ancient 8 bit processors with tiny memory and program capabilities are limiting if you want to build a central control system.

Lets face it, digital out and in and analogue out and in is pretty much old hat. Getting microcontrollers to talk to modern computers through USB is not easy for beginners and chew up valuable program space to process on chip. So you need to keep old laptops or computers on hand with serial ports or parallel ports and try to interface to microcontroller projects, the majority of them still serial controlled in most books out there, USB shied away from by most books and micro guys it seems.

If you add in the cost of programmers, building your own circuit boards, etc. to repeat the wheel you are talking hundreds of dollar or a hundred pounds or more of gear. You get a great education but to get work done look what I discovered.

$50 or so gets you a USB I/O board with more output/inputs and usb connector already (fusionbrain4), for $99 you get 8 240VAC 25Amp rated power relays you can control. For $99 you can get a linux plug computer and have a modern 32bit risc cpu running a friendly to use Linux os like Ubuntu. You can plug in the FusionBrain4 into Linux and program in a high level easy language like Python. Scrape down RSS feeds containing weather data from the internet and use it in your home garden automation to make intelligent systems better than whats on the market. Have a web server brought up in no time at all and you can publish the sensor readings to your iPhone over the internet and even override program settings and manually switch on and off circuits.

Why stop there, the computer can do home automation as easily as garden all at the same time. Or for me automated brewery system turning on and off pumps, electric heating elements, etc. to automate making beers at home with repeatable perfect precise steps better than I can do manually.

You can string 127 devices on the same USB bus so you can expand to your hearts content.

If you want space, look at the microcontroller then look at the plug computer, then with the SD slot add in 16gigs of SD memory, possibilities are endless with that space. One tiny computer running everything at under 2 Watts and just plugged into any old AC outlet in your house or garden or wherever.

But the down side is you are further abstracted from building your own hardware and etching your own circuit boards with acid and assembling everything and programming everything at the lowest level. Great for learning so keep at the articles! -- just when you shift to implementation of larger grand ideas you will find the cost of building old microcontroller systems a stumbling block when you just want to get it done.

I can see how the code and hardware in the articles work without needing any diagrams or drawings so you are explaining it really well. Just the odd beginners having trouble visualising your words I think leading to the comments requestion more.

Cheers

match for real world projects !

Very good tutorial !

Re: Not a match for real world...

I'd have to disagree with you on this. The Arduino can be had fully assembled for about $35. Simply plug it into a linux box via USB and download a program (sketch). It can also be programed via a cheap ISP programmer if desired.

USB has a limited distance for communication, so having multiple Arduino's, each controlling a portion of the house, is better than a single plug computer, IMHO. Various interfaces can be built or bought for the Arduino, ranging from serial (RS-232, RS-445) to Ethernet to wireless.

In addition, the Arduino can be powered by a 9V battery for a very long time. No mains outlet is needed as for the plug computer.

I plan to use the Arduino to control my solar heating system once I have all the parts needed. I may choose to use straight C++ instead of the Arduino language, but I'm not sure at this point.

Additionally, any failure won't take down the entire home's automation, only the part corresponding to the failed controller. A central computer can still control / monitor everything, but even a failure there should not disable primary functionality.

The Arduino can be used as a dumb device that simply provides I/O to USB conversion as you describe the fusion brain 4. Though, that has a PIC microcontroller, so I would hope it would be programmable to be standalone too.

It all depends on what you want. These are very much usable in the real world, and they are cheap and energy efficient.

why are you using the 9V connection??

I would connect the second speaker lead to ground not 9V.
The low impedance of the speaker could pull the Arduino digital output up above 5V if it's connected to the 9V supply.
Also, I don't think your circuit will work unless an external supply is connected.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

CAPTCHA
We can't accept links (unless you obfuscate them). You also need to negotiate the following CAPTCHA...

Username:   Password:
Create Account | About TuxRadar