Dan MullasserilGarrett MurphySeamus Whoriskey
Published

Seamus Says

An addicting game that will challenge your memory and fine motor skills!

AdvancedFull instructions provided20 hours307
Seamus Says

Things used in this project

Hardware components

Grove Starter Kit for LaunchPad
Seeed Grove Starter Kit for LaunchPad
×1
Breadboard (generic)
Breadboard (generic)
×1
5 mm LED: Red
5 mm LED: Red
×2
Jumper wires (generic)
Jumper wires (generic)
×1
3 mm LED: Green
3 mm LED: Green
×1

Software apps and online services

Energia
Texas Instruments Energia

Story

Read more

Schematics

Video Demonstration

ELEC 220 Circuit

The project's schematics, not including the grove modules

Code

All the code

C/C++
it's all the code
#include "TM1637.h"
#include "helpers.h"
#include "time.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#define CLK 39//pins definitions for TM1637 and can be changed to other ports
#define DIO 38
#define BUZZER_PIN 36  // pin of grove buzzer

TM1637 tm1637(CLK, DIO);

// Preallocations:

unsigned int volatile *pGPIODATA = (unsigned int *) (PortF + GPIODATA);
unsigned int volatile *pGPIODATAE = (unsigned int *) (PortE + GPIODATA);
unsigned int volatile *pGPIODATAA = (unsigned int *) (PortA + GPIODATA);
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 };
int pattern[100];
int pinList[] = {pin1, pin2, pin4};
int count = 3;
volatile int start = 0;
int volatile correct_pattern = 1;
const int PE1 = 27;
const int PE2 = 28;
const int PE3 = 29;
const int PE4 = 5;
volatile int button_pressed = 3;
int randomizePattern = 1;


/* Setup */

void setup() {
  // Pins for reading buttons
  SetupDigitalGPIO(PortE, pin1, INPUT, INTERRUPT);
  SetupDigitalGPIO(PortE, pin2, INPUT, INTERRUPT);
  SetupDigitalGPIO(PortE, pin3, INPUT, INTERRUPT);

  // Setup start button
  SetupDigitalGPIO(PortE, pin4, INPUT, INTERRUPT);

  // Setting up interrupts for buttons
  attachInterrupt(digitalPinToInterrupt(PE1), is_pressed0, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PE2), is_pressed1, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PE3), is_pressed2, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PE4), startGame, FALLING);

  // Pins for sending signals to lights
  SetupDigitalGPIO(PortF, pin1, OUTPUT, NoINTERRUPT);
  SetupDigitalGPIO(PortF, pin2, OUTPUT, NoINTERRUPT);
  SetupDigitalGPIO(PortF, pin4, OUTPUT, NoINTERRUPT);
  // Testing port
  SetupDigitalGPIO(PortA, pin2, OUTPUT, NoINTERRUPT);

  // Initializes the 4-digit display
  tm1637.init();
  tm1637.set(7);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;

  // Initializes the pizo buzzer
  pinMode(BUZZER_PIN, OUTPUT);
}


void random_pattern(int randomizePattern) {
  // Creates a random password based on a 'random' number, to further
  // randomize the pattern
  randomSeed(randomizePattern);
  for (int i = 0; i < 100; i++) {
    int randomNumber =  random() % 3;
    pattern[i] = randomNumber;
  }
}


void startGame() {
  // This activates when the start button is pressed.
  // Starts a light pattern that signals the start
  // of the game.

  // Creates the random pattern to be used for the game.
  random_pattern(randomizePattern);

  // Creates a light sequence to indicate the start of the game.
  *pGPIODATA |= pin4;
  delay(100);
  *pGPIODATA |= pin2;
  delay(100);
  *pGPIODATA |= pin1;
  // buzzer
  delay(400);
  *pGPIODATA &= ~pin1;
  delay(100);
  *pGPIODATA &= ~pin2;
  delay(100);
  *pGPIODATA &= ~pin4;
  delay(375);

  // Resets the 4 digit display
  tm1637.display(3, ' ');
  tm1637.display(2, ' ');
  tm1637.display(1, ' ');
  tm1637.display(0, ' ');

  // Begins the game
  correct_pattern = 1;
  start = 1;
  randomizePattern++;
  noInterrupts();
}


/* Code for buzzer */

