Building Binary Dice - Eleven Arduino Projects - Arduino: A Quick-Start Guide, Second Edition (2015)

Arduino: A Quick-Start Guide, Second Edition (2015)

Part II. Eleven Arduino Projects

Chapter 3. Building Binary Dice

Things will really start to get interesting now that you’ve learned the basics of Arduino development. You now have the skills to create your first complex, stand-alone projects. After you’ve worked through this chapter, you’ll know how to work with LEDs, buttons, breadboards, and resistors. Combining these parts with an Arduino gives you nearly endless opportunities for new and cool projects.

Our first project will be creating an electronic die. While regular dice display their results using one to six dots, ours will use LEDs instead. For our first experiments, a single LED was sufficient, but for the dice we need more than one. You need to connect several external LEDs to the Arduino. Because you cannot attach them all directly to the Arduino, you’ll learn how to work with breadboards. Also, you need a button that rolls the dice, so you’ll learn how to work with pushbuttons, too. To connect pushbuttons and LEDs to the Arduino, you need another important electronic part: the resistor. At the end of the chapter, you’ll have many new tools in your toolbox.

What You Need

1. A half-size breadboard

2. Three LEDs (for the exercises you’ll need additional LEDs)

3. Two 10kΩ resistors (see Current, Voltage, and Resistance, to learn more about resistors)

4. Three 1kΩ resistors

5. Two pushbuttons

6. Some wires of different lengths

7. An Arduino board, such as the Uno, Duemilanove, or Diecimila

8. A USB cable to connect the Arduino to your computer

images/binary_die_parts_with_numbers

Working with Breadboards

images/breadboards


Figure 8. Breadboards come in various types and sizes—the picture shows two.

Connecting parts directly to the Arduino is an option only in the simplest cases. Usually, you’ll prototype your projects on a breadboard that you connect to the Arduino. A breadboard is like a circuit board, but you don’t have to solder parts to it; instead, you simply plug them in.

All breadboards work the same way. They have a lot of sockets you can use for plugging in through-hole parts or wires. That alone wouldn’t be a big deal, but the sockets are connected in a special way. Figure 9, How sockets on a breadboard are connected shows how.

images/breadboards_flow


Figure 9. How sockets on a breadboard are connected

As you can see, most sockets are connected in columns. If one socket of a column is connected to a power supply, then automatically all the other sockets in this column are powered, too. On the bigger board in the photo, you can also see four rows of connected sockets. This is convenient for bigger circuits. Usually, you connect one row to your power supply and one to the ground. This way, you can distribute power and ground to any point on the board. Note that on some breadboards there are gaps between the sockets on a single row. On such breadboards you have to bridge the gaps using a wire if needed.

Now let’s see how to put parts on a breadboard.

Using an LED on a Breadboard

Up to now, we used the status LED that is installed on the Arduino board. This LED is nice for testing purposes, but it’s only sufficient for trivial electronics projects. Also, it’s very small and not very bright, so it’s a good idea to get some additional LEDs and learn how to connect them to the Arduino. It’s really easy.

We won’t use the same type of LEDs that are mounted on the Arduino board. They are surface-mounted devices (SMD) that are difficult to handle. At the beginning of your electronics career, you will rarely work with SMD parts, because for most of them you need special equipment and a lot of experience. They save costs as soon as you start mass production of an electronic device, but pure hobbyists won’t need them often.

images/leds

The LEDs we need are through-hole parts. They are named through-hole parts because they are mounted to a circuit board through holes. That’s why they usually have one or more long wires. First you put the wires through holes in a printed circuit board. Then you usually bend, solder, and cut them to attach the part to the board. Where available, you can also plug them into sockets as you have them on the Arduino or on breadboards.

