Table of Contents
You can build a lot of fun projects using the Raspberry Pi Pico, and to prove it, I’ll show you how to construct a replica of the classic “Simon” memory game.
But I have to warn you, this game can be addictive. So I won’t take any responsibility for the time you’ll use up playing with your new toy!
Simon Game
In 1978 the toy company Milton Bradley introduced a new toy, a memory game that they named Simon (as in “Simon Says” or “Simple Simon”). It became a smash hit, in fact, it was one of the top-selling toys that Christmas.
Milton Bradley was acquired by Hasbro a few years later, and they still produce several variations of Simon. So it really has become a multigenerational toy!
Playing Simon
The classic Simon game is a circular object that has four colored quadrants. Each quadrant has a colored surface, which is a switch that also illuminates.
The quadrant colors are green, red, yellow, and blue.
You start by pressing a button, after which one of the quadrants flashes its light. It also plays a tone, with a unique sound for every quadrant.
The object of the game is to remember which light flashed, and then repeat it.
If you succeed, then the game starts again, this time flashing the first light as well as a second one. Again, the object is to repeat the sequence.
As long as you successfully repeat the sequence, the game continues, flashing more lights and having you repeat them. It also gets faster as you get to higher levels.
If you fail, however, you are greeted with a disapproving tone, and you need to start again from scratch.
Building Simon
We will construct our version of Simon using LEDs, a piezo buzzer, and some pushbuttons. If you are handy with a 3D printer or have a circular case, you could emulate the actual arrangement of the original Simon game. However, I’m just using a solderless breadboard for my version.
The “brains” of our game is the Raspberry Pi Pico microcontroller, a 4-dollar technical wonder. And we’ll be programming it using C++ instead of the traditional Python, so we’ll be using the Arduino IDE as well.
Parts Required
Here is what you’ll need to construct a Simon game:
- A Raspberry Pi Pico microcontroller. You’ll also want to solder the pins onto the microcontroller, so you’ll need 2 20-pin male Dupont terminals.
- Four colored LEDs. I suggest you emulate the original Simon by using a Green, Red, Yellow, and Blue LED.
- Four Dropping resistors. Any value from 100 to 220 ohms will work, I used four 120-ohm resistors in my game.
- A Piezo buzzer. Make note of the marker on the buzzer to determine its polarity.
- Four Pushbutton switches. These need to be momentary contact, normally open switches. If you can get ones with colored tops to match your LEDs, that would be great, otherwise, any color will suffice.
Now, let’s see how we hook all of this together.
Simon Hookup
Here is how we will hook up our Simon game:
Make sure you get the buzzer polarity correct, the positive side is connected to Pico GPIO pin GP3. Also, be sure to note that the pins in the chart are the GPIO pins, not the physical pins.
Once you have everything connected, it’s time to write some code so our game can work.
Simon Code
In the past, we have coded for the Raspberry Pi Pico using MicroPython and CircuitPython. But this time we will be using C++ for our project. And for that, we’ll be using the Arduino IDE.
Raspberry Pi Pico on Arduino IDE
I have already shown you how to use the Pico with the new version 2.0 of the Arduino IDE, but this time we will be using the classic version 1.8x. Of course, you could use version 2.0 instead if you wish, the results will be identical.
The first step with the IDE will be to install the Boards Manager files for the Raspberry Pi Pico. You can do this as follows:
- Open the Arduino IDE
- Select the Tools menu from the top of the screen. A menu will open.
- Scroll down until you see a Board listing, and highlight it. A submenu will open to the right.
- At the top of the submenu, you’ll see Boards Manager. Click on it.
- The Boards Manager window will open
- Filter your results by typing “Pico” in the search box.
- Look for the Arduino Mbed RP2040 Boards listing.
- Click the Install button to install the board manager for the Raspberry Pi Pico.
- Close the Boards Manager window, and restart the Arduino IDE.
Now connect the Raspberry Pi Pico to a MicroUSB cable that is attached to your workstation. Go back into the Tools menu, chose the Board selection, and change your selection to Raspberry Pi Pico.
Arduino IDE Oddness
One unusual quirk with the Arduino IDE 1.8x when using the Pico is that initially, you won’t be able to select a port for it. However, you will see the entry of the port listed on the bottom status bar.
The “solution” to this bug is to simply upload a sketch to the Pico. After that, it will appear in the Tools menu under Ports. Just like any other microcontroller.
You can use a simple sketch like Blink, or you can just wait and upload our Simon sketch to the Pico.
Simon Sketch
Here is the sketch we will be using for our Simon Game:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
/* Pico "Simon" Game pico_simon.ino Emulates "Simon" memory game Uses Raspberry Pi Pico DroneBot Workshop 2022 https://dronebotworkshop.com */ // Define game constants and variables const int MAX_LEVEL = 100; int sequence[MAX_LEVEL]; int sound[MAX_LEVEL]; int player_sequence[MAX_LEVEL]; int level = 1; int note = 0; int velocity = 1000; // Piezo Sounds #define GRN_SOUND 261 #define RED_SOUND 293 #define YEL_SOUND 329 #define BLU_SOUND 349 #define BAD_SOUND 233 // LED Definitions #define GRN_LED 13 #define RED_LED 12 #define YEL_LED 11 #define BLU_LED 10 // Pushbutton Definitions #define GRN_BTN 18 #define RED_BTN 19 #define YEL_BTN 20 #define BLU_BTN 21 // Piezo Buzzer #define PIEZO 3 void setup() { // LEDs are Outputs pinMode(GRN_LED, OUTPUT); pinMode(RED_LED, OUTPUT); pinMode(YEL_LED, OUTPUT); pinMode(BLU_LED, OUTPUT); // Pushbuttons are Inputs with internal pullup resistors pinMode(GRN_BTN, INPUT_PULLUP); pinMode(RED_BTN, INPUT_PULLUP); pinMode(YEL_BTN, INPUT_PULLUP); pinMode(BLU_BTN, INPUT_PULLUP); // Buzzer is an Output pinMode(PIEZO, OUTPUT); } void loop() { if (level == 1) { generate_sequence(); // Flash the LEDs in sequence for (int i = GRN_LED; i >= BLU_LED; i--) { digitalWrite(i, HIGH); delay(100); digitalWrite(i, LOW); } } // Start game with Green button if (digitalRead(GRN_BTN) == LOW || level != 1) { delay(1000); show_sequence(); get_sequence(); } } void generate_sequence() { // Generates random sequence // Seed for true random number randomSeed(millis()); for (int i = 0; i < MAX_LEVEL; i++) { // Random values will match LED output pins sequence[i] = random(BLU_LED, (GRN_LED + 1)); switch (sequence[i]) { case BLU_LED: note = BLU_SOUND; break; case YEL_LED: note = YEL_SOUND; break; case RED_LED: note = RED_SOUND; break; case GRN_LED: note = GRN_SOUND; break; } // Sound will match LED output sound[i] = note; } } void show_sequence() { // Turn off all LEDs digitalWrite(GRN_LED, LOW); digitalWrite(RED_LED, LOW); digitalWrite(YEL_LED, LOW); digitalWrite(BLU_LED, LOW); Serial.print("level = "); Serial.println(level); for (int i = 0; i < level; i++) { digitalWrite(sequence[i], HIGH); tone(PIEZO, sound[i]); delay(velocity); digitalWrite(sequence[i], LOW); noTone(PIEZO); delay(200); } } void get_sequence() { // Get sequence user enters // Flag used if user pressed a button int flag = 0; for (int i = 0; i < level; i++) { // Reset flag flag = 0; while (flag == 0) { // Check Green if (digitalRead(GRN_BTN) == LOW) { digitalWrite(GRN_LED, HIGH); tone(PIEZO, GRN_SOUND); delay(velocity); noTone(PIEZO); player_sequence[i] = GRN_LED; flag = 1; delay(200); // See if selection is incorrect if (player_sequence[i] != sequence[i]) { wrong_sequence(); return; } digitalWrite(GRN_LED, LOW); } // Check Red if (digitalRead(RED_BTN) == LOW) { digitalWrite(RED_LED, HIGH); tone(PIEZO, RED_SOUND); delay(velocity); noTone(PIEZO); player_sequence[i] = RED_LED; flag = 1; delay(200); // See if selection is incorrect if (player_sequence[i] != sequence[i]) { wrong_sequence(); return; } digitalWrite(RED_LED, LOW); } // Check Yellow if (digitalRead(YEL_BTN) == LOW) { digitalWrite(YEL_LED, HIGH); tone(PIEZO, YEL_SOUND); delay(velocity); noTone(PIEZO); player_sequence[i] = YEL_LED; flag = 1; delay(200); // See if selection is incorrect if (player_sequence[i] != sequence[i]) { wrong_sequence(); return; } digitalWrite(YEL_LED, LOW); } // Check Blue if (digitalRead(BLU_BTN) == LOW) { digitalWrite(BLU_LED, HIGH); tone(PIEZO, BLU_SOUND); delay(velocity); noTone(PIEZO); player_sequence[i] = BLU_LED; flag = 1; delay(200); // See if selection is incorrect if (player_sequence[i] != sequence[i]) { wrong_sequence(); return; } digitalWrite(BLU_LED, LOW); } } } // Selection is correct right_sequence(); } void right_sequence() { // Sequence was correct // Turn off all LEDs digitalWrite(GRN_LED, LOW); digitalWrite(RED_LED, LOW); digitalWrite(YEL_LED, LOW); digitalWrite(BLU_LED, LOW); delay(250); // Turn on all LEDs digitalWrite(GRN_LED, HIGH); digitalWrite(RED_LED, HIGH); digitalWrite(YEL_LED, HIGH); digitalWrite(BLU_LED, HIGH); delay(500); // Turn off all LEDs digitalWrite(GRN_LED, LOW); digitalWrite(RED_LED, LOW); digitalWrite(YEL_LED, LOW); digitalWrite(BLU_LED, LOW); delay(500); // Increase difficulty if (level < MAX_LEVEL) { level++; } velocity -= 50; } void wrong_sequence() { // Sequence was incorrect for (int i = 0; i < 3; i++) { // Turn on all LEDs digitalWrite(GRN_LED, HIGH); digitalWrite(RED_LED, HIGH); digitalWrite(YEL_LED, HIGH); digitalWrite(BLU_LED, HIGH); tone(PIEZO, BAD_SOUND); delay(250); // Turn off all LEDs digitalWrite(GRN_LED, LOW); digitalWrite(RED_LED, LOW); digitalWrite(YEL_LED, LOW); digitalWrite(BLU_LED, LOW); noTone(PIEZO); delay(250); } // Reset difficulty level = 1; velocity = 1000; } |
We start by defining a number of game constants and variables, most of which are arrays.
- MAX_LEVEL determines the number of levels our game goes to. I doubt anyone could ever reach 100!
- The sequence array is the sequence that the game generates, the one you need to memorize.
- The sound array is an array of the corresponding sounds that the piezo buzzer will generate during playback of the sequence.
- The player_sequence array contains the entries that the player inputs. It is compared to the sequence array to see if you got the selection correct or incorrect.
- The level variable is the level the game is currently at. It starts at “1” and progresses as you correctly respond to the generated sequence.
- The note variable is the frequency of the sound produced by the piezo buzzer.
- The velocity variable is the time, in milliseconds, between LED flashes. As the game gets to higher levels this value is reduced, to make it more challenging.
We then define the frequencies for the piezo sounds (they correspond to musical notes) and the connections for the LEDs, pushbuttons, and the piezo buzzer.
In the Setup, we just set the LEDs and buzzer as outputs and the pushbuttons as inputs. We use the Pico’s internal pull-up resistors so that we don’t need external ones.
In the Loop, we see what level we are currently at. If it is level 1 then the game has just started, and we call the generate_sequence() function to populate the sequence and sound arrays with a random sequence.
The generate_sequence() function uses a random number generator that is seeded by calculating the time in milliseconds since the Pico was started, so we get a completely random sequence. It takes advantage of the sequential port numbers we used for the LED connections.
Back in the Loop, we then cycle the LEDs on and off in sequence, for a “chaser” effect. That continues until you press the Green button, which initiates the game.
If the green button was pressed, or if the level is more than 1 (indicating an ongoing game) then we call two functions after a 1-second delay:
- show_sequence() – This function displays the generated sequence. The level value determines how much of the sequence to show.
- get_sequence() – This function gets the input from the player and compares it to the sequence. If it matches, then the level is increased, the velocity is decreased, and the game continues. If it does not match, then the game starts from the beginning.
The right_sequence() and wrong_sequence() functions control the LEDs and buzzer, and are called in response to the results of comparing the player’s input to the generated sequence.
Playing Your Simon Game
Load the code to your Pico and the game will start.
The game begins with the four LEDs running in a light-0chaser mode, which it will continue to do until you press the green button.
After you press the green button, one of the four LEDs will illuminate, and the piezo buzzer will play a sound.
If you press the button corresponding to the LED that was lit then you’ll get a quick flash of the LEDs and the game will continue, this time with the original LED plus an additional one (it may also be the same LED twice, it’s entirely random).
Assuming you respond with the same sequence, the game will continue, each time adding another LED and flashing them a bit more rapidly.
But if you make an error the piezo buzzer will respond with a rather nasty note, the LEDs will flash, and you’ll be back to the beginning, with the LEDs in chaser mode. Pressing the green button will restart the game, with a different generated sequence.
Conclusion
This was a fun game to build, and it’s even more enjoyable to play. As OI warned y earlier, it can be addictive.
Although I just assembled mine on a solderless breadboard, you may want to build one on a perfboard, or even a self-designed PCB. Then you can play your Simon game any time you want to.
Enjoy the project!
Parts List
Here are some components that you might need to complete the experiments in this article. Please note that some of these links may be affiliate links, and the DroneBot Workshop may receive a commission on your purchases. This does not increase the cost to you and is a method of supporting this ad-free website.
COMING SOON!
This article is part of a series of 10 Projects for the Raspberry Pi. Check out the other articles in this series.
Raspberry Pi – 10 Years & 10 Projects
Music Everywhere with Balena Sound
Thank you for this project. I had a blast doing it with my son. A fun extension was adding a way to track the score. We added a scoreboard using 4 LEDs to show the score in binary. It was pretty simple (taking the mod of the score (mod2,mod4,mod8 etc) to light up each LED. I am sure there are lots of other interesting ways to show the score though. I couldn’t get the buzzer to work though. I think I might have the wrong kind (there are no markings on the side). Is it supposed to be a 3v… Read more »
Can’t get this to work at all. After copying the sketch to the Pico it does activate the lights randomly but not in the constant light chaser mode. It does a couple of random lights then all 4 flash a few times then it does another short random set of flashes then repeats. I’ve tried rebuilding the entire project at least a half dozen times and it just won’t run properly and I also get no sound from speaker. 🙁
Hi Dan Sorry to hear you’re having problems getting it to work, it obviously worked for me as I demoed it on the video! I suggest some basic troubleshooting, as you either have a wiring error or a defective component. Here is how I would go about it in your situation: 1 – I would load a simple sketch onto the Pico that just took each button input (a digitalRead) and wrote its output (a digitalWrite) to its associated LED. That way, we can determine if all the switches and LEDs are hooked up correctly. They may indeed be CONNECTED… Read more »
I had a problem with the buzzer and after troubleshooting and sizing up the pico pin out and your diagram of the sketch, I see that what you have labeled as GP3 for the positive buzzer connectivity is actually GP2 on the image. I fixed the issue by moving the positive connector to number 5 pin, which is the actual GP3.