目录
蜂鸣器播放提示音
蜂鸣器播放音乐(天空之城)
准备工作
主程序
中断函数
上一节讲了蜂鸣器驱动原理和乐理基础知识,这一节开始代码演示!
先创建工程:蜂鸣器播放提示音
把我们之前模块化的程序文件添加进来
但是这次我们 是要静态显示,所以要把Nixie.c文件中这里删掉
我们要实现的效果是我们按下按键之后,会出现按键提示音。
创建一个Buzzer.c和Buzzer.h文件
具体代码解释请看注释:
Buzzer.c
#include
#include //_nop_函数的头文件
//蜂鸣器端口:普中A2的板子是P2^5,其他板子的可以试试P1^5
sbit Buzzer=P2^5;
//在博主以后的博客中,这个函数就作为蜂鸣器的私有延时函数
void Buzzer_Delay500us() //@12.000MHz
{
unsigned char i;
_nop_();//延时一微秒的函数
i = 247;
while (--i);
}
//蜂鸣器的发声时长函数
void Buzzer_Time(unsigned int ms)
{
unsigned int i;//蜂鸣器翻转的次数
for(i=0;i
Buzzer.h
#ifndef __BUZZER_H__
#define __BUZZER_H__
void Buzzer_Time(unsigned int ms);
#endif
main.c
#include
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Buzzer.h"
unsigned char KeyNum;
void main()
{
Nixie(1,0);//第一位数码管显示0
while(1)
{
KeyNum=Key();//按键按下后将键码赋值给keyNum
if(KeyNum)//如果按键按下
{
Buzzer_Time(100);//蜂鸣器响100ms
Nixie(1,KeyNum);//第1位数码管,显示键码
}
}
}
效果请看视频:
蜂鸣器播放提示音
以上就是蜂鸣器播放提示音的代码演示!
接下来开始演示蜂鸣器播放音乐(天空之城)
开始之前,我们先接着上一篇解释一下这张表格(我们之后都叫它表1)
(PS:手机页面请把表格往左滑动就可看到重装载值)
表1:
音符 |
频率(Hz) |
周期(us) |
周期/2(us) |
取整 |
重装载值 |
索引 |
1 |
262 |
3816.793893 |
1908.396947 |
1908 |
63628 |
1 |
1# |
277 |
3610.108303 |
1805.054152 |
1805 |
63731 |
2 |
2 |
294 |
3401.360544 |
1700.680272 |
1701 |
63835 |
3 |
2# |
311 |
3215.434084 |
1607.717042 |
1608 |
63928 |
4 |
3 |
330 |
3030.30303 |
1515.151515 |
1515 |
64021 |
5 |
4 |
349 |
2865.329513 |
1432.664756 |
1433 |
64103 |
6 |
4# |
370 |
2702.702703 |
1351.351351 |
1351 |
64185 |
7 |
5 |
392 |
2551.020408 |
1275.510204 |
1276 |
64260 |
8 |
5# |
415 |
2409.638554 |
1204.819277 |
1205 |
64331 |
9 |
6 |
440 |
2272.727273 |
1136.363636 |
1136 |
64400 |
10 |
6# |
466 |
2145.922747 |
1072.961373 |
1073 |
64463 |
11 |
7 |
496 |
2016.129032 |
1008.064516 |
1008 |
64528 |
12 |
1 |
523 |
1912.045889 |
956.0229446 |
956 |
64580 |
13 |
1# |
554 |
1805.054152 |
902.5270758 |
903 |
64633 |
14 |
2 |
587 |
1703.577513 |
851.7887564 |
852 |
64684 |
15 |
2# |
622 |
1607.717042 |
803.8585209 |
804 |
64732 |
16 |
3 |
659 |
1517.450683 |
758.7253414 |
759 |
64777 |
17 |
4 |
698 |
1432.664756 |
716.3323782 |
716 |
64820 |
18 |
4# |
740 |
1351.351351 |
675.6756757 |
676 |
64860 |
19 |
5 |
784 |
1275.510204 |
637.755102 |
638 |
64898 |
20 |
5# |
831 |
1203.369434 |
601.6847172 |
602 |
64934 |
21 |
6 |
880 |
1136.363636 |
568.1818182 |
568 |
64968 |
22 |
6# |
932 |
1072.961373 |
536.4806867 |
536 |
65000 |
23 |
7 |
988 |
1012.145749 |
506.0728745 |
506 |
65030 |
24 |
1 |
1046 |
956.0229446 |
478.0114723 |
478 |
65058 |
25 |
1# |
1109 |
901.7132552 |
450.8566276 |
451 |
65085 |
26 |
2 |
1175 |
851.0638298 |
425.5319149 |
426 |
65110 |
27 |
2# |
1245 |
803.2128514 |
401.6064257 |
402 |
65134 |
28 |
3 |
1318 |
758.7253414 |
379.3626707 |
379 |
65157 |
29 |
4 |
1397 |
715.8196135 |
357.9098067 |
358 |
65178 |
30 |
4# |
1480 |
675.6756757 |
337.8378378 |
338 |
65198 |
31 |
5 |
1568 |
637.755102 |
318.877551 |
319 |
65217 |
32 |
5# |
1661 |
602.0469597 |
301.0234798 |
301 |
65235 |
33 |
6 |
1760 |
568.1818182 |
284.0909091 |
284 |
65252 |
34 |
6# |
1865 |
536.1930295 |
268.0965147 |
268 |
65268 |
35 |
7 |
1976 |
506.0728745 |
253.0364372 |
253 |
65283 |
36 |
接下来开始新创建一个工程:蜂鸣器播放音乐(天空之城)
把之前写好的定时器模块和Delay函数模块添加进来
接下来就对本节代码的每一个模块进行讲解,PS:讲解重点在代码的注释里。
为了方便可以重定义端口号(如果最后整个程序写完之后蜂鸣器没有响,那么请看看自己的板子是不是普中的A2开发板,如是,则要把P1^5改成P2^5):
//蜂鸣器端口定义
sbit Buzzer=P1^5;
乐理zhonggu,一个四分音符所用时间是500ms,重定义四分音符的时间,把500ms重命名为Speed:
//播放速度,值为四分音符的时长(ms)
#define SPEED 500
然后我们把表1上的音符与索引重定义:
//音符与索引对应表,P:休止符,L:低音,M:中音,H:高音,下划线:升半音符号#
#define P 0
#define L1 1
#define L1_ 2
#define L2 3
#define L2_ 4
#define L3 5
#define L4 6
#define L4_ 7
#define L5 8
#define L5_ 9
#define L6 10
#define L6_ 11
#define L7 12
#define M1 13
#define M1_ 14
#define M2 15
#define M2_ 16
#define M3 17
#define M4 18
#define M4_ 19
#define M5 20
#define M5_ 21
#define M6 22
#define M6_ 23
#define M7 24
#define H1 25
#define H1_ 26
#define H2 27
#define H2_ 28
#define H3 29
#define H4 30
#define H4_ 31
#define H5 32
#define H5_ 33
#define H6 34
#define H6_ 35
#define H7 36
其中0在乐谱上表示休止符,表示不弹,这里是没有声音的
然后根据表1上的频率和索引弄成一个数组:
//索引与频率对照表
unsigned int FreqTable[]={
0,//休止符,表示不弹
63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,
64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,
65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283,
};
接下来我们就把天空之城的乐谱中的每一个音符放进一个数组中
这是《天空之城》的乐谱:
这里我们定义十六分音符为1个时长(125ms),则八分音符就是2个时长,四分音符就是4个时长(500ms),二音符就是8个时长,全音符就是16个时长。时长即下面写的时值。
//乐谱
unsigned char code Music[]={
//音符,时值,
//1
P, 4,
P, 4,
P, 4,
M6, 2,
M7, 2,
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
M7, 4+4+4,
M3, 2,
M3, 2,
//2
M6, 4+2,
M5, 2,
M6, 4,
H1, 4,
M5, 4+4+4,
M3, 4,
M4, 4+2,
M3, 2,
M4, 4,
H1, 4,
//3
M3, 4+4,
P, 2,
H1, 2,
H1, 2,
H1, 2,
M7, 4+2,
M4_,2,
M4_,4,
M7, 4,
M7, 8,
P, 4,
M6, 2,
M7, 2,
//4
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
M7, 4+4+4,
M3, 2,
M3, 2,
M6, 4+2,
M5, 2,
M6, 4,
H1, 4,
//5
M5, 4+4+4,
M2, 2,
M3, 2,
M4, 4,
H1, 2,
M7, 2+2,
H1, 2+4,
H2, 2,
H2, 2,
H3, 2,
H1, 2+4+4,
//6
H1, 2,
M7, 2,
M6, 2,
M6, 2,
M7, 4,
M5_,4,
M6, 4+4+4,
H1, 2,
H2, 2,
H3, 4+2,
H2, 2,
H3, 4,
H5, 4,
//7
H2, 4+4+4,
M5, 2,
M5, 2,
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
H3, 4+4+4+4,
//8
M6, 2,
M7, 2,
H1, 4,
M7, 4,
H2, 2,
H2, 2,
H1, 4+2,
M5, 2+4+4,
H4, 4,
H3, 4,
H3, 4,
H1, 4,
//9
H3, 4+4+4,
H3, 4,
H6, 4+4,
H5, 4,
H5, 4,
H3, 2,
H2, 2,
H1, 4+4,
P, 2,
H1, 2,
//10
H2, 4,
H1, 2,
H2, 2,
H2, 4,
H5, 4,
H3, 4+4+4,
H3, 4,
H6, 4+4,
H5, 4+4,
//11
H3, 2,
H2, 2,
H1, 4+4,
P, 2,
H1, 2,
H2, 4,
H1, 2,
H2, 2+4,
M7, 4,
M6, 4+4+4,
P, 4,
0xFF //终止标志,防止数组越界之后乱音,用一个最大值来做一个终止标志,也可以设别的值
};
定义两个变量
//FreSelect就是FreqTable[]中的元素的下标,
//MusicSelect就是Music[]中的元素下标
unsigned char FreqSelect,MusicSelect;
void main()
{
Timer0Init();//定时器初始化,1ms后溢出调到中断函数中执行中断
//之后每次中断函数执行完之后返回主程序中进入while循环
while(1)
{
if(Music[MusicSelect]!=0xFF) //如果不是停止标志位
{
FreqSelect=Music[MusicSelect]; //选择音符对应的频率
//选择好Music[]里的音符(索引/编号的重定义)之后赋值给FreqTable[]的下标FreqSelect,
//然后在中断函数里就把FreqSelect这个下标对应的重装载值赋值给TL0和TH0,
//也就是让它产生对应的频率即可发出对应的音符
MusicSelect++;//Music[]的下标+1就是该音符的时长的下标
Delay(SPEED/4*Music[MusicSelect]); //选择音符对应的时值
//SPEED是500ms
//SPEED/4=一个十六分音符的时间125ms
//125ms*Music[MusicSelect]=125ms*时值=某个音符的时长
MusicSelect++;//Music[]的下标+1就是下一个音符的下标
//为了停顿后进入下一次while循环的MusicSelect的初值
TR0=0;//关闭定时器
Delay(5); //音符间短暂停顿
TR0=1;//开启定时器
}
else //如果是停止标志位0xFF
{
TR0=0;//关闭定时器
while(1);//程序就一直停在这里了
}
}
}
//如果不是休止符,定时器初始化后第一次进来时是FreqTable[0]=0,没有出声,
//第二次进来中断函数才真正开始选(重装载值)
void Timer0_Routine() interrupt 1 //中断函数每1ms进来一次
{
if(FreqTable[FreqSelect])
{
/*取对应频率值的重装载值到定时器*/
TL0 = FreqTable[FreqSelect]%256; //设置定时初值
TH0 = FreqTable[FreqSelect]/256; //设置定时初值
Buzzer=!Buzzer; //翻转蜂鸣器IO口
}
}
效果请看视频:
蜂鸣器播放音乐
蜂鸣器播放音乐部分完成!
本节的源码放在评论区了,自取!
如有问题,可评论区留言!