赞
踩
目录
上一节讲了蜂鸣器驱动原理和乐理基础知识,这一节开始代码演示!
先创建工程:蜂鸣器播放提示音
把我们之前模块化的程序文件添加进来
但是这次我们 是要静态显示,所以要把Nixie.c文件中这里删掉
我们要实现的效果是我们按下按键之后,会出现按键提示音。
创建一个Buzzer.c和Buzzer.h文件
具体代码解释请看注释:
Buzzer.c
- #include <REGX52.H>
- #include <INTRINS.H>//_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<ms*2;i++)//一个for循环500us=0.5ms,x*0.5ms*2延时xms
- {
- Buzzer=!Buzzer;//翻转蜂鸣器
- //蜂鸣器的标准提示音是1000Hz
- Buzzer_Delay500us();//每500us=0.5ms翻转一次,那蜂鸣响的周期就是1000Hz
- }
- }

Buzzer.h
- #ifndef __BUZZER_H__
- #define __BUZZER_H__
-
- void Buzzer_Time(unsigned int ms);
-
- #endif
main.c
- #include <REGX52.H>
- #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口
- }
- }
效果请看视频:
蜂鸣器播放音乐
蜂鸣器播放音乐部分完成!
本节的源码放在评论区了,自取!
如有问题,可评论区留言!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。