美文网首页Arduino 专题学习ArduinoArduino
项目六:蜂鸣器演奏乐曲

项目六:蜂鸣器演奏乐曲

作者: 0210吴鑫泽 | 来源:发表于2019-06-07 16:48 被阅读0次

    乐谱转化为播放程序的基本方法

    我们先来回顾一下七音依次播放的教程,通过设置频率和持续时长来控制蜂鸣器的播放。

    //定义音阶常量
          #define Do 262
          #define Re 294
          #define Mi 330
          #define Fa 349
          #define Sol 392
          #define La 440
          #define Si 494
          int buzzerPin=8;      //定义蜂鸣器针脚
          int scale[]={Do,Re,Mi,Fa,Sol,La,Si};  //定义音阶数组
    
           void setup() {
          pinMode(buzzerPin,OUTPUT);// 设置数字引脚为输出
          }
           void loop() {
          for(int i=0;i<7;i++){// 使用for循环依次播放音阶数组中的元素
          tone(buzzerPin,scale[i],1000);//依次读取音阶数组中的音阶频率,并且每个音阶持续1秒钟
          delay(1000); //等待1000毫秒
          noTone(buzzerPin);  //停止发声
          delay(1000);  //等待1000毫秒
          }
    
          }
    
    

    既然我们知道了控制音阶播放的原理,那我们是不是可以尝试用这种原理去进行作曲呢?

    //定义音阶常量
          #define Do 262
          #define Re 294
          #define Mi 330
          #define Fa 349
          #define Sol 392
          #define La 440
          #define Si 494
          int buzzerPin=4;      //定义蜂鸣器针脚
          int scale[]={Do,Re,Mi,Do,Do,Re,Mi,Do,Mi,Fa,Sol,Mi,Fa,Sol};  //定义音阶数组
    
           void setup() {
          pinMode(buzzerPin,OUTPUT);// 设置数字引脚为输出
          }
           void loop() {
          for(int i=0;i<14;i++){// 使用for循环依次播放音阶数组中的元素
          tone(buzzerPin,scale[1],1000);//依次读取音阶数组中的音阶频率,并且每个音阶持续1秒钟
          delay(500); //等待1000毫秒
          tone(buzzerPin,scale[2],1000);
          delay(500); 
          tone(buzzerPin,scale[3],1000);
          delay(500);
          tone(buzzerPin,scale[4],1000);
          delay(500);
          tone(buzzerPin,scale[5],1000);
          delay(500);
          tone(buzzerPin,scale[6],1000);
          delay(500);
          tone(buzzerPin,scale[7],1000);
          delay(500);
          tone(buzzerPin,scale[8],1000);
          delay(500);
          tone(buzzerPin,scale[9],1000);
          delay(500);
          tone(buzzerPin,scale[10],1000);
          delay(500);
          tone(buzzerPin,scale[11],1000);
          delay(500);
          tone(buzzerPin,scale[12],1000);
          delay(500);
          tone(buzzerPin,scale[13],1000);
          delay(500);
          tone(buzzerPin,scale[14],1000);
          delay(500);
          }
    
          }
    
    

    通过控制引脚发出的频率和持续长度来转换成音调和节拍,逐个音拼凑成一段乐曲,仅仅两句乐曲就占了如此大的篇幅,这就暴露出了几个问题:

    优点:简单易懂

    缺点:1.音符间节奏难控制
    2.程序冗长编写费力

    那我们有什么好的方法来解决呢?

    以下代码可以完美的解决这个问题:

    int speakerPin = 9;                             //蜂鸣器引脚定义
    
    int length = 15;                                  //曲目长度
    
    char notes[] = "ccggaagffeeddc "; //曲目音阶,最后空格表示结束
    
    int beats[] ={1,1,1,1,1,1,2,1,1,1,1,1,1,2,4 }; //节拍
    int tempo = 300;                                              //节奏 
    void playTone(int tone ,int duration)
    {
      for (long i= 0;i<duration*1000L;i+=tone*2)
      {
        digitalWrite(speakerPin,HIGH);
        delayMicroseconds(tone);
        digitalWrite(speakerPin,LOW);
        delayMicroseconds(tone);
      }
     }
    
     void playNote(char note,int duration)
     {
      char names[] ={'c','d','e','f','g','a','b','C'};
      int tones[]={1915,1700,1519,1432,1275,1136,1010,956};
      //利用对比位的方式来播放某一个音阶
      for(int i = 0;i<8;i++)
      {
        //将对比得到的音阶高电位时间长度传送给playTone函数播放 
        if(names[i]==note)
        playTone(tones[i],duration);
       }
      }
    void setup()
    {
      pinMode(speakerPin,OUTPUT); //引脚设定为输出
      }
    void loop()
    {for (int i =0;i<length;i++)
    {
      if(notes[i] == ' ')
       delay (beats[i]*tempo); //rest
       else
       playNote(notes[i],beats[i]*tempo);
       //pause between notes
       delay (tempo/2);
       }
     }      
    
    

    这段代码的精彩之处就在于可以直观快捷的控制曲目的节拍和节奏,并且可以直接对音调发出的顺序进行编排。中间通过自定义了两个函数playTone()和playNote()对音调和节拍进行了定义,使得后期播放效果非常完美。

    大家如果有什么疑问可以评论留言,我给大家一一解答。~

    相关文章

      网友评论

        本文标题:项目六:蜂鸣器演奏乐曲

        本文链接:https://www.haomeiwen.com/subject/lqxvxctx.html