In this section you’ll learn how to work with LEDs on a breadboard. Figure 10, Connecting an LED on a breadboard to the Arduino shows our circuit. It consists of an Arduino, a breadboard, an LED, three wires, and a 1kΩ resistor. (More on that part in a few minutes.) Connect the Arduino to the breadboard using two wires. Connect pin 12 with the ninth column of the breadboard, and connect the ground pin with the tenth column. This automatically connects all sockets in column 9 to pin 12 and all sockets in column 10 to the ground. This choice of columns was arbitrary; you could’ve used other columns instead.

images/led_breadboard


Figure 10. Connecting an LED on a breadboard to the Arduino

Plug the LED’s negative connector (the shorter one) into column 10 and its positive connector into column 9. When assembling an electronics project, parts fall into two categories: those you can mount any way you like and those that need a special direction. An LED has two connectors: an anode (positive) and a cathode (negative). It’s easy to mix them up, and my science teacher taught me the following mnemonic: the cathode is necative. It’s also easy to remember what the negative connector of an LED is: it is shorter, minus, less than. If you are a more positive person, then think of the anode as being bigger, plus, more. You can alternatively identify an LED’s connectors using its case. On the negative side the case is flat, while it’s round on the positive side.

When you plug parts or wires into a breadboard, you have to press them firmly until they slip in. You might need more than one try, especially on new boards, and it’s often useful to shorten the connectors with a wire cutter before plugging them into the breadboard. Make sure you can still identify the negative and positive connectors after you’ve shortened them. Shorten the negative one a bit more. Also wear safety glasses to protect your eyes when you’re cutting the connectors!

The things we’ve done up until now have been straightforward. That is, in principle we have only extended the Arduino’s ground pin and its IO pin number 12. Why do we have to add a resistor, and what is a resistor? A resistor limits the amount of current that flows through an electric connection. In our case, it protects the LED from consuming too much power, because this would destroy the LED. You always have to use a resistor when powering an LED! In Current, Voltage, and Resistance, you can learn more about resistors and their color bands. The following image shows a resistor in various stages: unprocessed, bent, and cut. (See Learning How to Use a Wire Cutter, to learn how to use a wire cutter.)

images/resistors

We don’t want to fiddle around too much with the connectors, so we build the circuit as shown in the following figure. That is, we use both sides of the breadboard by connecting them with a short wire. Note that the resistor bridges the sides, too.

images/basic_led

To make the LED blink, we can use the same sketch we used in Meeting the Arduino IDE. We only have to set LED_PIN to 12 instead of 13:

BinaryDice/Blink/Blink.ino

const unsigned int LED_PIN = 12;

const unsigned int PAUSE = 500;

void setup() {

pinMode(LED_PIN, OUTPUT);

}

void loop() {

digitalWrite(LED_PIN, HIGH);

delay(PAUSE);

digitalWrite(LED_PIN, LOW);

delay(PAUSE);

}

We’ve built a strong foundation for our project, and in the next section we’ll build upon it.

First Version of a Binary Die

You’re certainly familiar with a regular die displaying results in a range from one to six. To emulate such a die exactly with an electronic device, you’d need seven LEDs and some fairly complicated business logic. We’ll take a shortcut and display the result of a die roll in binary.

For a binary die, we need only three LEDs to represent the current result. We turn the result into a binary number, and for every bit that is set, we light up a corresponding LED. The following diagram shows how the die results are mapped to LEDs. (A black triangle stands for a shining LED.)

images/dice

We already know how to control a single LED on a breadboard. Controlling three LEDs is similar and requires only more wires, LEDs, 1kΩ resistors, and pins. Figure 11, A first working version of our binary die shows the first working version of a binary die.

images/binary_die_first_version


Figure 11. A first working version of our binary die

The most important difference is the common ground. When you need ground for a single LED, you can connect it to the LED directly. But we need ground for three LEDs now, so we’ll use the breadboard’s rows for the first time. Connect the row marked with a hyphen (-) to the Arduino’s ground pin, and all sockets in this row will work as ground pins, too. Then you can connect this row’s sockets to the LEDs using short wires.

