저는 전자공학 분야에는 완전히 초보자입니다. 코딩에는 어느 정도 배경이 있어 도움이 되었지만, 제가 만든 프로젝트들에 대해 언제나 새로운 아이디어와 제안을 환영합니다.
최근 압전 부저(Piezo Buzzer)와 관련된 코딩을 배우면서 지금까지 배운 내용을 바탕으로 이 작품을 만들었습니다. 새로운 기능이나 스위치로 확장할 여지가 많아 나중에 더 발전시킬 계획이지만, 지금은 다음 도전으로 넘어가려 합니다!
아래는 프리셋 곡 메뉴를 포함한 장치 작동 영상입니다. 솔직히 4번과 5번 곡은 동일하지만, 더 크고 나은 것들을 만들고 싶은 욕심에 추가 곡 코딩은 다음 기회로 미뤘습니다. 메인 루프와 개별 곡 루프의 기본 코딩은 여러분의 아이디어에 맞게 쉽게 수정할 수 있으니 자유롭게 변경해 보세요.
동작 영상
영상 링크 참조
하드웨어 설정 방법
피아노 건반 (스위치)
피아노 건반 스위치는 저항 래더(Resistor Ladder) 방식으로 연결했습니다. 저항들을 순차적으로 배치해 각 스위치를 전원에 연결합니다. 이 프로젝트에서는 (옴 단위) 1M, 10k, 4.7k, 1k, 560, 220옴을 사용했습니다.
맨 왼쪽 첫 번째 피아노 스위치는 전원에 연결되고, 다음 스위치와도 연결됩니다. 두 번째 스위치는 가장 작은 저항에 연결되고, 이후 각 스위치는 순서대로 다음 큰 저항에 연결됩니다. 마지막 스위치는 10k옴 저항을 통해 접지되며, 모든 7개 스위치가 Arduino의 아날로그 입력 핀 A0에 연결됩니다. 메인 스케치에서 각 피아노 건반에 해당하는 음표 주파수를 정의합니다. 이 프로젝트에서는 C4, D4, E4, F4, G4, A4, B4를 사용했으며, C4가 가장 왼쪽 스위치입니다. 주파수 값을 변경하거나 스위치를 추가해 완전히 커스터마이징할 수 있습니다!
LCD 화면
아래 회로도대로 LCD 핀을 연결하세요. LCD 3번 핀을 가변저항에 연결해 대비도를 조절합니다. 가변저항의 양쪽 끝은 전원과 접지에 연결합니다. LCD 15번 핀은 220옴 저항을 통해 전원에 연결합니다. 핀 배치가 다를 경우 코드를 entsprechend 수정하세요.
메뉴 스위치
메뉴 스위치를 전원에 연결하고 10k옴 저항을 통해 접지합니다. 이 스위치는 Arduino 7번 핀에도 연결해 코드로 제어할 수 있게 합니다.
LED
LED는 "메뉴 모드" 진입 시 피아노 건반이 비활성화됨을 표시합니다. 메뉴 버튼을 누르면 LED가 켜집니다. LED 애노드(양극)를 Arduino 6번 핀에 연결하고, 220옴 저항을 통해 접지합니다.
피에조 부저
피에조 부저 한 쪽을 Arduino 8번 핀에, 다른 쪽을 220옴 저항을 통해 접지에 연결합니다. 코드의 tone() 함수가 이 핀을 찾아 음을 재생합니다.
코드 작동 원리
설정 (Setup)
LiquidCrystal.h와 pitches.h 라이브러리 임포트
메뉴 스위치 이름 정의, 입/출력 핀 결정, 7개 피아노 건반의 주파수 값 설정
각 곡마다 새 탭을 만들어 코드 정리 및 추후 확장 용이
메인 루프
키보드 시작: LED 끄기, 모든 피아노 건반 활성화
메뉴 버튼 눌림 감지 시: 피아노 건반 비활성화, LED 켜기 ("메뉴 모드" 표시)
메뉴 접근
메뉴 버튼으로 곡 목록 순환, 피아노 건반 아무거나 눌러 선택된 곡 재생
LCD에 현재 재생 중인 곡 표시, 곡 종료 후 메뉴의 같은 위치로 복귀
메뉴 버튼 더블 클릭 시 메뉴 처음으로 재시작
피아노 모드 복귀: 메뉴의 나머지 곡들을 순환해 LCD가 비고 LED가 꺼지면 건반 작동 재개
코드
GitHub 저장소에서 전체 코드 확인 가능
메인 코드: Electronic Keyboard
// LCD 화면, 스위치 & LED 설정
#include <LiquidCrystal.h>
#include "pitches.h"
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int LCDswitchPin = 7;
int LCDswitchState = 0;
int prevLCDswitchState = 0;
int blueLED = 6;
int LCDswitchCounter = 0;
// 음표 키 - 주파수 값 설정
int notes[] = {262, 294, 330, 349, 392, 440, 494}; // C, D, E, F, G, A, B
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
pinMode(LCDswitchPin, INPUT);
pinMode(blueLED, OUTPUT);
digitalWrite(blueLED, LOW);
}
void loop() {
LCDswitchState = digitalRead(LCDswitchPin);
int keyVal = analogRead(A0);
Serial.println(keyVal);
lcd.noDisplay();
digitalWrite(blueLED, LOW);
if (LCDswitchState == HIGH) {
digitalWrite(blueLED, HIGH);
lcd.display();
lcd.clear();
LCDstart();
}
// 건반 음표 및 주파수 판별 (저항 래더 전압값 기준)
if(keyVal == 1023) { tone(8, notes[0]); } // C
else if(keyVal >= 990 && keyVal <= 1010) { tone(8, notes[1]); } // D
else if(keyVal >= 960 && keyVal <= 980) { tone(8, notes[2]); } // E
else if(keyVal >= 900 && keyVal <= 945) { tone(8, notes[3]); } // F
else if(keyVal >= 650 && keyVal <= 710) { tone(8, notes[4]); } // G
else if(keyVal >= 500 && keyVal <= 550) { tone(8, notes[5]); } // A
else if(keyVal >= 5 && keyVal <= 10) { tone(8, notes[6]); } // B
else if(keyVal <= 1) { noTone(8); } // 미누름
}
void LCDstart() {
int keyVal = analogRead(A0);
LCDswitchState = digitalRead(LCDswitchPin);
while (LCDswitchState == LOW) {
LCDswitchState = digitalRead(LCDswitchPin);
if (LCDswitchState == HIGH) {
LCDswitchCounter++;
Serial.print("number of button pushes: ");
Serial.println(LCDswitchCounter);
delay(300);
Song1title();
lcd.clear();
break;
} else {
LCDswitchCounter = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WHICH SONG WOULD");
lcd.setCursor(0, 1);
lcd.print("YOU LIKE TO PLAY");
delay(50);
}
}
}
// 각 곡 제목 표시 및 선택 로직 (Song1title ~ Song5title)
// 생략 - GitHub 참조
// 곡 재생 함수들 (Song1 ~ Song5)
// Song1: 슈퍼 마리오 브라더스 테마
// Song2: 슈퍼 마리오 브라더스 언더월드
// Song3: 제퍼디 테마
// Song4, Song5: 짧은 샘플 멜로디
// 각 곡은 melody[] 배열과 noteDurations[] 배열로 구성
// tone() 함수로 8번 핀에서 재생