Add Simon Game with Score Display and Pong Game
- Created pitches.h to define musical note frequencies. - Implemented Simon Game in simon-with-score.ino, featuring LED indicators, button inputs, and score display using a 74HC595 shift register. - Added game logic for sequence playback, user input validation, and game over conditions. - Included README.md for Simon Game instructions and hardware setup. - Added Wokwi project files for simulation of Simon Game. - Introduced Pong game with basic mechanics, including paddle movement and scoring, in pong.ino. - Included Wokwi project files for simulation of Pong game.pull/10/head
parent
c22a8aff14
commit
a145075eb8
|
|
@ -77,5 +77,4 @@ wokwi-libs/*/.cache/
|
|||
.claude/settings.local.json
|
||||
.history/*
|
||||
.daveagent/*
|
||||
example_zip/*
|
||||
data/*
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,260 @@
|
|||
// ServoOverdone.ino
|
||||
//
|
||||
// Example for multiple Servo objects in a array.
|
||||
//
|
||||
// Version 1, 28 July 2021, by Koepel.
|
||||
// Version 2, 15 August 2021, by Koepel.
|
||||
// changed timing, a little slower
|
||||
// diagram.json has servos in reverse order (I think it is visually better)
|
||||
// Added fourth sequence: "compass"
|
||||
//
|
||||
// Public Domain
|
||||
//
|
||||
|
||||
#include <Servo.h>
|
||||
|
||||
#define NUM_SERVOS 32
|
||||
Servo myServo[NUM_SERVOS];
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Attach pins from the Arduino Mega board to the Servo objects.
|
||||
// Starting from pin 22, there happen to be exactly 32 pins on the double row pins.
|
||||
for( int i=0; i<NUM_SERVOS; i++)
|
||||
{
|
||||
myServo[i].attach( i + 22); // pin 22 up to 53 is 32 pins
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Sequence one.
|
||||
// All servo motor are set to a random angle.
|
||||
for( int a=0; a<15; a++)
|
||||
{
|
||||
for( int i=0; i<NUM_SERVOS; i++)
|
||||
{
|
||||
myServo[i].write( random( 0, 181));
|
||||
delay( 2);
|
||||
}
|
||||
delay( 150);
|
||||
}
|
||||
|
||||
// Sequence two.
|
||||
// All servo motors move with the same angle.
|
||||
for( int i=0; i<NUM_SERVOS; i++)
|
||||
{
|
||||
myServo[i].write( 0); // set to begin position (horn is rotated left)
|
||||
}
|
||||
delay( 1000); // wait to let the viewer get used to it
|
||||
|
||||
for( int a=0; a<3; a++)
|
||||
{
|
||||
for( int r=0; r<=180; r++) // move horns to the right
|
||||
{
|
||||
for( int i=0; i<NUM_SERVOS; i++)
|
||||
{
|
||||
myServo[i].write( r);
|
||||
}
|
||||
delay( 6);
|
||||
}
|
||||
for( int r=180; r>=0; r--)
|
||||
{
|
||||
for( int i=0; i<NUM_SERVOS; i++) // move horns to the left
|
||||
{
|
||||
myServo[i].write( r);
|
||||
}
|
||||
delay( 6);
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence three.
|
||||
// A rotating wave.
|
||||
for( int a=0; a<6; a++)
|
||||
{
|
||||
for( int i=0; i<NUM_SERVOS; i++)
|
||||
{
|
||||
for( int j=0; j<NUM_SERVOS; j++)
|
||||
{
|
||||
// Calculate distance to active servo
|
||||
int d = j - i;
|
||||
if( d < 0)
|
||||
d = -d;
|
||||
if( d > (NUM_SERVOS / 2))
|
||||
d = NUM_SERVOS - d;
|
||||
|
||||
int angle = 90 - (10 * d);
|
||||
if( angle < 0)
|
||||
angle = 0;
|
||||
myServo[j].write( angle);
|
||||
}
|
||||
delay(40);
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence four.
|
||||
// A "compass"
|
||||
// Start by pointing upwards
|
||||
int pointer = NUM_SERVOS * 3 / 4;
|
||||
showPointer( pointer);
|
||||
delay( 1000); // let the viewer get used to new pattern
|
||||
|
||||
for( int i=0; i<5; i++)
|
||||
{
|
||||
showPointer( --pointer);
|
||||
delay( 150);
|
||||
}
|
||||
delay( 200);
|
||||
for( int i=0; i<9; i++)
|
||||
{
|
||||
showPointer( ++pointer);
|
||||
delay( 150);
|
||||
}
|
||||
delay( 200);
|
||||
for( int i=0; i<5; i++)
|
||||
{
|
||||
showPointer( --pointer);
|
||||
delay( 150);
|
||||
}
|
||||
delay( 200);
|
||||
for( int i=0; i<4; i++)
|
||||
{
|
||||
showPointer( ++pointer);
|
||||
delay( 150);
|
||||
}
|
||||
delay( 160);
|
||||
for( int i=0; i<2; i++)
|
||||
{
|
||||
showPointer( --pointer);
|
||||
delay( 150);
|
||||
}
|
||||
delay( 80);
|
||||
for( int i=0; i<1; i++)
|
||||
{
|
||||
showPointer( ++pointer);
|
||||
delay( 150);
|
||||
}
|
||||
|
||||
delay( 2000);
|
||||
}
|
||||
|
||||
// This function makes a "pointer" with the servos.
|
||||
// It is used to create the "compass".
|
||||
// The parameter 's' is the servo motor that has the pointer.
|
||||
// It is allowed that 's' is below zero or larger than the numbers of servo motors.
|
||||
void showPointer( int s)
|
||||
{
|
||||
int pointerA = s % NUM_SERVOS; // Using the '%' (remainder) for valid number
|
||||
int pointerB = (s + 1) % NUM_SERVOS; // pointer is made with the next servo motor
|
||||
int tailA = (s + 16) % NUM_SERVOS;
|
||||
int tailB = (s + 17) % NUM_SERVOS;
|
||||
|
||||
// make pointer with servo motor s and s+1.
|
||||
myServo[pointerA].write(180-56);
|
||||
myServo[pointerB].write(56);
|
||||
|
||||
// make tail with servo motor s+16 and s+17.
|
||||
myServo[tailA].write(95);
|
||||
myServo[tailB].write(85);
|
||||
|
||||
// Set servos right of pointer
|
||||
int n = (NUM_SERVOS / 2) - 2;
|
||||
int start = pointerB + 1;
|
||||
for( int i=0; i<n; i++)
|
||||
{
|
||||
int j = (start + i) % NUM_SERVOS;
|
||||
myServo[j].write( 2);
|
||||
}
|
||||
|
||||
// Set servos left of pointer
|
||||
start = tailB + 1;
|
||||
for( int i=0; i<n; i++)
|
||||
{
|
||||
int j = (start + i) % NUM_SERVOS;
|
||||
myServo[j].write( 178);
|
||||
}
|
||||
}
|
||||
|
||||
// The function GenerateDiagram() can be used to generate
|
||||
// the diagram.json file for Wokwi.
|
||||
// To use it, call it from the setup() function, and the
|
||||
// serial output can be copied into the diagram.json file.
|
||||
void GenerateDiagram()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.print( "{\n");
|
||||
Serial.print( " \"version\": 1,\n");
|
||||
Serial.print( " \"author\": \"Generated\",\n");
|
||||
Serial.print( " \"editor\": \"wokwi\",\n");
|
||||
Serial.print( " \"parts\": [\n");
|
||||
|
||||
Serial.print( " {\n");
|
||||
Serial.print( " \"type\": \"wokwi-arduino-mega\",\n");
|
||||
Serial.print( " \"id\": \"mega\",\n");
|
||||
Serial.print( " \"top\": 270,\n");
|
||||
Serial.print( " \"left\": 185,\n");
|
||||
Serial.print( " \"attrs\": {}\n");
|
||||
Serial.print( " },\n");
|
||||
|
||||
// Put the servo motor in reverse order in the diagram.json
|
||||
// I think that is visually better.
|
||||
// The horn now overlaps the next servo when the horn moves to the right.
|
||||
for( int i=NUM_SERVOS-1; i>=0; i--)
|
||||
{
|
||||
float rotate = float( i) * (360.0 / float( NUM_SERVOS));
|
||||
float rad = rotate / 360.0 * 2.0 * M_PI;
|
||||
float top = (300.0 * sin( rad)) + 300.0;
|
||||
float left = (300.0 * cos( rad)) + 300.0;
|
||||
Serial.print( " {\n");
|
||||
Serial.print( " \"type\": \"wokwi-servo\",\n");
|
||||
Serial.print( " \"id\": \"servo");
|
||||
Serial.print( i);
|
||||
Serial.print( "\",\n");
|
||||
Serial.print( " \"top\": ");
|
||||
Serial.print( top);
|
||||
Serial.print( ",\n");
|
||||
Serial.print( " \"left\": ");
|
||||
Serial.print( left);
|
||||
Serial.print( ",\n");
|
||||
Serial.print( " \"rotate\": ");
|
||||
Serial.print( rotate);
|
||||
Serial.print( ",\n");
|
||||
Serial.print( " \"attrs\": { \"hornColor\": \"Red\" }\n");
|
||||
Serial.print( " }");
|
||||
if( i != 0)
|
||||
Serial.print( ",");
|
||||
Serial.print( "\n");
|
||||
}
|
||||
|
||||
Serial.print( " ],\n");
|
||||
Serial.print( " \"connections\": [\n");
|
||||
|
||||
for( int i=0; i<NUM_SERVOS; i++)
|
||||
{
|
||||
int j = i + 1;
|
||||
if( j == NUM_SERVOS)
|
||||
j = 0;
|
||||
Serial.print( " [ \"servo");
|
||||
Serial.print( i);
|
||||
Serial.print( ":V+\", \"servo");
|
||||
Serial.print( j);
|
||||
Serial.print( ":V+\", \"Red\", [] ],\n");
|
||||
Serial.print( " [ \"servo");
|
||||
Serial.print( i);
|
||||
Serial.print( ":GND\", \"servo");
|
||||
Serial.print( j);
|
||||
Serial.print( ":GND\", \"Black\", [] ],\n");
|
||||
|
||||
Serial.print( " [ \"mega:");
|
||||
Serial.print( i + 22);
|
||||
Serial.print( "\", \"servo");
|
||||
Serial.print( i);
|
||||
Serial.print( ":PWM\", \"Green\", [ ] ],\n");
|
||||
}
|
||||
Serial.print( " [ \"mega:GND.2\", \"servo9:GND\", \"Black\", [ ] ],\n");
|
||||
Serial.print( " [ \"mega:5V\", \"servo9:V+\", \"Red\", [ ] ]\n");
|
||||
|
||||
Serial.print( " ]\n");
|
||||
Serial.print( "}\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,370 @@
|
|||
{
|
||||
"version": 1,
|
||||
"author": "Generated",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{
|
||||
"type": "wokwi-arduino-mega",
|
||||
"id": "mega",
|
||||
"top": 270,
|
||||
"left": 185,
|
||||
"attrs": {}
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo31",
|
||||
"top": 241.47,
|
||||
"left": 594.24,
|
||||
"rotate": 348.75,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo30",
|
||||
"top": 185.19,
|
||||
"left": 577.16,
|
||||
"rotate": 337.50,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo29",
|
||||
"top": 133.33,
|
||||
"left": 549.44,
|
||||
"rotate": 326.25,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo28",
|
||||
"top": 87.87,
|
||||
"left": 512.13,
|
||||
"rotate": 315.00,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo27",
|
||||
"top": 50.56,
|
||||
"left": 466.67,
|
||||
"rotate": 303.75,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo26",
|
||||
"top": 22.84,
|
||||
"left": 414.81,
|
||||
"rotate": 292.50,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo25",
|
||||
"top": 5.76,
|
||||
"left": 358.53,
|
||||
"rotate": 281.25,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo24",
|
||||
"top": 0.00,
|
||||
"left": 300.00,
|
||||
"rotate": 270.00,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo23",
|
||||
"top": 5.76,
|
||||
"left": 241.47,
|
||||
"rotate": 258.75,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo22",
|
||||
"top": 22.84,
|
||||
"left": 185.20,
|
||||
"rotate": 247.50,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo21",
|
||||
"top": 50.56,
|
||||
"left": 133.33,
|
||||
"rotate": 236.25,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo20",
|
||||
"top": 87.87,
|
||||
"left": 87.87,
|
||||
"rotate": 225.00,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo19",
|
||||
"top": 133.33,
|
||||
"left": 50.56,
|
||||
"rotate": 213.75,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo18",
|
||||
"top": 185.19,
|
||||
"left": 22.84,
|
||||
"rotate": 202.50,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo17",
|
||||
"top": 241.47,
|
||||
"left": 5.76,
|
||||
"rotate": 191.25,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo16",
|
||||
"top": 300.00,
|
||||
"left": 0.00,
|
||||
"rotate": 180.00,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo15",
|
||||
"top": 358.53,
|
||||
"left": 5.76,
|
||||
"rotate": 168.75,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo14",
|
||||
"top": 414.80,
|
||||
"left": 22.84,
|
||||
"rotate": 157.50,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo13",
|
||||
"top": 466.67,
|
||||
"left": 50.56,
|
||||
"rotate": 146.25,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo12",
|
||||
"top": 512.13,
|
||||
"left": 87.87,
|
||||
"rotate": 135.00,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo11",
|
||||
"top": 549.44,
|
||||
"left": 133.33,
|
||||
"rotate": 123.75,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo10",
|
||||
"top": 577.16,
|
||||
"left": 185.19,
|
||||
"rotate": 112.50,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo9",
|
||||
"top": 594.24,
|
||||
"left": 241.47,
|
||||
"rotate": 101.25,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo8",
|
||||
"top": 600.00,
|
||||
"left": 300.00,
|
||||
"rotate": 90.00,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo7",
|
||||
"top": 594.24,
|
||||
"left": 358.53,
|
||||
"rotate": 78.75,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo6",
|
||||
"top": 577.16,
|
||||
"left": 414.81,
|
||||
"rotate": 67.50,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo5",
|
||||
"top": 549.44,
|
||||
"left": 466.67,
|
||||
"rotate": 56.25,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo4",
|
||||
"top": 512.13,
|
||||
"left": 512.13,
|
||||
"rotate": 45.00,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo3",
|
||||
"top": 466.67,
|
||||
"left": 549.44,
|
||||
"rotate": 33.75,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo2",
|
||||
"top": 414.81,
|
||||
"left": 577.16,
|
||||
"rotate": 22.50,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo1",
|
||||
"top": 358.53,
|
||||
"left": 594.24,
|
||||
"rotate": 11.25,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-servo",
|
||||
"id": "servo0",
|
||||
"top": 300.00,
|
||||
"left": 600.00,
|
||||
"rotate": 0.00,
|
||||
"attrs": { "hornColor": "Red" }
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
[ "servo0:V+", "servo1:V+", "Red", [] ],
|
||||
[ "servo0:GND", "servo1:GND", "Black", [] ],
|
||||
[ "mega:22", "servo0:PWM", "Green", [ ] ],
|
||||
[ "servo1:V+", "servo2:V+", "Red", [] ],
|
||||
[ "servo1:GND", "servo2:GND", "Black", [] ],
|
||||
[ "mega:23", "servo1:PWM", "Green", [ ] ],
|
||||
[ "servo2:V+", "servo3:V+", "Red", [] ],
|
||||
[ "servo2:GND", "servo3:GND", "Black", [] ],
|
||||
[ "mega:24", "servo2:PWM", "Green", [ ] ],
|
||||
[ "servo3:V+", "servo4:V+", "Red", [] ],
|
||||
[ "servo3:GND", "servo4:GND", "Black", [] ],
|
||||
[ "mega:25", "servo3:PWM", "Green", [ ] ],
|
||||
[ "servo4:V+", "servo5:V+", "Red", [] ],
|
||||
[ "servo4:GND", "servo5:GND", "Black", [] ],
|
||||
[ "mega:26", "servo4:PWM", "Green", [ ] ],
|
||||
[ "servo5:V+", "servo6:V+", "Red", [] ],
|
||||
[ "servo5:GND", "servo6:GND", "Black", [] ],
|
||||
[ "mega:27", "servo5:PWM", "Green", [ ] ],
|
||||
[ "servo6:V+", "servo7:V+", "Red", [] ],
|
||||
[ "servo6:GND", "servo7:GND", "Black", [] ],
|
||||
[ "mega:28", "servo6:PWM", "Green", [ ] ],
|
||||
[ "servo7:V+", "servo8:V+", "Red", [] ],
|
||||
[ "servo7:GND", "servo8:GND", "Black", [] ],
|
||||
[ "mega:29", "servo7:PWM", "Green", [ ] ],
|
||||
[ "servo8:V+", "servo9:V+", "Red", [] ],
|
||||
[ "servo8:GND", "servo9:GND", "Black", [] ],
|
||||
[ "mega:30", "servo8:PWM", "Green", [ ] ],
|
||||
[ "servo9:V+", "servo10:V+", "Red", [] ],
|
||||
[ "servo9:GND", "servo10:GND", "Black", [] ],
|
||||
[ "mega:31", "servo9:PWM", "Green", [ ] ],
|
||||
[ "servo10:V+", "servo11:V+", "Red", [] ],
|
||||
[ "servo10:GND", "servo11:GND", "Black", [] ],
|
||||
[ "mega:32", "servo10:PWM", "Green", [ ] ],
|
||||
[ "servo11:V+", "servo12:V+", "Red", [] ],
|
||||
[ "servo11:GND", "servo12:GND", "Black", [] ],
|
||||
[ "mega:33", "servo11:PWM", "Green", [ ] ],
|
||||
[ "servo12:V+", "servo13:V+", "Red", [] ],
|
||||
[ "servo12:GND", "servo13:GND", "Black", [] ],
|
||||
[ "mega:34", "servo12:PWM", "Green", [ ] ],
|
||||
[ "servo13:V+", "servo14:V+", "Red", [] ],
|
||||
[ "servo13:GND", "servo14:GND", "Black", [] ],
|
||||
[ "mega:35", "servo13:PWM", "Green", [ ] ],
|
||||
[ "servo14:V+", "servo15:V+", "Red", [] ],
|
||||
[ "servo14:GND", "servo15:GND", "Black", [] ],
|
||||
[ "mega:36", "servo14:PWM", "Green", [ ] ],
|
||||
[ "servo15:V+", "servo16:V+", "Red", [] ],
|
||||
[ "servo15:GND", "servo16:GND", "Black", [] ],
|
||||
[ "mega:37", "servo15:PWM", "Green", [ ] ],
|
||||
[ "servo16:V+", "servo17:V+", "Red", [] ],
|
||||
[ "servo16:GND", "servo17:GND", "Black", [] ],
|
||||
[ "mega:38", "servo16:PWM", "Green", [ ] ],
|
||||
[ "servo17:V+", "servo18:V+", "Red", [] ],
|
||||
[ "servo17:GND", "servo18:GND", "Black", [] ],
|
||||
[ "mega:39", "servo17:PWM", "Green", [ ] ],
|
||||
[ "servo18:V+", "servo19:V+", "Red", [] ],
|
||||
[ "servo18:GND", "servo19:GND", "Black", [] ],
|
||||
[ "mega:40", "servo18:PWM", "Green", [ ] ],
|
||||
[ "servo19:V+", "servo20:V+", "Red", [] ],
|
||||
[ "servo19:GND", "servo20:GND", "Black", [] ],
|
||||
[ "mega:41", "servo19:PWM", "Green", [ ] ],
|
||||
[ "servo20:V+", "servo21:V+", "Red", [] ],
|
||||
[ "servo20:GND", "servo21:GND", "Black", [] ],
|
||||
[ "mega:42", "servo20:PWM", "Green", [ ] ],
|
||||
[ "servo21:V+", "servo22:V+", "Red", [] ],
|
||||
[ "servo21:GND", "servo22:GND", "Black", [] ],
|
||||
[ "mega:43", "servo21:PWM", "Green", [ ] ],
|
||||
[ "servo22:V+", "servo23:V+", "Red", [] ],
|
||||
[ "servo22:GND", "servo23:GND", "Black", [] ],
|
||||
[ "mega:44", "servo22:PWM", "Green", [ ] ],
|
||||
[ "servo23:V+", "servo24:V+", "Red", [] ],
|
||||
[ "servo23:GND", "servo24:GND", "Black", [] ],
|
||||
[ "mega:45", "servo23:PWM", "Green", [ ] ],
|
||||
[ "servo24:V+", "servo25:V+", "Red", [] ],
|
||||
[ "servo24:GND", "servo25:GND", "Black", [] ],
|
||||
[ "mega:46", "servo24:PWM", "Green", [ ] ],
|
||||
[ "servo25:V+", "servo26:V+", "Red", [] ],
|
||||
[ "servo25:GND", "servo26:GND", "Black", [] ],
|
||||
[ "mega:47", "servo25:PWM", "Green", [ ] ],
|
||||
[ "servo26:V+", "servo27:V+", "Red", [] ],
|
||||
[ "servo26:GND", "servo27:GND", "Black", [] ],
|
||||
[ "mega:48", "servo26:PWM", "Green", [ ] ],
|
||||
[ "servo27:V+", "servo28:V+", "Red", [] ],
|
||||
[ "servo27:GND", "servo28:GND", "Black", [] ],
|
||||
[ "mega:49", "servo27:PWM", "Green", [ ] ],
|
||||
[ "servo28:V+", "servo29:V+", "Red", [] ],
|
||||
[ "servo28:GND", "servo29:GND", "Black", [] ],
|
||||
[ "mega:50", "servo28:PWM", "Green", [ ] ],
|
||||
[ "servo29:V+", "servo30:V+", "Red", [] ],
|
||||
[ "servo29:GND", "servo30:GND", "Black", [] ],
|
||||
[ "mega:51", "servo29:PWM", "Green", [ ] ],
|
||||
[ "servo30:V+", "servo31:V+", "Red", [] ],
|
||||
[ "servo30:GND", "servo31:GND", "Black", [] ],
|
||||
[ "mega:52", "servo30:PWM", "Green", [ ] ],
|
||||
[ "servo31:V+", "servo0:V+", "Red", [] ],
|
||||
[ "servo31:GND", "servo0:GND", "Black", [] ],
|
||||
[ "mega:53", "servo31:PWM", "Green", [ ] ],
|
||||
[ "mega:GND.2", "servo9:GND", "Black", [ ] ],
|
||||
[ "mega:5V", "servo9:V+", "Red", [ ] ]
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
Servo
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Downloaded from https://wokwi.com/projects/305336312628511297
|
||||
|
||||
Simulate this project on https://wokwi.com
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"version": 1,
|
||||
"author": "Maverick",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{ "type": "wokwi-arduino-nano", "id": "nano", "top": 0, "left": 0, "attrs": {} },
|
||||
{ "type": "board-ssd1306", "id": "oled1", "top": 89.5, "left": 19.05, "attrs": {} },
|
||||
{
|
||||
"type": "wokwi-pushbutton",
|
||||
"id": "btn1",
|
||||
"top": 87.7,
|
||||
"left": 136.24,
|
||||
"attrs": { "color": "green", "key": "ArrowUp" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-pushbutton",
|
||||
"id": "btn2",
|
||||
"top": 134.3,
|
||||
"left": 135.54,
|
||||
"attrs": { "color": "green", "key": "ArrowDown" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-buzzer",
|
||||
"id": "bz1",
|
||||
"top": -103.22,
|
||||
"left": 59.98,
|
||||
"attrs": { "volume": "0.1" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-resistor",
|
||||
"id": "r1",
|
||||
"top": -22.03,
|
||||
"left": 29.82,
|
||||
"attrs": { "value": "1000" }
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
[ "nano:A4", "oled1:SDA", "gold", [ "v0" ] ],
|
||||
[ "oled1:SCL", "nano:A5", "cyan", [ "v-20.36", "h20.38" ] ],
|
||||
[ "oled1:VCC", "nano:3.3V", "red", [ "v-20.07", "h-37.37" ] ],
|
||||
[ "oled1:GND", "nano:GND.1", "black", [ "v-12.82", "h87.28" ] ],
|
||||
[ "btn1:2.l", "btn2:2.l", "black", [ "h-6.06", "v46.8" ] ],
|
||||
[ "btn1:2.l", "nano:GND.1", "black", [ "h-6.51", "v-36.84", "h14.77" ] ],
|
||||
[ "btn1:1.r", "nano:2", "black", [ "h13.06", "v-114.15", "h-100.6" ] ],
|
||||
[ "btn2:1.r", "nano:3", "black", [ "v-0.29", "h14.22", "v-160.46", "h-110.66" ] ],
|
||||
[ "bz1:2", "r1:2", "red", [ "v0" ] ],
|
||||
[ "r1:1", "nano:11", "red", [ "h-0.55", "v50.86" ] ],
|
||||
[ "bz1:1", "nano:GND.2", "black", [ "h34.91", "v64.63" ] ]
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Wokwi Library List
|
||||
# See https://docs.wokwi.com/guides/libraries
|
||||
|
||||
# Automatically added based on includes:
|
||||
Adafruit GFX Library
|
||||
|
||||
Adafruit SSD1306
|
||||
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
A simple Pong game.
|
||||
https://notabug.org/Maverick/WokwiPong
|
||||
|
||||
Based on Arduino Pong by eholk
|
||||
https://github.com/eholk/Arduino-Pong
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
#define UP_BUTTON 2
|
||||
#define DOWN_BUTTON 3
|
||||
|
||||
const unsigned long PADDLE_RATE = 64;
|
||||
const unsigned long BALL_RATE = 16;
|
||||
const uint8_t PADDLE_HEIGHT = 12;
|
||||
const uint8_t SCORE_LIMIT = 9;
|
||||
|
||||
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
|
||||
|
||||
bool game_over, win;
|
||||
|
||||
uint8_t player_score, mcu_score;
|
||||
uint8_t ball_x = 53, ball_y = 26;
|
||||
uint8_t ball_dir_x = 1, ball_dir_y = 1;
|
||||
|
||||
unsigned long ball_update;
|
||||
unsigned long paddle_update;
|
||||
|
||||
const uint8_t MCU_X = 12;
|
||||
uint8_t mcu_y = 16;
|
||||
|
||||
const uint8_t PLAYER_X = 115;
|
||||
uint8_t player_y = 16;
|
||||
|
||||
void setup()
|
||||
{
|
||||
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
||||
|
||||
// Display the splash screen (we're legally required to do so)
|
||||
display.display();
|
||||
unsigned long start = millis();
|
||||
|
||||
pinMode(UP_BUTTON, INPUT_PULLUP);
|
||||
pinMode(DOWN_BUTTON, INPUT_PULLUP);
|
||||
|
||||
display.clearDisplay();
|
||||
drawCourt();
|
||||
|
||||
while(millis() - start < 2000);
|
||||
|
||||
display.display();
|
||||
|
||||
ball_update = millis();
|
||||
paddle_update = ball_update;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
bool update_needed = false;
|
||||
unsigned long time = millis();
|
||||
|
||||
static bool up_state = false;
|
||||
static bool down_state = false;
|
||||
|
||||
up_state |= (digitalRead(UP_BUTTON) == LOW);
|
||||
down_state |= (digitalRead(DOWN_BUTTON) == LOW);
|
||||
|
||||
if(time > ball_update)
|
||||
{
|
||||
uint8_t new_x = ball_x + ball_dir_x;
|
||||
uint8_t new_y = ball_y + ball_dir_y;
|
||||
|
||||
// Check if we hit the vertical walls
|
||||
if(new_x == 0 || new_x == 127)
|
||||
{
|
||||
ball_dir_x = -ball_dir_x;
|
||||
new_x += ball_dir_x + ball_dir_x;
|
||||
|
||||
if (new_x < 64)
|
||||
{
|
||||
player_scoreTone();
|
||||
player_score++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mcu_scoreTone();
|
||||
mcu_score++;
|
||||
}
|
||||
|
||||
if (player_score == SCORE_LIMIT || mcu_score == SCORE_LIMIT)
|
||||
{
|
||||
win = player_score > mcu_score;
|
||||
game_over = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we hit the horizontal walls.
|
||||
if(new_y == 0 || new_y == 53)
|
||||
{
|
||||
wallTone();
|
||||
ball_dir_y = -ball_dir_y;
|
||||
new_y += ball_dir_y + ball_dir_y;
|
||||
}
|
||||
|
||||
// Check if we hit the CPU paddle
|
||||
if(new_x == MCU_X && new_y >= mcu_y && new_y <= mcu_y + PADDLE_HEIGHT)
|
||||
{
|
||||
mcuPaddleTone();
|
||||
ball_dir_x = -ball_dir_x;
|
||||
new_x += ball_dir_x + ball_dir_x;
|
||||
}
|
||||
|
||||
// Check if we hit the player paddle
|
||||
if(new_x == PLAYER_X && new_y >= player_y && new_y <= player_y + PADDLE_HEIGHT)
|
||||
{
|
||||
playerPaddleTone();
|
||||
ball_dir_x = -ball_dir_x;
|
||||
new_x += ball_dir_x + ball_dir_x;
|
||||
}
|
||||
|
||||
display.drawPixel(ball_x, ball_y, BLACK);
|
||||
display.drawPixel(new_x, new_y, WHITE);
|
||||
ball_x = new_x;
|
||||
ball_y = new_y;
|
||||
|
||||
ball_update += BALL_RATE;
|
||||
|
||||
update_needed = true;
|
||||
}
|
||||
|
||||
if(time > paddle_update)
|
||||
{
|
||||
paddle_update += PADDLE_RATE;
|
||||
|
||||
// CPU paddle
|
||||
display.drawFastVLine(MCU_X, mcu_y, PADDLE_HEIGHT, BLACK);
|
||||
const uint8_t half_paddle = PADDLE_HEIGHT >> 1;
|
||||
|
||||
if(mcu_y + half_paddle > ball_y)
|
||||
{
|
||||
int8_t dir = ball_x > MCU_X ? -1 : 1;
|
||||
mcu_y += dir;
|
||||
}
|
||||
|
||||
if(mcu_y + half_paddle < ball_y)
|
||||
{
|
||||
int8_t dir = ball_x > MCU_X ? 1 : -1;
|
||||
mcu_y += dir;
|
||||
}
|
||||
|
||||
if(mcu_y < 1)
|
||||
{
|
||||
mcu_y = 1;
|
||||
}
|
||||
|
||||
if(mcu_y + PADDLE_HEIGHT > 53)
|
||||
{
|
||||
mcu_y = 53 - PADDLE_HEIGHT;
|
||||
}
|
||||
|
||||
// Player paddle
|
||||
display.drawFastVLine(MCU_X, mcu_y, PADDLE_HEIGHT, WHITE);
|
||||
display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, BLACK);
|
||||
|
||||
if(up_state)
|
||||
{
|
||||
player_y -= 1;
|
||||
}
|
||||
|
||||
if(down_state)
|
||||
{
|
||||
player_y += 1;
|
||||
}
|
||||
|
||||
up_state = down_state = false;
|
||||
|
||||
if(player_y < 1)
|
||||
{
|
||||
player_y = 1;
|
||||
}
|
||||
|
||||
if(player_y + PADDLE_HEIGHT > 53)
|
||||
{
|
||||
player_y = 53 - PADDLE_HEIGHT;
|
||||
}
|
||||
|
||||
display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, WHITE);
|
||||
|
||||
update_needed = true;
|
||||
}
|
||||
|
||||
if(update_needed)
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
const char* text = win ? "YOU WIN!!" : "YOU LOSE!";
|
||||
display.clearDisplay();
|
||||
display.setCursor(40, 28);
|
||||
display.print(text);
|
||||
display.display();
|
||||
|
||||
delay(5000);
|
||||
|
||||
display.clearDisplay();
|
||||
ball_x = 53;
|
||||
ball_y = 26;
|
||||
ball_dir_x = 1;
|
||||
ball_dir_y = 1;
|
||||
mcu_y = 16;
|
||||
player_y = 16;
|
||||
mcu_score = 0;
|
||||
player_score = 0;
|
||||
game_over = false;
|
||||
drawCourt();
|
||||
}
|
||||
|
||||
display.setTextColor(WHITE, BLACK);
|
||||
display.setCursor(0, 56);
|
||||
display.print(mcu_score);
|
||||
display.setCursor(122, 56);
|
||||
display.print(player_score);
|
||||
display.display();
|
||||
}
|
||||
}
|
||||
|
||||
void playerPaddleTone()
|
||||
{
|
||||
tone(11, 250, 25);
|
||||
delay(25);
|
||||
noTone(11);
|
||||
}
|
||||
|
||||
void mcuPaddleTone()
|
||||
{
|
||||
tone(11, 225, 25);
|
||||
delay(25);
|
||||
noTone(11);
|
||||
}
|
||||
|
||||
void wallTone()
|
||||
{
|
||||
tone(11, 200, 25);
|
||||
delay(25);
|
||||
noTone(11);
|
||||
}
|
||||
|
||||
void player_scoreTone()
|
||||
{
|
||||
tone(11, 200, 25);
|
||||
delay(50);
|
||||
noTone(11);
|
||||
delay(25);
|
||||
tone(11, 250, 25);
|
||||
delay(25);
|
||||
noTone(11);
|
||||
}
|
||||
|
||||
void mcu_scoreTone()
|
||||
{
|
||||
tone(11, 250, 25);
|
||||
delay(25);
|
||||
noTone(11);
|
||||
delay(25);
|
||||
tone(11, 200, 25);
|
||||
delay(25);
|
||||
noTone(11);
|
||||
}
|
||||
|
||||
void drawCourt()
|
||||
{
|
||||
display.drawRect(0, 0, 128, 54, WHITE);
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Downloaded from https://wokwi.com/projects/348849468083274322
|
||||
|
||||
Simulate this project on https://wokwi.com
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
Simon is a simple electronic memory game: the user has to repeat a growing sequence of
|
||||
colors. The sequence is displayed by lighting up the LEDs. Each color also has a
|
||||
corresponding tone.
|
||||
|
||||
In each turn, the game will play the sequence, and then wait for the user to repeat
|
||||
the sequence by pressing the buttons according to the color sequence. If the user
|
||||
repeated the sequence correctly, the game will play a "leveling-up" sound, add a new
|
||||
color at the end of the sequence, and move to the next turn.
|
||||
|
||||
The game continues until the user has made a mistake. Then a game over sound is
|
||||
played, and the game restarts.
|
||||
|
||||

|
||||
|
||||
### Hardware
|
||||
|
||||
| Item | Quantity | Notes |
|
||||
| ---------------- | -------- | ---------------------------- |
|
||||
| Arduino Uno R3 | 1 | |
|
||||
| 5mm LED | 4 | Red, Green, Blue, and Yellow |
|
||||
| 12mm Push button | 4 | Red, Green, Blue, and Yellow |
|
||||
| Resistor | 4 | 220Ω |
|
||||
| Piezo Buzzer | 1 | |
|
||||
|
||||
<figure>
|
||||
<img src="https://i.imgur.com/cnNS8rsh.jpg" alt="Simon hardware kit" />
|
||||
<figcaption>
|
||||
Hardware for the Simon game,
|
||||
<a href="https://www.tindie.com/products/wokwi/kit-for-simon-style-game-arduino-shield/" target="_blank">
|
||||
kit available on Tindie
|
||||
</a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
|
||||
### Diagram
|
||||
|
||||
<figure>
|
||||
<img src="images/diagram.png" alt="diagram" style="width: 628px" />
|
||||
<figcaption>Simon connection diagram</figcaption>
|
||||
</figure>
|
||||
|
||||
### Pin Connections
|
||||
|
||||
| Arduino Pin | Device |
|
||||
| ----------- | ------------- |
|
||||
| 12 | Red LED |
|
||||
| 11 | Green LED |
|
||||
| 10 | Blue LED |
|
||||
| 9 | Yellow LED |
|
||||
| 8 | Buzzer |
|
||||
| 5 | Red Button |
|
||||
| 4 | Green Button |
|
||||
| 3 | Blue Button |
|
||||
| 2 | Yellow Button |
|
||||
|
||||
- The LEDs are connected through a 220Ω resistor each.
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
{
|
||||
"version": 1,
|
||||
"author": "Uri Shaked",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 183, "left": 18.6, "attrs": {} },
|
||||
{
|
||||
"type": "wokwi-buzzer",
|
||||
"id": "buzzer",
|
||||
"top": 16,
|
||||
"left": 124,
|
||||
"attrs": { "volume": "0.1" }
|
||||
},
|
||||
{ "type": "wokwi-led", "id": "led-red", "top": 10, "left": 6, "attrs": { "color": "red" } },
|
||||
{
|
||||
"type": "wokwi-led",
|
||||
"id": "led-green",
|
||||
"top": 73,
|
||||
"left": 6,
|
||||
"attrs": { "color": "green" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-led",
|
||||
"id": "led-blue",
|
||||
"top": 10,
|
||||
"left": 270,
|
||||
"attrs": { "color": "blue" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-led",
|
||||
"id": "led-yellow",
|
||||
"top": 73,
|
||||
"left": 270,
|
||||
"attrs": { "color": "yellow" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-pushbutton",
|
||||
"id": "btn-red",
|
||||
"top": 10,
|
||||
"left": 46,
|
||||
"attrs": { "color": "red", "key": "1", "label": "1" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-pushbutton",
|
||||
"id": "btn-green",
|
||||
"top": 76,
|
||||
"left": 46,
|
||||
"attrs": { "color": "green", "key": "2", "label": "2" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-pushbutton",
|
||||
"id": "btn-blue",
|
||||
"top": 10,
|
||||
"left": 200,
|
||||
"attrs": { "color": "blue", "key": "3", "label": "3" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-pushbutton",
|
||||
"id": "btn-yellow",
|
||||
"top": 76,
|
||||
"left": 200,
|
||||
"attrs": { "color": "yellow", "key": "4", "label": "4" }
|
||||
},
|
||||
{
|
||||
"type": "wokwi-74hc595",
|
||||
"id": "sr1",
|
||||
"top": 171.8,
|
||||
"left": 361.16,
|
||||
"rotate": 180,
|
||||
"attrs": {}
|
||||
},
|
||||
{
|
||||
"type": "wokwi-74hc595",
|
||||
"id": "sr2",
|
||||
"top": 171.8,
|
||||
"left": 457.16,
|
||||
"rotate": 180,
|
||||
"attrs": {}
|
||||
},
|
||||
{ "type": "wokwi-7segment", "id": "sevseg1", "top": 47.16, "left": 379.48, "attrs": {} },
|
||||
{ "type": "wokwi-7segment", "id": "sevseg2", "top": 47.16, "left": 446.68, "attrs": {} }
|
||||
],
|
||||
"connections": [
|
||||
[ "uno:GND.1", "buzzer:1", "black", [ "v-12", "*", "h0" ] ],
|
||||
[ "uno:2", "btn-yellow:1.l", "gold", [ "v-48", "*", "h-6" ] ],
|
||||
[ "uno:GND.1", "btn-yellow:2.r", "black", [ "v-12", "*", "h6" ] ],
|
||||
[ "uno:3", "btn-blue:1.l", "blue", [ "v-44", "*", "h-10" ] ],
|
||||
[ "uno:GND.1", "btn-blue:2.r", "black", [ "v-12", "*", "h6" ] ],
|
||||
[ "uno:4", "btn-green:2.r", "green", [ "v-40", "*", "h6" ] ],
|
||||
[ "uno:GND.1", "btn-green:1.l", "black", [ "v-12", "*", "h-6" ] ],
|
||||
[ "uno:5", "btn-red:2.r", "orange", [ "v-36", "*", "h10" ] ],
|
||||
[ "uno:GND.1", "btn-red:1.l", "black", [ "v-12", "*", "h-6" ] ],
|
||||
[ "uno:8", "buzzer:2", "purple", [ "v-32", "*", "h0" ] ],
|
||||
[ "uno:9", "led-yellow:A", "gold", [ "v-28", "*", "h0" ] ],
|
||||
[ "uno:GND.1", "led-yellow:C", "black", [ "v-12", "*", "h-15", "v4" ] ],
|
||||
[ "uno:10", "led-blue:A", "blue", [ "v-24", "*", "h8" ] ],
|
||||
[ "uno:GND.1", "led-blue:C", "black", [ "v-12", "*", "h-15", "v4" ] ],
|
||||
[ "uno:11", "led-green:A", "green", [ "v-20", "*", "h0" ] ],
|
||||
[ "uno:GND.1", "led-green:C", "black", [ "v-12", "*", "h-8", "v4" ] ],
|
||||
[ "uno:12", "led-red:A", "orange", [ "v-16", "*", "h6" ] ],
|
||||
[ "uno:GND.1", "led-red:C", "black", [ "v-12", "*", "h-8", "v4" ] ],
|
||||
[ "uno:5V", "sr1:VCC", "red", [ "v57.5", "h253.4" ] ],
|
||||
[ "uno:A2", "sr1:SHCP", "gray", [ "v19.1", "h138.4" ] ],
|
||||
[ "uno:A1", "sr1:STCP", "purple", [ "v28.7", "h157.5" ] ],
|
||||
[ "uno:A0", "sr1:DS", "blue", [ "v38.3", "h186.2" ] ],
|
||||
[ "sr1:SHCP", "sr2:SHCP", "gray", [ "v47", "h106.12" ] ],
|
||||
[ "sr1:STCP", "sr2:STCP", "purple", [ "v37.4", "h96.52" ] ],
|
||||
[ "sr1:Q7S", "sr2:DS", "blue", [ "h0.52", "v56.6", "h144" ] ],
|
||||
[ "sr1:VCC", "sr1:MR", "red", [ "v17", "h-57.6" ] ],
|
||||
[ "sr1:VCC", "sr2:MR", "red", [ "v17", "h38.4" ] ],
|
||||
[ "sr1:VCC", "sr2:VCC", "red", [ "v17", "h96" ] ],
|
||||
[ "sr1:OE", "sr2:OE", "black", [ "v26.6", "h96" ] ],
|
||||
[ "sr1:MR", "sevseg1:COM.1", "red", [ "v17", "h-57.6", "v-96", "h76.8" ] ],
|
||||
[ "sevseg1:COM.1", "sevseg2:COM.1", "red", [ "h0", "v9.6", "h57.6" ] ],
|
||||
[ "sr2:Q0", "sevseg2:A", "green", [ "v7.4", "h28.8", "v-182.4", "h-67.2" ] ],
|
||||
[ "sr2:Q1", "sevseg2:B", "green", [ "v0", "h9.6", "v-134.4", "h-48" ] ],
|
||||
[ "sr2:Q2", "sevseg2:C", "green", [ "v-38.4", "h-38.4" ] ],
|
||||
[ "sr2:Q3", "sevseg2:D", "green", [ "v-33.6", "h-33.6", "v-9.6", "h-14.4" ] ],
|
||||
[ "sr2:Q4", "sevseg2:E", "green", [ "v-28.8", "h-28.8", "v-9.6", "h-14.4" ] ],
|
||||
[ "sr2:Q5", "sevseg2:F", "green", [ "v-24", "h-24", "v-9.6", "h-24", "v-110.4", "h19.2" ] ],
|
||||
[ "sr2:Q6", "sevseg2:G", "green", [ "v-19.2", "h-43.2", "v-115.2", "h14.4" ] ],
|
||||
[ "sr1:GND", "sr2:GND", "black", [ "v-9.6", "h96" ] ],
|
||||
[ "sr1:Q1", "sevseg1:B", "green", [ "v-134.4", "h-19.2" ] ],
|
||||
[ "sr1:Q2", "sevseg1:C", "green", [ "v-38.4", "h-19.2" ] ],
|
||||
[ "sr1:Q3", "sevseg1:D", "green", [ "v-33.6", "h-24" ] ],
|
||||
[ "sr1:Q4", "sevseg1:E", "green", [ "v-28.8", "h-28.8" ] ],
|
||||
[ "uno:GND.3", "sr1:GND", "black", [ "v47.9", "h157.6", "v-259.2", "h9.6" ] ],
|
||||
[ "sr1:GND", "sr1:OE", "black", [ "v-9.6", "h-9.6", "v67.2", "h172.8" ] ],
|
||||
[ "sr1:Q0", "sevseg1:A", "green", [ "v65", "h-76.8", "v-240", "h57.6" ] ],
|
||||
[ "sr1:Q5", "sevseg1:F", "green", [ "v-24", "h-19.2", "v-110.4", "h19.2" ] ],
|
||||
[ "sr1:Q6", "sevseg1:G", "green", [ "v-19.2", "h-14.4", "v-110.4", "h14.4" ] ]
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/**************************************************
|
||||
This file defines constants with the frequency
|
||||
of different musical notes.
|
||||
*************************************************/
|
||||
|
||||
#define NOTE_B0 31
|
||||
#define NOTE_C1 33
|
||||
#define NOTE_CS1 35
|
||||
#define NOTE_D1 37
|
||||
#define NOTE_DS1 39
|
||||
#define NOTE_E1 41
|
||||
#define NOTE_F1 44
|
||||
#define NOTE_FS1 46
|
||||
#define NOTE_G1 49
|
||||
#define NOTE_GS1 52
|
||||
#define NOTE_A1 55
|
||||
#define NOTE_AS1 58
|
||||
#define NOTE_B1 62
|
||||
#define NOTE_C2 65
|
||||
#define NOTE_CS2 69
|
||||
#define NOTE_D2 73
|
||||
#define NOTE_DS2 78
|
||||
#define NOTE_E2 82
|
||||
#define NOTE_F2 87
|
||||
#define NOTE_FS2 93
|
||||
#define NOTE_G2 98
|
||||
#define NOTE_GS2 104
|
||||
#define NOTE_A2 110
|
||||
#define NOTE_AS2 117
|
||||
#define NOTE_B2 123
|
||||
#define NOTE_C3 131
|
||||
#define NOTE_CS3 139
|
||||
#define NOTE_D3 147
|
||||
#define NOTE_DS3 156
|
||||
#define NOTE_E3 165
|
||||
#define NOTE_F3 175
|
||||
#define NOTE_FS3 185
|
||||
#define NOTE_G3 196
|
||||
#define NOTE_GS3 208
|
||||
#define NOTE_A3 220
|
||||
#define NOTE_AS3 233
|
||||
#define NOTE_B3 247
|
||||
#define NOTE_C4 262
|
||||
#define NOTE_CS4 277
|
||||
#define NOTE_D4 294
|
||||
#define NOTE_DS4 311
|
||||
#define NOTE_E4 330
|
||||
#define NOTE_F4 349
|
||||
#define NOTE_FS4 370
|
||||
#define NOTE_G4 392
|
||||
#define NOTE_GS4 415
|
||||
#define NOTE_A4 440
|
||||
#define NOTE_AS4 466
|
||||
#define NOTE_B4 494
|
||||
#define NOTE_C5 523
|
||||
#define NOTE_CS5 554
|
||||
#define NOTE_D5 587
|
||||
#define NOTE_DS5 622
|
||||
#define NOTE_E5 659
|
||||
#define NOTE_F5 698
|
||||
#define NOTE_FS5 740
|
||||
#define NOTE_G5 784
|
||||
#define NOTE_GS5 831
|
||||
#define NOTE_A5 880
|
||||
#define NOTE_AS5 932
|
||||
#define NOTE_B5 988
|
||||
#define NOTE_C6 1047
|
||||
#define NOTE_CS6 1109
|
||||
#define NOTE_D6 1175
|
||||
#define NOTE_DS6 1245
|
||||
#define NOTE_E6 1319
|
||||
#define NOTE_F6 1397
|
||||
#define NOTE_FS6 1480
|
||||
#define NOTE_G6 1568
|
||||
#define NOTE_GS6 1661
|
||||
#define NOTE_A6 1760
|
||||
#define NOTE_AS6 1865
|
||||
#define NOTE_B6 1976
|
||||
#define NOTE_C7 2093
|
||||
#define NOTE_CS7 2217
|
||||
#define NOTE_D7 2349
|
||||
#define NOTE_DS7 2489
|
||||
#define NOTE_E7 2637
|
||||
#define NOTE_F7 2794
|
||||
#define NOTE_FS7 2960
|
||||
#define NOTE_G7 3136
|
||||
#define NOTE_GS7 3322
|
||||
#define NOTE_A7 3520
|
||||
#define NOTE_AS7 3729
|
||||
#define NOTE_B7 3951
|
||||
#define NOTE_C8 4186
|
||||
#define NOTE_CS8 4435
|
||||
#define NOTE_D8 4699
|
||||
#define NOTE_DS8 4978
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
/**
|
||||
Simon Game for Arduino with Score display
|
||||
|
||||
Copyright (C) 2022, Uri Shaked
|
||||
|
||||
Released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "pitches.h"
|
||||
|
||||
/* Constants - define pin numbers for LEDs,
|
||||
buttons and speaker, and also the game tones: */
|
||||
const uint8_t ledPins[] = {9, 10, 11, 12};
|
||||
const uint8_t buttonPins[] = {2, 3, 4, 5};
|
||||
#define SPEAKER_PIN 8
|
||||
|
||||
// These are connected to 74HC595 shift register (used to show game score):
|
||||
const int LATCH_PIN = A1; // 74HC595 pin 12
|
||||
const int DATA_PIN = A0; // 74HC595pin 14
|
||||
const int CLOCK_PIN = A2; // 74HC595 pin 11
|
||||
|
||||
#define MAX_GAME_LENGTH 100
|
||||
|
||||
const int gameTones[] = { NOTE_G3, NOTE_C4, NOTE_E4, NOTE_G5};
|
||||
|
||||
/* Global variables - store the game state */
|
||||
uint8_t gameSequence[MAX_GAME_LENGTH] = {0};
|
||||
uint8_t gameIndex = 0;
|
||||
|
||||
/**
|
||||
Set up the Arduino board and initialize Serial communication
|
||||
*/
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
pinMode(ledPins[i], OUTPUT);
|
||||
pinMode(buttonPins[i], INPUT_PULLUP);
|
||||
}
|
||||
pinMode(SPEAKER_PIN, OUTPUT);
|
||||
pinMode(LATCH_PIN, OUTPUT);
|
||||
pinMode(CLOCK_PIN, OUTPUT);
|
||||
pinMode(DATA_PIN, OUTPUT);
|
||||
|
||||
// The following line primes the random number generator.
|
||||
// It assumes pin A3 is floating (disconnected):
|
||||
randomSeed(analogRead(A3));
|
||||
}
|
||||
|
||||
/* Digit table for the 7-segment display */
|
||||
const uint8_t digitTable[] = {
|
||||
0b11000000,
|
||||
0b11111001,
|
||||
0b10100100,
|
||||
0b10110000,
|
||||
0b10011001,
|
||||
0b10010010,
|
||||
0b10000010,
|
||||
0b11111000,
|
||||
0b10000000,
|
||||
0b10010000,
|
||||
};
|
||||
const uint8_t DASH = 0b10111111;
|
||||
|
||||
void sendScore(uint8_t high, uint8_t low) {
|
||||
digitalWrite(LATCH_PIN, LOW);
|
||||
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, low);
|
||||
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, high);
|
||||
digitalWrite(LATCH_PIN, HIGH);
|
||||
}
|
||||
|
||||
void displayScore() {
|
||||
int high = gameIndex % 100 / 10;
|
||||
int low = gameIndex % 10;
|
||||
sendScore(high ? digitTable[high] : 0xff, digitTable[low]);
|
||||
}
|
||||
|
||||
/**
|
||||
Lights the given LED and plays a suitable tone
|
||||
*/
|
||||
void lightLedAndPlayTone(byte ledIndex) {
|
||||
digitalWrite(ledPins[ledIndex], HIGH);
|
||||
tone(SPEAKER_PIN, gameTones[ledIndex]);
|
||||
delay(300);
|
||||
digitalWrite(ledPins[ledIndex], LOW);
|
||||
noTone(SPEAKER_PIN);
|
||||
}
|
||||
|
||||
/**
|
||||
Plays the current sequence of notes that the user has to repeat
|
||||
*/
|
||||
void playSequence() {
|
||||
for (int i = 0; i < gameIndex; i++) {
|
||||
byte currentLed = gameSequence[i];
|
||||
lightLedAndPlayTone(currentLed);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Waits until the user pressed one of the buttons,
|
||||
and returns the index of that button
|
||||
*/
|
||||
byte readButtons() {
|
||||
while (true) {
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
byte buttonPin = buttonPins[i];
|
||||
if (digitalRead(buttonPin) == LOW) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Play the game over sequence, and report the game score
|
||||
*/
|
||||
void gameOver() {
|
||||
Serial.print("Game over! your score: ");
|
||||
Serial.println(gameIndex - 1);
|
||||
gameIndex = 0;
|
||||
delay(200);
|
||||
|
||||
// Play a Wah-Wah-Wah-Wah sound
|
||||
tone(SPEAKER_PIN, NOTE_DS5);
|
||||
delay(300);
|
||||
tone(SPEAKER_PIN, NOTE_D5);
|
||||
delay(300);
|
||||
tone(SPEAKER_PIN, NOTE_CS5);
|
||||
delay(300);
|
||||
for (byte i = 0; i < 10; i++) {
|
||||
for (int pitch = -10; pitch <= 10; pitch++) {
|
||||
tone(SPEAKER_PIN, NOTE_C5 + pitch);
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
noTone(SPEAKER_PIN);
|
||||
|
||||
sendScore(DASH, DASH);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
/**
|
||||
Get the user's input and compare it with the expected sequence.
|
||||
*/
|
||||
bool checkUserSequence() {
|
||||
for (int i = 0; i < gameIndex; i++) {
|
||||
byte expectedButton = gameSequence[i];
|
||||
byte actualButton = readButtons();
|
||||
lightLedAndPlayTone(actualButton);
|
||||
if (expectedButton != actualButton) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Plays a hooray sound whenever the user finishes a level
|
||||
*/
|
||||
void playLevelUpSound() {
|
||||
tone(SPEAKER_PIN, NOTE_E4);
|
||||
delay(150);
|
||||
tone(SPEAKER_PIN, NOTE_G4);
|
||||
delay(150);
|
||||
tone(SPEAKER_PIN, NOTE_E5);
|
||||
delay(150);
|
||||
tone(SPEAKER_PIN, NOTE_C5);
|
||||
delay(150);
|
||||
tone(SPEAKER_PIN, NOTE_D5);
|
||||
delay(150);
|
||||
tone(SPEAKER_PIN, NOTE_G5);
|
||||
delay(150);
|
||||
noTone(SPEAKER_PIN);
|
||||
}
|
||||
|
||||
/**
|
||||
The main game loop
|
||||
*/
|
||||
void loop() {
|
||||
displayScore();
|
||||
|
||||
// Add a random color to the end of the sequence
|
||||
gameSequence[gameIndex] = random(0, 4);
|
||||
gameIndex++;
|
||||
if (gameIndex >= MAX_GAME_LENGTH) {
|
||||
gameIndex = MAX_GAME_LENGTH - 1;
|
||||
}
|
||||
|
||||
playSequence();
|
||||
if (!checkUserSequence()) {
|
||||
gameOver();
|
||||
}
|
||||
|
||||
delay(300);
|
||||
|
||||
if (gameIndex > 0) {
|
||||
playLevelUpSound();
|
||||
delay(300);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Downloaded from https://wokwi.com/projects/328451800839488084
|
||||
|
||||
Simulate this project on https://wokwi.com
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue