Van Breadboard naar PCB: Bouw een Simon Says Spel – Deel 1
Onderdelen en Benodigdheden
| Onderdeel | Aantal | Opmerkingen |
|---|---|---|
| Arduino UNO | 1 | |
| Solderloos Breadboard Full Size | 1 | |
| LED (generiek) | 4 | |
| SparkFun Drukknop 12mm | 4 | |
| Buzzer | 1 | |
| Draadjes (generiek) | 12 | |
| Weerstand 10k ohm | 4 | |
| Weerstand 330 ohm | 4 | |
| USB-A naar B Kabel | 1 |
Apps en Online Diensten
| Arduino IDE |
Over dit Project
Inleiding
We kennen allemaal het klassieke Simon Says spel, waarbij je een reeks lichten moet nabootsen door de knop in te drukken die bij de juiste kleur hoort. Voor Hackster Live presenteerden we een PCB-ontwerptool genaamd Upverter. Dit is een leuk en simpel project om te maken en om te zetten in een PCB. Hieronder staat het basisproject met hardware en code.
Deze projectserie bestaat uit drie delen:
- Deel 1: De Simon Says Game maken (dit deel)
- Deel 2: Een PCB ontwerpen voor het Simon Says spel met Upverter
- Deel 3: Je eigen PCB frezen vanuit het ontwerp dat je in Upverter maakte
Wat je in deze serie leert
- Hoe een basisproject op een breadboard op te bouwen
- Hoe een PCB te ontwerpen in Upverter
- Hoe je eigen PCB te frezen met een CNC-machine
Software
Als je de Arduino IDE nog niet hebt voor het schrijven en uploaden van code naar je Arduino, download dan de nieuwste versie voor je besturingssysteem hier.
Hardware Opbouw
Ik gebruikte het voorbeeld uit SparkFun's Inventor's Kit als inspiratie en paste het licht aan. Bekijk het Fritzing-diagram hieronder.
Code
Het leuke aan dit spel is dat je zoveel variaties kunt maken. Zoals gezegd, gebruikte ik SparkFun's voorbeeld als startpunt voor de hardware en schreef de code vanaf nul. Als je niet zelf code wilt schrijven, kun je mijn code hieronder gebruiken, SparkFun's code met een paar aanpassingen, of zoeken naar andere Simon Says codes die bij je hardware passen.
Ik heb gedetailleerde commentaren en debug Serial print regels opgenomen, zodat je kunt zien wat er gebeurt op de seriële monitor tijdens het spelen. Bekijk de video van het Simon Says spel in actie hieronder!
Simon Says Spel Video
Let op: In de video stel ik het aantal lichten om te winnen in op 5. Dit kan verhoogd worden voor meer uitdaging, maar ik wilde de video kort houden.
Nu ben je klaar om je breadboard om te zetten in een PCB! Leer hoe in Breadboard to PCB Deel 2 - Een PCB ontwerpen met Upverter.
Code
Simon Says Arduino Code
int ledArray[] = {12, 9, 5, 2}; // ledArray[0]=groen, [1]=rood, [2]=geel, [3]=blauw
int buttonArray[] = {13, 10, 6, 3}; // buttonArray[0]=groen, [1]=rood, [2]=geel, [3]=blauw
int pinCount = 4;
int buzzer = 8;
int ledState = 0;
int gameState = 0;
#define NUMBERTOWIN 5 // Aantal lichten om te winnen - verander dit voor moeilijkheidsgraad
int gameValues[NUMBERTOWIN];
int roundNum = 0;
unsigned long previousMillis = 0; // voor pre-game state knipperen zonder delay
unsigned long interval1 = 500; // tijd tussen knipperen
// Functiedeclaraties
void setLed(int ledNum);
void displayClue(int roundNum);
boolean waitForInput(int buttonNum);
void setup() {
Serial.begin(9600);
Serial.println("setup");
for (int Pin = 0; Pin < pinCount; Pin++) {
pinMode(ledArray[Pin], OUTPUT); // alle LEDs als output
}
for (int Pin = 0; Pin < pinCount; Pin++) {
pinMode(buttonArray[Pin], INPUT_PULLUP); // alle knoppen als input met pullup
// Ik voegde 10k weerstanden toe na het schrijven van de code, optioneel
}
// Random seed van onverbonden analoge pin 0 voor willekeurigheid
randomSeed(analogRead(0));
}
void loop() {
if (gameState == 0) {
int button0 = digitalRead(buttonArray[0]);
int button1 = digitalRead(buttonArray[1]);
int button2 = digitalRead(buttonArray[2]);
int button3 = digitalRead(buttonArray[3]);
// Als geen knop ingedrukt (pullup = HIGH = niet ingedrukt), speel pre_game
if (button0 && button1 && button2 && button3) {
pre_game();
} else { // Knop ingedrukt -> start spel
Serial.println("Knop ingedrukt");
setLed(-1); // alle LEDs uit
roundNum = 0;
delay(1000);
gameState = 1;
}
}
if (gameState == 1) gamePlay();
if (gameState == 2) { // Gewonnen!
delay(500);
winning_sound();
winDisplay(); winDisplay(); winDisplay(); loseDisplay(); // 3x win, 1x lose voor overgang
Serial.println("winDisplay");
delay(1000);
gameState = 0;
}
if (gameState == 3) { // Verloren :(
delay(500);
losing_sound();
loseDisplay(); loseDisplay(); loseDisplay(); // 3x lose
Serial.println("loseDisplay");
delay(1000);
gameState = 0;
}
}
// Pre-game: LEDs laten knipperen om te tonen dat het spel klaarstaat
void pre_game() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval1) {
if (ledState == 0) { Serial.println("pre groen"); setLed(0); ledState = 1; }
else if (ledState == 1) { Serial.println("pre rood"); setLed(1); ledState = 2; }
else if (ledState == 2) { Serial.println("pre geel"); setLed(2); ledState = 3; }
else if (ledState == 3) { Serial.println("pre blauw"); setLed(3); ledState = 0; }
previousMillis = currentMillis;
}
}
// Hoofdspelloop
void gamePlay() {
Serial.println("gamePlay");
// Array vullen met willekeurige getallen voor het spel
for (int i = 0; i < NUMBERTOWIN; i++) {
gameValues[i] = floor(random(0, 4)); // 0-3
Serial.println(gameValues[i], DEC);
}
Serial.print("Start Ronde "); Serial.println(roundNum, DEC);
for (int r = 0; r < NUMBERTOWIN; r++) {
displayClue(roundNum);
for (int i = 0; i <= roundNum; i++) {
Serial.print("Wachten op input "); Serial.print(i + 1, DEC);
Serial.print(" van "); Serial.print(roundNum + 1, DEC); Serial.println("");
if (waitForInput(gameValues[i])) { // Correcte input
if (i == roundNum) {
Serial.println("Correct");
if (roundNum == NUMBERTOWIN - 1) { // Laatste ronde?
Serial.println("Je Wint!");
gameState = 2; return;
} else {
Serial.println("Doorgaan");
}
}
} else { // Foute input
Serial.println("Je Verliest!");
gameState = 3; return;
}
}
roundNum++;
delay(1000); // Korte pauze voor volgende ronde
}
}
// Zet specifieke LED aan/uit
void setLed(int ledNum) {
if (ledNum < 0) {
for (int i = 0; i < pinCount; i++) digitalWrite(ledArray[i], LOW);
} else {
for (int i = 0; i < pinCount; i++) {
digitalWrite(ledArray[i], (i == ledNum) ? HIGH : LOW);
}
}
}
// Toon de reeks (clue) voor de huidige ronde
void displayClue(int roundNum) {
setLed(-1); // alle uit
for (int i = 0; i <= roundNum; i++) {
setLed(gameValues[i]);
delay(750);
setLed(-1);
delay(250);
}
}
// Wacht op spelerinput, check of correct
boolean waitForInput(int buttonNum) {
while (true) {
int button0 = digitalRead(buttonArray[0]);
int button1 = digitalRead(buttonArray[1]);
int button2 = digitalRead(buttonArray[2]);
int button3 = digitalRead(buttonArray[3]);
// INPUT_PULLUP: LOW = ingedrukt
if (!button0 || !button1 || !button2 || !button3) {
delay(250); // debounce
// Licht bijbehorende LED kort aan
if (buttonNum == 0) { digitalWrite(ledArray[0], HIGH); delay(250); digitalWrite(ledArray[0], LOW); }
else if (buttonNum == 1) { digitalWrite(ledArray[1], HIGH); delay(250); digitalWrite(ledArray[1], LOW); }
else if (buttonNum == 2) { digitalWrite(ledArray[2], HIGH); delay(250); digitalWrite(ledArray[2], LOW); }
else if (buttonNum == 3) { digitalWrite(ledArray[3], HIGH); delay(250); digitalWrite(ledArray[3], LOW); }
// Check of juiste knop ingedrukt
if (buttonNum == 0 && button0 == 0) { Serial.println("0 Ingedrukt"); return true; }
else if (buttonNum == 1 && button1 == 0) { Serial.println("1 Ingedrukt"); return true; }
else if (buttonNum == 2 && button2 == 0) { Serial.println("2 Ingedrukt"); return true; }
else if (buttonNum == 3 && button3 == 0) { Serial.println("3 Ingedrukt"); return true; }
else return false;
}
}
}
// Win animatie: LEDs scrollen snel
void winDisplay() {
for (int i = 0; i < 4; i++) {
digitalWrite(ledArray[i], HIGH); delay(75); digitalWrite(ledArray[i], LOW); delay(75);
}
for (int i = 2; i >= 0; i--) {
digitalWrite(ledArray[i], HIGH); delay(75); digitalWrite(ledArray[i], LOW); delay(75);
}
}
// Winnende melodie
void winning_sound() {
Serial.println("buzzer1");
tone(buzzer, 294, 250); delay(200);
tone(buzzer, 294, 250); delay(200);
tone(buzzer, 294, 250); delay(200);
tone(buzzer, 392, 500); delay(500);
tone(buzzer, 392, 250); delay(200);
tone(buzzer, 440, 250); delay(200);
tone(buzzer, 392, 250); delay(200);
tone(buzzer, 440, 250); delay(200);
tone(buzzer, 494, 500);
}
// Verlies animatie: alle LEDs knipperen
void loseDisplay() {
for (int i = 0; i < 4; i++) digitalWrite(ledArray[i], HIGH);
delay(200);
for (int i = 0; i < 4; i++) digitalWrite(ledArray[i], LOW);
delay(200);
}
// Verliezende melodie
void losing_sound() {
Serial.println("losing_sound");
tone(buzzer, 98, 250); delay(250);
tone(buzzer, 93, 250); delay(250);
tone(buzzer, 87, 250); delay(250);
}
Schema's
Productieproces
- Bouw een real-time gyroscoop-spel met Arduino Nano & MPU-6050 sensor
- Arduino Digitale Dobbelsteen: Bouw Je Eigen LCD-willekeurige Getalgenerator
- Bouw Je Eigen 37-LED Roulette-spel met Arduino Nano
- DIY Arduino USB Gaming Controller – Bouw Je Eigen High-Performance Gamepad
- Interactieve Joystick Game met Arduino en LED Feedback
- Draagbare Afstandsdetector – Arduino Nano DIY Kit met HC-SR04, 18650 Accu en 3D-geprinte Behuizing
- Pixel Chaser: Interactieve één-tik LED-spel met Arduino Nano
- Koper Elektrolyseren Project: Bouw een Slim Systeem met Arduino UNO
- NeoPixel Matrix Pong op Arduino Nano: Bouw je eigen neon Pong-spel
- Luchtvaartproductie voor kleine werkplaatsen: Een praktische gids
- Complete gids voor 4-laags PCB-fabricatie – Stapsgewijs proces