目录
蜂鸣器播放提示音
蜂鸣器播放音乐(天空之城)
准备工作
主程序
中断函数
上一节讲了蜂鸣器驱动原理和乐理基础知识,这一节开始代码演示!
先创建工程:蜂鸣器播放提示音
把我们之前模块化的程序文件添加进来
但是这次我们 是要静态显示,所以要把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)
- 想要的频率在最左边,然后我们不能直接产生频率,我们只有周期,1除以频率就是周期。
- 我们需要半个周期给它翻转一次,翻转两次才是一个周期,所以翻转频率就是周期除以2,把这个频率取整就是我们的计数值(需要计这么多的数值然后就产生中断)。
- 那么它怎么计这么长呢?溢出才能产生中断对吧?我们就需要给它提前装好中间值(重装载值),在这个值开始计,计到65536溢出就产生中断了。
- 为了方便找到对应的音符,我们给这些音符弄个索引,相当于编号。
(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口
}
}
效果请看视频:
蜂鸣器播放音乐
蜂鸣器播放音乐部分完成!
本节的源码放在评论区了,自取!
如有问题,可评论区留言!
你可能感兴趣的:(51单片机学习笔记,单片机,学习,物联网,mcu,51单片机,嵌入式硬件)