
这里的“源”不是指电源。而是指震荡源。 也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫。 而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用2K~5K的方波去驱动它。 有源蜂鸣器往往比无源的贵,就是因为里面含有震荡电路。
(1)早期的蜂鸣器都是无源的
(2)内部结构和材料
(3)发生原理:是利用了压电效应的原理
(4)控制信号,是高低电平相间【一直有电或者一直没电是不会响,要交互产生方波】
(5)电路图:因为蜂鸣器要的电流很大,单独使用单片机是无法驱动的,所以要使用三极管
(6)音调如何控制:音调受震动频率控制,就等于控制信号的频率。频率越高音调越高,听起来越刺耳。【声音是振动产生的】
(7)声音大小如何控制。由硬件决定的。无法写代码取控制声音大小。
无源蜂鸣器只能在一定的范围内进行设置,太大或者太小都不行。【外部提供一个方波】
在内部添加震荡电路,不用使用外部的方波进行控制【但是内部的震荡电路是不可以改变的】
可以直接加电也可以直接通过方波进行工作【有源蜂鸣器包含无源蜂鸣器】




频率越低(1KHZ),声音越沙哑,
频率越高(10KHZ),声音越尖锐
- #include
-
- /**
- 使用延时函数,让蜂鸣器响起来
- */
-
- sbit BUZZER=P0^0; //buzzer的驱动引脚
-
-
- /**
- 计算这个延时函数是延时多久?
- 本单片机使用的是12MHZ,使用了12T(12分频)-->12MHZ/12T=1us
- 周期:1us【运行一个指令所用的时间】
- 100*10=1000个指令
- 1000 *1us=1ms=0.001s
- 频率=1s/0.001s=1kHZ
- */
- void delay(void){
- unsigned char i,j;
- for(i=0;i<100;i++){
- for(j=0;j<10;j++);
- }
-
- }
-
-
- void main(){
-
- while(1){
- BUZZER=1;//将引脚变外高电平
-
- delay();
- BUZZER=0;
- delay();
- }
- }
所以时间要控制好
如果时间太短,则可能会发不出声音【超声波】
如果时间太长,则声音很混沌甚至不发出声音【次声波】
控制delay中的i和j的大小,可以控制音调的振动频率,从而影响声音的尖锐。
如果i和j越大【时间大,频率越低】,则音调越小,声音越不尖锐
如果i和j越小【时间短,频率越高】,则音调越大,声音越尖锐





