Arduino 合成乐音:从零实现 88 键钢琴全音域
零部件与物料
| 零部件 | 数量 | 备注 |
|---|---|---|
| Arduino UNO | 1 | 主控板 |
| 扬声器 0.25W 8Ω | 1 | 输出方波乐音 |
| 电阻 150-220Ω | 1 | 限流保护 |
软件与在线服务
- Arduino IDE
项目简介
Arduino 内置 tone() 函数虽能产生方波,但最低频率限制在 31Hz,无法覆盖 88 键钢琴的最低几个键(A0=27.5Hz)。本项目完全摒弃查表法,改用数学公式实时计算频率,并通过 delayMicroseconds() 手工合成方波,突破 31Hz 限制,实现全 88 键音域播放。
核心原理
- 频率计算:钢琴键编号 1-88 对应频率公式
f = 440 * 2^((n-49)/12),其中 49 号键为 A4 (440Hz) - 方波合成:周期 T = 1/f,高低电平各占 T/2,用
delayMicroseconds()控制翻转时序 - 长延时处理:
delayMicroseconds()最大可靠延时约 16383μs,低音周期超出时,拆分为多次循环调用
电路连接
极简电路:扬声器一端接 GND,另一端经 220Ω 电阻接 Arduino Digital Pin 12。
核心代码片段
const uint8_t SPEAKER_PIN = 12;
// 计算第 n 键 (1-88) 的半周期微秒数
unsigned long halfPeriod(uint8_t key) {
float freq = 440.0 * pow(2.0, (key - 49) / 12.0);
return (unsigned long)(1000000.0 / freq / 2.0);
}
// 播放指定键,持续 duration_ms 毫秒
void playKey(uint8_t key, unsigned long duration_ms) {
if (key < 1 || key > 88) return;
unsigned long hp = halfPeriod(key);
unsigned long cycles = (duration_ms * 1000UL) / (hp * 2);
for (unsigned long i = 0; i < cycles; i++) {
digitalWrite(SPEAKER_PIN, HIGH);
delayMicroseconds(hp);
digitalWrite(SPEAKER_PIN, LOW);
delayMicroseconds(hp);
}
}
// 处理长半周期(低音键)
void delayLong(unsigned long us) {
while (us > 16000) {
delayMicroseconds(16000);
us -= 16000;
}
delayMicroseconds(us);
}
完整演示曲目
代码中内置《小星星》、《欢乐颂》等示例曲谱,以 {键号, 时值} 结构体数组存储,主循环遍历播放。完整带注释代码见 Gist 链接。
技术亮点
- 零查表、纯计算,代码极其精简(单屏可容纳核心逻辑)
- 覆盖 27.5Hz-4186Hz 全钢琴音域
- 展示微秒级定时、数学建模、嵌入式声学合成基础
- 适合作为 Arduino 音频合成、音乐理论教学案例
原理图
制造工艺
- 用 Arduino 打造绚丽显示器 Ambilight 系统
- 用 Arduino 制作万能红外遥控器:分步指南
- 自制可拳击的可编程键盘按钮:基于 Arduino 与压电元件的分步指南
- Arduino Mega 2560 接 NEO-6M GPS 模块完整教程
- Arduino 井字棋游戏:MAX7219 点阵屏 + 纸板外壳 DIY
- Arduino DIY 电压表:Nokia 5110 屏幕显示,手把手教学
- 语音控制家电:Google Assistant + 蓝牙 + Arduino UNO
- Arduino 连接 NMEA-0183 设备全攻略:从硬件接线到协议解析
- 基于 Arduino 和超声波传感器的自动门控制系统
- 蓝牙遥控 Arduino 小车完整 DIY 指南
- Arduino Modbus 从机开发全攻略:基于 RS485 扩展板的分步实现指南
- DIY 迷你示波器:基于 Arduino Nano 与 OLED 显示屏的逐步教程