• 【51单片机】10-蜂鸣器


    1.蜂鸣器的原理

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

    1.无源蜂鸣器原理

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

    (2)内部结构和材料

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

    (4)控制信号,是高低电平相间【一直有电或者一直没电是不会响,要交互产生方波】

    (5)电路图因为蜂鸣器要的电流很大,单独使用单片机是无法驱动的,所以要使用三极管

    (6)音调如何控制:音调受震动频率控制,就等于控制信号的频率。频率越高音调越高,听起来越刺耳。【声音是振动产生的】

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

    2.有源蜂鸣器

    怎么区别有源蜂鸣器和无源蜂鸣器?(全面)-科森电子官网

    1.无源蜂鸣器的缺陷

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

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

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

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

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

    4.三极管驱动

    5.蜂鸣器发声音频率

    2.让蜂鸣器响起来

    1.接线确定

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

    频率越低(1KHZ),声音越沙哑,

    频率越高(10KHZ),声音越尖锐

    1. #include
    2. /**
    3. 使用延时函数,让蜂鸣器响起来
    4. */
    5. sbit BUZZER=P0^0; //buzzer的驱动引脚
    6. /**
    7. 计算这个延时函数是延时多久?
    8. 本单片机使用的是12MHZ,使用了12T(12分频)-->12MHZ/12T=1us
    9. 周期:1us【运行一个指令所用的时间】
    10. 100*10=1000个指令
    11. 1000 *1us=1ms=0.001s
    12. 频率=1s/0.001s=1kHZ
    13. */
    14. void delay(void){
    15. unsigned char i,j;
    16. for(i=0;i<100;i++){
    17. for(j=0;j<10;j++);
    18. }
    19. }
    20. void main(){
    21. while(1){
    22. BUZZER=1;//将引脚变外高电平
    23. delay();
    24. BUZZER=0;
    25. delay();
    26. }
    27. }

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

    所以时间要控制好

    如果时间太短,则可能会发不出声音【超声波】

    如果时间太长,则声音很混沌甚至不发出声音【次声波】

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

    如果i和j越大【时间大,频率越低】,则音调越小,声音越不尖锐

    如果i和j越小【时间短,频率越高】,则音调越大,声音越尖锐

    4.时钟周期的计算

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

    1.上节驱动方法的问题

    (1)不容易精确控制时间

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

    2.定时器控制蜂鸣器响

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

    (1)10KHz=>1/10000s=>0.0001s===》0.1ms===>100us===>高电平+低电平的时间都为50us。所以要定的时间就是50us

    (2)外部晶振12MHz+12T设置==>内部时钟频率1MHz===》1us【一个时间周期】===》TL0=255-50=205,TH0=255

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

    我们在设置TH0和TL0应该将获得的时间取其补码【因为加法计数器是从65535-某一个数值】

    比如:我们是TL0=50; TH0=0;

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

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

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

    (65536-50000)/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

    1. //宏定义一个时钟频率
    2. //10KHz---》10 000s
    3. #define XKHZ 10 //10*10的三次方Hz 要定多少Khz,就定义在这里
    4. //宏定义us
    5. //这里我们除以2,是因为想要分给TH0和TL0
    6. //1000---》1000ms
    7. //这里是XKHZ会被换算成XKs
    8. // 1/XKHz===>时钟周期
    9. //这里“1000”是通过---》1/1KHz*1000【换算ms】*1000【换算us】
    10. #define US (1000/XKHZ)/2
    11. sbit BUZZER=P0^0; //buzzer的驱动引脚
    12. //【注意点】因为51单片机是加法计数器,所以实际上我们要算的范围
    13. //应该是65535-US,而不是0-US
    14. #define N (65535 -US)
    15. void delay(void){
    16. unsigned char i,j;
    17. for(i=0;i<100;i++){
    18. for(j=0;j<10;j++);
    19. }
    20. }
    21. void timer0_isr(void) interrupt 1 using 1{
    22. //这里再一次赋值,是因为我们想要他循环,所以我们要在他每一次进来的时候重新赋值
    23. TL0=N % 256;//低位取余
    24. TH0=N / 256;//高位取商
    25. BUZZER=!BUZZER;
    26. }

    5.完整代码

    注意点:

    1)频率=1s/周期

    2)我们计算出频率后要记得/2,因为要均等分配给TL0和TH0

    3)因为51单片机是典型的加法定时器,所以我们如果使用16位寄存器,则应该是使用65535-TL/TH--->才会得出我们要计数的个数

    4)当我们要真正计算TH和TL的时候,是要/256【不是255~~~~~~~】

    1. #include
    2. /**
    3. 用定时器控制蜂鸣器的音调
    4. */
    5. //定义一个时钟周期
    6. #define XKHZ 10 //10*10的三次方Hz 要定多少Khz,就定义在这里
    7. //宏定义us
    8. //这里我们除以2,是因为想要分给TH0和TL0
    9. // 1/XKHz===>时钟频率
    10. //宏定义一个时钟频率
    11. //10KHz【周期】---》10 000s---》频率=1s/10KHZ=1s/10 000=0.0001=100us
    12. #define US (1000/XKHZ)/2
    13. //【注意点】因为51单片机是加法计数器,所以实际上我们要算的范围
    14. //应该是65535-US,而不是0-US
    15. #define N (65535 -US)
    16. sbit BUZZER=P0^0;//buzzer的驱动引脚
    17. void timer0_isr(void) interrupt 1 using 1{
    18. //这里再一次赋值,是因为我们想要他循环,所以我们要在他每一次进来的时候重新赋值
    19. TL0=N % 256;//低位取余
    20. TH0=N / 256;//高位取商
    21. BUZZER=!BUZZER;
    22. }
    23. void main(){
    24. TMOD=0x01;//T0使用16bit定时器
    25. /**
    26. (1)10KHz=>1/10000s=>0.0001s===》0.1ms===>100us===>高电平+低电平的时间都为50us。所以要定的时间就是50us
    27. (2)外部晶振12MHz+12T设置==>内部时钟频率1MHz===》1us【一个时间周期】===》TL0=255-50=205,TH0=255
    28. */
    29. TL0=50;
    30. TH0=0;
    31. TR0=1;//T0打开开始计数
    32. ET0=1;//T0中断允许
    33. EA=1;//总中断允许
    34. while(1);
    35. }

    4.蜂鸣器发出滴滴声音

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

    1.有声音和无声音长短一致

    1. #include
    2. /**
    3. 用定时器控制蜂鸣器音调;有声音和无声音长短一致【count值一样】
    4. */
    5. sbit BUZZER=P0^0; //buzzer的驱动引脚
    6. //宏定义一个时钟频率
    7. #define XKHZ 50 //10*10的三次方Hz 要定多少Khz,就定义在这里
    8. //这里“1000”是通过---》1/1KHz*1000【换算ms】*1000【换算us】
    9. #define US (1000/XKHZ)/2
    10. #define N (65535 -US)
    11. //计数器
    12. unsigned int count;
    13. //判断此时是从”有声音“到"没声音”,还是从“没声音”到“有声音”
    14. unsigned char flag=0; //flag=0表示有声音,flag=1表示没有声音
    15. void delay(void){
    16. unsigned char i,j;
    17. for(i=0;i<100;i++){
    18. for(j=0;j<10;j++);
    19. }
    20. }
    21. void timer0_isr(void) interrupt 1 using 1{
    22. //这里再一次赋值,是因为我们想要他循环,所以我们要在他每一次进来的时候重新赋值
    23. TL0=N % 256;//低位取余
    24. TH0=N / 256;//高位取商
    25. if(count--==0){//说明此时要进行翻转,5000中的1次
    26. count=5000;
    27. //判断此时是从“有声音”像“无声音”,还是“无声音”到“有声音”
    28. if(flag==0){//进入的时候是“有声音”
    29. //则表示此时是想要从“有声音”向“无声音”进行转换
    30. flag=1;
    31. }else{
    32. flag=0;
    33. //取反,才可以发出声音
    34. BUZZER=!BUZZER;
    35. }
    36. }else{//说明不用进行翻转,5000中的4999次
    37. //这里我们也要进行判断
    38. //判断此时是从“有声音”像“无声音”,还是“无声音”到“有声音”
    39. if(flag==0){//进入的时候是“有声音”
    40. //取反,才可以发出声音
    41. BUZZER=!BUZZER;
    42. }else{
    43. //空的,因为不进行任何操作
    44. }
    45. }
    46. }
    47. void main(){
    48. //【第一步】初始化:我们使用的是定时器T0
    49. TMOD=0x01; //T0使用16位bit定时器
    50. //********************************************************
    51. TL0=N % 256;//低位取余
    52. TH0=N / 256;//高位取商
    53. //********************************************************
    54. //打开计数器;TCON中的TR0【定时器T0的运行控制位】
    55. TR0=1; //T0打开开始计数
    56. //T0的中断溢出位,表示允许中断
    57. ET0=1; //T0中断允许
    58. EA=1; //打开中断允许
    59. BUZZER=1;
    60. //设置响和不响的周期时间
    61. count=500; //对应5KHZ---》count=200us【上面我们计算出来的】*5000us=100ms
    62. //count=20000;//对应20KHZ------》count=5us*20 000us=100ms
    63. //count=5000;//对应1KHZ-----》count=1000us*100us=100ms
    64. //初始化,有声音
    65. flag=0;
    66. }

    2.有声音和无声音的长度不一致 

    1. #include
    2. /**
    3. 用定时器控制蜂鸣器音调:有声音和无声音的长度不一致
    4. */
    5. sbit BUZZER = P0^0; // buzzer的驱动引脚
    6. #define XKHZ 4 // 要定多少Khz,就直接写这里
    7. #define US (500/XKHZ)
    8. #define N (65535-US)
    9. unsigned int count;
    10. unsigned char flag = 0; // flag = 0表示有声音,flag = 1表示没声音
    11. void timer0_isr(void) interrupt 1 using 1
    12. {
    13. TL0 = N % 256;
    14. TH0 = N / 256;
    15. if (count-- == 0)
    16. {
    17. // 说明到了翻转的时候了
    18. // count = 600;
    19. if (flag == 0)
    20. {
    21. // 之前是处于有声音的,说明本次是从有声音到无声音的翻转
    22. flag = 1;
    23. count = 600*10;
    24. }
    25. else
    26. {
    27. // 之前是处于没声音的,说明本次是从没声音到有声音的翻转
    28. flag = 0;
    29. BUZZER = !BUZZER;
    30. count = 600;
    31. }
    32. }
    33. else
    34. {
    35. // 常规情况,也就是不反转时
    36. if (flag == 0)
    37. {
    38. BUZZER = !BUZZER; // 4999次声音
    39. }
    40. else
    41. {
    42. // 空的就可以,因为不进行任何IO操作就是没声音
    43. }
    44. }
    45. }
    46. void main(void)
    47. {
    48. TMOD = 0x01; // T0使用16bit定时器
    49. TL0 = N % 256;
    50. TH0 = N / 256;
    51. TR0 = 1; // T0打开开始计数
    52. ET0 = 1; // T0中断允许
    53. EA = 1; // 总中断允许
    54. BUZZER = 1;
    55. // 设置响和不响的周期时间
    56. count = 600;
    57. flag = 0;
    58. while (1);
    59. }

    5.让蜂鸣器唱歌

    1.为什么蜂鸣器可以唱歌

    (1)发声音频可变---》延迟函数(delay)

    (2)发声音长度可变---》定时器

    1. unsigned char i;
    2. for(i=0;i<200;i++){//控制声音响应时间长短
    3. Sound=~Sound;
    4. DelayXms(1);//控制声音的不同
    5. }
    6. for(i=0;i<50;i++){
    7. Sound=~Sound;
    8. DelayXms(2);
    9. }

    2.分析写好的唱歌程序

    (1)复制代码过去

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

    3.”code“关键字的使用

    因为我们加入的歌曲的编码是固定不变的,但是51单片机的内存有限制,所以我们只能把歌曲的编码放在常量区中,才使得其不会占据内存。则加上“code”关键字。

    1. unsigned char code music_tab[] =
    2. {
    3. 0x18, 0x30, 0x1C , 0x10, //格式为: 频率常数, 节拍常数, 频率常数, 节拍常数,
    4. 0x20, 0x40, 0x1C , 0x10,
    5. 0x18, 0x10, 0x20 , 0x10,
    6. 0x1C, 0x10, 0x18 , 0x40,
    7. 0x1C, 0x20, 0x20 , 0x20,
    8. 0x1C, 0x20, 0x18 , 0x20,
    9. 0x20, 0x80, 0xFF , 0x20,
    10. 0x30, 0x1C, 0x10 , 0x18,
    11. 0x20, 0x15, 0x20 , 0x1C,
    12. }

    4.音节的构成

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

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

    (2)音长:0x30【偶数次】

    注意点:

    5.音频 VS 音调

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

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

    1. /************************************************************************
    2. [文件名] C51音乐程序(八月桂花)
    3. [功能] 通过单片机演奏音乐
    4. /**********************************************************************/
    5. #include
    6. //提供移位函数,可以省略
    7. //#include
    8. //本例采用89C52, 晶振为11.0592MHZ
    9. //关于如何编制音乐代码, 其实十分简单,各位可以看以下代码.
    10. //频率常数即音乐术语中的音调,而节拍常数即音乐术语中的多少拍;
    11. //所以拿出谱子, 试探编吧!
    12. sbit Beep = P0^0 ; // 要根据实际的接线来修改
    13. unsigned char n = 0; //n为节拍常数变量
    14. unsigned char code music_tab[] =
    15. {
    16. 0x18, 0x30, 0x1C , 0x10, //格式为: 频率常数, 节拍常数, 频率常数, 节拍常数,
    17. 0x20, 0x40, 0x1C , 0x10,
    18. 0x18, 0x10, 0x20 , 0x10,
    19. 0x1C, 0x10, 0x18 , 0x40,
    20. 0x1C, 0x20, 0x20 , 0x20,
    21. 0x1C, 0x20, 0x18 , 0x20,
    22. 0x20, 0x80, 0xFF , 0x20,
    23. 0x30, 0x1C, 0x10 , 0x18,
    24. 0x20, 0x15, 0x20 , 0x1C,
    25. 0x20, 0x20, 0x20 , 0x26,
    26. 0x40, 0x20, 0x20 , 0x2B,
    27. 0x20, 0x26, 0x20 , 0x20,
    28. 0x20, 0x30, 0x80 , 0xFF,
    29. 0x20, 0x20, 0x1C , 0x10,
    30. 0x18, 0x10, 0x20 , 0x20,
    31. 0x26, 0x20, 0x2B , 0x20,
    32. 0x30, 0x20, 0x2B , 0x40,
    33. 0x20, 0x20, 0x1C , 0x10,
    34. 0x18, 0x10, 0x20 , 0x20,
    35. 0x26, 0x20, 0x2B , 0x20,
    36. 0x30, 0x20, 0x2B , 0x40,
    37. 0x20, 0x30, 0x1C , 0x10,
    38. 0x18, 0x20, 0x15 , 0x20,
    39. 0x1C, 0x20, 0x20 , 0x20,
    40. 0x26, 0x40, 0x20 , 0x20,
    41. 0x2B, 0x20, 0x26 , 0x20,
    42. 0x20, 0x20, 0x30 , 0x80,
    43. 0x20, 0x30, 0x1C , 0x10,
    44. 0x20, 0x10, 0x1C , 0x10,
    45. 0x20, 0x20, 0x26 , 0x20,
    46. 0x2B, 0x20, 0x30 , 0x20,
    47. 0x2B, 0x40, 0x20 , 0x15,
    48. 0x1F, 0x05, 0x20 , 0x10,
    49. 0x1C, 0x10, 0x20 , 0x20,
    50. 0x26, 0x20, 0x2B , 0x20,
    51. 0x30, 0x20, 0x2B , 0x40,
    52. 0x20, 0x30, 0x1C , 0x10,
    53. 0x18, 0x20, 0x15 , 0x20,
    54. 0x1C, 0x20, 0x20 , 0x20,
    55. 0x26, 0x40, 0x20 , 0x20,
    56. 0x2B, 0x20, 0x26 , 0x20,
    57. 0x20, 0x20, 0x30 , 0x30,
    58. 0x20, 0x30, 0x1C , 0x10,
    59. 0x18, 0x40, 0x1C , 0x20,
    60. 0x20, 0x20, 0x26 , 0x40,
    61. 0x13, 0x60, 0x18 , 0x20,
    62. 0x15, 0x40, 0x13 , 0x40,
    63. 0x18, 0x80, 0x00
    64. };
    65. // T0定时控制的是音乐的节拍(某一个音节持续的时间)而不管音调(频率)
    66. // 音调是直接使用delay做出来的。
    67. void int0() interrupt 1 //采用中断0 控制节拍
    68. {
    69. TH0 = 0xd8;
    70. TL0 = 0xef;
    71. n--;
    72. }
    73. void delay (unsigned char m) //控制频率延时
    74. {
    75. unsigned i = 3 * m;
    76. while (--i);
    77. }
    78. void delayms(unsigned char a) //豪秒延时子程序
    79. {
    80. while (--a); //采用while(--a) 不要采用while(a--); 各位可编译一下看看汇编结果就知道了!
    81. }
    82. void main()
    83. {
    84. unsigned char p, m; // m为频率常数变量
    85. unsigned char i = 0;
    86. //此处表示将:低4位留下了,高4位去除
    87. TMOD &= 0x0f;
    88. TMOD |= 0x01; // timer0 工作在模式1,16位定时器下
    89. /**
    90. 将TH和TL合起来就变为:0xd8ef--》55535---》
    91. 65535-10000=55535---》10000us---》0.0001s--》10ms
    92. */
    93. TH0 = 0xd8;
    94. TL0 = 0xef; // 这个TH和TL的值合起来定了1个10ms左右的一个时间
    95. IE = 0x82;
    96. play:
    97. while (1)
    98. {
    99. a: p = music_tab[i]; //表示指向第一个
    100. if (p == 0x00) // 一遍播放完了,延时1s后自动开始下一遍
    101. {
    102. i=0;
    103. delayms(1000); //表示播放完一次,延迟1s,接着下一次播放
    104. //如果想要播放一次,则下面goto注释
    105. goto play; //跳转接着播放
    106. } //如果碰到结束符,延时1秒,回到开始再来一遍
    107. else if (p == 0xff) //0xff:休止符
    108. {
    109. i = i + 1;//跳过这一组数据
    110. delayms(100);
    111. TR0 = 0; //TR0:关闭定时器
    112. goto a;
    113. } //若碰到休止符,延时100ms,继续取下一音符
    114. else //常规情况p==正常情况
    115. {
    116. m = music_tab[i++]; // m取频率常数【A,B,C】
    117. n = music_tab[i++];// n取节拍常数 【1/2,1/3,1/4】
    118. }
    119. //打开开定时器1
    120. TR0 = 1;
    121. while (n != 0) //节拍不等于0
    122. {
    123. //~:按位取反
    124. //!:逻辑取反
    125. Beep = ~Beep; //修改蜂鸣器电平 【~】与【!】一样
    126. delay(m); //等待节拍完成, 通过P1口输出音频(可多声道哦!)
    127. }
    128. TR0 = 0; //关定时器1
    129. }
    130. }

    6.切歌,暂停功能

    单片机应用番外篇——蜂鸣器的应用之可实现切歌、暂停功能的简单音乐盒_哔哩哔哩_bilibili

    1. /**
    2. 使用中断处理程序控制音乐的暂停和播放,切换
    3. */
    4. //外部中断初始化
    5. void EX_init(){
    6. IT0=1;//下降沿触发方式 INT0
    7. IT1=1;//下降沿触发方式 INT1
    8. EX0=1; //外部中断0中断允许位
    9. EX1=1; //打开中断开关
    10. EA=1;//打开总的中断开关
    11. }
    12. //暂停功能
    13. void EX0_isr() interrupt 0
    14. {
    15. DelayXms(10);//消除抖动
    16. if(INT0==0)//这里是INT1已经定义了,对应P3.2这个IO口,可以直接使用
    17. {
    18. //暂停通过定时计数器,则将计数器进行取反
    19. TR0=~TR0;
    20. TR1=~TR1;
    21. }
    22. }
    23. //切歌功能
    24. void EX1_isr() interrupt 2
    25. {
    26. DelayXms(10);//消除抖动
    27. if(INT1==0)//这里是INT1已经定义了,对应P3.2这个IO口,可以直接使用
    28. {
    29. state++;
    30. if(state==3){ //因为此时我们只有3曲歌
    31. state=0;
    32. }
    33. }
    34. }
    35. unsigned char state=0;//控制切歌
    36. void main(){
    37. EX_init();
    38. InitialSound();
    39. while(1){
    40. switch(state){ //这个切歌,通过外部中断1,则进行转换
    41. case 0:
    42. Play(Music_Girl,0,2,345);break;
    43. case 1:
    44. Play(Music_haw,0,23,543);break;
    45. default:break;
    46. }
    47. }
    48. }
  • 相关阅读:
    keepalived实现nginx负载均衡机高可用
    Redis学习笔记【四】完结
    ubuntu16 虚拟机单盘扩容
    Python使用pynput模块后台监控鼠标及按键
    域名个人信息备案的能用 websocket 吗
    【夯实Kafka知识体系及基本功】分析一下(Broker)服务的可靠性机制分析「原理篇」
    一站式BI解决方案:从数据采集到处理分析,全面满足决策支持需求
    算法进阶指南图论 道路与航线
    umich cv-5-2 神经网络训练2
    推荐一个屏幕上鼠标高亮显示的小工具
  • 原文地址:https://blog.csdn.net/m0_63077733/article/details/133362701