蜂鸣器,是一种可以发出单调声音的器件,在电子 DIY 领域应用广泛,因为它使用简单,不像扬声器一样需要用准确的音频信号来控制。蜂鸣器分为有源蜂鸣器和无源蜂鸣器。其中 “源” 不是指电源,而是指振荡源,有源蜂鸣器只需要通直流电压就能发出蜂鸣声;而无源蜂鸣器则需要用一定频率的信号来驱动。
本实验使用的是无源蜂鸣器。
工作原理
蜂鸣器输入信号的频率决定了蜂鸣器的声音频率,而 Arduino 默认的 PWM 输出频率是固定在 490.196Hz 的,所以不能简单地使用 analogWrite()
函数来控制蜂鸣器。 Arduino 为蜂鸣器控制设计了一个专用函数 tone(pin, frequency, duration)
,其中 pin 指输出引脚,frequency 指输出频率(单位 Hz),duration 是声音持续的时间(单位 ms)。最后一个参数可以不填,不填时将持续输出。对应的,还有一个 noTone(pin)
函数,用于停止指定引脚上的方波输出。
因此,我们使用 Arduino 中的 tone()
函数就可以比较精确地控制声音的频率和持续时间。但是想要输出特定的音符,则需要查频率表,比较麻烦。好在 Arduino 库中为我们提供了一个文件 —— pitches.h,该文件包含典型音符的所有音高值。例如,NOTE_C4
是中央 C,NOTE_FS4
是 F#,等等。这个注释表最初是由 Brett Hagman 编写的,想制作音符时会发现它很有用!
硬件连接
将蜂鸣器输入接在 Arduino 的 8 号数字 IO 上,再接上 GND 和 VCC 即可。
乐理知识
简谱左上角通常有类似下面这样的符号,用于表示曲子的调号和拍数。调号一般是用 1 等于 A、B、C、D、E、F、G 来表示,如 1=C 表示该简谱是用 C 调来记谱的,如果要表示升降号的调,则在字母前加 # 号或者 b 号。调号后面的分数是拍号,其中分母表示以几分音符为一拍,分子表示每小节有多少拍。拍号决定了乐曲的基本节奏和强弱的循环规律。
1
=
C
4
4
1 = \rm{C {\frac{4}{4}}}
1=C44
因此,上述符号表示该简谱是 C 调来记谱的,以四分音符为一拍,每小节四拍。
1
=
D
2
4
1 = \rm{D {\frac{2}{4}}}
1=D42
再比如,这个符号表示该简谱是 D 调来记谱的,以四分音符为一拍,每小节两拍。
《致爱丽丝》原名《a小调巴加泰勒》,它的调号和拍号如下所示。其中 Am 调是建立在根音 A 上的小三和弦,由【A C E】构成。然后以八分音符为一拍,每小节三拍。
1
=
A
m
3
8
1 = \rm{Am {\frac{3}{8}}}
1=Am83
讲了那么多,其实我也不太懂。。。 😿 哭唧唧
致爱丽丝
我将上面一小段翻译成 pitches.h 中预定义的音符,调子和拍子好像也没整对。。。不过听起来是爱丽丝的味道 😸
/*
Play a melody
*/
#include "pitches.h"
// 记录曲子的音符
int melody[] = { 0, 0, NOTE_E5, NOTE_D5, NOTE_E5, NOTE_D5, NOTE_E5, NOTE_B4, NOTE_D5, NOTE_C5,
NOTE_A4, 0, NOTE_C4, NOTE_E4, NOTE_A4, NOTE_B4, 0, NOTE_E4, NOTE_G4, NOTE_B4,
NOTE_C5, 0, NOTE_E4, NOTE_E5, NOTE_D5, NOTE_E5, NOTE_D5, NOTE_E5, NOTE_B4, NOTE_D5, NOTE_C5,
NOTE_A4, 0, NOTE_C4, NOTE_E4, NOTE_A4, NOTE_B4, 0, NOTE_E4, NOTE_C5, NOTE_B4,
NOTE_A4
};
// 音符持续时间:4为四分音符,8为八分音符
int noteDurations[] = { 4, 4, 8, 8, 8, 8, 8, 8, 8, 8,
4, 8, 8, 8, 8, 4, 8, 8, 8, 8,
4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
4, 8, 8, 8, 8, 4, 8, 8, 8, 8,
4, 4, 8, 8, 8, 8, 8, 8, 8, 8,
4
};
void setup() {
// 遍历整个曲子的音符
for(int thisNote = 0; thisNote < sizeof(melody)/sizeof(melody[0]); thisNote++) {
// 需要根据音符类型换算音符的持续时间
int noteDuration = 1000/noteDurations[thisNote];
tone(8, melody[thisNote], noteDuration);
// 为了能辨别出不同的音调,需要在两个音调间设置一定的延时,增加30%比较合适
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
noTone(8);
}
}
void loop() {
}
播放效果
点击视频:https://weibo.com/tv/v/IjgAGqoHt?fid=1034:4445920067256332