นี่คือตัวอย่างการใช้งานฟังก์ชัน tone() บน Arduino Nano แบบจัดเต็ม วิธีเดียวกันนี้ก็เอาไปใช้กับ Arduino รุ่นอื่นๆ หรือบอร์ดที่คล้ายกันได้เลยจ้า
เราใช้ปุ่มกดสองปุ่ม: ปุ่มแรกสำหรับเริ่มเล่นเพลง ส่วนปุ่มที่สองจะรีเซ็ตเมโลดี้กลับไปใช้โทนเดิม (อ็อกเทฟที่ 4) แล้วก็มีโพเทนชิออมิเตอร์ 10k ไว้ปรับอ็อกเทฟของเมโลดี้ได้ถึง 7 อ็อกเทฟเหมือนเปียโนเลย จะขึ้นจะลงก็หมุนเอา แต่ละอ็อกเทฟก็มี 12 โน้ตนะ รวมโน้ตที่ยืดยาวด้วย

เรายังใส่ LED 4 ดวงไว้แสดงการเปลี่ยนโน้ตด้วยแสงไฟให้ดูตื่นเต้นอีกต่างหาก
เราไม่ได้ใช้ไฟล์ pitches.h นะ แต่ใช้ลำดับโน้ต MIDI (p) แทน โดยเริ่มจากโน้ตหลัก A4 (440 Hz) ทางคณิตศาสตร์แล้ว แต่ละโน้ตสามารถแทนได้สมบูรณ์แบบด้วยการคูณแบบเอ็กซ์โพเนนเชียลของโน้ต A4 ตามสมการนี้:
f = 2 ^ ((p - 69) / 12) x 440 Hz
โดยใช้เมทริกซ์ MeSderM [X][3] ซึ่ง X คือจำนวนโน้ตทั้งหมด (ขึ้นอยู่กับเมโลดี้) เรากำหนดหมายเลขโน้ต, ตัวคูณระยะเวลาโน้ต, และ LED ที่จะติดสว่างเมื่อเล่นโน้ตนั้น
ในเคสนี้ และในเมโลดี้ส่วนใหญ่ มักจะมีท่อนที่ซ้ำกัน เราเลยสร้างฟังก์ชัน melodyY(int RepX, int iniX, int endX) ขึ้นมาเพื่อเล่นส่วนหนึ่งของโน้ต (ตั้งแต่ iniX ถึง endX) ซ้ำตามจำนวนครั้งที่ต้องการ (RepX)
ใน loop() เมโลดี้จะเริ่มเล่นเมื่อกดปุ่มที่ 1 ขณะเล่นก็จะตรวจสอบค่าจากโพเทนชิออมิเตอร์เพื่อกำหนดโทนเสียงของแต่ละโน้ต ถ้ากดปุ่มที่ 2 เมื่อไหร่ ก็จะกลับไปใช้โทนเดิมทันที
เช่นเดียวกัน ถ้าเมโลดี้เล่นจบแล้ว การกดปุ่มที่ 2 จะรีเซ็ตเมโลดี้กลับไปยังระดับเสียงเดิม และลูปก็จะเล่นเมโลดี้ใหม่ถ้ากดปุ่มที่ 1 อีกครั้ง
สุดท้าย ผ่าน Serial Monitor น้องจะสามารถดูความถี่ของแต่ละโน้ตและการเปลี่ยนแปลงที่เกิดขึ้นเมื่อขยับโพเทนชิออมิเตอร์ได้ตลอดช่วง
โค้ดนี้ยังไม่ได้ออปติไมซ์นะ มันปรับปรุงให้ดีขึ้นได้อีก เดี๋ยวรุ่นพี่จะปล่อยเวอร์ชัน 2 ให้ในอนาคต
เมโลดี้ที่ใช้คือเพลงนี้: Marvel Spiderman Theme (c)
นอกจากนี้ รุ่นพี่ยังทำตัวอย่างเดียวกันนี้ไว้ใน TinkerCAD (ใช้ Arduino Micro) ด้วย น้องสามารถก๊อปปี้โค้ดไปดัดแปลงให้เข้ากับรสนิยมตัวเองได้เลย
รายละเอียดเทคนิคเพิ่มเติม
การสังเคราะห์เสียงดิจิทัล
โปรเจกต์นี้เปลี่ยน Arduino Nano ขนาดกะทัดรัดให้กลายเป็นเครื่องดนตรีโมโนโฟนิก
- การสร้างคลื่นสี่เหลี่ยม: ใช้ฟังก์ชัน
tone()เพื่อสร้างคลื่นสี่เหลี่ยม PWM ที่ความถี่เฉพาะซึ่งตรงกับโน้ตดนตรี (เช่น A4 = 440Hz, C5 = 523Hz) - ความแม่นยำของระดับเสียง: โค้ดคำนวณความถี่ทางคณิตศาสตร์จากหมายเลขโน้ต MIDI ทำให้มั่นใจได้ว่าระดับเสียงจะแม่นยำตามค่าอ้างอิงมาตรฐาน A4 = 440 Hz
ฮาร์ดแวร์เอาท์พุต
- Piezo vs. Speaker: โปรเจคนี้สามารถขับ Piezo Buzzer ที่มีอิมพีแดนซ์สูงได้ตรงๆ จากขา Digital เลยจ้า แต่ถ้าอยากได้เสียงดีๆ จากลำโพงเล็ก 8 โอห์ม แนะนำให้ใส่ตัวต้านทาน (Resistor) 100Ω แบบอนุกรมด้วยนะ ไว้จำกัดกระแส ปลอดภัยไว้ก่อน อย่าให้ชิปทำงานหนักเกินไป!
- เล่นเมโลดี้: ฟังก์ชัน
melodyY()มีตัวจัดการลำดับ (sequence-handler) คอยควบคุมความยาวของโน้ตและช่วงพักระหว่างโน้ต ทำให้ Arduino Nano ของเราเล่นเพลงที่โปรแกรมไว้ได้ไพเราะเลยล่ะ
โค้ด:
const int LED_GRN = 8;
const int LED_RED = 6;
const int LED_BLE = 4;
const int LED_YLW = 2;
const int BUZZER = 13;
const int BTN1 = 5;
const int BTN2 = 3;
const int POT = A0;
const int MeSderM[] [3] = {{60 ,6, LED_GRN}, {63 ,8, LED_RED}, {67 ,2, LED_BLE}, {66 ,6, LED_BLE}, {63 ,8, LED_RED}, {60 ,2, LED_GRN}, {60 ,6, LED_GRN}, {63 ,8, LED_RED}, {67 ,6, LED_BLE}, {68 ,8, LED_YLW}, {67 ,8, LED_YLW}, {66 ,6, LED_BLE}, {63 ,6, LED_RED}, {60 ,2, LED_GRN}, {65 ,6, LED_RED}, {68 ,8, LED_BLE}, {72 ,2, LED_YLW}, {71 ,6, LED_YLW}, {68 ,8, LED_BLE}, {65 ,2, LED_RED}, {60 ,6, LED_GRN}, {63 ,8, LED_BLE}, {67 ,2, LED_YLW}, {66 ,6, LED_BLE}, {63 ,8, LED_RED}, {60 ,2, LED_GRN}, {68 ,6, LED_YLW}, {67 ,1, LED_BLE}, {67 ,8, LED_BLE}, {65 ,8, LED_RED}, {63 ,8, LED_GRN}, {65 ,8, LED_RED}, {63 ,8, LED_GRN}, {60 ,1, LED_GRN}, {67 ,6, LED_RED}, {68 ,8, LED_BLE}, {70 ,2, LED_YLW}, {68 ,6, LED_YLW}, {67 ,2, LED_BLE}, {65 ,6, LED_RED}, {63 ,8, LED_GRN}, {65 ,2, LED_RED}, {63 ,6, LED_GRN}, {62 ,8, LED_RED}, {63 ,2, LED_GRN}, {67 ,6, LED_RED}, {68 ,8, LED_BLE}, {70 ,2, LED_YLW}, {68 ,6, LED_YLW}, {67 ,2, LED_BLE}, {65 ,6, LED_RED}, {63 ,8, LED_GRN}, {65 ,2, LED_RED}, {63 ,6, LED_GRN}, {65 ,8, LED_RED}, {67 ,1, LED_BLE}, {67 ,8, LED_BLE}, {65 ,8, LED_RED}, {63 ,8, LED_GRN}, {65 ,8, LED_RED}, {63 ,8, LED_GRN}, {60 ,1, LED_GRN}, {67 ,6, LED_BLE}, {65 ,6, LED_RED}, {63 ,8, LED_GRN}, {65 ,6, LED_RED}, {67 ,6, LED_BLE}, {74 ,1, LED_YLW}};
const int LEDS[] = {LED_GRN, LED_RED, LED_BLE, LED_YLW};
int PotV = 0;
int AntO = 0;
int OctX = 0;
void Btn2Read(){
if (digitalRead(BTN2)==HIGH){
OctX=0;
}
}
void melodyY(int RepX, int iniX, int endX) {
for (int RepI = 0; RepI < RepX; RepI++) {
for (int thisNote = iniX; thisNote < endX; thisNote++) {
PotV = map(analogRead(POT), 0, 1023, -3, 4);
if (AntO != PotV){
AntO = PotV;
OctX = PotV;
}
Btn2Read();
int noteDuration = 1000 / MeSderM[thisNote][1];
digitalWrite(MeSderM[thisNote][2], HIGH);
float NteX = MeSderM[thisNote][0]+OctX*12-69;
NteX = pow(2, NteX/12)*440;
String str1 = "Eighth: " + String(4+OctX) + "; Freq: " + String(NteX,3);
Serial.println(str1);
tone(BUZZER, NteX, noteDuration);
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes*2/3);
Btn2Read();
digitalWrite(MeSderM[thisNote][2], LOW);
delay(pauseBetweenNotes/3);
Btn2Read();
noTone(BUZZER);
}
}
}
void setup() {
Serial.begin(9600);
for(int i=0; i<4; i++){
pinMode(LEDS[i], OUTPUT);
digitalWrite(LEDS[i], LOW);
}
pinMode(BTN1, INPUT);
pinMode(BTN2, INPUT);
}
void loop() {
if (digitalRead(BTN1)==HIGH)
{
melodyY(2,0,34);
melodyY(1,34,56);
melodyY(1,0,34);
melodyY(1,56,68);
}
Btn2Read();
}