硬體電路:
按鈕接在 D2、D3、D4
蜂鳴器接在 D6
LED接在 D7、D8、D9
硬體材料:
1. Arduino UNO R3 板子 x 1
2. 麵包板 x 1
3. LED燈 x 3,任意顏色
4. 杜邦線公對公 x 13
5. 220歐姆電阻 x 4
6. 按鈕 x 3
7. 10K歐姆電阻 x 3
8. 蜂鳴器 x 1
完成圖:
Arduino IDE 程式碼:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 程式碼參考來源 https://github.com/SJHOne/MintDuino-Repeat-After-Me-Game | |
*/ | |
#define BUTTON_BASE 2 // 按鈕腳位 2 ~ 4 | |
#define BUZZER_PIN 6 // 蜂鳴器腳位 6 | |
#define LED_BASE 7 // LED 腳位 7 ~ 9 | |
#define WINSTATE 12 // 在一回合中,最多需要回答 12 次的聲音頻率,須為 4 的倍數 | |
#define RESPONSETIME 3000 // 每回合中,回答每個聲音頻率之間的等待時間 | |
int band = WINSTATE / 4; // 遊戲結束後,判斷等級用 | |
int turn = 0; // 每回合需要回的聲音頻率次數 | |
int input1 = LOW; // 按鈕一按下的狀態 | |
int input2 = LOW; // 按鈕一按下的狀態 | |
int input3 = LOW; // 按鈕一按下的狀態 | |
int counter = 0; // 目前等了多久時間 | |
int beepdelay = 200; | |
int pausedelay = 100; | |
int randomArray[100]; //Intentionally long to store up to 100 inputs (doubtful anyone will get this far) | |
int tonearray[3]; | |
void ProcessSingleOutput(int value); | |
void playTone(int tone, int duration); | |
void fail(int correct); | |
void FlashAll(); | |
/////////////////////////////////////////////////////////////////////////// | |
void setup() { | |
Serial.begin(9600); | |
pinMode(BUZZER_PIN, OUTPUT); | |
tonearray[0] = 1915; | |
tonearray[1] = 1519; | |
tonearray[2] = 1275; | |
for (int f = 0; f < 3; f++) | |
{ | |
pinMode(LED_BASE + f, OUTPUT); | |
pinMode(BUTTON_BASE+ f, INPUT); | |
digitalWrite(BUTTON_BASE+ f, HIGH); // turn on pullup resistors | |
ProcessSingleOutput(f+1); | |
} | |
randomSeed(analogRead(0)); // Added to generate "more randomness" with the randomArray for the output function | |
delay(1000); | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
void ProcessSingleOutput(int value) | |
{ | |
value--; | |
digitalWrite(LED_BASE + value, HIGH); | |
playTone(tonearray[value], beepdelay); // Passes tone value and duration of the tone to the playTone function | |
delay(beepdelay); | |
digitalWrite(LED_BASE + value, LOW); | |
delay(pausedelay); | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
// function for generating the array to be matched by the player | |
void output() | |
{ | |
Serial.println(""); | |
Serial.print("Turn: "); | |
Serial.println(turn); | |
randomArray[turn] = random(1, 4); // Assigning a random number (1-3) to the randomArray[y], y being the turn count | |
for (int x = 0; x <= turn; x++) | |
{ | |
Serial.print(randomArray[x]); | |
Serial.print(" "); | |
ProcessSingleOutput(randomArray[x]); | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
void ProcessSingleInput(int value, int x) | |
{ | |
digitalWrite(LED_BASE + value, HIGH); | |
playTone(tonearray[value], 200); // Passes tone value and duration of the tone to the playTone function | |
delay(200); | |
digitalWrite(LED_BASE + value, LOW); | |
delay(50); | |
Serial.print(" "); | |
Serial.print(value+1); | |
if ((value+1) != randomArray[x]) | |
{ | |
fail(randomArray[x]); | |
} else { | |
counter = 0; | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
// Function for allowing user input and checking input against the generated array | |
void input() | |
{ | |
for (int x = 0; x <= turn;) | |
{ | |
input1 = digitalRead(BUTTON_BASE); | |
input2 = digitalRead(BUTTON_BASE+1); | |
input3 = digitalRead(BUTTON_BASE+2); | |
counter++; | |
if (counter > RESPONSETIME) | |
{ | |
Serial.println("TIMEOUT!"); | |
fail(randomArray[x]); | |
x++; | |
} | |
delay(1); | |
if (input1 == HIGH) | |
{ | |
ProcessSingleInput(0, x); | |
x++; | |
} | |
if (input2 == HIGH) | |
{ | |
ProcessSingleInput(1, x); | |
x++; | |
} | |
if (input3 == HIGH) | |
{ | |
ProcessSingleInput(2, x); | |
x++; | |
} | |
} | |
delay(500); | |
turn++; // Increments the turn count, also the last action before starting the output function over again | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
// Function used if the player fails to match the sequence | |
void fail(int correct) | |
{ | |
digitalWrite(LED_BASE, HIGH); | |
digitalWrite(LED_BASE+1, HIGH); | |
digitalWrite(LED_BASE+2, HIGH); | |
playTone(6000,1000); // Rather Rude Rasp | |
digitalWrite(LED_BASE, LOW); | |
digitalWrite(LED_BASE+1, LOW); | |
digitalWrite(LED_BASE+2, LOW); | |
correct--; | |
for (int y = 0; y <= 2; y++) | |
{ | |
// Flashes light that should have been pressed | |
digitalWrite(LED_BASE + correct, HIGH); | |
//playTone(tonearray[correct], 200); | |
delay(200); | |
digitalWrite(LED_BASE + correct, LOW); | |
delay(50); | |
} | |
Serial.println(""); | |
Serial.print("OOPS! Should have pressed "); | |
Serial.println(correct+1); | |
delay(500); | |
// Now Score | |
// 1 - Beginner | |
// 2 - Amateur | |
// 3 - Expert | |
// 4 - Champ | |
int scoreband = turn / band; | |
for (int y=0; y<=5; y++) | |
{ | |
// Flashes score light | |
digitalWrite(LED_BASE + scoreband, HIGH); | |
playTone(tonearray[scoreband], 200); | |
digitalWrite(LED_BASE + scoreband, LOW); | |
delay(50); | |
} | |
Serial.print("You Score "); | |
Serial.println(scoreband+1); | |
delay(500); | |
FlashAll(); | |
delay(500); | |
turn = -1; // Resets turn value so the game starts over without need for a reset button | |
counter = 0; | |
beepdelay = 200; | |
pausedelay = 100; | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
void win() | |
{ | |
Serial.println("WIN!"); | |
for (int y=0; y < 4; y++) | |
{ | |
for (int f = 0; f < 3; f++) | |
{ | |
digitalWrite(LED_BASE + f, HIGH); | |
playTone(tonearray[f], 100); | |
digitalWrite(LED_BASE + f, LOW); | |
delay(25); | |
} | |
} | |
FlashAll(); | |
turn = -1; // Resets turn value so the game starts over without need for a reset button | |
beepdelay = 200; | |
pausedelay = 100; | |
delay(1000); | |
} | |
void FlashAll() | |
{ | |
/////////////////////////////////////////////////////////////////////////// | |
// Flashes all lights | |
for (int y=0; y<=5; y++) | |
{ | |
digitalWrite(LED_BASE, HIGH); | |
digitalWrite(LED_BASE+1, HIGH); | |
digitalWrite(LED_BASE+2, HIGH); | |
delay(200); | |
digitalWrite(LED_BASE, LOW); | |
digitalWrite(LED_BASE+1, LOW); | |
digitalWrite(LED_BASE+2, LOW); | |
delay(200); | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
// Low C = 1915 | |
// D = 1700 | |
// E = 1519 | |
// F = 1432 | |
// G = 1275 | |
// A = 1136 | |
// B = 1014 | |
// High C = 956 | |
void playTone(int tone, int duration) | |
{ | |
for (long i = 0; i < duration * 1000L; i += tone * 2) | |
{ | |
digitalWrite(BUZZER_PIN, HIGH); | |
delayMicroseconds(tone); | |
digitalWrite(BUZZER_PIN, LOW); | |
delayMicroseconds(tone); | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
// Slowly cranks up the pressure | |
void increaseSpeed() | |
{ | |
if (turn == band) | |
{ | |
beepdelay = 170; | |
pausedelay = 80; | |
return; | |
} | |
if (turn == band * 2) | |
{ | |
beepdelay = 150; | |
pausedelay = 60; | |
return; | |
} | |
if (turn == band*3) | |
{ | |
beepdelay = 120; | |
pausedelay = 40; | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
void loop() | |
{ | |
output(); | |
input(); | |
increaseSpeed(); | |
if( turn >= WINSTATE ) { | |
win(); | |
turn = -1; | |
counter = 0; | |
} | |
} |
示範影片:
題外話:原本打算用mBlock來寫,發現mBlock的Arduino模式沒有辦法產生陣列之類的資料儲存方式,即使我用建立清單的方式,也不能轉成Arduino IDE所能編譯的C語言語法,所以只好用C來寫,剛好在Github上找到有人寫好的程式碼,就直接修改成我想要的功能。
沒有留言:
張貼留言