-
아두이노 프로젝트 | 젤다의 전설 시간의 오카리나Technology/Arduino 2023. 11. 17. 18:00
1. 시간의 오카리나
젤다의 전설 시간의 오카리나 일본 닌텐도에서 발매한 게임 <젤다의 전설 시간의 오카리나>에서 나오는 시간의 오카리나를 아두이노 플랫폼으로 구현해보자. 구현하고자 하는 시간의 오카리나는 택트 스위치 5개와 피에조 부저로 구성되어 있으며, 사리아의 노래(saria's song), 폭풍의 노래(song of storms), 젤다의 자장가(zelda's lullaby), 시간의 노래(song of time), 에포나의 노래(epona's song)이 저장되어 있다. 각 스위치를 누르면 이에 해당하는 음계 소리가 나면서 음계가 저장된다. 만약 사용자가 알맞은 음계 6개를 연속적으로 연주하면 정답 효과음과 함께 이에 해당하는 노래가 재생되고, 알맞지 않은 음계 6개를 연속적으로 연주하면 오답 효과음이 재생되며 저장된 음계가 초기화되도록 프로그램을 작성해보자.
2. 프로젝트
2.1. 회로 구성
회로 구성 브레드보드용 4핀 택트스위치 6x6 breadboard friendly switch 4p [SZH-TH0018]
TACT 스위치 / DIP TYPE / 4PIN / 빵판에 바로 연결사용하는 특별한 택트스위치입니다. 부품다리가 휘어져있는 다른 제품들과 다르게 브레드보드에 알맞은 길이로 곧게 뻗어있습니다.
www.devicemart.co.kr
1/2W 1% Axial Resistor 221F (220Ω)
일반막대저항 / 탄소피막 / 1/2W / F급(±1%) / 220옴
www.devicemart.co.kr
IMT12D2001AP
세라믹 부저 /HC12G-P series (원래 제품명) 피에조 부조 / PIEZO(DIP) / 30mA / 2048Hz / 85dB / 12mm(D)x8.5mm(H) / 수동소저 제품입니다.
www.devicemart.co.kr
2.2. 프로그램 작성
// 4옥타브 음계 주파수 정의 #define C4 262 #define D4 294 #define E4 330 #define F4 349 #define G4 392 #define A4 440 #define B4 494 // 5옥타브 음계 주파수 정의 #define C5 523 #define D5 587 #define E5 659 #define F5 698 #define G5 784 #define A5 880 #define B5 988 // 6옥타브 음계 주파수 정의 #define C6 1047 #define D6 1175 #define E6 1319 #define F6 1397 #define G6 1568 #define A6 1760 #define B6 1976 int Switch[] = {12, 11, 10, 9, 8}; // 정수형 배열 선언 후 디지털 핀 번호로 초기화 int Sign[] = {0, 0, 0, 0, 0}; // 정수형 배열 선언 후 0으로 초기화 int Buzzer = 2; // 정수형 변수 선언 후 디지털 핀 번호 2로 초기화 long Note_Serial[] = {0, 0, 0, 0, 0, 0}; // 정수형 배열 선언 후 0으로 초기화 int Counter = 0; // 정수형 변수 선언 후 0으로 초기화 void setup() { // 디지털 12, 11, 10, 9, 8번 핀을 입력(INPUT) 모드로 설정 for (int i = 0; i < 5; i++) { pinMode(Switch[i], INPUT); } pinMode(Buzzer, OUTPUT); // 디지털 2번 핀을 출력(OUTPUT) 모드로 설정 } void loop() { // 디지털 핀 12, 11, 10, 9, 8번 핀으로부터 받은 신호를 배열에 저장 for (int i = 0; i < 5; i++) { Sign[i] = digitalRead(Switch[i]); } delay(100); // 100 ms 대기 // 첫 번째 택트 스위치 if (Sign[0] == 1) // 첫 번째 배열 요소에 저장된 값이 1이면 실행 { // 디지털 12번 핀으로부터 받은 디지털 신호가 1인 동안 실행 while (digitalRead(Switch[0]) == 1) { tone(Buzzer, D4); // 디지털 2번 핀에 D4에 해당하는 디지털 신호 출력 } Note_Serial[Counter] = 1; // 연속적인 음계 정보 저장 Counter = Counter + 1; // 연속적인 음계 개수를 1 늘린 후 저장 } // 두 번째 택트 스위치 else if (Sign[1] == 1) { while (digitalRead(Switch[1]) == 1) { tone(Buzzer, F4); } Note_Serial[Counter] = 2; Counter = Counter + 1; } // 세 번째 택트 스위치 else if (Sign[2] == 1) { while (digitalRead(Switch[2]) == 1) { tone(Buzzer, A4); } Note_Serial[Counter] = 3; Counter = Counter + 1; } // 네 번째 택트 스위치 else if (Sign[3] == 1) { while (digitalRead(Switch[3]) == 1) { tone(Buzzer, B4); } Note_Serial[Counter] = 4; Counter = Counter + 1; } // 다섯 번째 택트 스위치 else if (Sign[4] == 1) { while (digitalRead(Switch[4]) == 1) { tone(Buzzer, D5); } Note_Serial[Counter] = 5; Counter = Counter + 1; } else { noTone(Buzzer); // 디지털 2번 핀에 디지털 신호 미출력 } delay(100); // 연속적인 음계 개수가 6개면 실행 if (Counter == 6) { // 연속적인 음계 정보를 실수 자료형으로 변형 long Serial_Num = Note_Serial[0] * 100000 + Note_Serial[1] * 10000 + Note_Serial[2] * 1000 + Note_Serial[3] * 100 + Note_Serial[4] * 10 + Note_Serial[5] * 1; // 연속적인 음계 정보가 234234이면 사리아의 노래를 재생 if (Serial_Num == 234234) { Correct_Sound(Buzzer); // Correct_Sound 함수 실행 Sarias_Song(Buzzer); // Sarias_Song 함수 실행 // 연속적인 음계 정보 초기화 for (int i = 0; i < 6; i++) { Note_Serial[i] = 0; } Counter = 0; } // 연속적인 음계 정보가 125125이면 폭풍의 노래를 재생 else if (Serial_Num == 125125) { Correct_Sound(Buzzer); Song_of_Storm(Buzzer); for (int i = 0; i < 6; i++) { Note_Serial[i] = 0; } Counter = 0; } // 연속적인 음계 정보가 453453이면 젤다의 자장가를 재생 else if (Serial_Num == 453453) { Correct_Sound(Buzzer); Zeldas_Lullaby(Buzzer); for (int i = 0; i < 6; i++) { Note_Serial[i] = 0; } Counter = 0; } // 연속적인 음계 정보가 312312면 시간의 노래를 재생 else if (Serial_Num == 312312) { Correct_Sound(Buzzer); Song_of_Time(Buzzer); for (int i = 0; i < 6; i++) { Note_Serial[i] = 0; } Counter = 0; } // 연속적인 음계 정보가 543543이면 에포나의 노래를 재생 else if (Serial_Num == 543543) { Correct_Sound(Buzzer); Eponas_Song(Buzzer); for (int i = 0; i < 6; i++) { Note_Serial[i] = 0; } Counter = 0; } else { Wrong_Sound(Buzzer); // Wrong_Sound 함수 실행 Counter = 0; // 변수를 0으로 초기화 // 연속적인 음계 정보 초기화 for (int i = 0; i < 6; i++) { Note_Serial[i] = 0; } } } } // 사리아의 노래 void Sarias_Song(int Buzzer) { int Note[20] = { // 정수형 배열 선언 후 음계 정보를 저장 F4, A4, B4, F4, A4, B4, F4, A4, B4, E5, D5, B4, C5, B4, G4, E4, D4, E4, G4, E4 }; float Tempo[20] = { // 실수형 배열 선언 후 박자 정보를 저장 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 0.5, 0.5, 1, 0.5, 0.5, 0.5, 0.5, 2.5, 0.5, 0.5, 0.5, 3 }; int Size = sizeof(Note) / sizeof(int); // 배열의 길이 연산 // 사리아의 노래 재생 for (int i = 0; i < Size; i++) { float NoteDuration = 300 * Tempo[i]; // 실수형 변수 선언 후 초기화 // 디지털 2번 핀에 Note[i]에 해당하는 디지털 신호를 NoteDuration동안 출력 tone(Buzzer, Note[i], NoteDuration); float PauseBetweenNotes = NoteDuration * 1.30; // 실수형 변수 선언 후 초기화 delay(PauseBetweenNotes); // PauseBetweenNotes동안 대기 } } // 폭풍의 노래 void Song_of_Storm(int Buzzer) { int Note[23] = { D4, F4, D5, D4, F4, D5, E5, F5, E5, F5, E5, C5, A4, A4, D4, F4, G4, A4, A4, D4, F4, G4, E4 }; float Tempo[23] = { 0.5, 0.5, 2, 0.5, 0.5, 2, 1.5, 0.5, 0.5, 0.5, 0.5, 0.5, 2, 1, 1, 0.5, 0.5, 3, 1, 1, 0.5, 0.5, 3 }; int Size = sizeof(Note) / sizeof(int); for (int i = 0; i < Size; i++) { float NoteDuration = 250*Tempo[i]; tone(Buzzer, Note[i], NoteDuration); float PauseBetweenNotes = NoteDuration * 1.30; delay(PauseBetweenNotes); } } // 젤다의 자장가 void Zeldas_Lullaby(int Buzzer) { int Note[13] = { B4, D5, A4, G4, A4, B4, D5, A4, B4, D5, A5, G5, D5 }; float Tempo[13] = { 2, 1, 2, 0.5, 0.5, 2, 1, 3, 2, 1, 2, 1, 4 }; int Size = sizeof(Note) / sizeof(int); for (int i = 0; i < Size; i++) { float NoteDuration = 500 * Tempo[i]; tone(Buzzer, Note[i], NoteDuration); float PauseBetweenNotes = NoteDuration * 1.30; delay(PauseBetweenNotes); } } // 시간의 노래 void Song_of_Time(int Buzzer) { int Note[17] = { A4, D4, F4, A4, D4, F4, A4, C5, B4, G4, F4, G4, A4, D4, C4, E4, D4 }; float Tempo[17] = { 1, 2, 1, 1, 2, 1, 0.5, 0.5, 1, 1, 0.5, 0.5, 1, 1, 0.5, 0.5, 4 }; int Size = sizeof(Note) / sizeof(int); for (int i = 0; i < Size; i++) { float NoteDuration = 500 * Tempo[i]; tone(Buzzer, Note[i], NoteDuration); float PauseBetweenNotes = NoteDuration * 1.30; delay(PauseBetweenNotes); } } // 에포나의 노래 void Eponas_Song(int Buzzer) { int Note[11] = { D5, B4, A4, D5, B4, A4, D5, B4, A4, B4, A4 }; float Tempo[11] = { 0.5, 0.5, 2, 0.5, 0.5, 2, 0.5, 0.5, 1, 1, 2 }; int Size = sizeof(Note) / sizeof(int); for (int i = 0; i < Size; i++) { float NoteDuration = 500 * Tempo[i]; tone(Buzzer, Note[i], NoteDuration); float PauseBetweenNotes = NoteDuration * 1.30; delay(PauseBetweenNotes); } } // 정답 알림음 void Correct_Sound(int Buzzer) { int Note[5] = {C4, D4, E4, F4, F6}; delay(100); noTone(Buzzer); delay(500); for (int i = 0; i < 6; i++) { tone(Buzzer, Note[i]); delay(100); } noTone(Buzzer); delay(500); } // 오답 알림음 void Wrong_Sound(int Buzzer) { noTone(Buzzer); delay(500); tone(Buzzer, F4); delay(100); noTone(Buzzer); delay(100); tone(Buzzer, F4); delay(1000); noTone(Buzzer); delay(500); }
[함께 읽으면 좋은 페이지]
아두이노 디지털 신호 입력 | 택트 스위치
1. 디지털 신호 입력 아두이노 소프트웨어에서 디지털 신호를 받을 핀을 설정하고 함수를 작성하여 아두이노 하드웨어에 업로드하면, 앞서 설정한 핀을 통해 디지털 신호를 입력 받을 수 있다.
vedacube.tistory.com
아두이노 | 피에조 부저
1. 피에조 부저 압전 효과(piezoelectric effect)는 수정이나 세라믹 같은 결정체에 압력을 가했을 때 전압이 발생하는 현상이다. 반대로 결정체에 전압을 가하면 물리적인 변형을 일으킬 수 있는데,
vedacube.tistory.com
아두이노 프로젝트 | 디지털 피아노
1. 디지털 피아노 일상에서 쉽게 발견할 수 있는 디지털 피아노를 아두이노 플랫폼으로 구현해보자. 구현하고자 하는 디지털 피아노는 택트 스위치 7개와 피에조 부저, 가변저항으로 구성되어
vedacube.tistory.com
참고문헌
saskiot. (2017). Legend of Zelda electronic ocarina. YouTube. https://www.youtube.com/watch?v=2q0E0348nAI. 2023.10.22.
반응형'Technology > Arduino' 카테고리의 다른 글
아두이노 프로젝트 | 자동차 후방 감지기 (0) 2023.12.01 아두이노 | 초음파센서 모듈 HC-SR04 (1) 2023.11.24 아두이노 프로젝트 | 디지털 피아노 (0) 2023.11.10 아두이노 | 피에조 부저 (1) 2023.11.03 아두이노 프로젝트 | 밝기 조절이 가능한 스탠드 (0) 2023.09.01