简介
使用单片机的蜂鸣器模拟钢琴声进而播放出完整乐曲,2点要素:1.单片机使用无源蜂鸣器,2.如何识别乐谱,并转化为单片机可识别的信号,无源蜂鸣器可以实现不同频率的音调,而音乐,最重要的是搞懂音调和节拍,音调我们知道就是不同频率的高低→蜂鸣器改变频率,节拍就是时长→单片机的定时器可以实现毫秒级定时。万事俱备,开工。
硬件条件
蜂鸣器是一种将电信号转化为声音信号的器件,常用来产生设备的按键音、报警音等提示音。
按照驱动方式可以分为有源蜂鸣器和无源蜂鸣器。
有源蜂鸣器:内部自带震荡源,将正负极接上直流电压即可持续发生,频率固定;
无源蜂鸣器:内部不带震荡源,需要控制器提供震荡脉冲才可发声,调整提供震荡脉冲的频率,可发出不同频率的声音。
我们想要控制频率来实现歌曲的音调,所以选用的是无源蜂鸣器。
由于蜂鸣器的工作电流一般比较大,以致于单片机的I/O 口是无法直接驱动的*(但AVR可以驱动小功率蜂鸣器),所以要利用放大电路来驱动,一般使用三极管来放大电流就可以了。
上图是普中51单片机开发板的原理图,J7连接的是芯片的一个I/O口。可以看到,当 J7 端子有一个高电平进来时,PNP 三极管TP1截止,蜂鸣器(BZ1)不得电,当 J7 端子有一个低电平进来时,PNP 三极管TP1 导通,蜂鸣器得电,如果 J7 端子有一个一定频率的脉冲信号(高低电平不断翻转)时,这个无源蜂鸣器发出声音。
硬件基础完毕,接下来是软件编程。
软件条件
想要编程,就得知道音乐是怎么产生的。
首先,我们拿到一张谱子,然后看谱,当我们识别完乐谱后,按照乐谱用手操纵乐器从头到尾按顺序演奏完毕。
所以首先识谱,分辨出音调和节拍。
不过音乐的基本知识就不为难自己了,我是个音乐白痴。。所以我就这么理解了…
隐约记得音乐课上似乎讲过do、re、mi、fa、sol、la、si、do…
OK,百度了下,钢琴键盘与五线谱、简谱音高对照表,本次使用简谱。
钢琴按键音调
从上图看到,最上面一排是钢琴键盘,左边的音名那里,我们看到钢琴键盘上是CDEFGABC,然后小写字母再循环一遍,然后小写字母加上标再循环一遍,分别叫做大字组,小字组,小字一组,小字二组,以此类推,每组分别是7个白键+5个黑键。其中,大写字母C和小写字母c、c1、c2等相差8度,而钢琴的黑键和白键相差半音,乐谱符号“#”代表升音,“b”代表降音。
引用百度的回答:在音乐中,一个音就叫一度,音阶1234567中,1到2就是两度(有大二度,小二度之分),1到3就是三度(大三度、小三度),。。。。1到7就是七度,而从中音1到高音1就是一个八度。 那么我们就可以说高音1比中音1高一个八度。这就是“一个音比另一个音高八度”的意思。
从上图中可以看出,其实就是7个音调,然后按照音量高低被命名为不同组(大字组、小字组…),加上黑白键相差的高/低半音,一组可以有7+5=12个音调,这12个音调有个人工规律,叫十二平均律,音调对应频率的关系为等比数列,推导如下:
条件1:相隔纯八度的两个音,它们的频率比值是1比2,不是其他的比值
条件2:十二平均律的原理就是将相隔纯八度的两音之间,划分为十二份,每相邻的两个音,其比值要相同,才能称之为平均,注意,是比值,而不是差值
要满足条件1与2,则这个比值只能是2开12次方
我们知道,要做比较必定有基准。国际通用的标准音定义a1=440HZ,以C调为例,其音调和频率关系如下:
根据公式T(周期)=1/f(频率),频率我们已经确定了,就可以使用单片机的定时器做出不同频率的音调了,接下来就是节拍(时长)的实现了。
节拍
乐谱的左上方有写“1=C 4/4”,其中“1=C”意思就是乐谱是C调,乐谱里面的1234567(do、re、mi、fa、sol、la、si)相对应的不是ABCDEFG而是CDEFGAB!而如果这里规定是F调的话,那么就说明1唱F,2就要唱G,3要唱A,……7要唱E,就是所谓的要相应的左移或者右移,以此类推。
“4/4”叫作拍号,图中从下往上读,意思是以四分音符为一拍,每小节四拍。每拍的时间应该多长,在音乐上一般用BPM(beats per minute,每分钟多少拍)来标识。演奏时其实不用真的去追求严格意义上的拍长,感觉对了就行了。就像炒菜一样,淡一点就是少放点盐,不用真的去称出精准的 1.34 克来~
在五线谱中,会注明每分钟的拍数,
OK,现在已经有了一拍的时间长度了,不过肯定是不够用的,如果想表示半拍,或者1/4拍,或者 2 拍、4拍,那该怎么办?
在给出答案前,我们得先学习一个新的东西:音符时值。
音符时值是个相对时长的单位,它的参考系是拍长,我们先来了解一下各种音符时值的表示符号:
- 全音符 = 2 * 二分音符 :一个空心圆
- 二分音符 = 2 * 四份音符 :空心圆带一条杠
- 四分音符 = 2 * 八分音符号 :实心圆带一条杠
- 八分音符 = 2 * 十六分音符 : 符尾一条线
- 十六分音符 = 2 * 三十二分音符:符尾两条线
以上都是二分关系,那如果是 1.5 倍关系怎么搞?音乐家们使用附点音符的概念来解决这个问题。
这个点表示增加原来时长的一半,而减少时长的线是加在音符下面的,叫减时线,每增加一条减时线,时值减少二分之一。
这样音乐的时长问题就解决了,从上面再看一遍,时长是2倍关系,和二进制一样,太好了,大道至简,殊途同归。
程序
基本思想是把12个音调的频率做成一张表,按照简谱在程序中调用对应频率,并乘以相应音符时值,这样一首曲子就出来了。
下面是来自B站江协科技的程序,可以作为固定模板使用,只需要更改SPEED和unsigned char code Music[]部分即可,SPEED就是节拍,另一个是我们从简谱上得出的音符和时值,程序其它部分不用改动。嗯,音乐完成。
1 | #include <REGX52.H> |