Everything else in this circuit should look familiar, because we only had to clone the basic LED circuit from the previous section three times. Note that we have connected the three LEDs to pins 10, 11, and 12. The only thing missing is some software:

BinaryDice/BinaryDice/BinaryDice.ino

Line 1

const unsigned int LED_BIT0 = 12;

-

const unsigned int LED_BIT1 = 11;

-

const unsigned int LED_BIT2 = 10;

-

5

void setup() {

-

pinMode(LED_BIT0, OUTPUT);

-

pinMode(LED_BIT1, OUTPUT);

-

pinMode(LED_BIT2, OUTPUT);

-

10

randomSeed(analogRead(A0));

-

long result = random(1, 7);

-

output_result(result);

-

}

-

15

void loop() {

-

}

-

-

void output_result(const long result) {

-

digitalWrite(LED_BIT0, result & B001);

20

digitalWrite(LED_BIT1, result & B010);

-

digitalWrite(LED_BIT2, result & B100);

-

}

This is all the code we need to implement the first version of a binary die. As usual, we define some constants for the output pins the LEDs are connected to. In the setup function, we set all the pins into OUTPUT mode. For the die, we need random numbers in the range from one to six. Therandom function returns random numbers in a specified range using a pseudorandom number generator. In line 10, we initialize the generator with some noise we read from analog input pin A0. (See Generating Random Numbers, to learn why we have to do that.) You might wonder where the constant A0 is from. The Arduino IDE defines constants for all analog pins named A0, A1, and so on. Then we actually generate a new random number between one and six and output it using the output_result function. (The seven in the call to random is correct, because it expects the upper limit plus one.)

Generating Random Numbers

Some computing problems are surprisingly difficult, and creating good random numbers is one of them. After all, one of the most important properties of a computer is deterministic behavior. Still, we often need—at least seemingly—random behavior for a variety of purposes, ranging from games to cryptographic algorithms.

The most popular approach (used in Arduino’s random function) is to create pseudorandom numbers.[42] They seem to be random, but they actually are the result of a formula. Different kinds of algorithms exist, but usually each new pseudorandom number is calculated from its predecessors. This implies that you need an initialization value to create the first random number of the sequence. This initialization value is called a random seed, and to create different sequences of pseudorandom numbers, you have to use different random seeds.

Creating pseudorandom numbers is cheap, but if you know the algorithm and the random seed, you can easily predict them. So, you shouldn’t use them for cryptographic purposes.

In the real world, you can find countless random processes, and with the Arduino, it’s easy to measure them to create real random numbers. Often it’s sufficient to read some random noise from analog pin 0 and pass it as the random seed to the randomSeed function. You can also use this noise to create real random numbers; there is even a library for that purpose.[43]

If you need strong random numbers, the Arduino is a perfect device for creating them. You can find many projects that observe natural processes solely to create random numbers. One of them watches an hourglass using the Arduino.[44]

The function output_result takes a number and outputs its lower three bits by switching on or off our three LEDs accordingly. Here we use the & operator and binary literals. The & operator takes two numbers and combines them bitwise. When two corresponding bits are 1, the result of the &operator is 1, too. Otherwise, it is 0. The B prefix allows you to put binary numbers directly into your source code. For example, B11 is the same as 3.

You might have noticed that the loop function was left empty, and you might wonder how such a die works. It’s pretty simple: whenever you restart the Arduino, it outputs a new number, and to roll the die again, you have to press the reset button.

Compile the code, upload it to the Arduino, and play with your binary die. You have mastered your first advanced electronics project! Enjoy it for a moment!

Whenever you want to see a new result, you have to reset the Arduino. That’s probably the most pragmatic user interface you can build, and for a first prototype, this is okay. But it’s more elegant to control the dice with your own button. That’s what we’ll do in the next section.

Working with Buttons

