蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。
蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。
想要压电式蜂鸣器发声,需提供一定频率的脉冲信号;想要电磁式蜂鸣器发声,只需提供电源即可。
我们开发板上使用的蜂鸣器是无源蜂鸣器,属于压电式蜂鸣器类型。这里说的有源和无源,并不是指电源的意思,而是指蜂鸣器内部是否含有振荡电路,有源蜂鸣器内部自带振荡电路,只需提供电源即可发声,而无源蜂鸣器则需提供一定频率的脉冲信号才能发声,频率大小通常在1.5-5KHz 之间。
对于无源蜂鸣器,如果改变频率就可以调节蜂鸣器音调,产生各种不同音色、音调的声音。如果改变输出电平的高低电平占空比,则可以改变蜂鸣器的声音大小。
对于有源蜂鸣器,通常内部已经固定了频率,对于调节频率或占空比可能改变不了蜂鸣器的音调和音量,当然也有的有源蜂鸣器可以实现和无源蜂鸣器一样的效果。
在前面章节中我们已经对51 单片机的GPIO 做了简单介绍,并且还使用了其中IO 口直接控制开发板上的LED。对于本章要实现蜂鸣器的控制,我们能否直接使用单片机的IO 口驱动呢?答案是否定的,因为51 单片机IO 口的驱动能力较弱(即使外接上拉电阻),而蜂鸣器驱动需要约30mA,所以非常困难,即使可以驱动,那对于整个芯片的其它IO 剩下驱动能力就更加弱甚至无法工作。所以我们不会直接使用IO 口驱动蜂鸣器,而是通过三极管把电流放大后再驱动蜂鸣器,这样51 单片机的IO 口只需要提供不到1mA 的电流就可控制蜂鸣器。所以我们也经常说到51 单片机是用来做控制的,而不是驱动。
从图中可以看出,蜂鸣器模块独立,J7 端子可接任意IO 控制,因此可直接连接到51 单片机的管脚上。图中使用三极管进行电流放大,从而驱动蜂鸣器,当管脚输出高电平,三极管截止,蜂鸣器不得电;当管脚输出低电平,三极管导通,蜂鸣器得电。
开发板上使用的是无源蜂鸣器,它需要一定频率的脉冲(高低电平)才会发声,因此需要让单片机管脚以一定频率不断输出高低电平信号才能控制蜂鸣器发出声音。
两种控制蜂鸣器的程序代码:
第一种:
/********************************************************************
******************
实验名称:蜂鸣器实验
接线说明:
实验现象:下载程序后蜂鸣器发出声音,一段时间后关闭
注意事项:
*********************************************************************
******************/
#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
sbit BEEP=P0^0; //将P0.0 管脚定义为BEEP
/********************************************************************
***********
* 函数名: delay_10us
* 函数功能: 延时函数,ten_us=1 时,大约延时10us
* 输入: ten_us
* 输出: 无
*********************************************************************
**********/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void delay1ms(void) //误差 0us
{
unsigned char a,b;
for(b=199;b>0;b--)
for(a=1;a>0;a--);
}
/********************************************************************
***********
* 函数名: main
* 函数功能: 主函数
* 输入: 无
* 输出: 无
*********************************************************************
**********/
void main()
{
u16 i=2000;
while(1)
{
while(i--)//循环2000 次
{
BEEP=!BEEP;//产生一定频率的脉冲信号
delay1ms();
}
i=0;//清零
BEEP=0;//关闭蜂鸣器
}
}
第二种:使用定时中断的方法
#include <reg51.h>
sbit buzzer =P0^0;
void buzzer_isr() interrupt 1 using 1 //定时器T0中断执行程序
{
TL0 = 0x17; //计数器重新赋值
TH0 = 0xfc;
buzzer = !buzzer;
}
void main()
{
TMOD = 0x01; //工作模式1,16位定时/计数器
TL0 = 0x17; //定时时间1ms
TH0 = 0xfc;
TR0 = 1;
ET0 = 1;
EA = 1;
while(1);
}
可以让蜂鸣器唱歌的程序:
/************************************************************************
[文件名] C51音乐程序(八月桂花)
[功能] 通过单片机演奏音乐
/**********************************************************************/
#include <REG51.H>
//#include <INTRINS.H>
//本例采用89C52, 晶振为11.0592MHZ
//关于如何编制音乐代码, 其实十分简单,各位可以看以下代码.
//频率常数即音乐术语中的音调,而节拍常数即音乐术语中的多少拍;
//所以拿出谱子, 试探编吧!
sbit Beep = P0^0 ; // 要根据实际的接线来修改
unsigned char n = 0; //n为节拍常数变量
unsigned char code music_tab[] =
{
0x18, 0x30, 0x1C , 0x10, //格式为: 频率常数, 节拍常数, 频率常数, 节拍常数,
0x20, 0x40, 0x1C , 0x10,
0x18, 0x10, 0x20 , 0x10,
0x1C, 0x10, 0x18 , 0x40,
0x1C, 0x20, 0x20 , 0x20,
0x1C, 0x20, 0x18 , 0x20,
0x20, 0x80, 0xFF , 0x20,
0x30, 0x1C, 0x10 , 0x18,
0x20, 0x15, 0x20 , 0x1C,
0x20, 0x20, 0x20 , 0x26,
0x40, 0x20, 0x20 , 0x2B,
0x20, 0x26, 0x20 , 0x20,
0x20, 0x30, 0x80 , 0xFF,
0x20, 0x20, 0x1C , 0x10,
0x18, 0x10, 0x20 , 0x20,
0x26, 0x20, 0x2B , 0x20,
0x30, 0x20, 0x2B , 0x40,
0x20, 0x20, 0x1C , 0x10,
0x18, 0x10, 0x20 , 0x20,
0x26, 0x20, 0x2B , 0x20,
0x30, 0x20, 0x2B , 0x40,
0x20, 0x30, 0x1C , 0x10,
0x18, 0x20, 0x15 , 0x20,
0x1C, 0x20, 0x20 , 0x20,
0x26, 0x40, 0x20 , 0x20,
0x2B, 0x20, 0x26 , 0x20,
0x20, 0x20, 0x30 , 0x80,
0x20, 0x30, 0x1C , 0x10,
0x20, 0x10, 0x1C , 0x10,
0x20, 0x20, 0x26 , 0x20,
0x2B, 0x20, 0x30 , 0x20,
0x2B, 0x40, 0x20 , 0x15,
0x1F, 0x05, 0x20 , 0x10,
0x1C, 0x10, 0x20 , 0x20,
0x26, 0x20, 0x2B , 0x20,
0x30, 0x20, 0x2B , 0x40,
0x20, 0x30, 0x1C , 0x10,
0x18, 0x20, 0x15 , 0x20,
0x1C, 0x20, 0x20 , 0x20,
0x26, 0x40, 0x20 , 0x20,
0x2B, 0x20, 0x26 , 0x20,
0x20, 0x20, 0x30 , 0x30,
0x20, 0x30, 0x1C , 0x10,
0x18, 0x40, 0x1C , 0x20,
0x20, 0x20, 0x26 , 0x40,
0x13, 0x60, 0x18 , 0x20,
0x15, 0x40, 0x13 , 0x40,
0x18, 0x80, 0x00
};
// T0定时控制的是音乐的节拍(某一个音节持续的时间)而不管音调(频率)
// 音调是直接使用delay做出来的。
void int0() interrupt 1 //采用中断0 控制节拍
{
TH0 = 0xd8;
TL0 = 0xef;
n--;
}
void delay (unsigned char m) //控制频率延时
{
unsigned i = 3 * m;
while (--i);
}
void delayms(unsigned char a) //豪秒延时子程序
{
while (--a); //采用while(--a) 不要采用while(a--); 各位可编译一下看看汇编结果就知道了!
}
void main()
{
unsigned char p, m; // m为频率常数变量
unsigned char i = 0;
TMOD &= 0x0f;
TMOD |= 0x01; // timer0 工作在模式1,16位定时器下
TH0 = 0xd8;
TL0 = 0xef; // 这个TH和TL的值合起来定了1个10ms左右的一个时间
IE = 0x82;
play:
while (1)
{
a: p = music_tab[i];
if (p == 0x00) // 一遍播放完了,延时1s后自动开始下一遍
{
i=0, delayms(1000);
goto play;
} //如果碰到结束符,延时1秒,回到开始再来一遍
else if (p == 0xff)
{
i = i + 1;
delayms(100), TR0 = 0;
goto a;
} //若碰到休止符,延时100ms,继续取下一音符
else
{
m = music_tab[i++], n = music_tab[i++];
} // m取频率常数 和 n取节拍常数
TR0 = 1; //开定时器1
while (n != 0)
{
Beep = ~Beep;
delay(m); //等待节拍完成, 通过P1口输出音频(可多声道哦!)
}
TR0 = 0; //关定时器1
}
}