【51单片机】10-蜂鸣器-CSDN博客

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    1.蜂鸣器的原理

    这里的“源”不是指电源。而是指震荡源。 也就是说有源蜂鸣器内部带震荡源所以只要一通电就会叫。 而无源内部不带震荡源所以如果用直流信号无法令其鸣叫。必须用2K~5K的方波去驱动它。 有源蜂鸣器往往比无源的贵就是因为里面含有震荡电路。

    1.无源蜂鸣器原理

    1早期的蜂鸣器都是无源的

    2内部结构和材料

    3发生原理是利用了压电效应的原理

    4控制信号是高低电平相间

    5电路图

    6音调如何控制:音调受震动频率控制就等于控制信号的频率。频率越高音调越高听起来越刺耳。

    7声音大小如何控制。由硬件决定的。无法写代码取控制声音大小。

    2.有源蜂鸣器

    1.无源蜂鸣器的缺陷

    无源蜂鸣器只能在一定的范围内进行设置太大或者太小都不行。【外部提供一个方波】

    2.内置震荡电路后形成有源蜂鸣器

    在内部添加震荡电路不用使用外部的方波进行控制【但是内部的震荡电路是不可以改变的】

    3.有源蜂鸣器也可以用频率信号驱动

    可以直接加电也可以直接通过方波进行工作【有源蜂鸣器包含无源蜂鸣器】

    4.三极管驱动

    5.蜂鸣器发声音频率

    2.让蜂鸣器响起来

    1.接线确定

    2.使用delay让蜂鸣器响起来

    #include<reg51.h>
    
    
    sbit BUZZER=P0^0;   //buzzer的驱动引脚
    
    
    
    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();
    	}
    }

     3.调节delay控制音乐的变化

    控制delay中的i和j的大小可以控制音调的振动频率从而影响声音的尖锐。

    如果i和j越大则音调越小声音越不尖锐

    如果i和j越小则音调越大声音越尖锐

    4.时钟周期的计算

    3.用定时器控制蜂鸣器音调

    1.上节驱动方法的问题

    1不容易精确控制时间

    2CPU控制蜂鸣器中不能做其他事

    2.定时器控制蜂鸣器响

    在一定时间后通过定时器中的中断处理程序取减低蜂鸣器的电平从控制蜂鸣器的响应

    110KHz=>1/10000s=>100us===>高电平+低电平的时间都为50us。所以要定的时间就是50us

    2外部晶振12MHz+12T设置==>内部时钟频率1MHz===》1us===》TL0=255-50=205TH0=255

    3.注意点1:TL0和TH0的计算

    我们在设置TH0和TL0应该将获得的时间取其补码

    比如我们是TL0=50 TH0=0

            则我们应该写入“TL0=205;TH0=255"

    	TL0=205;
    	TH0=0;
    	TL0=205 % 256;//低位取余
    	TH0=255/ 256;//高位取商

    4.注意点2定时器的计算

    (65536-50000)/256

    计数器是16位的由高8位TH0和低8位TL0组成可以存储2^16=65536个数例如当设定计算值为65536-50000=15536时也就是计数器从15536开始计时到65536溢出产生中断对于晶振频率为12MHz的单片机来说执行一个机器周期时长为1us所以这里计时50000us15536(D)转换为16进制是3CB0(H)此时TH0=3C,TL0=B0分别装入定时器即可为了免除这些计算步骤很多编程者采用"TH0=(65536-50000)/256;TL0=(65536-50000)%256",那么为什么要介入256呢我们可以做一下运算256D=0100H512D=0200H,512(D)有两个256所以高8位就是02那么15536有多少个256就是15536/256个就相当于高8位有多少数值商存入高8位剩下的不足一个256存入低8位15536%256。

    直接使用宏定义

    【注意点】我们51是加法计数器所以是65535-US

    //宏定义一个时钟频率
    #define XKHZ 10  //10*10的三次方Hz   要定多少Khz就定义在这里
    //宏定义us
    //这里我们除以2是因为想要分给TH0和TL0
    //1000---》1000ms
    #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;
    	
    }

    4.蜂鸣器发出滴滴声音

    通过count可以控制有声音和无声音的长短

    #include<reg51.h>
    
    /**
    
    	用定时器控制蜂鸣器音调
    */
    //宏定义一个时钟频率
    #define XKHZ 10  //10*10的三次方Hz   要定多少Khz就定义在这里
    #define US (1000/XKHZ)/2
    sbit BUZZER=P0^0;   //buzzer的驱动引脚
    #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){
    		//说明到了翻转的时候了
    		//count=5000;//记得重新赋值要不然就只能响一次
    		if(flag==0){
    			//说明之前处于有声音的说明本次是从有声音到无声音的翻转
    			flag=1;
                //此时“无声音”比“有声音”的时间还长了3倍
    			count=600*3;
    		}else{
    			//说明之前没声音的说明本次是没声音到有声音的翻转
    			flag=0;
    			//下面这句话加上了则表示在翻转的时候也会出现声音
    			BUZZER=!BUZZER;
    			count=600;
    		}
    	}else{//常规情况也就是不翻转时候
    		if(flag==0){
    			BUZZER=!BUZZER; //4999次声音
    		}else{
    			//空的因为不进行任何IO操作就是没有声音
    		}
    		
    	}
    	
    	
    }
    
    
    
    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=5000;     //5000*100us=500ms
    	//初始化有声音
    	flag=0;
    	
    }

    5.让蜂鸣器唱歌

    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);
    }

    2.分析写好的唱歌程序

    1复制代码过去

    2修改控制蜂鸣器的IO引脚定义

    3.”code“关键字的使用

    因为我们加入的歌曲的编码是固定不变的但是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,
    }

    4.音节的构成

    0x18, 0x30, 0x1C , 0x10,【2个一组】

    1音调【振动频率决定】0x18【奇数次】

    2音长0x30【偶数次】

    注意点

    5.音频 VS 音调

    1音节定时器T0控制的是音乐的节拍某一个音节持续时间而不管音调频率

    2音调【音频】是直接使用delay做出来的控制发出什么样子的声音

    
    /************************************************************************  
    [文件名]  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;   
    
    	//此处表示将低4位留下了高4位去除
      	TMOD &= 0x0f;   
      	TMOD |= 0x01;  		// timer0 工作在模式116位定时器下 
      	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++];
    				n = music_tab[i++];
    			}  // m取频率常数【ABC】 和 n取节拍常数 【1/21/31/4】   
    			
    			//打开开定时器1   
    				TR0 = 1;                               
    				while (n != 0) //节拍不等于0
    				{ 
    					Beep = ~Beep;   //修改蜂鸣器电平 【~】与【】一样
    					delay(m);        	//等待节拍完成, 通过P1口输出音频(可多声道哦!)    
    				}
    					TR0 = 0;                         	//关定时器1    
    			}   
    }
      
    
    
    

    6.切歌暂停功能

    单片机应用番外篇——蜂鸣器的应用之可实现切歌、暂停功能的简单音乐盒_哔哩哔哩_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;
    		}
    	}
    	
    }
  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6