In this section you’ll learn how pushbuttons work in principle and how you can use them with an Arduino. We’ll start small and build a circuit that uses a pushbutton to control a single LED.

What exactly is a pushbutton? The following figure shows three views of a typical pushbutton. It has four connectors that fit perfectly on a breadboard (at least after you have straightened them with a pair of pliers). Two opposite pins connect when the button is pushed; otherwise, they are disconnected.

images/buttons

The following picture shows a simple circuit using a pushbutton. Connect pin 7 (chosen completely arbitrarily) to the pushbutton, and connect the pushbutton via a 10kΩ resistor to ground. Then connect the 5-volt power supply to the other pin of the button. Make sure the pushbutton’s orientation is right. Its connected pins have to bridge the gap of the breadboard.

images/simple_button

All in all, this approach seems straightforward, but why do we need a resistor again? The problem is that we expect the pushbutton to return a default value (LOW) in case it isn’t pressed. But when the button isn’t pressed, it would be directly connected to ground and would flicker because of static and interference. Only a little bit of current flows through the resistor, and this helps prevent random fluctuations in the voltage at the input pin.

When the button is pressed, there will still be 5 volts at the Arduino’s digital pin, but when the button isn’t pressed, it will cleanly read the connection to ground. We call this a pull-down resistor; a pull-up resistor works exactly the other way around. That is, you have to connect the Arduino’s signal pin to power through the pushbutton and connect the other pin of the pushbutton to ground using a resistor.

Now that we’ve eliminated all this ugly unstable real-world behavior, we can return to the stable and comforting world of software development. The following program checks whether a pushbutton is pressed and lights an LED accordingly:

BinaryDice/SimpleButton/SimpleButton.ino

const unsigned int BUTTON_PIN = 7;

const unsigned int LED_PIN = 13;

void setup() {

pinMode(LED_PIN, OUTPUT);

pinMode(BUTTON_PIN, INPUT);

}

void loop() {

const int BUTTON_STATE = digitalRead(BUTTON_PIN);

if (BUTTON_STATE == HIGH)

digitalWrite(LED_PIN, HIGH);

else

digitalWrite(LED_PIN, LOW);

}

We connect the button to pin 7 and the LED to pin 13 and initialize those pins in the setup function. In loop, we read the current state of the pin connected to the button. If it is HIGH, we turn the LED on. Otherwise, we turn it off.

Upload the program to the Arduino, and you’ll see that the LED is on as long as you press the button. As soon as you release the button, the LED turns off. This is pretty cool, because now we nearly have everything we need to control our die using our own button. But before we proceed, we’ll slightly enhance our example and turn the button into a real light switch.

To build a light switch, we start with the simplest possible solution. Do not change the current circuit, and upload the following program to your Arduino:

BinaryDice/UnreliableSwitch/UnreliableSwitch.ino

Line 1

const unsigned int BUTTON_PIN = 7;

-

const unsigned int LED_PIN = 13;

-

-

void setup() {

5

pinMode(LED_PIN, OUTPUT);

-

pinMode(BUTTON_PIN, INPUT);

-

}

-

int led_state = LOW;

-

void loop() {

10

const int CURRENT_BUTTON_STATE = digitalRead(BUTTON_PIN);

-

if (CURRENT_BUTTON_STATE == HIGH) {

-

if (led_state == LOW)

-

led_state = HIGH;

-

else

15

led_state = LOW;

-

digitalWrite(LED_PIN, led_state);

-

}

-

}

We begin with the usual pin constants, and in setup we set the modes of the pins we use. In line 8, we define a global variable named led_state to store the current state of our LED. It will be LOW when the LED is off and HIGH otherwise. In loop, we check the button’s current state. When we press the button, its state switches to HIGH, and we toggle the content of led_state. That is, if led_state was HIGH, we set it to LOW, and vice versa. At the end, we set the physical LED’s state to our current software state accordingly.

