Skip to content

Arduino - 音调库

Arduino - 使用 tone() 进行现代声音生成

Section titled “Arduino - 使用 tone() 进行现代声音生成”

本章探讨如何使用Arduino的内置tone()函数生成声音和旋律。tone()函数可以在任何数字引脚上产生指定频率的方波。这是为您的项目添加听觉反馈的绝佳方式,从简单的蜂鸣声到复杂的音乐曲调。您可以将输出引脚连接到压电蜂鸣器或小型扬声器以听到声音。

安全警告: Arduino引脚发出的信号是5V(或3.3V)方波。请勿将其直接连接到声卡或放大器等标准音频输入端,因为这种高电压可能导致永久性损坏。如果您需要与音频设备接口,请使用分压电路和耦合电容来安全地降低电压并消除直流偏置。

要完成本教程,您将需要:

  • 1 × Arduino UNO开发板(或任何其他Arduino开发板)
  • 1 × 压电蜂鸣器或一个8欧姆扬声器
  • 1 × 100欧姆电阻(用于扬声器限流)
  • 跳线

电路很简单。我们将声音产生组件连接到数字引脚8。

使用压电蜂鸣器:

将正极(通常较长的一条腿)连接到Arduino的数字引脚8。将负极连接到Arduino的GND。

使用8欧姆扬声器:

将扬声器的一个接线端通过一个100欧姆电阻连接到Arduino的数字引脚8。将另一个接线端连接到Arduino的GND。电阻器可保护Arduino引脚免受过大电流的损害。

以下是电路的文本表示:

Arduino Component
GND ---------------- (-) Piezo Buzzer / Speaker Terminal 2
PIN 8 -------------- (+) Piezo Buzzer / (Resistor) -> Speaker Terminal 1

原始教程使用了单独的pitches.h文件。虽然这可行,但现代C++实践允许我们在主草图内清晰地定义这些常量,使其自包含。我们还将使用现代技术使代码更健壮和高效。

打开Arduino IDE,创建一个新的草图(文件 > 新建),然后粘贴以下代码。

/*
* 现代旋律播放器
*
* 此草图使用 tone() 函数播放简单旋律。
* 它演示了使用 PROGMEM 进行高效内存使用和健壮的数组处理。
*/
// 包含 PROGMEM 头文件以优化内存
#include <avr/pgmspace.h>
// --- 音符定义 ---
// 这些是赫兹(Hz)的频率
#define NOTE_C4 262
#define NOTE_G3 196
#define NOTE_A3 220
#define NOTE_B3 247
#define NOTE_C5 523
#define REST 0 // 一个休止/暂停
// --- 引脚配置 ---
const int buzzerPin = 8;
// --- 旋律和持续时间 ---
// PROGMEM 将此数据存储在闪存中,节省宝贵的RAM。
const int melody[] PROGMEM = {
NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, REST, NOTE_B3, NOTE_C4
};
// 音符持续时间:4 = 四分音符,8 = 八分音符等。
const int noteDurations[] PROGMEM = {
4, 8, 8, 4, 4, 4, 4, 4
};
void setup() {
// tone() 不需要 setup,但设置引脚模式是良好实践。
pinMode(buzzerPin, OUTPUT);
// 获取旋律中的音符总数。
// 使用 sizeof() 使代码适用于任何长度的旋律。
int numNotes = sizeof(melody) / sizeof(melody[0]);
// 遍历旋律中的音符
for (int thisNote = 0; thisNote < numNotes; thisNote++) {
// 节奏(例如,一个四分音符长 1000ms)
int tempo = 1000;
// 从 PROGMEM 读取音符持续时间
int durationType = pgm_read_word_near(&noteDurations[thisNote]);
int noteDuration = tempo / durationType;
// 从 PROGMEM 读取音符频率
int frequency = pgm_read_word_near(&melody[thisNote]);
// 使用 tone(pin, frequency, duration) 播放音符
tone(buzzerPin, frequency, noteDuration);
// 为了让音符播放完毕并在音符之间添加短暂的停顿,
// 我们计算一个停顿。30% 的停顿通常听起来不错。
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// 停止音调以确保它不与下一个音调重叠。
noTone(buzzerPin);
}
}
void loop() {
// 旋律在 setup() 中播放一次。loop 是空的。
// 您可以在此处添加代码以在按钮按下时重播旋律。
}

tone(pin, frequency, duration): 这是核心函数。它在给定pin上以指定的frequency(赫兹)生成一个方波,持续duration(毫秒)。duration是可选的;如果省略,音调将一直播放直到您调用noTone(pin)。

PROGMEM: 这对于像Arduino Uno这样内存受限的设备来说是一个关键特性。它告诉编译器将melody和noteDurations数组存储在更大的闪存程序存储器中,而不是非常有限的SRAM(RAM)中。这为您的变量和其他运行时需求留下了更多RAM,从而防止了大型程序中的崩溃。

sizeof(melody) / sizeof(melody[0]): 这是计算数组元素数量的标准、健壮的C++方法。它比硬编码数字(如8)更好,因为如果您从melody数组中添加或删除音符,此计算将自动更新,从而防止错误。

  • 没有声音? 检查您的接线。蜂鸣器/扬声器是否连接到正确的引脚(8)和GND?如果使用扬声器,您是否包含了电阻器?
  • 声音失真? 小型扬声器可能在抖动。确保它已固定。压电蜂鸣器通常产生更清晰(尽管更“数字化”)的声音。
  • 深入学习: 尝试通过更改音符和持续时间来创建自己的旋律。您可以在loop()函数中添加一个按钮,以便按需触发旋律。或者,将电位器连接到模拟引脚,并使用其读数来控制音乐的节奏。

上传草图后,Arduino将立即通过连接的蜂鸣器或扬声器播放预编程的旋律。旋律将播放一次,然后程序将在loop()函数中保持空闲。