蜂鸣器按照驱动方式可分为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器内部带有振荡器,只要给BZ段一个低电平,蜂鸣器就会响;而无源蜂鸣器内部不带震荡源,必须给500HZ~4.5KHZ之间的频率脉冲信号它才会响。比较而言,有源蜂鸣器内部多一个震荡电路。驱动发音较为简单;无源蜂鸣器的价格较低,声音频率可以控制。
无源蜂鸣器是直流电压驱动的,只需对驱动口输出驱动电平,并通过放大电路放大驱动电流,就能使蜂鸣器发出声音,改变单片机引脚输出波形的频率,可以调整控制蜂鸣器音调,产生各种不同音色、音调的声音; 改变输出电平的高低电平占空比,则可以控制蜂鸣器的声音大小。
蜂鸣器正常工作的前提条件是两端有电压差,如下图所示我们可以看到蜂鸣器的引脚为BUZZ(ER),其中一端已经接了+5V电源,所以只需另一端接低电平,该蜂鸣器即可以正常工作。
BUZZ引脚对应的I/O口是P0^ 6, BUZZ和P0^6 之间有M74HC573和ULN2003两个芯片,M74HC573就是一个简单的锁存器,输出前后状态相同,注意保证它的使能端有效即可,在前面几个模块也已经多次出现,在这里就不赘述了,主要介绍一下ULN2003。
ULN2003:高耐压、大电流复合晶体管阵列,由七个硅NPN 复合晶体管组成,每一对达林顿都串联一个2.7K 的基极电阻,在5V 的工作电压下它能与TTL 和CMOS 电路直接相连,可以直接处理原先需要标准逻辑缓冲器来处理的数据,输入5VTTL电平,输出可达500mA/50V。内部结构图如下:
由上图我们可以看到,ULN2003其实主要有7个反相器组成。这意味着如果我们需要BUZZ引脚为低电平,那么I/O口 P0^ 6 输出应该为高电平,即P0^6 = 1
,同时我们要保证M74HC573的使能端有效,即 Y5C=1。我们看一下Y5C的相关模块:
Y5和WR经过与非门得到Y5C,若Y5C=1,则需要Y5=0且WR=0。当J13的跳线帽2和3相连时(即WR和GND短接),表示的是蜂鸣器 继电器模块,所以我们只需要再满足Y5=0即可。这就又涉及到了74HC138模块:
74HC138 这个芯片大家就不陌生了,3-8译码器。若想Y5=0,则需要满足P2^ 7 = 1
,P2^ 6= 0
,P2^5 = 1
,即将P2口高三位写成101,其余位清零即可。
P2 = ((P2 & 0x1F)|0xA0);//通过Y5C控制74HC573使能有效
注意这个模块写完后要关闭使能:
P2 = P2 & 0x1F;//P2 &= 0x1F 关闭使能
其实和LED模块比起来就是多了ULN2003芯片的使用,其它基本相同。继电器模块和蜂鸣器模块基本上完全相同。区别在于控制继电器的I/0口是P0^4,引脚是RELAY。继电器工作时, P0 ^6 = 1
。
关于蜂鸣器,继电器,LED灯的常用模板:
#include<reg52.h>
sbit buzz = P0^6;//蜂鸣器对应的引脚是P0^6
sbit relay = P0^4;//继电器对应的引脚
sbit led = P0^0;//P0^0 ~ P0^7对应8个LED灯
void main()
{
P2 = ((P2 & 0x1F) | 0xA0);//Y5控制使能端有效
buzz = 0;//打开蜂鸣器
P2 = P2 & 0x1F;//使能端无效,关闭蜂鸣器
P2 = ((P2 & 0x1F) | 0xA0);//Y5控制使能端有效
relay = 1;//打开继电器
P2 = P2 & 0x1F;//使能端无效,关闭继电器
P2 = ((P2 & 0x1F) | 0x80);//Y4控制使能端有效
led = 0; //点亮其中一个LED小灯
P2 = P2 & 0x1F;//使能端无效
while(1);
}
原理图:
和CT107D开发板的原理基本相同,稍微简单一些,P1^5 = 1
时,经过ULN2003,BZ = 0,蜂鸣器可以工作。
示例代码如下:
//演奏音乐八月桂花
#include <reg52.h>
#include <intrins.h>
sbit Beep = P1^5;
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
};
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;
TH0=0xd8;TL0=0xef;
IE=0x82;
play:
while(1)
{
a: p=music_tab[i];
if(p==0x00) {
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++];} //取频率常数 和 节拍常数
TR0=1; //开定时器1
while(n!=0) Beep=~Beep,delay(m); //等待节拍完成, 通过P1口输出音频(可多声道哦!)
TR0=0; //关定时器1
}
}