Our solution is really simple, but unfortunately, it doesn’t work. Play around with it, and you’ll quickly notice some annoying behavior. If you press the button, the LED sometimes will turn on and then off immediately. Also, if you release it, the LED will often remain in a more or less arbitrary state; that is, sometimes it will be on and sometimes off.

The problem is that the Arduino executes the loop method over and over again. Although the Arduino’s CPU is comparatively slow, this would happen quite often—regardless of whether we are currently pressing the button. But if you press it and keep it pressed, its state will constantly beHIGH, and you’d constantly toggle the LED’s state (because this happens so fast, it seems like the LED is constantly on). When you release the button, the LED is in a more or less arbitrary state.

To improve the situation, we have to store not only the LED’s current state, but also the pushbutton’s previous state:

BinaryDice/MoreReliableSwitch/MoreReliableSwitch.ino

const unsigned int BUTTON_PIN = 7;

const unsigned int LED_PIN = 13;

void setup() {

pinMode(LED_PIN, OUTPUT);

pinMode(BUTTON_PIN, INPUT);

}

int old_button_state = LOW;

int led_state = LOW;

void loop() {

const int CURRENT_BUTTON_STATE = digitalRead(BUTTON_PIN);

if (CURRENT_BUTTON_STATE != old_button_state && CURRENT_BUTTON_STATE == HIGH) {

if (led_state == LOW)

led_state = HIGH;

else

led_state = LOW;

digitalWrite(LED_PIN, led_state);

}

old_button_state = CURRENT_BUTTON_STATE;

}

After initializing the button and LED pins, we declare two variables: old_button_state stores the previous state of our pushbutton, and led_state stores the LED’s current state. Both can be either HIGH or LOW.

In the loop function, we still have to read the current button state, but now we not only check whether it is HIGH, but we also check whether it has changed since the last time we read it. Only when both conditions are met do we toggle the LED’s state. So, we no longer turn the LED on and off over and over again as long as the button is pressed. At the end of our program, we have to store the button’s current state in old_button_state.

Upload the new version, and you’ll see that this solution works much better than our old one. But you will still find some cases when the button doesn’t behave fully as expected. Problems mainly occur in the moment you release the button.

These problems occur because the mechanical buttons bounce for a few milliseconds when you press them. In the following figure, you can see a typical signal produced by a mechanical button. Right after you have pressed the button, it doesn’t emit a clear signal. To overcome this effect, you have to debounce the button. It’s usually sufficient to wait a short period of time until the button’s signal stabilizes. Debouncing ensures that the input pin reacts only once to a push of the button:

images/bouncing

In addition to debouncing, we still have to store the current state of the LED in a variable. Here’s how to do that:

BinaryDice/DebounceButton/DebounceButton.ino

Line 1

const unsigned int BUTTON_PIN = 7;

-

const unsigned int LED_PIN = 13;

-

void setup() {

-

pinMode(LED_PIN, OUTPUT);

5

pinMode(BUTTON_PIN, INPUT);

-

}

-

-

int old_button_state = LOW;

-

int led_state = LOW;

10

-

void loop() {

-

const int CURRENT_BUTTON_STATE = digitalRead(BUTTON_PIN);

-

if (CURRENT_BUTTON_STATE != old_button_state &&

-

CURRENT_BUTTON_STATE == HIGH)

15

{

-

if (led_state == LOW)

-

led_state = HIGH;

-

else

-

led_state = LOW;

20

digitalWrite(LED_PIN, led_state);

-

delay(50);

-

}

-

old_button_state = CURRENT_BUTTON_STATE;

-

}

This final version of our LED switch differs from the previous one in only a single line: to debounce the button, we wait for 50 milliseconds in line 21 before we enter the main loop again. For the moment this solution is sufficient, but you’ll learn about an even better one in a few minutes.

That’s everything you need to know about pushbuttons for now. In the next section, we’ll use two buttons to turn our binary die into a real game.

