Arduino 播放音乐的原理
需要用到的材料:adruino uno一块(其他Arduino板子也可,注意引脚就行),面保线若干条,蜂鸣器或小喇叭一个。
首先讲下简单的乐理知识,知道音乐是怎么演奏出来的自然就可以通过代码来进行编排了。
1.演奏单音符
一首乐曲有若干音符组成,一个音符对应一个频率。我们知道到相对应的频率让 Arduino 输出到蜂鸣器,蜂鸣器就会发出相应频率下的声音。Arduino官方网站给出了不同音符对应的不同频率的头文件,具体请见下文介绍。
2.音符的演奏时间
每个音符都会播放一定的时间,这样才能构成一首优美的曲子,而不是每个音符都播放一样长的时间。如何确定每个音符演奏的单位时间呢?我们知道,音符节奏分为1拍、1/2拍、1/4拍、1/8拍,我们规定一拍音符的时间为1;半拍为0.5;1/4拍为0.25;1/8拍为0.125……,所以我们可以为每个音符赋予这样的拍子播放出来,音乐就成了。Arduino已经给出了像样的程序,即 Arduino 的 Tone 库。
我们用它可以帮助我们快速制作音乐。
这是ArduinoTone函数的官方介绍地址:http://arduino.cc/en/Tutorial/Tone,使用函数为Tone():http://arduino.cc/en/Reference/Tone
如果要查看Tone的完整维护记录和使用说明请访问:http://code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
制作方法
所需硬件:Arduino板子一块,小型扬声器一个,导线两根。如果扬声器声音太大,也可适当配置220欧姆电阻一个与扬声器串联。
首先看看官方的例子。
该例子里,我们将扬声器一端串联电阻后接到数字8(D8)接口,另一端接地(GND)。接线原理图如下:
接好线之后,将以下代码粘贴到Arduino IDE中。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
/* Melody Plays a melody circuit: * 8-ohm speaker on digital pin 8 created 21 Jan 2010 modified 30 Aug 2011 by Tom Igoe This example code is in the public domain. http://arduino.cc/en/Tutorial/Tone */ #include "pitches.h" // notes in the melody: int melody[] = { NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4}; // note durations: 4 = quarter note, 8 = eighth note, etc.: int noteDurations[] = { 4, 8, 8, 4,4,4,4,4 }; void setup() { // iterate over the notes of the melody: for (int thisNote = 0; thisNote < 8; thisNote++) { // to calculate the note duration, take one second // divided by the note type. //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc. int noteDuration = 1000/noteDurations[thisNote]; tone(8, melody[thisNote],noteDuration); // to distinguish the notes, set a minimum time between them. // the note's duration + 30% seems to work well: int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); // stop the tone playing: noTone(8); } } void loop() { // no need to repeat the melody. } |
该程序中使用了这两个函数:
tone(pin, frequency)
tone(pin, frequency, duration)
函数的参数说明:
pin: 你要接扬声器的接口,是整数(int 型)
frequency:频率,是一个整数(int 型)
duration: 音符持续的时间,是毫秒值,无符号长整型( unsigned long 型)
无返回值
我们还注意到上面代码中调用了头文件“pitches.h”。这个文件是什么呢?这个头文件正式上面提到的不同音符对应的不同频率的头文件。该pitches.h文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
/************************************************* * Public Constants *************************************************/ #define NOTE_B0 31 #define NOTE_C1 33 #define NOTE_CS1 35 #define NOTE_D1 37 #define NOTE_DS1 39 #define NOTE_E1 41 #define NOTE_F1 44 #define NOTE_FS1 46 #define NOTE_G1 49 #define NOTE_GS1 52 #define NOTE_A1 55 #define NOTE_AS1 58 #define NOTE_B1 62 #define NOTE_C2 65 #define NOTE_CS2 69 #define NOTE_D2 73 #define NOTE_DS2 78 #define NOTE_E2 82 #define NOTE_F2 87 #define NOTE_FS2 93 #define NOTE_G2 98 #define NOTE_GS2 104 #define NOTE_A2 110 #define NOTE_AS2 117 #define NOTE_B2 123 #define NOTE_C3 131 #define NOTE_CS3 139 #define NOTE_D3 147 #define NOTE_DS3 156 #define NOTE_E3 165 #define NOTE_F3 175 #define NOTE_FS3 185 #define NOTE_G3 196 #define NOTE_GS3 208 #define NOTE_A3 220 #define NOTE_AS3 233 #define NOTE_B3 247 #define NOTE_C4 262 #define NOTE_CS4 277 #define NOTE_D4 294 #define NOTE_DS4 311 #define NOTE_E4 330 #define NOTE_F4 349 #define NOTE_FS4 370 #define NOTE_G4 392 #define NOTE_GS4 415 #define NOTE_A4 440 #define NOTE_AS4 466 #define NOTE_B4 494 #define NOTE_C5 523 #define NOTE_CS5 554 #define NOTE_D5 587 #define NOTE_DS5 622 #define NOTE_E5 659 #define NOTE_F5 698 #define NOTE_FS5 740 #define NOTE_G5 784 #define NOTE_GS5 831 #define NOTE_A5 880 #define NOTE_AS5 932 #define NOTE_B5 988 #define NOTE_C6 1047 #define NOTE_CS6 1109 #define NOTE_D6 1175 #define NOTE_DS6 1245 #define NOTE_E6 1319 #define NOTE_F6 1397 #define NOTE_FS6 1480 #define NOTE_G6 1568 #define NOTE_GS6 1661 #define NOTE_A6 1760 #define NOTE_AS6 1865 #define NOTE_B6 1976 #define NOTE_C7 2093 #define NOTE_CS7 2217 #define NOTE_D7 2349 #define NOTE_DS7 2489 #define NOTE_E7 2637 #define NOTE_F7 2794 #define NOTE_FS7 2960 #define NOTE_G7 3136 #define NOTE_GS7 3322 #define NOTE_A7 3520 #define NOTE_AS7 3729 #define NOTE_B7 3951 #define NOTE_C8 4186 #define NOTE_CS8 4435 #define NOTE_D8 4699 #define NOTE_DS8 4978 |
可以看到,这是一张类似表格的东西,里面是定义的大量的宏,即用宏名代替了频率名,对应到键盘的各个按键上。可是,不懂音乐的我们如何能够取出我们所要的音符对应的宏名呢?
首先看看钢琴大谱表与钢琴琴键的对照表:
从上图我们可以将各音符的音名直观的看出来,但是,我又只会简谱,如何看呢?为了方便我自己,也希望能方便大家,我将其制作为了直观的表格,见下图:(如需要Excel格式文件的请留言联系我)
上图辛苦的制作过程:
对照上面的表格,我们就能制作自己的音乐了。
自己的作品——播放生日快乐歌
最近老婆要过生日,我打算用Arduino为她做一首生日快乐送给她。(发布这篇文章的时候生日已经过了,不想早发布是怕她看见了,惊喜就没那么大了,嘿嘿!)
首先找到生日快乐的简谱:
可以看到其节拍是3/4,但是我按照其节拍做下来之后觉得唱的太慢了,就没按照它的来。(灵活处理嘛)
再对照上表,制作其旋律函数为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
int melody[] = { NOTE_G4,//5 NOTE_G4,//5 NOTE_A4,//6 NOTE_G4,//5 NOTE_C5,//1. NOTE_B4,//7 0, NOTE_G4,//5 NOTE_G4,//5 NOTE_A4,//6 NOTE_G4,//5 NOTE_D5,//2. NOTE_C5,//1. 0, NOTE_G4,//5 NOTE_G4,//5 NOTE_G5,//5. NOTE_E5,//3. NOTE_C5,//1. NOTE_B4,//7 NOTE_A4,//6 0, NOTE_F5,//4. NOTE_F5,//4. NOTE_E5,//3. NOTE_C5,//1. NOTE_D5,//2. NOTE_C5,//1. 0, }; |
持续时间函数为:(注意休止符也需要时间的)
1 2 3 4 5 6 7 8 9 10 |
int noteDurations[] = { 8,8,4,4,4,4, 4, 8,8,4,4,4,4, 4, 8,8,4,4,4,4,2, 8, 8,8,4,4,4,2, 4, }; |
可以直接把上面的两个函数覆盖官方的例子,写入Arduino就行了,可以灵活的修改修改接口。不过,为了更好看起见,我添加了3个彩色自闪LED灯,一闪一闪的很好看,我想老婆会更喜欢的。所以,稍微添加了几行代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
/* Happy Birthday Tone for Daner. Made by TAHO on 6th,Nov. 2013 taholab.com tahoroom@163.com version 1.0 */ #include "pitches.h" /*将D8口用作输出*/ #define AUDIO_PIN 8 void setup() { // iterate over the notes of the melody: pinMode(9,OUTPUT);//for light pinMode(10,OUTPUT);//for light pinMode(11,OUTPUT);//for light } void loop() { // no need to repeat the melody. ColorLight();//Turn on the lights play();//Play the music. delay(300);//Pause for a while. } // notes in the melody: int melody[] = { NOTE_G4,//5 NOTE_G4,//5 NOTE_A4,//6 NOTE_G4,//5 NOTE_C5,//1. NOTE_B4,//7 0, NOTE_G4,//5 NOTE_G4,//5 NOTE_A4,//6 NOTE_G4,//5 NOTE_D5,//2. NOTE_C5,//1. 0, NOTE_G4,//5 NOTE_G4,//5 NOTE_G5,//5. NOTE_E5,//3. NOTE_C5,//1. NOTE_B4,//7 NOTE_A4,//6 0, NOTE_F5,//4. NOTE_F5,//4. NOTE_E5,//3. NOTE_C5,//1. NOTE_D5,//2. NOTE_C5,//1. 0, }; int noteDurations[] = { 8,8,4,4,4,4, 4, 8,8,4,4,4,4, 4, 8,8,4,4,4,4,2, 8, 8,8,4,4,4,2, 4, }; void play() { for (int thisNote = 0; thisNote < 29; thisNote++) { // to calculate the note duration, take one second // divided by the note type. //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc. int noteDuration = 1000/noteDurations[thisNote]; tone(AUDIO_PIN, melody[thisNote],noteDuration); // to distinguish the notes, set a minimum time between them. // the note's duration + 30% seems to work well: int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); // stop the tone playing: noTone(8); } } void ColorLight() { digitalWrite(9, HIGH); digitalWrite(10, HIGH); digitalWrite(11, HIGH); } |
pitches.h 文件就不用再修改了。
成品出来了!看图!(为了她好拿,我用了拓展盾板,底下再粘上了一块 9V 电池,其实很简单的。本打算做个最小电路给她,由于一些原因没有及时买到晶振材料,因此作罢。)
看视频!
更多图:
老婆好高兴,她非常满意!拿去给朋友炫耀了,哈哈!
感谢楼主,我也想用tone函数让arduino唱歌,楼主的文章很给力,请问可否共享excel文件?谢谢!
jxndlym@foxmail.com
预祝楼主新年快乐。
谢谢,也祝你新年快乐!Excel文件已经发送到你的邮箱,希望能帮到你。
您好~可以共享一下您的Excel对照表吗?
www@stu.xmu.edu.cn,万分感谢!
不用客气,已经发送,请查收。
有这样的老公真幸福,羡慕中。。。。
嘿嘿,谢谢夸奖!!
这个的程序的作者,请问可以留下邮件吗?
我是新手希望你可以教我下这个程序的一些疑问。谢谢
我的邮箱是tahoroom@163.com,我也在学习,欢迎交流!
不错,兄弟
多谢支持!
老公,我很喜欢,你太棒了
哈哈哈哈!老婆喜欢就好,做的一般般啦~~