一、蜂鸣器介绍
蜂鸣器是一种将电信号转换为声音信号的器件,常用来产生设备的按键音、报警音等提示信号
蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器
有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定
无源蜂鸣器:内部不带振荡源,需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音
二、驱动电路
-
三极管驱动
如果电路处于放大状态(放大电路),那么就可以通过基极(连接电阻的那一端)来控制导通和截止关系。三级管有NPN形和PNP形:
放大状态:放大状态是指放大器工作时的状态,即输入信号经过放大器放大后的输出信号状态。放大器的作用是将输入信号放大到一定的幅度,从而使得信号能够被后续电路或设备正确地处理和识别
NPN:给1导通,给0截断
PNP:给0导通,给1截断
-
集成电路驱动
三、ULN2003
因为芯片中都是非门,所以给1,是低电平,给1时导通,给0时类似于处于高阻状态,既不是高电平,也不是低电平。
四、键盘与音符对照
简单的学习一下乐理知识:
钢琴键盘是可分组的,中央C~b1,称为小字1组,一组由7个白键5个黑键组成的,左边的为小字组,小字组左边为大字组,如果大字左边还有则称为大字1组,小字1组右边为小字2组,以此类推。
每个组相同的音都相差8度,比如c1到从c2要升高8度,c1到c要降低8度。
相邻的两个音是半音的关系,相邻不是单看白键,是黑白同看,例如c1和d1中间的黑键和c1差半音,和d1也差半音,c1和b1差一个全音,e1和f1是相邻的白键,他们也是差半音。
根据上图所示,音名c1对应着简谱中的1,c2对应着简谱中的1‘(1上一点)代表升高8度,c对应着(1下一点)下降8度,C对应着(1下两点)代表下降两个8度,这是白键的表示方式。如果是黑键则需要用到#(升音符号)、b(降音符号)。例如向弹c1和b1之间的黑键符号表示为^#1或者^b2(#和b在左上方)表示含义为升半音,如果是弹f1也可以用^#3,表示e1升半音弹f1键。
五、音符与频率对照
频率由低音6为基准,对应着a,频率为440,从这个基准开始到a1(中音6)时频率为880,在A时为220,中间总共有12个键(包括黑键),中间以等比数列进行平分的,所以又称为12平分率
所以从a到b的频率为440*2^(1/12) = 466.1638,从a到g则是440/2^(1/12) = 415.3047。
在单片机中我们用定时器中断来产生频率,定时器中断的时间是TH0和TL0的重装值确定的,接下来需要确定一下重装值,单片机不好直接产生频率,所以要先计算各个频率的周期值,周期值等于1/频率单位是s,我们将单位换成us。
51单片机是12T单片机,他的机器周期是震荡周期的十二分之一,假如晶振是12MHZ的,那么机器周期就是1MHZ,一个周期定时器计数加一,定时器加1的时间就是1us(如果是11.0592MHZ则为机器周期 = 11.0595/12,定时器加1的时间则是1.机器周期)。
I/O口翻转2次才是一个周期,先置1,再置0,如果一个周期是3000多us那么翻转的频率是周期的2倍,翻转的时间是他的二分之一,所以重装载时间 = 65536 - 周期/2。
六、简谱
二分音符 四分音符 全音音符 八分音符
一般以4分音符为精准,比如4分音符是500ms,那么二分音符就是1s,全音音符就是2s。
在小星星简谱中,可以看到没有升降音(由于是C调,全弹白键),但是有“—”符号,这代表时长音,例如5—(表示2分之一音符)的时长是6的两倍。如果表示全音符则为5— — —(3条杠),如果表示降低时间则在数字下面加—,例如8分音符:5,16分则加两条以此类推
从下往上读,这个表示以4分音符为1拍,每小节有4拍。
3 3:表示需要松开再按3键
表示不要松开,延音符,这样表示节拍清晰可见
在上小星星简谱讲了如何表示整倍数时间,接下来讲一下如何表示不是整倍数的时间,例如表示1.5个4分之一节拍,需要用到附点".",附点表示在原来的时基础上延长二分之一,例如第二节的第一拍为“i.”表示1.5个4分之一节拍。
七、蜂鸣器播放提示音
频率 = 1/f ,过500us翻转一次,1ms为一周期,频率 = 1/1ms = 1000hz
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);
while(1)
{
KeyNum=Key();
if(KeyNum)
{
Buzzer_Time(100);
Nixie(1,KeyNum);
}
}
}
Buzzer.c
#include <REGX52.H>
#include <INTRINS.H>
//蜂鸣器端口:
sbit Buzzer=P1^5;
/**
* @brief 蜂鸣器私有延时函数,延时500us
* @param 无
* @retval 无
*/
void Buzzer_Delay500us() //@12.000MHz
{
unsigned char i;
_nop_();
i = 247;
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();
}
}
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,消影
}
八、蜂鸣器播放音乐
将对应的定时器初值和时间存入数组,通过访问数字的方式来使得蜂鸣器响应对应的频率,来奏响音乐,再读取对应的时间来获得使得频率响对应时长,再奏响一个频响对应时间后将定时器关闭一下,来使每个频响有间隔达到演奏音乐效果。
main.c
#include <REGX52.H>
#include "Delay.h"
#include "Timer0.h"
//蜂鸣器端口定义
sbit Buzzer=P1^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口
}
}
Timer.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;
}
}
*/