Adding Your Own Button

Now that you know how to work with pushbuttons, you no longer have to abuse the Arduino’s reset button to control the die. You can add your own pushbutton instead. As Figure 12, Our binary die with its own start button, we need to change our current circuit only slightly. Actually, we don’t have to change the existing parts at all; we only need to add some things. First, we plug a button into the breadboard and connect it to pin 7. Then we connect the button to the ground via a 10kΩ resistor and use a small piece of wire to connect it to the 5-volt pin.

images/binary_die_one_button


Figure 12. Our binary die with its own start button

That’s all the hardware we need. Here’s the corresponding software:

BinaryDice/DiceWithButton/DiceWithButton.ino

const unsigned int LED_BIT0 = 12;

const unsigned int LED_BIT1 = 11;

const unsigned int LED_BIT2 = 10;

const unsigned int BUTTON_PIN = 7;

void setup() {

pinMode(LED_BIT0, OUTPUT);

pinMode(LED_BIT1, OUTPUT);

pinMode(LED_BIT2, OUTPUT);

pinMode(BUTTON_PIN, INPUT);

randomSeed(analogRead(A0));

}

int current_value = 0;

int old_value = 0;

void loop() {

current_value = digitalRead(BUTTON_PIN);

if (current_value != old_value && current_value == HIGH) {

output_result(random(1, 7));

delay(50);

}

old_value = current_value;

}

void output_result(const long result) {

digitalWrite(LED_BIT0, result & B001);

digitalWrite(LED_BIT1, result & B010);

digitalWrite(LED_BIT2, result & B100);

}

That’s a perfect merge of the original code and the code needed to control a debounced button. As usual, we initialize all pins we use: three output pins for the LEDs and one input pin for the button. We also initialize the random seed, and in the loop function we wait for new button presses. Whenever the button gets pressed, we roll the die and output the result using the LEDs. We’ve replaced the reset button with our own!

Now that you know how easy it is to add a pushbutton, we’ll add another one in the next section to turn our simple die into a game.

Building a Dice Game

Turning our rudimentary die into a full-blown game requires adding another pushbutton. With the first one we can still roll the die, and with the second one we can program a guess. When we roll the die again and the current result equals our guess, the three LEDs on the die will blink. Otherwise, they will remain dark.

To enter a guess, press the guess button the correct number of times. If you think the next result will be a 3, press the guess button three times and then press the start button.

To add another button to the circuit, do exactly the same thing as you did for the first one. Figure 13, Our binary die now has a guess button shows that we have added yet another button circuit to the breadboard. This time we’ve connected it to pin 5.

images/binary_die_two_buttons


Figure 13. Our binary die now has a guess button.

Now we need some code to control the new button. You might be tempted to copy it from the previous program—after all, we copied the hardware design, right? In the real world, some redundancy is totally acceptable, because you actually need two physical buttons, even if they are the same in principle. In the world of software, redundancy is a no-go, though, because it quickly leads to maintenance hell. You should always make sure that every important piece of information is represented only once in your program. Instead of copying numbers, you should use constants. Instead of copying code, you should use functions or classes. This way your code will become more compact and more readable. As a bonus, it will be much easier to change your code, because when you copy code you have to remember all the places you’ve copied it to when you have to make a change. If you’ve isolated the code in a single place, you have to change it only once.

So, we won’t copy our debounce logic, but we’ll use the Bounce2 library[45] that was written for this purpose. Download the library[46] and unpack its contents into ~/Documents/Arduino/libraries (on a Mac) or My Documents\Arduino\libraries (on a Windows machine). Usually that’s all you have to do, but it never hurts to read the installation instructions and documentation on the web page.

Now that’s all done, our dice game is complete. Here’s the code of the final version:

BinaryDice/DiceGame/DiceGame.ino

Line 1

#include <Bounce2.h>

-

