Components and supplies
Arduino Nano R3
Tactile Switch, Top Actuated
Resistor 475 ohm
Analog Accelerometer: ADXL335
Speaker, Piezo
LED Dot Matrix Display, Red
Resistor 10k ohm
Solderless Breadboard Full Size
Project description
Code
Gravity Simon Game Code
arduino
Setup and gameplay
1// GRAVITY SIMON GAME 2// This program will execute a remake version of Simon Game controlled with an 3// accelerometer sensor and will display and play sounds accordingly to the 4// orientation of the sensor. 5 6// Created October 16, 2020 7// by Policarpo Baquera 8// Carnegie Mellon University 9// More info at: https://create.arduino.cc/projecthub/plcrpbqr/gravity-simon-game-df5d00 10 11/* //////////////////////////////////// ADXL335 SETUP //////////////////////////////////// */ 12#include "Arduino.h" 13#include <math.h> 14const byte pinX = A7; 15const byte pinY = A6; 16const int xMinVal = 289; const int yMinVal = 279; //const int zMinVal = 291; 17const int xMaxVal = 424; const int yMaxVal = 416; //const int zMaxVal = 424; 18int angle = 0; 19 20/* //////////////////////////////////////// BUTTON /////////////////////////////////////// */ 21const byte pinButton = 13; 22 23/* Struct to track and debounce the state of a push button switch */ 24typedef struct buttonTracker { 25 int lastReading; // last raw value read 26 long lastChangeTime; // last time the raw value changed 27 byte pin; // the pin this is tracking changes on 28 byte buttonState; // debounced state of the button 29} butt; 30 31butt b; 32 33/* /////////////////////////////////////// SPEAKER /////////////////////////////////////// */ 34#include"pitches.h" 35const byte pinSpeaker = 10; 36const int SCALE[8] = {NOTE_C3, NOTE_D3, NOTE_E3, NOTE_F3, NOTE_G3, NOTE_A3, NOTE_B3, NOTE_C4}; 37const int readyMelody[4] = {NOTE_C3, NOTE_C3, NOTE_C3, NOTE_C4}; 38const int correctMelody[2] = {NOTE_B3, NOTE_C4}; 39const int wrongMelody[4] = {NOTE_D3, NOTE_CS3}; 40 41/* /////////////////////////////////////// DISPLAY /////////////////////////////////////// */ 42/* LED Matrix pin values */ 43const byte pin01 = 6; 44const byte pin02 = 7; 45const byte pin03 = 8; 46const byte pin04 = 9; 47const byte pin05 = 2; 48const byte pin06 = 3; 49const byte pin07 = 4; 50const byte pin08 = 5; 51const byte pin09 = A0; 52const byte pin10 = A1; 53const byte pin11 = A2; 54const byte pin12 = A3; 55const byte pin13 = 12; 56const byte pin14 = 11; 57const byte pin15 = A4; 58const byte pin16 = A5; 59 60/* Define cols and rows pin values for LED Matrix */ 61#define SIZE 8 62const byte COLS[8] = {pin05, pin02, pin07, pin01, pin12, pin08, pin14, pin09}; 63const byte ROWS[8] = {pin13, pin03, pin04, pin10, pin06, pin11, pin15, pin16}; 64 byte CROW = 0; 65 66/* Struct for animation frames */ 67typedef struct { 68 byte *p; // Hex Pattern 69 int t; // Animation time 70} pattern; 71 72/* Patterns */ 73byte ARRp[8] = {0x18, 0x3C, 0x7E, 0xDB, 0x18, 0x18, 0x18, 0x18}; 74byte GOp[8] = {0x00, 0x66, 0x99, 0xB9, 0x89, 0x99, 0x66, 0x00}; 75byte THREEp[8] = {0x00, 0x38, 0x04, 0x04, 0x38, 0x04, 0x38, 0x00}; 76byte TWOp[8] = {0x00, 0x3C, 0x10, 0x08, 0x04, 0x24, 0x18, 0x00}; 77byte ONEp[8] = {0x00, 0x08, 0x08, 0x08, 0x28, 0x18, 0x08, 0x00}; 78byte CORRECTp[8] = {0x00, 0x00, 0x10, 0x28, 0x44, 0x02, 0x00, 0x00}; 79byte WRONGp[8] = {0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00}; 80byte C1p[8] = {0xFF, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0xFF}; 81byte D1p[8] = {0xFF, 0x8F, 0x87, 0x83, 0x81, 0x81, 0x81, 0xFF}; 82byte E1p[8] = {0xFF, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0xFF}; 83byte F1p[8] = {0xFF, 0x81, 0x81, 0x81, 0x83, 0x87, 0x8F, 0xFF}; 84byte G1p[8] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0xFF}; 85byte A1p[8] = {0xFF, 0x81, 0x81, 0x81, 0xC1, 0xE1, 0xF1, 0xFF}; 86byte B1p[8] = {0xFF, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xFF}; 87byte C2p[8] = {0xFF, 0xF1, 0xE1, 0xC1, 0x81, 0x81, 0x81, 0xFF}; 88 89/* Frames and animations */ 90pattern ARR1; // ARROW 0.8s frame 91pattern ARR2; // ARROW 0.2s frame 92pattern ARR[2]; // ARROW 1.0s animation 93pattern GO; // GO 1s frame 94pattern THREE; // THREE 1s frame 95pattern TWO; // TWO 1s frame 96pattern ONE; // ONE 1s frame 97pattern COUNT[4]; // COUNT 4s animation 98pattern CORRECT; // CORRECT 2s frame 99pattern WRONG; // WRONG 2s frame 100pattern noteC1; 101pattern noteD1; 102pattern noteE1; 103pattern noteF1; 104pattern noteG1; 105pattern noteA1; 106pattern noteB1; 107pattern noteC2; 108pattern NOTES[8]; 109 110/* //////////////////////////////////////// GAME ///////////////////////////////////////// */ 111/* Game state */ 112enum modes{introMode, readyMode, melodyMode, gameMode, resultMode}; 113enum modes state; 114byte currentMelody; 115int currentNote; 116 117/* Game rounds */ 118typedef struct{ 119 byte *notes; 120 int *duration; 121 int len; 122} game; 123 124game game1; 125game game2; 126game game3; 127game game4; 128game gameCollection[4]; 129 130/* Game melodies */ 131byte notes1[4] = { 0, 0, 4, 2}; 132int durat1[4] = {1000, 1000, 1000, 1000}; 133byte notes2[5] = { 4, 1, 2, 5, 4}; 134int durat2[5] = {1500, 500, 1000, 1000, 2000}; 135byte notes3[7] = { 1, 3, 1, 2, 0, 4, 7}; 136int durat3[7] = { 800, 800, 800, 800, 800, 800, 800}; 137byte notes4[9] = { 0, 7, 6, 5, 4, 1, 2, 3, 4}; 138int durat4[9] = {1000, 1000, 1500, 500, 500, 500, 500, 500, 1000}; 139 140/* Player status */ 141typedef struct playerTracker { 142 byte lastReading; // last raw value read 143 long lastChangeTime; // last time the raw value changed 144 byte state; // debounced state of the button 145 bool success; 146} player; 147 148player p; 149 150/* //////////////////////////////////////// SETUP //////////////////////////////////////// */ 151void setup() { 152 // Button 153 initButton(b, pinButton); 154 // Accelerometer 155 pinMode(pinX, INPUT); 156 pinMode(pinY, INPUT); 157 // Matrix setup and patterns 158 initMatrix(); 159 initPatterns(); 160 initGame(p); 161} 162 163void initButton(butt &button, int pinButton) { 164 pinMode(pinButton, INPUT); 165 button.lastReading = digitalRead(pinButton); 166 button.lastChangeTime = millis(); 167 button.pin = pinButton; 168 button.buttonState = button.lastReading; 169} 170 171void initMatrix() { 172 for(int i = 0; i < 8; i++) { 173 pinMode(COLS[i], OUTPUT); 174 pinMode(ROWS[i], OUTPUT); 175 } 176 for(int i = 0; i < SIZE; i++) { 177 digitalWrite(COLS[i], LOW); 178 } 179 for(int i = 0; i < 8; i++) { 180 digitalWrite(ROWS[i], HIGH); 181 } 182} 183 184void initPatterns() { 185 ARR1.p = ARRp; ARR1.t = 1000; 186 ARR2.p = ARRp; ARR2.t = 500; 187 ARR[0] = ARR1; ARR[1] = ARR2; 188 GO.p = GOp; GO.t = 1000; 189 THREE.p = THREEp; THREE.t = 1000; 190 TWO.p = TWOp; TWO.t = 1000; 191 ONE.p = ONEp; ONE.t = 1000; 192 COUNT[0] = THREE; COUNT[1] = TWO; COUNT[2] = ONE; COUNT[3] = GO; 193 CORRECT.p = CORRECTp; CORRECT.t = 2000; 194 WRONG.p = WRONGp; WRONG.t = 2000; 195 noteC1.p = C1p; 196 noteD1.p = D1p; 197 noteE1.p = E1p; 198 noteF1.p = F1p; 199 noteG1.p = G1p; 200 noteA1.p = A1p; 201 noteB1.p = B1p; 202 noteC2.p = C2p; 203 NOTES[0] = noteC1; NOTES[1] = noteD1; NOTES[2] = noteE1; NOTES[3] = noteF1; 204 NOTES[4] = noteG1; NOTES[5] = noteA1; NOTES[6] = noteB1; NOTES[7] = noteC2; 205} 206 207void initGame(player &pl) { 208 // Initialize the game 209 state = introMode; 210 currentMelody = 0; 211 currentNote = 0; 212 // Initialize player's status 213 pl.lastReading = 0; 214 pl.lastChangeTime = millis(); 215 pl.state = pl.lastReading; 216 pl.success = false; // false means the user has failed, true means he has succeed 217 // Initialize game rounds and assign melodies 218 game1.notes = notes1; game1.duration = durat1; game1.len = 4; 219 game2.notes = notes2; game2.duration = durat2; game2.len = 5; 220 game3.notes = notes3; game3.duration = durat3; game3.len = 7; 221 game4.notes = notes4; game4.duration = durat4; game4.len = 9; 222 gameCollection[0] = game1; 223 gameCollection[1] = game2; 224 gameCollection[2] = game3; 225 gameCollection[3] = game4; 226} 227 228/* ///////////////////////////////////////// LOOP ///////////////////////////////////////// */ 229void loop() { 230 if (state == introMode){ 231 introScreen(); 232 if (buttonPressed(b) == true) state = readyMode; 233 } 234 if (state == readyMode) { 235 readyScreen(); 236 state = melodyMode; 237 } 238 if (state == melodyMode) { 239 melodyScreen(); 240 state = gameMode; 241 } 242 if (state == gameMode) { 243 gameScreen(); 244 } 245 if (state == resultMode) { 246 resultScreen(); 247 state = readyMode; 248 } 249} 250 251void introScreen() { 252 for (byte i = 0; i < 2; i++){ 253 unsigned long startTime = millis(); 254 while(ARR[i].t > ((millis() - startTime))) { 255 if (i == 0) lightRow(ARR[i].p[CROW]); 256 else lightRowDim(ARR[i].p[CROW]); 257 } 258 } 259} 260 261void readyScreen() { 262 for (byte i = 0; i < 4; i++){ 263 tone(pinSpeaker, readyMelody[i]); 264 unsigned long startTime = millis(); 265 while(COUNT[i].t > ((millis() - startTime))) { 266 if ((COUNT[i].t - 400) < ((millis() - startTime))) noTone(pinSpeaker); 267 lightRow(COUNT[i].p[CROW]); 268 } 269 } 270} 271 272void melodyScreen() { 273 int lenM = gameCollection[currentMelody].len; 274 byte* notesM = gameCollection[currentMelody].notes; 275 int* durationM = gameCollection[currentMelody].duration; 276 for (byte i = 0; i < lenM; i++){ 277 tone(pinSpeaker, SCALE[notesM[i]]); 278 unsigned long startTime = millis(); 279 while(durationM[i] > ((millis() - startTime))) { 280 if ((durationM[i]- 100) < ((millis() - startTime))) noTone(pinSpeaker); 281 lightRow(NOTES[notesM[i]].p[CROW]); 282 } 283 } 284} 285 286void gameScreen() { 287 readAccel(); 288 readPos(p); 289 if (buttonPressed(b) == false) { 290 noTone(pinSpeaker); 291 for (int i = 0; i < 8; i++){ 292 lightRowDim(NOTES[p.state].p[CROW]); 293 } 294 } else checkGame(); 295} 296 297void resultScreen() { 298 for (byte i = 0; i < 2; i++){ 299 unsigned long startTime = millis(); 300 if (p.success) { 301 tone(pinSpeaker, correctMelody[i]); 302 while(500 > ((millis() - startTime))) { 303 lightRow(CORRECT.p[CROW]); 304 } 305 } else { 306 tone(pinSpeaker, wrongMelody[i]); 307 while(500 > ((millis() - startTime))) { 308 lightRow(WRONG.p[CROW]); 309 } 310 } 311 } 312 noTone(pinSpeaker); 313 delay(1000); 314} 315 316void checkGame(){ 317 byte note = gameCollection[currentMelody].notes[currentNote]; 318 if (p.state != note) { 319 p.success = false; 320 currentNote = 0; 321 state = resultMode; 322 delay(200); 323 noTone(pinSpeaker); 324 delay(50); 325 } else if (p.state == note && currentNote == (gameCollection[currentMelody].len - 1)) { 326 p.success = true; 327 currentNote = 0; 328 currentMelody = (currentMelody + 1) % 4; 329 state = resultMode; 330 delay(200); 331 noTone(pinSpeaker); 332 delay(50); 333 } else { 334 p.success = false; 335 currentNote++; 336 } 337 while (digitalRead(b.pin) == true) { 338 for (int i = 0; i < 8; i++){ 339 lightRow(NOTES[p.state].p[CROW]); 340 tone(pinSpeaker, SCALE[p.state]); 341 } 342 } 343} 344 345bool buttonPressed(butt &button) { 346 // Swith must stay stable this long (in msec) to register 347 const long debounceTime = 50; 348 // Default to no change until we find out otherwise 349 boolean result = false; 350 // Get the current raw reading from the switch 351 int reading = digitalRead(button.pin); 352 if (reading != button.lastReading) { 353 button.lastChangeTime = millis(); 354 button.lastReading = reading; 355 } 356 if ((millis() - button.lastChangeTime) > debounceTime) { 357 button.buttonState = reading; 358 result = (button.buttonState == 1); 359 } 360 return result; 361} 362 363void readAccel() { 364 int xRead = 0, yRead = 0; 365 int xAng = 0, yAng = 0; 366 int sampleSize = 4; 367 for(int i = 0; i < sampleSize ; i++) { 368 xRead += analogRead(pinX); 369 yRead += analogRead(pinY); 370 //zRead += analogRead(pinZ); 371 } 372 xRead = xRead / sampleSize; 373 yRead = yRead / sampleSize; 374 //zRead = zRead / sampleSize; 375 xAng = map(xRead, xMinVal, xMaxVal, -90, 90); 376 yAng = map(yRead, yMinVal, yMaxVal, -90, 90); 377 //zAng = map(zRead, zMinVal, zMaxVal, -90, 90); 378 //x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI); 379 //y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI); 380 angle = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI); 381 //Serial.print("angle = "); Serial.println(z); 382} 383 384void readPos(player &pl) { 385 // Player position must stay stable this long (in msec) to register 386 const long debounceTime = 20; 387 // Get the current raw reading from the accelerometer 388 byte reading = 0; 389 if (158 < angle && angle <= 203) reading = 0; 390 if (203 < angle && angle <= 248) reading = 1; 391 if (248 < angle && angle <= 293) reading = 2; 392 if (293 < angle && angle <= 338) reading = 3; 393 if (338 < angle || angle <= 23) reading = 4; 394 if ( 23 < angle && angle <= 68) reading = 5; 395 if ( 68 < angle && angle <= 113) reading = 6; 396 if (113 < angle && angle <= 158) reading = 7; 397 if (reading != pl.lastReading) { 398 pl.lastChangeTime = millis(); 399 pl.lastReading = reading; 400 } 401 if ((millis() - pl.lastChangeTime) > debounceTime) { 402 pl.state = reading; 403 } 404} 405 406void lightRow(byte hex) { 407 digitalWrite(ROWS[CROW], LOW); 408 for(byte i = 0; i < 8; i++) { 409 digitalWrite(COLS[i], (hex>>i) & 0x01); 410 } 411 for(byte i = 0; i < 8; i++) { 412 digitalWrite(COLS[i], LOW); 413 } 414 digitalWrite(ROWS[CROW], HIGH); 415 CROW = (CROW + 1) % SIZE; 416} 417 418void lightRowDim(byte hex) { 419 digitalWrite(ROWS[CROW], LOW); 420 for(byte i = 0; i < 8; i++) { 421 digitalWrite(COLS[i], (hex>>i) & 0x01); 422 } 423 for(byte i = 0; i < 8; i++) { 424 digitalWrite(COLS[i], LOW); 425 } 426 digitalWrite(ROWS[CROW], HIGH); 427 delay(1); 428 CROW = (CROW + 1) % SIZE; 429}
Pitches Library
arduino
Library with musical note frequencies.
1#define NOTE_B0 31 2#define NOTE_C1 33 3#define NOTE_CS1 35 4#define NOTE_D1 37 5#define NOTE_DS1 39 6#define NOTE_E1 41 7#define NOTE_F1 44 8#define NOTE_FS1 46 9#define NOTE_G1 49 10#define NOTE_GS1 52 11#define NOTE_A1 55 12#define NOTE_AS1 58 13#define NOTE_B1 62 14#define NOTE_C2 65 15#define NOTE_CS2 69 16#define NOTE_D2 73 17#define NOTE_DS2 78 18#define NOTE_E2 82 19#define NOTE_F2 87 20#define NOTE_FS2 93 21#define NOTE_G2 98 22#define NOTE_GS2 104 23#define NOTE_A2 110 24#define NOTE_AS2 117 25#define NOTE_B2 123 26#define NOTE_C3 131 27#define NOTE_CS3 139 28#define NOTE_D3 147 29#define NOTE_DS3 156 30#define NOTE_E3 165 31#define NOTE_F3 175 32#define NOTE_FS3 185 33#define NOTE_G3 196 34#define NOTE_GS3 208 35#define NOTE_A3 220 36#define NOTE_AS3 233 37#define NOTE_B3 247 38#define NOTE_C4 262 39#define NOTE_CS4 277 40#define NOTE_D4 294 41#define NOTE_DS4 311 42#define NOTE_E4 330 43#define NOTE_F4 349 44#define NOTE_FS4 370 45#define NOTE_G4 392 46#define NOTE_GS4 415 47#define NOTE_A4 440 48#define NOTE_AS4 466 49#define NOTE_B4 494 50#define NOTE_C5 523 51#define NOTE_CS5 554 52#define NOTE_D5 587 53#define NOTE_DS5 622 54#define NOTE_E5 659 55#define NOTE_F5 698 56#define NOTE_FS5 740 57#define NOTE_G5 784 58#define NOTE_GS5 831 59#define NOTE_A5 880 60#define NOTE_AS5 932 61#define NOTE_B5 988 62#define NOTE_C6 1047 63#define NOTE_CS6 1109 64#define NOTE_D6 1175 65#define NOTE_DS6 1245 66#define NOTE_E6 1319 67#define NOTE_F6 1397 68#define NOTE_FS6 1480 69#define NOTE_G6 1568 70#define NOTE_GS6 1661 71#define NOTE_A6 1760 72#define NOTE_AS6 1865 73#define NOTE_B6 1976 74#define NOTE_C7 2093 75#define NOTE_CS7 2217 76#define NOTE_D7 2349 77#define NOTE_DS7 2489 78#define NOTE_E7 2637 79#define NOTE_F7 2794 80#define NOTE_FS7 2960 81#define NOTE_G7 3136 82#define NOTE_GS7 3322 83#define NOTE_A7 3520 84#define NOTE_AS7 3729 85#define NOTE_B7 3951 86#define NOTE_C8 4186 87#define NOTE_CS8 4435 88#define NOTE_D8 4699 89#define NOTE_DS8 4978 90#define END -1
Gravity Simon Game Code
arduino
Setup and gameplay
1// GRAVITY SIMON GAME 2// This program will execute a remake version of Simon Game controlled with an 3// accelerometer sensor and will display and play sounds accordingly to the 4// orientation of the sensor. 5 6// Created October 16, 2020 7// by Policarpo Baquera 8// Carnegie Mellon University 9// More info at: https://create.arduino.cc/projecthub/plcrpbqr/gravity-simon-game-df5d00 10 11/* //////////////////////////////////// ADXL335 SETUP //////////////////////////////////// */ 12#include "Arduino.h" 13#include <math.h> 14const byte pinX = A7; 15const byte pinY = A6; 16const int xMinVal = 289; const int yMinVal = 279; //const int zMinVal = 291; 17const int xMaxVal = 424; const int yMaxVal = 416; //const int zMaxVal = 424; 18int angle = 0; 19 20/* //////////////////////////////////////// BUTTON /////////////////////////////////////// */ 21const byte pinButton = 13; 22 23/* Struct to track and debounce the state of a push button switch */ 24typedef struct buttonTracker { 25 int lastReading; // last raw value read 26 long lastChangeTime; // last time the raw value changed 27 byte pin; // the pin this is tracking changes on 28 byte buttonState; // debounced state of the button 29} butt; 30 31butt b; 32 33/* /////////////////////////////////////// SPEAKER /////////////////////////////////////// */ 34#include"pitches.h" 35const byte pinSpeaker = 10; 36const int SCALE[8] = {NOTE_C3, NOTE_D3, NOTE_E3, NOTE_F3, NOTE_G3, NOTE_A3, NOTE_B3, NOTE_C4}; 37const int readyMelody[4] = {NOTE_C3, NOTE_C3, NOTE_C3, NOTE_C4}; 38const int correctMelody[2] = {NOTE_B3, NOTE_C4}; 39const int wrongMelody[4] = {NOTE_D3, NOTE_CS3}; 40 41/* /////////////////////////////////////// DISPLAY /////////////////////////////////////// */ 42/* LED Matrix pin values */ 43const byte pin01 = 6; 44const byte pin02 = 7; 45const byte pin03 = 8; 46const byte pin04 = 9; 47const byte pin05 = 2; 48const byte pin06 = 3; 49const byte pin07 = 4; 50const byte pin08 = 5; 51const byte pin09 = A0; 52const byte pin10 = A1; 53const byte pin11 = A2; 54const byte pin12 = A3; 55const byte pin13 = 12; 56const byte pin14 = 11; 57const byte pin15 = A4; 58const byte pin16 = A5; 59 60/* Define cols and rows pin values for LED Matrix */ 61#define SIZE 8 62const byte COLS[8] = {pin05, pin02, pin07, pin01, pin12, pin08, pin14, pin09}; 63const byte ROWS[8] = {pin13, pin03, pin04, pin10, pin06, pin11, pin15, pin16}; 64 byte CROW = 0; 65 66/* Struct for animation frames */ 67typedef struct { 68 byte *p; // Hex Pattern 69 int t; // Animation time 70} pattern; 71 72/* Patterns */ 73byte ARRp[8] = {0x18, 0x3C, 0x7E, 0xDB, 0x18, 0x18, 0x18, 0x18}; 74byte GOp[8] = {0x00, 0x66, 0x99, 0xB9, 0x89, 0x99, 0x66, 0x00}; 75byte THREEp[8] = {0x00, 0x38, 0x04, 0x04, 0x38, 0x04, 0x38, 0x00}; 76byte TWOp[8] = {0x00, 0x3C, 0x10, 0x08, 0x04, 0x24, 0x18, 0x00}; 77byte ONEp[8] = {0x00, 0x08, 0x08, 0x08, 0x28, 0x18, 0x08, 0x00}; 78byte CORRECTp[8] = {0x00, 0x00, 0x10, 0x28, 0x44, 0x02, 0x00, 0x00}; 79byte WRONGp[8] = {0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00}; 80byte C1p[8] = {0xFF, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0xFF}; 81byte D1p[8] = {0xFF, 0x8F, 0x87, 0x83, 0x81, 0x81, 0x81, 0xFF}; 82byte E1p[8] = {0xFF, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0xFF}; 83byte F1p[8] = {0xFF, 0x81, 0x81, 0x81, 0x83, 0x87, 0x8F, 0xFF}; 84byte G1p[8] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0xFF}; 85byte A1p[8] = {0xFF, 0x81, 0x81, 0x81, 0xC1, 0xE1, 0xF1, 0xFF}; 86byte B1p[8] = {0xFF, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xFF}; 87byte C2p[8] = {0xFF, 0xF1, 0xE1, 0xC1, 0x81, 0x81, 0x81, 0xFF}; 88 89/* Frames and animations */ 90pattern ARR1; // ARROW 0.8s frame 91pattern ARR2; // ARROW 0.2s frame 92pattern ARR[2]; // ARROW 1.0s animation 93pattern GO; // GO 1s frame 94pattern THREE; // THREE 1s frame 95pattern TWO; // TWO 1s frame 96pattern ONE; // ONE 1s frame 97pattern COUNT[4]; // COUNT 4s animation 98pattern CORRECT; // CORRECT 2s frame 99pattern WRONG; // WRONG 2s frame 100pattern noteC1; 101pattern noteD1; 102pattern noteE1; 103pattern noteF1; 104pattern noteG1; 105pattern noteA1; 106pattern noteB1; 107pattern noteC2; 108pattern NOTES[8]; 109 110/* //////////////////////////////////////// GAME ///////////////////////////////////////// */ 111/* Game state */ 112enum modes{introMode, readyMode, melodyMode, gameMode, resultMode}; 113enum modes state; 114byte currentMelody; 115int currentNote; 116 117/* Game rounds */ 118typedef struct{ 119 byte *notes; 120 int *duration; 121 int len; 122} game; 123 124game game1; 125game game2; 126game game3; 127game game4; 128game gameCollection[4]; 129 130/* Game melodies */ 131byte notes1[4] = { 0, 0, 4, 2}; 132int durat1[4] = {1000, 1000, 1000, 1000}; 133byte notes2[5] = { 4, 1, 2, 5, 4}; 134int durat2[5] = {1500, 500, 1000, 1000, 2000}; 135byte notes3[7] = { 1, 3, 1, 2, 0, 4, 7}; 136int durat3[7] = { 800, 800, 800, 800, 800, 800, 800}; 137byte notes4[9] = { 0, 7, 6, 5, 4, 1, 2, 3, 4}; 138int durat4[9] = {1000, 1000, 1500, 500, 500, 500, 500, 500, 1000}; 139 140/* Player status */ 141typedef struct playerTracker { 142 byte lastReading; // last raw value read 143 long lastChangeTime; // last time the raw value changed 144 byte state; // debounced state of the button 145 bool success; 146} player; 147 148player p; 149 150/* //////////////////////////////////////// SETUP //////////////////////////////////////// */ 151void setup() { 152 // Button 153 initButton(b, pinButton); 154 // Accelerometer 155 pinMode(pinX, INPUT); 156 pinMode(pinY, INPUT); 157 // Matrix setup and patterns 158 initMatrix(); 159 initPatterns(); 160 initGame(p); 161} 162 163void initButton(butt &button, int pinButton) { 164 pinMode(pinButton, INPUT); 165 button.lastReading = digitalRead(pinButton); 166 button.lastChangeTime = millis(); 167 button.pin = pinButton; 168 button.buttonState = button.lastReading; 169} 170 171void initMatrix() { 172 for(int i = 0; i < 8; i++) { 173 pinMode(COLS[i], OUTPUT); 174 pinMode(ROWS[i], OUTPUT); 175 } 176 for(int i = 0; i < SIZE; i++) { 177 digitalWrite(COLS[i], LOW); 178 } 179 for(int i = 0; i < 8; i++) { 180 digitalWrite(ROWS[i], HIGH); 181 } 182} 183 184void initPatterns() { 185 ARR1.p = ARRp; ARR1.t = 1000; 186 ARR2.p = ARRp; ARR2.t = 500; 187 ARR[0] = ARR1; ARR[1] = ARR2; 188 GO.p = GOp; GO.t = 1000; 189 THREE.p = THREEp; THREE.t = 1000; 190 TWO.p = TWOp; TWO.t = 1000; 191 ONE.p = ONEp; ONE.t = 1000; 192 COUNT[0] = THREE; COUNT[1] = TWO; COUNT[2] = ONE; COUNT[3] = GO; 193 CORRECT.p = CORRECTp; CORRECT.t = 2000; 194 WRONG.p = WRONGp; WRONG.t = 2000; 195 noteC1.p = C1p; 196 noteD1.p = D1p; 197 noteE1.p = E1p; 198 noteF1.p = F1p; 199 noteG1.p = G1p; 200 noteA1.p = A1p; 201 noteB1.p = B1p; 202 noteC2.p = C2p; 203 NOTES[0] = noteC1; NOTES[1] = noteD1; NOTES[2] = noteE1; NOTES[3] = noteF1; 204 NOTES[4] = noteG1; NOTES[5] = noteA1; NOTES[6] = noteB1; NOTES[7] = noteC2; 205} 206 207void initGame(player &pl) { 208 // Initialize the game 209 state = introMode; 210 currentMelody = 0; 211 currentNote = 0; 212 // Initialize player's status 213 pl.lastReading = 0; 214 pl.lastChangeTime = millis(); 215 pl.state = pl.lastReading; 216 pl.success = false; // false means the user has failed, true means he has succeed 217 // Initialize game rounds and assign melodies 218 game1.notes = notes1; game1.duration = durat1; game1.len = 4; 219 game2.notes = notes2; game2.duration = durat2; game2.len = 5; 220 game3.notes = notes3; game3.duration = durat3; game3.len = 7; 221 game4.notes = notes4; game4.duration = durat4; game4.len = 9; 222 gameCollection[0] = game1; 223 gameCollection[1] = game2; 224 gameCollection[2] = game3; 225 gameCollection[3] = game4; 226} 227 228/* ///////////////////////////////////////// LOOP ///////////////////////////////////////// */ 229void loop() { 230 if (state == introMode){ 231 introScreen(); 232 if (buttonPressed(b) == true) state = readyMode; 233 } 234 if (state == readyMode) { 235 readyScreen(); 236 state = melodyMode; 237 } 238 if (state == melodyMode) { 239 melodyScreen(); 240 state = gameMode; 241 } 242 if (state == gameMode) { 243 gameScreen(); 244 } 245 if (state == resultMode) { 246 resultScreen(); 247 state = readyMode; 248 } 249} 250 251void introScreen() { 252 for (byte i = 0; i < 2; i++){ 253 unsigned long startTime = millis(); 254 while(ARR[i].t > ((millis() - startTime))) { 255 if (i == 0) lightRow(ARR[i].p[CROW]); 256 else lightRowDim(ARR[i].p[CROW]); 257 } 258 } 259} 260 261void readyScreen() { 262 for (byte i = 0; i < 4; i++){ 263 tone(pinSpeaker, readyMelody[i]); 264 unsigned long startTime = millis(); 265 while(COUNT[i].t > ((millis() - startTime))) { 266 if ((COUNT[i].t - 400) < ((millis() - startTime))) noTone(pinSpeaker); 267 lightRow(COUNT[i].p[CROW]); 268 } 269 } 270} 271 272void melodyScreen() { 273 int lenM = gameCollection[currentMelody].len; 274 byte* notesM = gameCollection[currentMelody].notes; 275 int* durationM = gameCollection[currentMelody].duration; 276 for (byte i = 0; i < lenM; i++){ 277 tone(pinSpeaker, SCALE[notesM[i]]); 278 unsigned long startTime = millis(); 279 while(durationM[i] > ((millis() - startTime))) { 280 if ((durationM[i]- 100) < ((millis() - startTime))) noTone(pinSpeaker); 281 lightRow(NOTES[notesM[i]].p[CROW]); 282 } 283 } 284} 285 286void gameScreen() { 287 readAccel(); 288 readPos(p); 289 if (buttonPressed(b) == false) { 290 noTone(pinSpeaker); 291 for (int i = 0; i < 8; i++){ 292 lightRowDim(NOTES[p.state].p[CROW]); 293 } 294 } else checkGame(); 295} 296 297void resultScreen() { 298 for (byte i = 0; i < 2; i++){ 299 unsigned long startTime = millis(); 300 if (p.success) { 301 tone(pinSpeaker, correctMelody[i]); 302 while(500 > ((millis() - startTime))) { 303 lightRow(CORRECT.p[CROW]); 304 } 305 } else { 306 tone(pinSpeaker, wrongMelody[i]); 307 while(500 > ((millis() - startTime))) { 308 lightRow(WRONG.p[CROW]); 309 } 310 } 311 } 312 noTone(pinSpeaker); 313 delay(1000); 314} 315 316void checkGame(){ 317 byte note = gameCollection[currentMelody].notes[currentNote]; 318 if (p.state != note) { 319 p.success = false; 320 currentNote = 0; 321 state = resultMode; 322 delay(200); 323 noTone(pinSpeaker); 324 delay(50); 325 } else if (p.state == note && currentNote == (gameCollection[currentMelody].len - 1)) { 326 p.success = true; 327 currentNote = 0; 328 currentMelody = (currentMelody + 1) % 4; 329 state = resultMode; 330 delay(200); 331 noTone(pinSpeaker); 332 delay(50); 333 } else { 334 p.success = false; 335 currentNote++; 336 } 337 while (digitalRead(b.pin) == true) { 338 for (int i = 0; i < 8; i++){ 339 lightRow(NOTES[p.state].p[CROW]); 340 tone(pinSpeaker, SCALE[p.state]); 341 } 342 } 343} 344 345bool buttonPressed(butt &button) { 346 // Swith must stay stable this long (in msec) to register 347 const long debounceTime = 50; 348 // Default to no change until we find out otherwise 349 boolean result = false; 350 // Get the current raw reading from the switch 351 int reading = digitalRead(button.pin); 352 if (reading != button.lastReading) { 353 button.lastChangeTime = millis(); 354 button.lastReading = reading; 355 } 356 if ((millis() - button.lastChangeTime) > debounceTime) { 357 button.buttonState = reading; 358 result = (button.buttonState == 1); 359 } 360 return result; 361} 362 363void readAccel() { 364 int xRead = 0, yRead = 0; 365 int xAng = 0, yAng = 0; 366 int sampleSize = 4; 367 for(int i = 0; i < sampleSize ; i++) { 368 xRead += analogRead(pinX); 369 yRead += analogRead(pinY); 370 //zRead += analogRead(pinZ); 371 } 372 xRead = xRead / sampleSize; 373 yRead = yRead / sampleSize; 374 //zRead = zRead / sampleSize; 375 xAng = map(xRead, xMinVal, xMaxVal, -90, 90); 376 yAng = map(yRead, yMinVal, yMaxVal, -90, 90); 377 //zAng = map(zRead, zMinVal, zMaxVal, -90, 90); 378 //x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI); 379 //y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI); 380 angle = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI); 381 //Serial.print("angle = "); Serial.println(z); 382} 383 384void readPos(player &pl) { 385 // Player position must stay stable this long (in msec) to register 386 const long debounceTime = 20; 387 // Get the current raw reading from the accelerometer 388 byte reading = 0; 389 if (158 < angle && angle <= 203) reading = 0; 390 if (203 < angle && angle <= 248) reading = 1; 391 if (248 < angle && angle <= 293) reading = 2; 392 if (293 < angle && angle <= 338) reading = 3; 393 if (338 < angle || angle <= 23) reading = 4; 394 if ( 23 < angle && angle <= 68) reading = 5; 395 if ( 68 < angle && angle <= 113) reading = 6; 396 if (113 < angle && angle <= 158) reading = 7; 397 if (reading != pl.lastReading) { 398 pl.lastChangeTime = millis(); 399 pl.lastReading = reading; 400 } 401 if ((millis() - pl.lastChangeTime) > debounceTime) { 402 pl.state = reading; 403 } 404} 405 406void lightRow(byte hex) { 407 digitalWrite(ROWS[CROW], LOW); 408 for(byte i = 0; i < 8; i++) { 409 digitalWrite(COLS[i], (hex>>i) & 0x01); 410 } 411 for(byte i = 0; i < 8; i++) { 412 digitalWrite(COLS[i], LOW); 413 } 414 digitalWrite(ROWS[CROW], HIGH); 415 CROW = (CROW + 1) % SIZE; 416} 417 418void lightRowDim(byte hex) { 419 digitalWrite(ROWS[CROW], LOW); 420 for(byte i = 0; i < 8; i++) { 421 digitalWrite(COLS[i], (hex>>i) & 0x01); 422 } 423 for(byte i = 0; i < 8; i++) { 424 digitalWrite(COLS[i], LOW); 425 } 426 digitalWrite(ROWS[CROW], HIGH); 427 delay(1); 428 CROW = (CROW + 1) % SIZE; 429}
Downloadable files
Schematic
Schematic
Schematic
Schematic
Comments
Only logged in users can leave comments