1.简介
蜂鸣器是一种将电信号转换为声音信号的器件,常用来产生设备的按键音、报警音等提示信号。
蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器。
有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定。
无源蜂鸣器:内部不带振荡源,需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音。
如果需要实现演奏音乐的功能,需要使用无源蜂鸣器。
2.硬件实现方式
在普中A2开发板中通过ULN2003D与蜂鸣器本体实现发声,下面两张图分别是ULN2003D与蜂鸣器的引脚图:
蜂鸣器演奏音乐设计思路/2-1.png)
蜂鸣器演奏音乐设计思路/2-2.png)
从图中可以看到,ULN2003D的一个引脚与蜂鸣器的BZ口连接,我们只要控制该引脚电平翻转频率就可以就控制蜂鸣器发出对应频率的声音。需要注意的是图中有误,对应控制BZ的引脚并非P15口,实际上为P25口。
3.代码实现逻辑
我们通过定时器来控制不同频率的声音的发出。
以C大调为基准,中音6的基准频率为440Hz,每半音以此乘除2^(1/12)倍,取整后得到低中高三个八度的全体音符赫兹对照表。
由于我们一个完整的周期要先给一个上升沿,再给一个下降沿,因此假设tms翻转一次,2tms为一个周期,频率f=1/(2t)。
即经过10^6/(2f)个脉冲周期,每次需要发生时就使定时器隔tms翻转一次P25口
由于系统晶振频率为11.0592MHz,在12分频以后每隔12/11.0592μs脉冲一次,即脉冲周期为:12/11.0592μs。。
两者相乘,得到最终的时间为:11059200/(12*2*f)。
重载值为:65535-11059200/(12*2*f)。
将所有音调对应的重载值计算取整后,存入数组中,取名为FreqTable,在定时器中断中只需要调用对应的重载值即可发出对应频率的声音。FreqTable[0]为休止符,增加判断条件可以使定时器空过实现休止功能:
1 | unsigned int FreqTable[]={ |
同时,定义一个数组,(加上code关键字防止内存占用过大),取名为Music,用于存放乐谱。即FreqTable中对应的音调重载值索引。为了方便编写,可以事先宏定义好各音调对应的重载值索引,如:
1 |
|
Music数组的格式为:音符,时值,音符,时值,……,音符,时值,0xFF。
在主函数中,我们使用如下代码来实现乐谱演奏的逻辑:
1 | unsigned char FreqSelect,MusicSelect; |
FreqSelect用于选择频率,其值为Music[MusicSelect],即Music数组中的重载值索引。例如:MusicSelect=0时,FreqSelect=Music[0](选中音符)。
然后MusicSelect++(此时Music[MusicSelect]为选中音符对应的时长)。Delay的时长由SPEED/4*Music[MusicSelect]决定。
由此就完成了“演奏指定音符指定时长”的功能。
再对定时器进行一次开关,实现同音调中间的间隔。
而在定时器中断函数中,我们使用如下代码来实现控制音调的逻辑:
1 | void Timer0_Routine() interrupt 1 |
此时的定时器仅用于发出不同频率的声音,与“间隔多长时间演奏下一个音符”无关。我们通过主函数可以知道,Delay(SPEED/4*Music[MusicSelect]);
实现了“间隔多长时间演奏下一个音符”的功能,当过了对应的时长后会对定时器进行一次重启,该定时器就会根据重启后的重载值:FreqTable[FreqSelect]发出对应频率的声音。
4.“シリウスの心臓”对应的Music数组
下面给出シリウスの心臓对应的Music数组:
1 | unsigned char code Music[]={ |
不知道什么原因,当程序运行到第34小节时会重新回到第一小节循环,该原因还有待探明。