const unsigned int LED_BIT0 = 12;

-

const unsigned int LED_BIT1 = 11;

-

const unsigned int LED_BIT2 = 10;

5

const unsigned int GUESS_BUTTON_PIN = 5;

-

const unsigned int START_BUTTON_PIN = 7;

-

const unsigned int BAUD_RATE = 9600;

-

const unsigned int DEBOUNCE_DELAY = 20;

-

10

int guess = 0;

-

Bounce start_button;

-

Bounce guess_button;

-

-

void setup() {

15

pinMode(LED_BIT0, OUTPUT);

-

pinMode(LED_BIT1, OUTPUT);

-

pinMode(LED_BIT2, OUTPUT);

-

pinMode(START_BUTTON_PIN, INPUT);

-

pinMode(GUESS_BUTTON_PIN, INPUT);

20

start_button.attach(START_BUTTON_PIN);

-

start_button.interval(DEBOUNCE_DELAY);

-

guess_button.attach(GUESS_BUTTON_PIN);

-

guess_button.interval(DEBOUNCE_DELAY);

-

randomSeed(analogRead(A0));

25

Serial.begin(BAUD_RATE);

-

}

-

-

void loop() {

-

handle_guess_button();

30

handle_start_button();

-

}

-

-

void handle_guess_button() {

-

if (guess_button.update()) {

35

if (guess_button.read() == HIGH) {

-

guess = (guess % 6) + 1;

-

output_result(guess);

-

Serial.print("Guess: ");

-

Serial.println(guess);

40

}

-

}

-

}

-

-

void handle_start_button() {

45

if (start_button.update()) {

-

if (start_button.read() == HIGH) {

-

const int result = random(1, 7);

-

output_result(result);

-

Serial.print("Result: ");

50

Serial.println(result);

-

if (guess > 0) {

-

if (result == guess) {

-

Serial.println("You win!");

-

hooray();

55

} else {

-

Serial.println("You lose!");

-

}

-

}

-

delay(2000);

60

guess = 0;

-

}

-

}

-

}

-

void output_result(const long result) {

65

digitalWrite(LED_BIT0, result & B001);

-

digitalWrite(LED_BIT1, result & B010);

-

digitalWrite(LED_BIT2, result & B100);

-

}

-

70

void hooray() {

-

for (unsigned int i = 0; i < 3; i++) {

-

output_result(7);

-

delay(500);

-

output_result(0);

75

delay(500);

-

}

-

}

Admittedly that’s a lot of code, but you know most of it already, and the new parts are fairly easy. In the first line, we include the Bounce2 library we’ll use later to debounce our two buttons. Then we define constants for the pins we use, and we define the variable guess that will hold the player’s current guess.

The Bounce2 library declares a class named Bounce, and you have to create a Bounce object for every button you want to debounce. That’s what happens in lines 11 and 12.

In the setup method, we initialize all our pins and set the random seed. We also initialize the serial port, because we’ll output some debug messages. In lines 20 to 23, we initialize the two Bounce objects. The attach method connects a Bounce object to a certain pin. With the interval method you can set a button’s debounce delay in milliseconds.

Our loop function has been reduced to two function calls. One is responsible for dealing with guess button pushes, and the other one handles pushes of the start button. In handle_guess_button, we use the Bounce class for the first time. To determine the current state of our guess_buttonobject, we have to call its update method. Afterward, we read its current status using the read method.

If the button was pressed, its state is set to HIGH, and we increment the guess variable. To make sure that the guess is always in the range between 1 and 6, we use the modulus operator (%) in line 36. This operator divides two values and returns the remainder. For 6, it returns values between 0 and 5, because when you divide a number by 6, the remainder is always between 0 and 5. Add 1 to the result, and you get values between 1 and 6. Finally, we output the current guess using the three LEDs, and we also print it to the serial port.

