2014年5月3日 星期六

[Arduino] 會唱歌的蜂鳴器 – Controlling Piezo

image
這篇介紹怎麼用 Arduino 讓常見的蜂鳴器唱歌!

首先介紹一下甚麼是聲音,一幫來說我們說話唱歌發出的都是聲音,聲音簡單的組成為兩項:聲音的高低與聲音的大小,這個應該不用特別解說了,重點是電子訊號怎麼控制聲音的這兩項組成,聲音的大小不用說,靠的是通過的電壓高低,至於控制高低音,靠的是控制頻率

要讓蜂鳴器唱歌基本上就是讓蜂鳴器可以產生不同頻率的聲音, Arduino 上只要用兩個指令:tone() / noTone() 就可以達到 (相關介紹可以看這裡)
  • Arduino 由指定的 pin 發出特定頻率(duty cycle = 50%,PWM 介紹看這裡)的方波一段時間控制蜂鳴器發出的聲音
  • tone(pin, frequency, duration)
    • pin:輸出方波訊號的 digital pin
    • frequency (unsigned int):讓蜂鳴器發出的聲音的對應頻率
    • duration (unsigned long):發出聲音的長短
    • 這邊我在測試的時候發現一個問題,使用 tone() 的時候如果沒搭配 delay (duration) 聲音會亂掉
  • noTone (pin):將指定 pin 的聲音停止,Arduino 的缺點就是沒辦法讓兩之 pin 同時輸出,所以很可惜的沒辦法用 Arduino 做和絃~,當 pin2 發出聲音的時候要讓 pin3 發出聲音,要先 noTone (2) 停止 pin2 發出的訊號,不然不會有任何作用

下面我們回憶一下小時候音樂課學的頻率與音階的關係:
image
輸入 tone(2,262,1000),就可以讓接在 pin2 上的蜂鳴器發出 Do~ 的聲音 1 秒。

好了!我們可以讓蜂鳴器唱歌了!!

Step 1. 準備材料
蜂鳴器 x1 (沒了)

Step 2. 接線圖 (超簡單)
image
image


Step 3. Sketch 及說明:

首先我們要讓他唱的歌是小星星,簡譜如下
image

int speakerPin = 2;
// 依照簡譜的順序,填入代表的音符,空白代表休止符
char notes[] = "ccggaagffeeddc ";
// 決定每個音階的拍子,注意這邊用 unsigned long 所以拍子只能是正整數
unsigned long beats[] = {1,1,1,1,1,1,2,1,1,1,1,1,1,2,4};
// 利用 sizeof(),算出總共要多少音符
int length = sizeof(notes);
// 決定一拍多長,這邊一拍 300 ms
int tempo = 300;

void setup() {
  pinMode(speakerPin, OUTPUT);
}

void loop() {
  // 利用 for 來播放我們設定的歌曲,一個音一個音撥放
  for (int i = 0; i < length; i++) {
 // 如果是空白的話,不撥放音樂
    if (notes[i] == ' ') {
      delay(beats[i] * tempo); // rest
    } else {
  // 呼叫 palyNote() 這個 function,將音符轉換成訊號讓蜂鳴器發聲
      playNote(speakerPin,notes[i], beats[i] * tempo);
    }
    // 每個音符之間的間隔,這邊設定的長短會有連音 or 段音的效果
    delay(tempo/10);
  }
}

void playNote(int OutputPin, char note, unsigned long duration) {
   // 音符字元與對應的頻率由兩個矩陣表示
  char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
  int tones[] = { 261, 294, 330, 349, 392, 440, 494, 523 };
  // 播放音符對應的頻率
  for (int i = 0; i < 8; i++) {
    if (names[i] == note) {
      tone(OutputPin,tones[i], duration);
  //下方的 delay() 及 noTone (),測試過後一定要有這兩行,整體的撥放出來的東西才不會亂掉,可能是因為 Arduino 送出tone () 頻率後會馬上接著執行下個指令,不會等聲音播完,導致撥出的聲音混合而亂掉
      delay(duration);
      noTone(OutputPin);
    }
  }
}


這邊要注意的是,因為 tone () 的時間只能整數,所以有半拍的音樂 beats = 0.5 是不會有動作的,建議就是直接將所有拍子 x2 去寫。下方就是我自己弄得比較難一點的歌~







2 則留言:

  1. 很棒,我修改了一下,做了一個進階版,同時讓六個LED燈閃爍顯示音階

    回覆刪除

Anything That's Worth Chatting

Related Posts Plugin for WordPress, Blogger...