(1)不容易精确控制时间
(2)CPU控制蜂鸣器中不能做其他事
在一定时间后,通过定时器中的中断处理程序取减低蜂鸣器的电平,从控制蜂鸣器的响应
(1)10KHz=>1/10000s=>0.0001s===》0.1ms===>100us===>高电平+低电平的时间都为50us。所以要定的时间就是50us
(2)外部晶振12MHz+12T设置==>内部时钟频率1MHz===》1us【一个时间周期】===》TL0=255-50=205,TH0=255
我们在设置TH0和TL0应该将获得的时间取其补码【因为加法计数器是从65535-某一个数值】
比如:我们是TL0=50; TH0=0;
则我们应该写入“TL0=205;TH0=255;"
- TL0=205;
- TH0=0;
- TL0=205 % 256;//低位取余
- TH0=255/ 256;//高位取商
计数器是16位的,由高8位TH0和低8位TL0组成,可以存储2^16=65536个数,例如当设定计算值为65536-50000=15536时,也就是计数器从15536开始计时,到65536溢出,产生中断,对于晶振频率为12MHz+12T的单片机来说,执行一个机器周期时长为1us,所以这里计时50000us,15536(D)转换为16进制是3CB0(H),此时TH0=3C,TL0=B0分别装入定时器即可,为了免除这些计算步骤,很多编程者采用"TH0=(65536-50000)/256;TL0=(65536-50000)%256",那么为什么要介入256呢?我们可以做一下运算,256(D)=0100(H),512(D)=0200(H),512(D)有两个256,所以高8位就是02,那么15536有多少个256?就是15536/256个,就相当于高8位有多少数值,商存入高8位,剩下的不足一个256,存入低8位,15536%256。
直接使用宏定义
【注意点】我们51是加法计数器,所以是65535-US
- //宏定义一个时钟频率
- //10KHz---》10 000s
- #define XKHZ 10 //10*10的三次方Hz 要定多少Khz,就定义在这里
- //宏定义us
- //这里我们除以2,是因为想要分给TH0和TL0
- //1000---》1000ms
- //这里是XKHZ会被换算成XKs
- // 1/XKHz===>时钟周期
- //这里“1000”是通过---》1/1KHz*1000【换算ms】*1000【换算us】
- #define US (1000/XKHZ)/2
- sbit BUZZER=P0^0; //buzzer的驱动引脚
- //【注意点】因为51单片机是加法计数器,所以实际上我们要算的范围
- //应该是65535-US,而不是0-US
- #define N (65535 -US)
-
- void delay(void){
- unsigned char i,j;
- for(i=0;i<100;i++){
- for(j=0;j<10;j++);
- }
-
- }
-
-
- void timer0_isr(void) interrupt 1 using 1{
- //这里再一次赋值,是因为我们想要他循环,所以我们要在他每一次进来的时候重新赋值
-
- TL0=N % 256;//低位取余
- TH0=N / 256;//高位取商
- BUZZER=!BUZZER;
-
- }
注意点:
1)频率=1s/周期
2)我们计算出频率后要记得/2,因为要均等分配给TL0和TH0
3)因为51单片机是典型的加法定时器,所以我们如果使用16位寄存器,则应该是使用65535-TL/TH--->才会得出我们要计数的个数
4)当我们要真正计算TH和TL的时候,是要/256【不是255~~~~~~~】
- #include
- /**
- 用定时器控制蜂鸣器的音调
- */
-
- //定义一个时钟周期
- #define XKHZ 10 //10*10的三次方Hz 要定多少Khz,就定义在这里
- //宏定义us
- //这里我们除以2,是因为想要分给TH0和TL0
- // 1/XKHz===>时钟频率
- //宏定义一个时钟频率
- //10KHz【周期】---》10 000s---》频率=1s/10KHZ=1s/10 000=0.0001=100us
- #define US (1000/XKHZ)/2
- //【注意点】因为51单片机是加法计数器,所以实际上我们要算的范围
- //应该是65535-US,而不是0-US
- #define N (65535 -US)
-
- sbit BUZZER=P0^0;//buzzer的驱动引脚
-
- void timer0_isr(void) interrupt 1 using 1{
- //这里再一次赋值,是因为我们想要他循环,所以我们要在他每一次进来的时候重新赋值
-
- TL0=N % 256;//低位取余
- TH0=N / 256;//高位取商
- BUZZER=!BUZZER;
-
- }
-
-
- void main(){
-
- TMOD=0x01;//T0使用16bit定时器
- /**
- (1)10KHz=>1/10000s=>0.0001s===》0.1ms===>100us===>高电平+低电平的时间都为50us。所以要定的时间就是50us
- (2)外部晶振12MHz+12T设置==>内部时钟频率1MHz===》1us【一个时间周期】===》TL0=255-50=205,TH0=255
- */
- TL0=50;
- TH0=0;
-
- TR0=1;//T0打开开始计数
- ET0=1;//T0中断允许
- EA=1;//总中断允许
-
-
- while(1);
- }