The handling of the start button in handle_start_button works exactly the same as the handling of the guess button. When the start button is pressed, we calculate a new result and output it on the serial port. Then we check whether the user has entered a guess (guess is greater than zero in this case) and whether the user has guessed the correct result. In either case, we print a message to the serial port, and if the user guessed right, we also call the hooray method. hooray lets all three LEDs blink several times.

At the end of the method, we wait for two seconds until the game starts again, and we reset the current guess to zero.

After you’ve uploaded the software to the Arduino, start the IDE’s serial monitor. It will print the current value of the guess variable whenever you press the guess button. Press the start button, and the new result appears. In the following figure, you can see a typical output of our binary die.

images/dice_game_win

In this chapter, you completed your first really complex Arduino project. You needed a breadboard, LEDs, buttons, resistors, and wires, and you wrote a nontrivial piece of software to make all the hardware come to life.

More LEDs, Dice, and Cubes

Building binary dice is fun, and it’s an easy project even for beginners. But what about the opposite—reading real dice? Steve Hoefer[47] has built a dice reader using an Arduino, and it’s impressive. He uses five pairs of infrared emitters and receivers to “scan” a die’s surface. It’s a fairly advanced project, and you can learn a lot from it.

Another interesting project is an LED cube: building a cube consisting of LEDs.[48] It’s surprisingly difficult to control more than a few LEDs, but you can produce astonishing results.

In the next chapter, we’ll write an even more sophisticated program for generating Morse code. You’ll also learn how to create your own Arduino libraries that you can easily share with the rest of the world.

What If It Doesn’t Work?

Don’t panic! A lot of things will probably go wrong when you work with breadboards for the first time. The biggest problem usually is that you didn’t connect parts correctly. It takes some time to find the right technique for plugging LEDs, wires, resistors, and buttons into the breadboard. You have to press firmly but not too hard—otherwise, you’ll bend the connectors, and they won’t fit. It’s usually easier to plug in parts after you’ve shortened the connectors. When cutting the connectors, wear safety glasses to protect your eyes!

While fiddling around with the parts, don’t forget that some of them—LEDs, for example—need a certain direction. Pushbuttons are candidates for potential problems, too. Take a close look at the pushbuttons here and make sure that you’ve mounted them in the right direction.

Even simple things, such as ordinary wires, can lead to problems, especially if they aren’t the right length. If a wire is too short and might potentially slip out of its socket, replace it immediately. Wires are too cheap to waste your valuable time with unnecessary and annoying debugging sessions.

It might be—although it’s rare—that you actually have a damaged LED. If none of the tricks mentioned helps, try another LED.

Exercises

· Binary dice are all very well when you’re playing Monopoly with your geeky friends, but most people prefer more familiar dice. Try turning binary dice into decimal dice with seven LEDs. Arrange the LEDs like the eyes on regular dice.

· The 1kΩ resistors we used to protect our LEDs in this chapter are rather big. Read Resistors, and replace them with smaller ones, for example 470Ω. Can you see the difference in brightness?

· LEDs can be used for more than displaying binary dice results. Provided you have enough LEDs, you can easily build other things, such as a binary clock.[49] You already know enough about electronics and Arduino programming to build your own binary clock. Try it or think about other things you could display using a few LEDs.

Footnotes

[42]

http://en.wikipedia.org/wiki/Pseudo-random_numbers

[43]

http://code.google.com/p/tinkerit/wiki/TrueRandom

[44]

http://www.circuitlake.com/usb-hourglass-sand-timer.html

[45]

https://github.com/thomasfredericks/Bounce-Arduino-Wiring

[46]

https://github.com/thomasfredericks/Bounce-Arduino-Wiring/archive/master.zip

[47]

http://grathio.com/2009/08/dice-reader-version-2.html

[48]

http://www.instructables.com/id/The-4x4x4-LED-cube-Arduino/

[49]

http://www.instructables.com/id/My-Arduino-Binary-Clock/