#include "pitches.h" // 包含音符频率定义头文件
#define SPEAKER_PIN 8 // 定义扬声器连接引脚
#define DEBOUNCE_DELAY 50 // 按键消抖延迟(毫秒)
// 按钮引脚数组(从低音到高音排列)
const uint8_t buttonPins[] = {12, 11, 10, 9, 7, 6, 5, 4};
// 对应按钮的音符频率数组(C大调音阶)
const int buttonTones[] = {
NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4, // 中音组C-F
NOTE_G4, NOTE_A4, NOTE_B4, NOTE_C5 // 中音组G-B + 高音C
};
// 《一闪一闪亮晶晶》的音符和节奏
const int twinkleMelody[] = {
NOTE_C4, NOTE_C4, NOTE_G4, NOTE_G4, NOTE_A4, NOTE_A4, NOTE_G4,
NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_C4
};
const int twinkleDurations[] = {
4, 4, 4, 4, 4, 4, 2,
4, 4, 4, 4, 4, 4, 2
};
const int numTones = sizeof(buttonPins) / sizeof(buttonPins[0]); // 计算按钮/音符数量
unsigned long lastPressTime = 0; // 记录上次按键时间
uint8_t lastPressedButton = 0; // 记录上次按下的按钮
int playMode = 0; // 播放模式:0=按钮控制,1=自动播放
void setup() {
// 初始化所有按钮引脚为输入模式,启用内部上拉电阻
for (uint8_t i = 0; i < numTones; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
pinMode(SPEAKER_PIN, OUTPUT); // 初始化扬声器引脚为输出模式
Serial.begin(9600); // 初始化串口通信
Serial.println("Send '0' for button control, '1' to play Twinkle Twinkle Little Star");
}
void playTwinkleTwinkle() {
static unsigned long noteStartTime = 0;
static int currentNote = 0;
if (currentNote >= sizeof(twinkleMelody)/sizeof(twinkleMelody[0])) {
// 曲子播放完毕
noTone(SPEAKER_PIN);
playMode = 0; // 自动返回按钮控制模式
return;
}
unsigned long currentTime = millis();
int noteDuration = 1000 / twinkleDurations[currentNote];
// 播放当前音符
if (currentTime - noteStartTime >= noteDuration * 2) {
// 切换到下一个音符
noteStartTime = currentTime;
currentNote++;
if (currentNote < sizeof(twinkleMelody)/sizeof(twinkleMelody[0])) {
tone(SPEAKER_PIN, twinkleMelody[currentNote], noteDuration);
}
}
}
void loop() {
// 检查串口输入
if (Serial.available() > 0) {
int input = Serial.read();
if (input == '0') {
playMode = 0;
noTone(SPEAKER_PIN);
Serial.println("Button control mode");
} else if (input == '1') {
playMode = 1;
Serial.println("Playing Twinkle Twinkle Little Star");
}
}
if (playMode == 1) {
// 自动播放模式
playTwinkleTwinkle();
} else {
// 按钮控制模式
boolean buttonActive = false;
// 检测按钮状态
for (uint8_t i = 0; i < numTones; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
// 检测到按钮按下
if (lastPressedButton != i + 1 || millis() - lastPressTime > DEBOUNCE_DELAY) {
lastPressedButton = i + 1;
lastPressTime = millis();
// 播放对应音符
tone(SPEAKER_PIN, buttonTones[i]);
buttonActive = true;
}
}
}
// 如果没有按钮按下,停止播放
if (!buttonActive) {
lastPressedButton = 0;
noTone(SPEAKER_PIN);
}
}
}