void playNote(char note, int duration) {
  // play the tone corresponding to the note name
  for (int i = 0; i < 8; i++) {
    if (names[i] == note) {
      int tone = tones[i];
      for (long i = 0; i < duration * 1000L; i += tone * 2) {
        digitalWrite(BUZZER_PIN, HIGH);
        delayMicroseconds(tone);
        digitalWrite(BUZZER_PIN, LOW);
        delayMicroseconds(tone);
      }
    }
  }
}


/* Code for the counter */

void update_counter(int count) {
  // This function updates the 4 digit display to show the current score
  // of the player.
  interrupts();
  if (count > 9999) {

  }
  else if (count > 999) {
    tm1637.display(0, (count / 1000));
    tm1637.display(1, ((count / 100) % 10));
    tm1637.display(2, ((count / 10) % 10));
    tm1637.display(3, (count % 10));
  }
  else if (count > 99) {
    tm1637.display(1, (count / 100));
    tm1637.display(2, ((count / 10) % 10));
    tm1637.display(3, (count % 10));
  }
  else if (count > 9) {
    tm1637.display(2, (count / 10));
    tm1637.display(3, (count % 10));
  }
  else {
    tm1637.display(3, count);
  }
  noInterrupts();
}


/* Start of code that displays the pattern */

void blink (int light_color) {
  // This function turns the light corresponding to light_color on and then off.
  noInterrupts();
  if (light_color < 3) {
    int pinSwitched = pinList[light_color];
    *pGPIODATA |= pinSwitched;
    playNote(names[light_color], 200);
    delay(1000);
    *pGPIODATA &= ~pinSwitched;
  }

  delay(250);
}


void display_pattern(int count) {
  // This function turns lights on in an order
  // corresponding to the pattern.
  int i = 0;
  button_pressed = 3;
  while (i < count) {
    blink(pattern[i]);
    i++;
  }
}


/* Start of check button code */

// Interrupts for each of the three game buttons
void is_pressed0() {
  button_pressed = 0;
  playNote('c', 200);
}

void is_pressed1() {
  button_pressed = 1;
  playNote('d', 200);
}

void is_pressed2() {
  button_pressed = 2;
  playNote('e', 200);
}


int check_pattern(int count) {
  // For each item in the pattern...
  int i = 0;
  delay(375);
  for (i; i < count; i++) {
    button_pressed = 3;
    // Wait for 3 seconds or until a button is pressed
    int is_right = check_each(pattern[i]);
    if (is_right == 0) {
      return 0;
      break;
    }
  }
  return 1;

}

int check_each(int color) {
  // Checks what button is pressed in a certain interval of time
  // If no button or the wrong button is pressed, returns 0, if
  // the button pressed is correct, return 1.
  interrupts();
  *pGPIODATAA |= pin2;
  int j = 0;
  button_pressed = 3;
  while (button_pressed == 3) {
    j++;
    delay(1.5);
    if (j > 2000) {
      break;
    }

  }
  *pGPIODATAA &= ~pin2;
  noInterrupts();
  if (button_pressed == color) {
    delay(250);
    return 1;
  }

  else {
    return 0;
  }
}


void loop() {

  // Loop to ensure that the game does not start before the
  // start button is pressed.
  while (start == 0) {}

  count = 3;
  delay(1000);

  // Once the start button is pressed,
  while (correct_pattern == 1) {
    // Set the button pressed to none
    button_pressed = 3;
    // Update counter with the correct score
    update_counter(count);
    // Display pattern the length of the correct score
    display_pattern(count);
    // Check for the correct pattern to be entered
    correct_pattern = check_pattern(count);
    delay(250);
    count++;
  }
  // Game over lights and sounds
  if (correct_pattern == 0) {
    *pGPIODATA |= pin1;
    *pGPIODATA |= pin2;
    *pGPIODATA |= pin4;
    playNote('e', 200);
    playNote('d', 200);
    playNote('c', 200);
    delay(3000);
    *pGPIODATA &= ~pin1;
    *pGPIODATA &= ~pin2;
    *pGPIODATA &= ~pin4;
  }
  // set start to 0, so game can be reset
  interrupts();
  start = 0;
}

Credits

Dan Mullasseril

Dan Mullasseril

1 project • 0 followers
Garrett Murphy

Garrett Murphy

0 projects • 0 followers
Seamus Whoriskey

Seamus Whoriskey

0 projects • 0 followers

Comments