Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / IoT / Arduino

Simone Says

5.00/5 (1 vote)
11 Mar 2021CPOL6 min read 6.4K   26  
The classic electronic game brought to you by Arduino Micro Pro
A Simone Says game cobbled together using an Arduino Micro Pro, a 74HC595 Shift-Register, an LCD1602, two potentiometers, a few buttons, a power switch and the power to annoy all present with beep beep sounds of delight.

Introduction

Image 1

The original game of Simon was originally produced in 1978 and must have required a lot more work to build without the ease of C++ and Arduino to help its creators. It was a popular game when I was a kid and though I never owned one, I did get to play with cousins and neighbours who did and it was lots of fun. The novelty of electronic games in the late 1970's made this game far more popular than it would ever be had it came out this century but it can still be a pleasant pasttime just to reminisce about the good old days when Lennon was still around and 8-track tapes played the BeeGees while your sister hogged the land-line to talk to that creepy boy with the April Wine t-shirt.

You can watch a brief video here.

Background

The original game had only four colors and used a timer to keep you honest. This version has five colors and no timer. You're welcome to add a timer if you want, I just didn't bother. It's not like anyone is going to get upset and take it away from me if I'm too slow to key-in the right sequence. The code is fairly simple but the way I built it did require a bit of finesse to wire it up since I have 5 LEDs, 5 buttons in a voltage divider configuration and the 74HC595 shift register all soldiered together on one 6x4 cm board. I don't have that much experience wiring and building these Arduino project so, for me, it got a little crowded but I managed to put it together on the first try, so I was quite pleased. If you're new to Arduino and soldiering in general, I would recommend using a bigger board or pinning the shift-register on a separate board because I think I was just lucky when I managed to get it right on the first shot.

You might want to ease up on the coffee-jitters and switch to green-tea for this one.

The Code

The main loop() of the Arduino code is fairly simple. Since the Setup() initializes everything and then enters a forever-loop that plays a song and animates the LEDs until the player presses the start key the loop() method doesn't start until after that happens. Conveniently, the delay time between the power coming on and the player pressing the 'start' button is used as the RandomSeed() value, otherwise you would be playing the same sequence of puzzles everytime you played.

The code below shows the main loop(). You can see that the first thing it does is test if the player has pressed a button. If she has then it tests whether the player's input is correct or not. When the correct sequence has been entered completely a new tone is added to the puzzle and the code enters this loop again after the sequence has been played back for the player to hear. This repeats for as long as the player's inputs are correct. When the player fails to complete the puzzle, we exit this loop and go into GameOver() mode where the player's score is compared with the high score and a merry song is played.

Voila, the game of Simone!

C++
//
void loop()
{
  // loops waiting for player input
  delay(10);
  int intButtonPressed = ButtonPressed();
  if (intButtonPressed != intButtonLast)
  {
    intButtonLast = intButtonPressed;
    if (intButtonPressed != 0)
    {
      // when player presses a button LED/Tone reflect player input
      LED_On(intButtonPressed);
      // player input string has last input appended to it
      strPlayerInput.concat((char)((int)'0' + intButtonPressed));

      // if the player's input is correct
      if (ComparePlayerInputWithPuzzle())
      {
        // if the player has entered the entire puzzle correctly
        if (strPuzzle.length() == strPlayerInput.length())
        {
          // the puzzle has one more note added to it, 
          // it is played back for the player and player input is erased
          Puzzle_AddTone();
          Puzzle_Play();
          strPlayerInput = "";
          intButtonLast =  -1;
        }
      }
      else
      {
        PlayerInputIncorrect();
      }
    }
    else
      LED_On(0);  // turns off all LEDs
  }
}
//

Wiring

Image 2

In the diagram above, you can see how everything is connected. The LCD1602 may be a little intimidating, I know I take extra time to get it right whenever I make a build that has one, but if you look at the diagram below (my road-map for anything LCD related), you should get by. The two buttons in the image are superfluous but the wiring is correct. You may have to choose different Arduino pins to connect to but all you'll have to do is make sure that when you declare the LiquidCrystal you identify the correct pins as shown in the code below.

Image 3

Points of Interest

The input buttons are differentiated using a voltage divider configuration. That is, each button has a different resistor in series with it that is then tied to a resistor common to all of the buttons. When any button is pressed, the voltage drop across that button's corresponding resistor is measured by an analog pin and the code uses the voltage value it reads with a call to analogRead() to determine which button was pressed. If you want to learn more about controlling multiple buttons with one analog pin and a voltage divider, read my Reps Counter article or another article I wrote specifically about using a voltage divider to control a matrix of buttons. It's a simple concept but the benefit is that you can use a single analog pin to control a myriad of buttons instead of resorting to 74HC165 Load Registers.

There was initially (first publishing) a de-bouncing issue.  The problem with buttons is that in the real world voltages don't go from zero to VCC instantaneously.  In the best of times there's a vertical transition over a short period of time (nano-seconds) during which the voltage increases/decreases from one to the other whenever the user presses a button.  Besides that, the buttons themselves make contact - break contact and bounce a few times before settling in their physical position of either closed or open circuit.  This causes problems when the Arduino relies on a precise voltage measure of one of its analog pins to determine which button the user has pressed.  If the Arduino polls the input analog pin during a voltage transition it will likely get the voltage wrong.  To resolve this problem, the ButtonPressed() method now polls the input pin twice with a short (20 millisecond) delay between the two attempts to read the voltage.  If both these readings result in the same button being pressed (or no button at all) then it returns the correct value otherwise it ignores the user-input and returns zero (no button pressed).  It was kind of a bummer before when you're playing the game and every now and then Simone tells you you got it wrong when you're sure you got it right.  She on top of it now... much better.

My build has a potentiometer between the buzzer and the microcontroller (two potentiometers including the one connected to the LCD). The buzzer's potentiometer gives the player a volume control which those suffering through your idle-time will probably appreciate. I also have a used cell-phone battery on a Lithium-Ion charger. It was pretty easy to connect but the battery only produces less than 4V when fully charged, so the LCD doesn't get too bright. Still works pretty good.

History

  • 9th March, 2021: Initial version
  • 4th January 2022 - fixed 'de-bouncing' issue with the buttons

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)