蜂鸣器使用
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);//按键初始化清0
while(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[]={
//音符,时值,
//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 //终止标志
};
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