1、蜂鸣器原理
无源蜂鸣器模块根据输入的 不同方波信号(作为震荡源)可以发出不同的声音。驱动电路中三极管电阻一般为1K-4K都行,能够让三极管导通即可。(三极管即带箭头的部分,基极和发射机(PNP)或者集电极(NPN)能够导通,并产生驱动电流,则发射极和集电极即可导通)
芯片驱动蜂鸣器
2、达林顿晶体阵列芯片(每路都是驱动使用的达林顿晶体管,能够增大驱动能力)
通过电路可以看到,当对应的输入脚输入低电平,内部三极管断开,位高阻态。当输入高电平,输出角输出低电平才有驱动能力。com口使用的二极管为继电器续流二极管,防止驱动继电器反向开合有高压脉冲。com口需要接地,为所有的驱动共地,外部的模块应为上拉。
可见,电路中com的按钮为测试按钮,当输入引脚没有输入高电平时,输出引脚为高阻态,当按下lamp按钮时,com会提供低电平,通过测试二极管导通。
输入接TTL电平,2.4~5V=1,0V=0。
3、乐谱知识
从左往右分别是大字组、小子组、小字1组、小子2组。相邻组相差8度。从左往右又低到高。相邻为半音关系(包括黑键)。隔了一个音是全音的关系。简谱1对应小子1组c1,为中央c。升高1组,简谱上面加点。
想表示黑色键,使用升音#和降音b符号,例如#1为中央c,c1的高半音黑键。#e1表示f1。-表示时常。每个数字1拍,-表示之前的音在保持1拍。
一般以4分音符作为基准,为100ms 、200ms、500ms,乐谱上会写。简谱一般4分音符为基准。在简谱里-起到时值延长的作用,而在五线谱里是起到休止的作用。缩短为数字下面划线。一般以2备或者/2为一个。
4、谱子
1=D是调号,表示D调(D调会谈黑键),C调一般全弹白键,4/4是拍哈号,以4分音符为1拍,每小节4拍。附点表示,1· 当前音符延长时常的1/2。两音符见出线连接,表示延音线。两个音之间是按下去不放的。
5、C调(C调包含的音,数字震荡源频率对照)
频率对照:低音1-高音7 表示 琴键的c-
6、ST89C51/52/52RC定时器重装值:使用12MHz(12T)
音符 | 频率(Hz) | 周期(us) | 周期/2(us) | 取整 | 重装载值 | 索引 |
1 | 262 | 3816.794 | 1908.396947 | 1908 | 63628 | 1 |
1# | 277 | 3610.108 | 1805.054152 | 1805 | 63731 | 2 |
2 | 294 | 3401.361 | 1700.680272 | 1701 | 63835 | 3 |
2# | 311 | 3215.434 | 1607.717042 | 1608 | 63928 | 4 |
3 | 330 | 3030.303 | 1515.151515 | 1515 | 64021 | 5 |
4 | 349 | 2865.33 | 1432.664756 | 1433 | 64103 | 6 |
4# | 370 | 2702.703 | 1351.351351 | 1351 | 64185 | 7 |
5 | 392 | 2551.02 | 1275.510204 | 1276 | 64260 | 8 |
5# | 415 | 2409.639 | 1204.819277 | 1205 | 64331 | 9 |
6 | 440 | 2272.727 | 1136.363636 | 1136 | 64400 | 10 |
6# | 466 | 2145.923 | 1072.961373 | 1073 | 64463 | 11 |
7 | 496 | 2016.129 | 1008.064516 | 1008 | 64528 | 12 |
1 | 523 | 1912.046 | 956.0229446 | 956 | 64580 | 13 |
1# | 554 | 1805.054 | 902.5270758 | 903 | 64633 | 14 |
2 | 587 | 1703.578 | 851.7887564 | 852 | 64684 | 15 |
2# | 622 | 1607.717 | 803.8585209 | 804 | 64732 | 16 |
3 | 659 | 1517.451 | 758.7253414 | 759 | 64777 | 17 |
4 | 698 | 1432.665 | 716.3323782 | 716 | 64820 | 18 |
4# | 740 | 1351.351 | 675.6756757 | 676 | 64860 | 19 |
5 | 784 | 1275.51 | 637.755102 | 638 | 64898 | 20 |
5# | 831 | 1203.369 | 601.6847172 | 602 | 64934 | 21 |
6 | 880 | 1136.364 | 568.1818182 | 568 | 64968 | 22 |
6# | 932 | 1072.961 | 536.4806867 | 536 | 65000 | 23 |
7 | 988 | 1012.146 | 506.0728745 | 506 | 65030 | 24 |
1 | 1046 | 956.0229 | 478.0114723 | 478 | 65058 | 25 |
1# | 1109 | 901.7133 | 450.8566276 | 451 | 65085 | 26 |
2 | 1175 | 851.0638 | 425.5319149 | 426 | 65110 | 27 |
2# | 1245 | 803.2129 | 401.6064257 | 402 | 65134 | 28 |
3 | 1318 | 758.7253 | 379.3626707 | 379 | 65157 | 29 |
4 | 1397 | 715.8196 | 357.9098067 | 358 | 65178 | 30 |
4# | 1480 | 675.6757 | 337.8378378 | 338 | 65198 | 31 |
5 | 1568 | 637.7551 | 318.877551 | 319 | 65217 | 32 |
5# | 1661 | 602.047 | 301.0234798 | 301 | 65235 | 33 |
6 | 1760 | 568.1818 | 284.0909091 | 284 | 65252 | 34 |
6# | 1865 | 536.193 | 268.0965147 | 268 | 65268 | 35 |
7 | 1976 | 506.0729 | 253.0364372 | 253 | 65283 | 36 |
频率确定方式,以低音6即a作为基准频率440。8度插之间频率2倍差,即a1=880,A=220。8度之间有12个键,是以等比数列平分。即6# = 。
7、测试
因为我的51开发板引脚为P2^5和其他的开发板不一样,所以需要根据自己的改一下引脚。
举例:P1^5
7.1、测试蜂鸣器,根据按钮进行显示和响声
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);//按键初始化清0while(1){KeyNum=Key();if(KeyNum){Buzzer_Time(200);Nixie(1,KeyNum);//保持}}
}
Buzzer.c
#include <REGX52.H>
#include <INTRINS.H>//蜂鸣器端口:
sbit Buzzer=P2^5;/*** @brief 蜂鸣器私有延时函数,延时500us* @param 无* @retval 无*/
void Buzzer_Delay500us_12() //@12.000MHz
{unsigned char i;_nop_();i = 247;while (--i);
}void Buzzer_Delay500us_11() //@11.0592MHz
{unsigned char i, j;_nop_();_nop_();i = 6;j = 93;do{while (--j);} while (--i);
}/*** @brief 蜂鸣器发声* @param ms 发声的时长,范围:0~32767* @retval 无*/
void Buzzer_Time(unsigned int ms)
{unsigned int i;for(i=0;i<ms*2;i++){Buzzer=!Buzzer;Buzzer_Delay500us_11();}
}
Buzzer.h
#ifndef __BUZZER_H__
#define __BUZZER_H__void Buzzer_Time(unsigned int ms);#endif
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,0x07,0x7F,0x6F};/*** @brief 数码管显示* @param Location 要显示的位置,范围:1~8* @param Number 要显示的数字,范围:段码表索引范围* @retval 无*/
void Nixie(unsigned char Location,Number)
{switch(Location) //位码输出{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=0x00; //段码清0,消影
}
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
7.2、天空之城音乐
main.c
#include <REGX52.H>
#include "Delay.h"
#include "Timer0.h"//蜂鸣器端口定义
sbit Buzzer=P2^5;//播放速度,值为四分音符的时长(ms)
#define SPEED 500//音符与索引对应表,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//索引与频率对照表
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,
};//乐谱
unsigned char code Music[]={//音符,时值,//1P, 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,//2M6, 4+2,M5, 2,M6, 4,H1, 4,M5, 4+4+4,M3, 4,M4, 4+2,M3, 2,M4, 4,H1, 4,//3M3, 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,//4H1, 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,//5M5, 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,//6H1, 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,//7H2, 4+4+4,M5, 2,M5, 2,H1, 4+2,M7, 2,H1, 4,H3, 4,H3, 4+4+4+4,//8M6, 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,//9H3, 4+4+4,H3, 4,H6, 4+4,H5, 4,H5, 4,H3, 2,H2, 2,H1, 4+4,P, 2,H1, 2,//10H2, 4,H1, 2,H2, 2,H2, 4,H5, 4,H3, 4+4+4,H3, 4,H6, 4+4,H5, 4+4,//11H3, 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 //终止标志
};unsigned char FreqSelect,MusicSelect;void main()
{Timer0Init();while(1){if(Music[MusicSelect]!=0xFF) //如果不是停止标志位{FreqSelect=Music[MusicSelect]; //选择音符对应的频率MusicSelect++;Delay(SPEED/4*Music[MusicSelect]); //选择音符对应的时值MusicSelect++;TR0=0;Delay(5); //音符间短暂停顿TR0=1;}else //如果是停止标志位{TR0=0;while(1);}}
}void Timer0_Routine() interrupt 1
{if(FreqTable[FreqSelect]) //如果不是休止符{/*取对应频率值的重装载值到定时器*/TL0 = FreqTable[FreqSelect]%256; //设置定时初值TH0 = FreqTable[FreqSelect]/256; //设置定时初值Buzzer=!Buzzer; //翻转蜂鸣器IO口}
}
Time0.c
#include <REGX52.H>/*** @brief 定时器0初始化,1毫秒@12.000MHz* @param 无* @retval 无*/
void Timer0Init(void)
{TMOD &= 0xF0; //设置定时器模式TMOD |= 0x01; //设置定时器模式TL0 = 0x18; //设置定时初值TH0 = 0xFC; //设置定时初值TF0 = 0; //清除TF0标志TR0 = 1; //定时器0开始计时ET0=1;EA=1;PT0=0;
}/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x18; //设置定时初值TH0 = 0xFC; //设置定时初值T0Count++;if(T0Count>=1000){T0Count=0;}
}
*/
Time.h
#ifndef __TIMER0_H__
#define __TIMER0_H__void Timer0Init(void);#endif