通过count可以控制有声音和无声音的长短
- #include
-
- /**
- 用定时器控制蜂鸣器音调;有声音和无声音长短一致【count值一样】
- */
-
-
- sbit BUZZER=P0^0; //buzzer的驱动引脚
-
- //宏定义一个时钟频率
- #define XKHZ 50 //10*10的三次方Hz 要定多少Khz,就定义在这里
- //这里“1000”是通过---》1/1KHz*1000【换算ms】*1000【换算us】
- #define US (1000/XKHZ)/2
- #define N (65535 -US)
-
- //计数器
- unsigned int count;
-
- //判断此时是从”有声音“到"没声音”,还是从“没声音”到“有声音”
- unsigned char flag=0; //flag=0表示有声音,flag=1表示没有声音
-
-
- void delay(void){
- unsigned char i,j;
- for(i=0;i<100;i++){
- for(j=0;j<10;j++);
- }
-
- }
-
-
- void timer0_isr(void) interrupt 1 using 1{
- //这里再一次赋值,是因为我们想要他循环,所以我们要在他每一次进来的时候重新赋值
-
- TL0=N % 256;//低位取余
- TH0=N / 256;//高位取商
-
- if(count--==0){//说明此时要进行翻转,5000中的1次
- count=5000;
- //判断此时是从“有声音”像“无声音”,还是“无声音”到“有声音”
- if(flag==0){//进入的时候是“有声音”
- //则表示此时是想要从“有声音”向“无声音”进行转换
- flag=1;
-
- }else{
- flag=0;
- //取反,才可以发出声音
- BUZZER=!BUZZER;
- }
-
- }else{//说明不用进行翻转,5000中的4999次
- //这里我们也要进行判断
- //判断此时是从“有声音”像“无声音”,还是“无声音”到“有声音”
- if(flag==0){//进入的时候是“有声音”
-
- //取反,才可以发出声音
- BUZZER=!BUZZER;
-
- }else{
- //空的,因为不进行任何操作
- }
- }
-
-
- }
-
-
-
- void main(){
-
- //【第一步】初始化:我们使用的是定时器T0
- TMOD=0x01; //T0使用16位bit定时器
- //********************************************************
- TL0=N % 256;//低位取余
- TH0=N / 256;//高位取商
- //********************************************************
-
-
- //打开计数器;TCON中的TR0【定时器T0的运行控制位】
- TR0=1; //T0打开开始计数
- //T0的中断溢出位,表示允许中断
- ET0=1; //T0中断允许
- EA=1; //打开中断允许
-
-
- BUZZER=1;
-
- //设置响和不响的周期时间
- count=500; //对应5KHZ---》count=200us【上面我们计算出来的】*5000us=100ms
- //count=20000;//对应20KHZ------》count=5us*20 000us=100ms
- //count=5000;//对应1KHZ-----》count=1000us*100us=100ms
- //初始化,有声音
- flag=0;
-
- }

- #include
- /**
- 用定时器控制蜂鸣器音调:有声音和无声音的长度不一致
- */
-
- sbit BUZZER = P0^0; // buzzer的驱动引脚
-
- #define XKHZ 4 // 要定多少Khz,就直接写这里
- #define US (500/XKHZ)
- #define N (65535-US)
-
-
- unsigned int count;
- unsigned char flag = 0; // flag = 0表示有声音,flag = 1表示没声音
-
-
- void timer0_isr(void) interrupt 1 using 1
- {
- TL0 = N % 256;
- TH0 = N / 256;
-
- if (count-- == 0)
- {
- // 说明到了翻转的时候了
- // count = 600;
-
- if (flag == 0)
- {
- // 之前是处于有声音的,说明本次是从有声音到无声音的翻转
- flag = 1;
- count = 600*10;
- }
- else
- {
- // 之前是处于没声音的,说明本次是从没声音到有声音的翻转
- flag = 0;
- BUZZER = !BUZZER;
- count = 600;
- }
- }
- else
- {
- // 常规情况,也就是不反转时
- if (flag == 0)
- {
- BUZZER = !BUZZER; // 4999次声音
- }
- else
- {
- // 空的就可以,因为不进行任何IO操作就是没声音
- }
- }
-
- }
-
-
-
- void main(void)
- {
- TMOD = 0x01; // T0使用16bit定时器
- TL0 = N % 256;
- TH0 = N / 256;
-
- TR0 = 1; // T0打开开始计数
- ET0 = 1; // T0中断允许
- EA = 1; // 总中断允许
-
- BUZZER = 1;
-
- // 设置响和不响的周期时间
- count = 600;
- flag = 0;
-
- while (1);
- }
-
-
(1)发声音频可变---》延迟函数(delay)
(2)发声音长度可变---》定时器
- unsigned char i;
- for(i=0;i<200;i++){//控制声音响应时间长短
- Sound=~Sound;
- DelayXms(1);//控制声音的不同
- }
-
- for(i=0;i<50;i++){
- Sound=~Sound;
- DelayXms(2);
- }
(1)复制代码过去
(2)修改控制蜂鸣器的IO引脚定义
因为我们加入的歌曲的编码是固定不变的,但是51单片机的内存有限制,所以我们只能把歌曲的编码放在常量区中,才使得其不会占据内存。则加上“code”关键字。
- 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,
- }

