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