2017年2月2日 星期四

arduino-蜂鳴器練習

參考書籍:數位時代的端士刀來了:Arduino開創物聯網大局

好久沒有寫網誌了,也好久沒有寫程式了(從大四跨系選修程式語言到現在)
準備要玩arduino,就記錄一下學習新事物的過程吧

要發出聲音需要蜂鳴器,蜂鳴器分成有源蜂鳴器、無源蜂鳴器兩種
有源蜂鳴器只能發出單頻率的聲音,可以拿來寫警告音或是練習摩斯密碼
無源蜂鳴器就可以發出不同頻率的聲音了


  • 這次在修改程式的時候遇到幾個問題
    1. 升半音的頻率是多少?
      查了資料發現升降半音的頻率是原頻率*2^(1/12)  [原頻率乘於2的12分之1次方]
    2. 想要定義節拍長度該如何?
      在22行int time[]={   };    //輸入節拍,設定聲響時間長度
    3. 不發出聲音的休止符要怎麼處理?
      一開始我是設定#define O1 000  頻率為0,結果發現蜂鳴器會發出雜音,後來在程式中加入了is else的函數,可是還是有缺陷,因為這樣就不能設定休止符拍子數了,目前剩下這個bug無法解決
      if(time[i]>0)                        //判斷時間是否為不發聲的0,如果不是發聲
           delay(time[i]*250);
      else{                                 //判斷時間是否為不發聲的0,如果是不發聲
            noTone(p);
            delay(250);
            }
    4. 變調該如何處理
      第一首「給愛麗絲」前段問題解決了,結果第二首的「恭喜恭喜」出現了變調...,還變了兩次,所以我又要學會讀五線譜上變調時的拍子怎麼讀,可是最後還是卡在變太多種了,我無法解決0.5拍的問題...(其實只要換成整數倍就好了,不過我懶惰惹...)
    總之學習就是這樣,一直解決問題,運用舊經驗、google、書籍學到新東西,附上這次修改的三個函數


    以下是我改寫的函數部分,歌曲是 給愛麗絲 的前半段,也就是垃圾車的音樂啦

    -----  程式分隔線  -----
    //定義音階常數
    #define C41 262  //1 Do
    #define D41 294  //2 Re
    #define E41 330  //3 Mi
    #define F41 349  //4 Fa
    #define G41 392  //5 Sol
    #define G42 415  //#5 #Sol
    #define A41 440  //6 La
    #define B41 494  //7 Si
    #define C51 523  //1 Do_h
    #define D51 587  //2 Re_h
    #define D52 622  //#2 #Re_h
    #define E51 659  //3 Mi_h
    #define F51 698  //4 Fa_h
    #define G51 784  //5 Sol_h
    #define A51 880  //6 La_h
    #define B51 988  //7 Si_h
    #define O1 000  //休止符
    //要學習升降半音的方式是:頻率*2^(1/12)
    int p=10;
    int scale[]={E51,D52,E51,D52,E51,B41,D51,C51,A41,O1,E41,A41,B41,E41,G42,B41,C51,E41,E51,D52,E51,D52,E51,B41,D51,C51,A41,O1,E41,A41,B41,E41,C51,B41,A41};  //輸入歌曲音調
    int time[]={1,1,1,1,1,1,1,1,3,0,1,1,3,1,1,1,3,1,1,1,1,1,1,1,1,1,3,0,1,1,3,1,1,1,3};    //輸入節拍,設定聲響時間長度
    int length;

    void setup() {
      pinMode(p,OUTPUT);                      //設定針腳輸出模式
      length=sizeof(scale)/sizeof(scale[0]);  //取得曲譜陣列的長度
    }

    void loop() {
      for(int i=0;i<length;i++){
        tone(p,scale[i]);
     
        if(time[i]>0)                        //判斷時間是否為不發聲的0,如果不是發聲
          delay(time[i]*250);
        else{                                 //判斷時間是否為不發聲的0,如果是不發聲
          noTone(p);
          delay(250);
          }
        noTone(p);
        delay(0);
      }
      delay(1000);
    }

    -----  下一首是恭喜恭喜  -----
    //定義音階常數
    #define G40 196  //5 Sol
    #define G402 208  //#5 #Sol
    #define A40 220  //6 La
    #define B40 247  //7 Si
    #define C41 262  //1 Do
    #define D41 294  //2 Re
    #define E41 330  //3 Mi
    #define F41 349  //4 Fa
    #define G41 392  //5 Sol
    #define G42 415  //#5 #Sol
    #define A41 440  //6 La
    #define B41 494  //7 Si
    #define C51 523  //1 Do_h
    #define D51 587  //2 Re_h
    #define D52 622  //#2 #Re_h
    #define E51 659  //3 Mi_h
    #define F51 698  //4 Fa_h
    #define G51 784  //5 Sol_h
    #define A51 880  //6 La_h
    #define B51 988  //7 Si_h
    #define O1 000  //0
    //要學習升降半音的方式是:頻率*2^(1/12)
    int p=10;
    int scale[]={A40,B40,C41,D41,F41,E41,E41,E41,A41,A41,E41,E41,D41,D41,D41,F41,E41,D41,D41,C41,C41,C41,B40,A40,G402,A40,A40,D41,E41,C41,E41,B40,E41,A40,E41,D41,E41,C41,E41,B40,E41,A40};  //輸入歌曲音調
    int time[]={1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,2,2,1,2,1,2,1,2,1,2,1,2,1,3,3,2};    //輸入節拍,設定聲響時間長度
    int length;

    void setup() {
      pinMode(p,OUTPUT);                      //設定針腳輸出模式
      length=sizeof(scale)/sizeof(scale[0]);  //取得曲譜陣列的長度
    }

    void loop() {
      for(int i=0;i<length;i++){
        tone(p,scale[i]);
     
        if(time[i]>0)                        //判斷時間是否為不發聲的0,如果不是發聲
          delay(time[i]*250);
        else{                                 //判斷時間是否為不發聲的0,如果是不發聲
          noTone(p);
          delay(250);
          }
        noTone(p);
        delay(0);
      }
      delay(1000);
    }

    -----  下一個是有源蜂鳴器的摩斯密碼  -----

    int b=10;    //蜂鳴器針腳
    int s=300;   //基準時間
    void dot();  //宣告點訊號
    void dash(); //宣告劃訊號
    void wait(); //宣告字母間隔

    void setup() {
      pinMode(b,OUTPUT);    //設定針腳模式為輸出
    }
    //交替向針腳輸出高低電壓
    void loop() {
      dot();dot();dot();    //呼叫dot()函數發送3個點訊號
      wait();
      dash();dash();dash(); //呼叫dash()函數發送3個劃訊號
      wait();
      dot();dot();dot();    //呼叫dot()函數發送3個點訊號
      delay(3000);
    }

    //定義dot()函數
    void dot(){
      digitalWrite(b,HIGH);
      delay(s);
      digitalWrite(b,LOW);
      delay(s*2);
    }
    //定義dash()函數
    void dash(){
      digitalWrite(b,HIGH);
      delay(s*3);
      digitalWrite(b,LOW);
      delay(s*2);
    }
    //定義wait()函數
    void wait(){
      delay(s*7);
    }

  • 6 則留言:

    1. 如果要加上led燈 該如何修改呢

      回覆刪除
      回覆
      1. 你可以google arduino led就可以有一些資料了

        刪除
    2. 蘇武牧羊
      7.新年好
      8.小毛驢
      9.紅河谷
      有這四首code

      回覆刪除
      回覆
      1. 只要修改
        int scale[]={A40,B40,C41,D41,F41,E41,E41,E41,A41,A41,E41,E41,D41,D41,D41,F41,E41,D41,D41,C41,C41,C41,B40,A40,G402,A40,A40,D41,E41,C41,E41,B40,E41,A40,E41,D41,E41,C41,E41,B40,E41,A40}; //輸入歌曲音調
        int time[]={1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,2,2,1,2,1,2,1,2,1,2,1,2,1,3,3,2}; //輸入節拍,設定聲響時間長度
        這兩個部分,要彈命運交響曲應該也是可以的

        刪除
    3. 您好 冒昧請問一下
      如果要用和旋
      該如何寫兩個蜂鳴器在一塊ic版上的腳本呢

      回覆刪除
      回覆
      1. 哇 我從來沒思考過是否可以用成和弦
        如果把兩個蜂鳴器接在不同pin腳位上,然後設定兩個p值,一個為p1一個為p2
        就可以一次控制兩個蜂鳴器

        不過要如何同步發聲達到和弦效果我就不知道了

        刪除