你们也知道,圣诞节就快到了,让arduino完成一个比较应景的案例也会让节日过得更有意思。
arduino可以做的放歌案例除了用语音模块外,比较简单成本最低的就是利用蜂鸣器了,只要控制好频率和节拍,蜂鸣器也可以演奏音乐的,但你要准备的东西也会复杂一点。
简谱不理解是什么??!!
很简单,你小学时候的音乐课本上面的谱子就是了,下面这张是Jingle Bells的简谱,歌词是中文版不用太认真,调子是一样的。
简谱上除了中文,其他的应该都看不懂了吧
敲黑板,这个地方要好好理解一下,后面要用到!!!
1 = F 4/4
,这里的 F
表示这个曲子是 F 调的,下面会讲到,而 4/4
表示曲子是四四拍的简单了解简谱后,该怎么把音符转换成蜂鸣器对应频率呢,看看音符频率表
低音
音符→ 音调↓ |
1# | 2# | 3# | 4# | 5# | 6# | 7# |
A | 221 | 248 | 278 | 294 | 330 | 371 | 416 |
B | 248 | 278 | 294 | 330 | 371 | 416 | 467 |
C | 131 | 147 | 165 | 175 | 196 | 221 | 248 |
D | 147 | 165 | 175 | 196 | 221 | 248 | 278 |
E | 165 | 175 | 196 | 221 | 248 | 278 | 312 |
F | 175 | 196 | 221 | 234 | 262 | 294 | 330 |
G | 196 | 221 | 234 | 262 | 294 | 330 | 371 |
音符→ 音调↓ |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
A | 441 | 495 | 556 | 589 | 661 | 742 | 833 |
B | 495 | 556 | 624 | 661 | 742 | 833 | 935 |
C | 262 | 294 | 330 | 350 | 393 | 441 | 495 |
D | 294 | 330 | 350 | 393 | 441 | 495 | 556 |
E | 330 | 350 | 393 | 441 | 495 | 556 | 624 |
F | 350 | 393 | 441 | 495 | 556 | 624 | 661 |
G | 393 | 441 | 495 | 556 | 624 | 661 | 742 |
音符→ 音调↓ |
1# | 2# | 3# | 4# | 5# | 6# | 7# |
A | 882 | 990 | 1112 | 1178 | 1322 | 1484 | 1665 |
B | 990 | 1112 | 1178 | 1322 | 1484 | 1665 | 1869 |
C | 525 | 589 | 661 | 700 | 786 | 882 | 990 |
D | 589 | 661 | 700 | 786 | 882 | 990 | 1112 |
E | 661 | 700 | 786 | 882 | 990 | 1112 | 1284 |
F | 700 | 786 | 882 | 935 | 1049 | 1178 | 1322 |
G | 786 | 882 | 990 | 1049 | 1178 | 1322 | 1484 |
看明白简谱和频率表就开始写程序啦,首先宏定义曲目要用到的音符频率
//中音NTF 0为空拍
#define NTF0 -1
#define NTF1 350
#define NTF2 393
#define NTF3 441
#define NTF4 495
#define NTF5 556
#define NTF6 624
#define NTF7 661
//高音NTFH
#define NTFH1 700
#define NTFH2 786
#define NTFH3 882
#define NTFH4 935
#define NTFH5 965
#define NTFH6 996
#define NTFH7 1023
//低音NTFL
#define NTFL1 175
#define NTFL2 196
#define NTFL3 221
#define NTFL4 234
#define NTFL5 262
#define NTFL6 294
#define NTFL7 330
按照Jingle Bells简谱定义音符数组
//音符频率数组
int tune[]=
{
NTF3,NTF3,NTF3,NTF3,NTF3,NTF3,
NTF3,NTF5,NTF1,NTF2,NTF3,NTF0,
NTF4,NTF4,NTF4,NTF4,NTF4,NTF3,NTF3,NTF3,NTF3,
NTF5,NTF5,NTF4,NTF2,NTF1,NTF0,
NTFL5,NTF3,NTF2,NTF1,NTFL5,NTF0,NTFL5,NTFL5,
NTFL5,NTF3,NTF2,NTF1,NTFL6,NTF0,
NTFL6,NTF4,NTF3,NTF2,NTFL7,NTF0,
NTF5,NTF5,NTF4,NTF2,NTF3,NTF1,NTF0,
NTFL5,NTF3,NTF2,NTF1,NTFL5,NTF0,
NTFL5,NTF3,NTF2,NTF1,NTFL6,NTF0,NTFL6,
NTFL6,NTF4,NTF3,NTF2,NTF5,NTF5,NTF5,NTF5,
NTF6,NTF5,NTF4,NTF2,NTF1,NTF0
};
按简谱定义音符节拍数组
//音符节拍数组
float durt[]=
{
0.5,0.5,1,0.5,0.5,1,
0.5,0.5,0.75,0.25,1.5,0.5,
0.5,0.5,1,0.5,0.5,0.5,0.5,0.25,0.25,
0.5,0.5,0.5,0.5,1.5,0.5,
0.5,0.5,0.5,0.5,1,0.5,0.25,0.25,
0.5,0.5,0.5,0.5,1,1,
0.5,0.5,0.5,0.5,1,1,
0.5,0.5,0.5,0.5,1,0.75,0.25,
0.5,0.5,0.5,0.5,1,1,
0.5,0.5,0.5,0.5,1,0.5,0.5,
0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,
0.5,0.5,0.5,0.5,0.75,0.25
};
接着是主题函数部分
//定义蜂鸣器引脚,音符长度变量
int buzzer_pin = 9;
int length;
//setup函数,初始化引脚,计算长度
void setup()
{
pinMode(buzzer_pin, OUTPUT);
length = sizeof(tune)/sizeof(tune[0]);
}
//loop函数
void loop()
{
//for循环演奏曲子
for(int x=0;x<length;x++)
{
tone(buzzer_pin, tune[x]);
delay(500*durt[x]); //这里的500为控制每个音符的时长来定曲子的节奏
noTone(buzzer_pin);
}
delay(500); //开始下一轮循环的时间间隔
}
程序对于蜂鸣器单独演奏曲子来说简短有效,对于在曲子演奏中间要一边做点其他事情,可能就有些些麻烦了
圣诞节案例肯定不能少了圣诞树不是嘛,这种圣诞树小装饰在某宝上十几二十块就能买到带带灯的,我手头就搞了一个出来,店家给的蚊帐布一样的原材料要自己动手,也是花了不少时间搞,主要是灯带的固定很是头疼,下面看一下效果图,还是可以接受的
商家随机给的颜色布料,粉色的,老夫也是无奈,还有圈上彩灯后的效果,还怪不错的咧
是吧,节日一摆上那是很有气氛了,还给了些圣诞鞋小挂饰什么的,没给弄上去,两节5号电池供电,常亮状态,为了能达到彩灯控制效果,我把线剪了接到arduino控制的继电器上面,通过继电器控灯,程序也写了,以最原始的方式,另外加了OLED屏幕的节日祝福显示,具体代码如下
#include
//引脚定义
int buzzer_0 = 5;
int relay_0 = 12;
U8GLIB_SSD1306_128X64 u8g_0(U8G_I2C_OPT_NONE);
//setup函数
void setup() {
pinMode(buzzer_0, OUTPUT);
pinMode(relay_0, OUTPUT);
//OLED屏幕显示 Merry Christmas
u8g_0.firstPage();
do {
u8g_0.setFont(u8g_font_9x18);
u8g_0.drawStr(5, 30, "Merry");
u8g_0.drawStr(40, 55, "Christmas");
} while (u8g_0.nextPage());
}
//loop函数
void loop() {
tone(buzzer_0, 441, 0); // T1-1
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(480);
noTone(buzzer_0);
digitalWrite(relay_0, HIGH);
tone(buzzer_0, 441, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(230);
noTone(buzzer_0);
digitalWrite(relay_0, LOW);
tone(buzzer_0, 441, 0); // T1-2
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 556, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 350, 0);
delay(0);
delay(355);
noTone(buzzer_0);
digitalWrite(relay_0, HIGH);
tone(buzzer_0, 393, 0);
delay(0);
delay(125);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(750);
noTone(buzzer_0);
tone(buzzer_0, -1, 0);
delay(0);
delay(230);
noTone(buzzer_0);
digitalWrite(relay_0, LOW);
tone(buzzer_0, 495, 0); // T1-3
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 495, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 495, 0);
delay(0);
delay(500);
noTone(buzzer_0);
tone(buzzer_0, 495, 0);
delay(0);
delay(230);
noTone(buzzer_0);
digitalWrite(relay_0, HIGH);
tone(buzzer_0, 495, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(125);
noTone(buzzer_0);
tone(buzzer_0, 441, 0);
delay(0);
delay(105);
noTone(buzzer_0);
digitalWrite(relay_0, LOW);
tone(buzzer_0, 556, 0); // T1-4
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 556, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 495, 0);
delay(0);
delay(230);
noTone(buzzer_0);
digitalWrite(relay_0, HIGH);
tone(buzzer_0, 393, 0);
delay(0);
delay(250);
noTone(buzzer_0);
tone(buzzer_0, 350, 0);
delay(0);
delay(750);
noTone(buzzer_0);
tone(buzzer_0, -1, 0);
delay(0);
delay(230);
noTone(buzzer_0);
... //此处省略200+行重复代码
delay(1500); //循环演奏的时间间隔
}
上述代码只取了完整曲子的1/3段,因为每个音符都是以tone函数,delay函数,noTone函数的形式在循环,4个小段加起来30个音符左右,还有OLED显示和继电器控制的程序前前后后140行代码左右,全曲82个音符总370行代码,也是敲得心累,上面把后边200+行的重复函数代码省略了,只是频率跟延时不同。
案例扩展实现了简介控制圣诞树灯光闪烁,其实个人觉得接PWM引脚做成呼吸灯效果会更棒,也不用听继电器在滴答滴答叫,这个就看你们个人的idea了,分享到这,下回见~