蜂鸣器原理
乐谱说明
#是升半音(右上角)
b为降半音
分为全音符,二分音符,四分音符。。。。
一般四分音符1为500ms,二分音符为1s=1000ms,数字下面加一根线是250ms
以四分音符为一拍,每小节有4拍
右边加一个点,相当于加上半拍
这左上角有个符号,表示需要按下右上角的升音键(#)黑键
上面这条线叫做延音线
C调音符与频率对照表
以a为基准频率是440Hz,左右两边都是倍数关系,中间是按照等比数列进行平分
,
以上一个为基准,然后按照这个公式算出结果(满足:12频分率)
算出周期(s)
因为一个周期是需要上去,再下来
然后就可以算出重装载值
完整代码(蜂鸣器播放提示音)
//main.c #include <REGX52.H> #include "Key.h" #include "Delay.h" #include "Nixie.h" #include "Buzzer.h" unsigned char KeyNum; void main() { while(1){ KeyNum=Key(); if(KeyNum) { Buzzer_Time(1000); Nixie(1,KeyNum); } } }
//Key.c #include <REGX52.H> #include "Delay.h" /** * @brief 获取独立按键码 * @param 无 * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0 */ unsigned char Key() { unsigned char KeyNumber=0; if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;} if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;} if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;} if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;} return KeyNumber; }
//key.h #ifndef __KEY_H__ #define __KEY_H__ unsigned char Key(); #endif
//Delay.c void Delay(unsigned int xms) { while(xms--){ unsigned char data i, j; i = 2; j = 239; do { while (--j); } while (--i); } }
//Delay.h #ifndef __DELAY_H__ #define __DELAY_H__ void Delay(unsigned int xms); #endif
//Buzzer.h #ifndef __BUZZER_H__ #define __BUZZER_H__ void Buzzer_Time(unsigned int time); #endif
//Buzzer.c #include <REGX52.H> #include <INTRINS.H> //蜂鸣器端口: sbit Buzzer=P0^6;//蜂鸣器 /** * @brief 蜂鸣器私有延时函数,延时500us * @param 无 * @retval 无 */ void Buzzer_Delay500us() //@12.000MHz { unsigned char i; _nop_(); i = 247; while (--i); } /** * @brief 蜂鸣器发生 * @param ms 发生的时长 * @retval 无 */ void Buzzer_Time(unsigned int ms){ unsigned int i; for(i=0;i<=ms*2;i++) { Buzzer=!Buzzer; //500us翻转一次,1000Hz Buzzer_Delay500us();//这个是毫秒级的,每格一毫秒翻转一次(高电平一毫秒,低电平一毫秒,一个周期就是两毫秒) } }
//Nixie.h #ifndef __NIXIE_H__ #define __NIXIE_H__ void Nixie(unsigned char Location,Number); #endif
//Nixie.c #include <REGX52.H> #include "Delay.h" unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x7,0x7F,0x6F}; //利用数组,将数字和灯的二进制形式联系起来 /** * @brief 动态显示数码管显示 * @param Location表示位置,范围:1~8。Number表示想要的数字 * @retval */ void Nixie(unsigned char Location,Number){ //利用调用函数(包含位置和数字),让成像更加的方便 switch(Location){ //利用switch函数实现对多重情况的分类 case 1:P2_4=1;P2_3=1;P2_2=1;break; case 2:P2_4=1;P2_3=1;P2_2=0;break; case 3:P2_4=1;P2_3=0;P2_2=1;break; case 4:P2_4=1;P2_3=0;P2_2=0;break; case 5:P2_4=0;P2_3=1;P2_2=1;break; case 6:P2_4=0;P2_3=1;P2_2=0;break; case 7:P2_4=0;P2_3=0;P2_2=1;break; case 8:P2_4=0;P2_3=0;P2_2=0;break; } P0=NixieTable[Number];//输出想要的数字 // Delay(1); // P0_0=0x00; }
完整程序(蜂鸣器播放音乐)
//main.c #include <REGX52.H> #include "Delay.h" #include "Timer0.h" #define SPEED 250//方便修改演唱的速度500为半拍 #define P 0//休止符 #define LL1 1 #define LL1_ 2 #define LL2 3 #define LL2_ 4 #define LL3 5 #define LL4 6 #define LL4_ 7 #define LL5 8 #define LL5_ 9 #define LL6 10 #define LL6_ 11 #define LL7 12 #define L1 13 #define L1_ 14 #define L2 15 #define L2_ 16 #define L3 17 #define L4 18 #define L4_ 19 #define L5 20 #define L5_ 21 #define L6 22 #define L6_ 23 #define L7 24 #define M1 25 #define M1_ 26 #define M2 27 #define M2_ 28 #define M3 29 #define M4 30 #define M4_ 31 #define M5 32 #define M5_ 33 #define M6 34 #define M6_ 35 #define M7 36 #define H1 37 #define H1_ 38 #define H2 39 #define H2_ 40 #define H3 41 #define H4 42 #define H4_ 43 #define H5 44 #define H5_ 45 #define H6 46 #define H6_ 47 #define H7 48 #define HH1 49 #define HH1_ 50 #define HH2 51 #define HH2_ 52 #define HH3 53 #define HH4 54 #define HH4_ 55 #define HH5 56 #define HH5_ 57 #define HH6 58 #define HH6_ 59 #define HH7 60 sbit Bezzer=P2^5;//蜂鸣器的串口 sbit Key1=P3^1; sbit Key2=P3^0; sbit Key3=P3^2; sbit Key4=P3^3; //蜂鸣器各个音符高低音数组,(与定时器连用) unsigned int code FreqTable[]={ 0/*表示休止符*/, 56733,58761,60029,60898,61530,62010,62387,62692,62943,63153,63331,63485, 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, 65290,65300,65310,65318,65327,65334,65341,65348,65354,65359,65365,65370 }; //写入谱子(索引),后面跟的是多少个16分音符,也就是半拍 //梦灯笼 unsigned char code Music1[]={ //1 H1,8+8, L5,2, M1,2, M2,2, M5,2, M1,4, M5,4, //2 M5,8+8, P,4, H1,8+4, //3 M5,4, M1,2, M6,2, M6,2, M5,2, M1,4, L5,2, L6,2, M1,4, L5,4, L4,4, //4 M5,4, M1,2, L7,2, P,4, M1,4, P,2, M1,4, M2,2, M3,2, M5,2, M3,2, //5 L5,8+8, L1,8+8, //6 L4,4, M1,4, M2,4, L5,4, M1,8, L3,2, L4,2, M1,4, //7 L5,8+8, L4,8+8, //8 L1,8+8+8+8, 0xff }; //红色高跟鞋 unsigned char code Music2[]={ //1 P,4, H3,2, H3,2, H3,2, H3,2, H2,4, M7,8, M7,4, H1,4, //2 H1,4, H1,4, M6,4, H1,4, H1,8+8, //3 P,4, H3,2, H3,2, H3,2, H3,2, H2,4, M7,8, M7,4, H1,4, //4 H1,4, H1,4, M6,4, H1,4, H1,8+8, 0xff }; //see you again unsigned char code Music3[]={ //1 M5,4, H2,4, H1,4, M5,4+4, H1,2, H2,2, H3,2, H2,2, H1,2, H2,2, //2 M5,4, H2,4, H1,4, M5,4+4, H1,2, H2,2, H3,2, H2,2, H1,2, H2,2, //3 M5,4, H2,4, H1,4, M5,4+4, H1,2, H2,2, H3,2, H2,2, H1,2, H2,2, //4 M5,4, H2,4, H1,4, M5,4, M1,4, M3,4, M5,4, //5 M6,8+4, M5,4, M5,8, P,8+4, M1,2, //6 M2,4, M2,4, M1,4, M2,4, M3,8, P,4, M3,2, M5,2, //7 M6,4, M7,4, M6,4, M5,4, M3,4, M2,4, M2_,4, M1,4, 0XFF }; 小星星 //unsigned char Music[]={ // 12+1,4, // 12+1,4, // 19+1,4, // 19+1,4, // 21+1,4, // 21+1,4, // 19+1,4+4, // 17+1,4, // 0,4, // 17+1,4, // 16+1,4, // 16+1,4, // 14+1,4, // 14+1,4, // 12+1,4+4, // // 0xFF/*用于结束*/ //}; //晴天 unsigned char code Music4[]={ //1 L3,4, L5,4, M2,4, L5,4, L1,4, L2,2, L3,2, M2,4, L5,4, //2 LL5,4, L2,4, M2,4, L5,4, LL5,4, L2,4, LL4_,4, L2,4, //3 L3,4, L5,4, M2,4, L3,4, L1,4, L2,2, L3,2, M2,4, L5,4, //4 LL5,4, L2,4, M2,4, L5,4, LL5,4, L2,4, LL4_,2, L5,2, L2,4, //5 L3,4, L5,4, M2,4, L5,4, L1,4, L2,2, L3,2, M2,4, L5,4, //6 LL5,4, L2,4, M2,4, L5,4, LL5,4, L2,4, LL4_,4, L2,4, //6 L3,4, L5,4, M2,4, L3,4, L1,4, L2,2, L3,2, M2,4, L5,4, //7 LL5,4, L2,4, M2,4, L5,4, LL5,4, L2,4, LL4_,2, L5,2, L2,4, 0XFF }; unsigned char FreqSelect,MusicSelect;//频率选择 void main(){ Timer0Init(); while(1){ if(Key1==0) { while(Music1[MusicSelect]!=0xff) { FreqSelect=Music1[MusicSelect]; MusicSelect++; Delay(SPEED/4*Music1[MusicSelect]);//以16分音符为基准 MusicSelect++; TR0=0;//模拟抬手 Delay(5); TR0=1; } TR0=0; } if(Key2==0) { while(Music2[MusicSelect]!=0xff) { FreqSelect=Music2[MusicSelect]; MusicSelect++; Delay(SPEED/4*Music2[MusicSelect]);//以16分音符为基准 MusicSelect++; TR0=0;//模拟抬手 Delay(5); TR0=1; } TR0=0; } if(Key3==0) { while(Music3[MusicSelect]!=0xff) { FreqSelect=Music3[MusicSelect]; MusicSelect++; Delay(SPEED/4*Music3[MusicSelect]);//以16分音符为基准 MusicSelect++; TR0=0;//模拟抬手 Delay(5); TR0=1; } TR0=0; } if(Key4==0) { while(Music4[MusicSelect]!=0xff) { FreqSelect=Music4[MusicSelect]; MusicSelect++; Delay(SPEED/4*Music4[MusicSelect]);//以16分音符为基准 MusicSelect++; TR0=0;//模拟抬手 Delay(5); TR0=1; } TR0=0; } } } //定时器中断函数模板 void Timer0_Routine() interrupt 1 { if(FreqTable[FreqSelect])//如果是休止符就不发声 { TL0 = FreqTable[FreqSelect]%256; TH0 = FreqTable[FreqSelect]/256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下 Bezzer=!Bezzer;//直接进行翻转,(1ms,频率=1s/周期=> f=1s/2ms=500hz ) } }
//Timer0.c #ifndef __TIMER0_H__ #define __TIMER0_H__ void Timer0Init(void); //1毫秒@12.000MHz #endif
//Timer0.c #include <REGX51.H> /** * @brief 定时器初始化,1毫秒@12.000MHz * @param 无 * @retval 无 */ void Timer0Init(void) //1毫秒@12.000MHz { // AUXR &= 0x7F; //定时器时钟12T模式//这句话在旧版的89C52中是可以删去的 TMOD &= 0xF0; //设置定时器模式//用来设置工作方式(高四位)(用来设置T1的工方式) TMOD |= 0x01; //设置定时器模式//用来设置工作方式(高四位)(用来设置T0的工方式) TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 //上面是ISP生成 //下面是自己写 ET0=1;//打开中断的第一个开关 EA=1;//打开第二个开关 PT0=0;//打开第三个开关 } /*定时器中断函数模板 void Timer0_Routine() interrupt 1 { static unsigned int T0Count;//定义静态变量//定义了一个新的函数,用来尝试计时一分钟 //计数器是同步计数,起始值是64536计时才是1ms。 TH0=64535/256; TL0=64535%256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下 T0Count++;//来计中断的次数 if(T0Count>=1000){ T0Count=0;//将T0Count恢复原值 P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用 } } */
//Delay.h #ifndef __DELAY_H__ #define __DELAY_H__ void Delay(unsigned int xms); #endif