0x18, 0x30, 0x1C , 0x10,【2个一组】
(1)音调【振动频率决定】:0x18【奇数次】
(2)音长:0x30【偶数次】



(1)音节:定时器T0控制的是音乐的节拍(某一个音节持续时间)而不管音调(频率)
(2)音调【音频】:是直接使用delay做出来的,控制发出什么样子的声音
-
- /************************************************************************
- [文件名] C51音乐程序(八月桂花)
- [功能] 通过单片机演奏音乐
-
- /**********************************************************************/
-
- #include
- //提供移位函数,可以省略
- //#include
- //本例采用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;
-
- //此处表示将:低4位留下了,高4位去除
- TMOD &= 0x0f;
- TMOD |= 0x01; // timer0 工作在模式1,16位定时器下
- /**
- 将TH和TL合起来就变为:0xd8ef--》55535---》
- 65535-10000=55535---》10000us---》0.0001s--》10ms
- */
- 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); //表示播放完一次,延迟1s,接着下一次播放
- //如果想要播放一次,则下面goto注释
- goto play; //跳转接着播放
- } //如果碰到结束符,延时1秒,回到开始再来一遍
- else if (p == 0xff) //0xff:休止符
- {
- i = i + 1;//跳过这一组数据
- delayms(100);
- TR0 = 0; //TR0:关闭定时器
- goto a;
- } //若碰到休止符,延时100ms,继续取下一音符
- else //常规情况p==正常情况
- {
- m = music_tab[i++]; // m取频率常数【A,B,C】
- n = music_tab[i++];// n取节拍常数 【1/2,1/3,1/4】
- }
-
- //打开开定时器1
- TR0 = 1;
- while (n != 0) //节拍不等于0
- {
- //~:按位取反
- //!:逻辑取反
- Beep = ~Beep; //修改蜂鸣器电平 【~】与【!】一样
- delay(m); //等待节拍完成, 通过P1口输出音频(可多声道哦!)
- }
- TR0 = 0; //关定时器1
- }
- }
-
-
-
-
单片机应用番外篇——蜂鸣器的应用之可实现切歌、暂停功能的简单音乐盒_哔哩哔哩_bilibili
- /**
- 使用中断处理程序控制音乐的暂停和播放,切换
- */
-
- //外部中断初始化
-
- void EX_init(){
-
- IT0=1;//下降沿触发方式 INT0
- IT1=1;//下降沿触发方式 INT1
- EX0=1; //外部中断0中断允许位
- EX1=1; //打开中断开关
- EA=1;//打开总的中断开关
-
- }
-
- //暂停功能
- void EX0_isr() interrupt 0
- {
- DelayXms(10);//消除抖动
- if(INT0==0)//这里是INT1已经定义了,对应P3.2这个IO口,可以直接使用
- {
- //暂停通过定时计数器,则将计数器进行取反
- TR0=~TR0;
- TR1=~TR1;
- }
- }
-
- //切歌功能
- void EX1_isr() interrupt 2
- {
- DelayXms(10);//消除抖动
- if(INT1==0)//这里是INT1已经定义了,对应P3.2这个IO口,可以直接使用
- {
- state++;
- if(state==3){ //因为此时我们只有3曲歌
- state=0;
- }
- }
- }
-
- unsigned char state=0;//控制切歌
-
- void main(){
-
- EX_init();
- InitialSound();
- while(1){
- switch(state){ //这个切歌,通过外部中断1,则进行转换
- case 0:
- Play(Music_Girl,0,2,345);break;
- case 1:
- Play(Music_haw,0,23,543);break;
- default:break;
- }
- }
-
- }