2012/02/16

Arduino練習:loudspeaker揚聲器

之前一直在跟LED奮鬥(以開關切換LED明滅狀態呼吸燈霹靂車燈),現在玩玩聲音吧。

先發出一段官方範例程式碼的聲音,然後再播放兒歌妹妹揹著洋娃娃,然後再播放周杰倫的青花瓷。

電路圖(Fritzing格式)與程式原始碼,可在此下載。 

電路圖:

從Arduino板子的腳位8接到100 ohm電阻,電阻另一端接到揚聲器的正極,揚聲器的負極接地GND。


P.S. 我原本不清楚揚聲器、喇叭、蜂鳴器、loudspeaker、buzzer、等等有何不同,看了這幾篇後才了解:蜂鳴器(buzzer)與喇叭(speaker)有何不同,壓電式蜂鳴器(piezo buzzer)與電磁式蜂鳴器(magnetic buzzer)有何不同如何選用蜂鳴器。所以下圖、我買的應該叫做蜂鳴器揚聲器(到底是哪一個啊)。


程式碼:

我們將使用函式tone()發出聲音。

首先需要各音階的頻率。其中的NOTE_C5就是一般的中音Do(523Hz),NOTE_D5是Re(587Hz),NOTE_E5是Mi(659Hz),NOTE_F5是Fa(698Hz),NOTE_G5是So(784Hz),NOTE_A5是La(880Hz),NOTE_B5是Si(988Hz),而NOTE_C6是高音Do(1047Hz)。

我把NOTE_定義為頻率0,將拿來當做休止符。

#define NOTE_    0
#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

然後準備歌曲的資料,底下先用個短短的範例。
int melody[] = {
  NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};

int noteDurations[] = {
  4, 8, 8, 4, 4, 4, 4, 4
};
4代表四分音符,8代表八分音符,以此類推,數字越小,音符的持續時間越長。

然後寫個函式,傳入歌曲的資料,進行播放。
void play(int *melody, int *noteDurations, int num){
  for(int note = 0; note < num; note++){
    int noteDuration = 3000 / noteDurations[note];
    tone(8, melody[note], noteDuration);

    delay(noteDuration * 1.30);
  }
}
函式的第一個參數是所有音符的頻率,第二個參數是每一個音符要播放多久,第三個參數代表總共有幾個音符。

函式裡,先根據noteDurations算出該音符的播放時間長度,我以3000 milliseconds(三秒)為基準,你可以自行修改。

然後以tone()函式播放,第一個參數是腳位,第二個參數是音符的頻率,第三個參數代表播放多久。

然後,根據播放時間長度,增加0.3倍的延遲時間。前一個音符撥放完後,停頓一下下,再播放下一個。

然後就是setup()與loop()了。
void setup(){
}

void loop(){
  play(melody, noteDurations, sizeof(melody) / sizeof(int));
 
  delay(2000);
}
setup()不作事。在loop()裡播放歌曲,放完後停兩秒再播放一次。

上面這份歌曲資料是從Arduino官方範例抄來的,底下則是兒歌妹妹揹著洋娃娃的歌曲資料。

int melody[] = {
  NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_E4, NOTE_D4, NOTE_C4,
  NOTE_E4, NOTE_D4, NOTE_C4, NOTE_A3, NOTE_G3, NOTE_A3, NOTE_G3,
  NOTE_A3, NOTE_A3, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_D4, NOTE_E4,
  NOTE_D4, NOTE_D4, NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_C4,
};

int noteDurations[] = {
  6, 16, 8, 8, 8, 8, 4,
  6, 16, 8, 8, 8, 8, 4,
  6, 16, 8, 8, 8, 8, 4,
  6, 16, 8, 8, 8, 8, 4,
};

如果還不過癮的話,可以試試看周杰倫的青花瓷。

int melody[] = {
  NOTE_, NOTE_D4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_A3, NOTE_G3, NOTE_,
  NOTE_, NOTE_D4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_C4, NOTE_E4, NOTE_D4, NOTE_C4, NOTE_C4, NOTE_,
 
  NOTE_, NOTE_G3, NOTE_A3, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_E4, NOTE_E4, NOTE_,
  NOTE_, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_C4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_,
 
  NOTE_, NOTE_D4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_A3, NOTE_G3, NOTE_,
  NOTE_, NOTE_G3, NOTE_A3, NOTE_E4, NOTE_G4, NOTE_G4, NOTE_E4, NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_C4, NOTE_C4, NOTE_,
 
  NOTE_, NOTE_D4, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_C4, NOTE_D4,
  NOTE_C4, NOTE_A3, NOTE_D4, NOTE_C4, NOTE_C4, NOTE_A3, NOTE_C4, NOTE_C4, NOTE_C4, NOTE_,
  //
  NOTE_, NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_E4, NOTE_A3, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_,
  NOTE_, NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_E4, NOTE_G3, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_D4, NOTE_C4, NOTE_,
 
  NOTE_, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_A4, NOTE_G4, NOTE_F4, NOTE_G4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_,
  NOTE_, NOTE_C4, NOTE_D4, NOTE_C4, NOTE_C4, NOTE_D4, NOTE_C4, NOTE_D4, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_E4, NOTE_E4, NOTE_,
 
  NOTE_, NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_E4, NOTE_A3, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_,
  NOTE_, NOTE_G4, NOTE_G4, NOTE_E4, NOTE_D4, NOTE_E4, NOTE_G3, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_D4, NOTE_C4, NOTE_,
 
  NOTE_, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_G4, NOTE_A4, NOTE_G4, NOTE_F4, NOTE_G4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4,
  NOTE_G3, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_C4, NOTE_,
};

int noteDurations[] = {
  16, 16, 16, 16, 8, 16, 16, 8, 16, 16, 16, 16, 8, 8,
  16, 16, 16, 16, 8, 16, 16, 8, 16, 16, 16, 16, 8, 8,
 
  16, 16, 16, 16, 8, 16, 16, 8, 16, 16, 16, 16, 16, 16, 8,
  16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 8, 8,
 
  16, 16, 16, 16, 8, 16, 16, 8, 16, 16, 16, 16, 8, 8,
  16, 16, 16, 16, 8, 16, 16, 8, 16, 16, 16, 16, 8, 8,
 
  16, 16, 16, 16, 16, 16, 16, 16, 8,
  16, 16, 16, 16, 16, 16, 8, 16, 4, 8,
  //
  16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 4, 8,
  16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 4, 8,
 
  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 4, 8,
  16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 8, 8,
 
  16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 4, 8,
  16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 4, 8,
 
  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 4,
  16, 8, 16, 16, 16, 4, 8,
};

完成後,播放出來的聲音效果,我有上傳到YouTube,有興趣的話可以聽聽看:範例樂音妹妹揹著洋娃娃青花瓷


參考資料:

48 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. 請問一下 我想讓蜂鳴器在特定情形下發出聲音
    但在 case裡 break前 卻顯示編譯錯誤
    如下:
    switch (results.value){

    case 0xA806A5B3:
    tone(8,659,500);
    delay(500);
    digitalWrite(led,HIGH);
    delay(1000);
    digitalWrite(led,LOW);
    break;

    ReplyDelete
    Replies
    1. 單獨在 loop的時候卻沒問題

      void loop() {
      tone(8,659,500);
      delay(500);
      }

      Delete
    2. 編譯錯誤訊息是?

      Delete
    3. Arduino:1.6.1 (Windows 8.1), 板子:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

      建置選項已變更,重建所有

      C:\Users\敬翰\AppData\Local\Temp\build6611449641508316141.tmp/core.a(Tone.cpp.o): In function `__vector_13':

      C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Tone.cpp:536: multiple definition of `__vector_13'

      IRremote\IRremote.cpp.o:C:\Users\敬翰\Documents\Arduino\libraries\IRremote/IRremote.cpp:259: first defined here

      c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.8.1/../../../../avr/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions

      collect2.exe: error: ld returned 1 exit status

      編譯時發生錯誤

      這份報告的詳情將會在
      "編譯時顯示詳細輸出資訊"
      在檔案 > 偏好設定裡啟用。

      Delete
    4. 你有重複定義的東西,
      看看
      C:\Users\敬翰\Documents\Arduino\libraries\IRremote/IRremote.cpp
      的第259行是什麼

      或許可能IRRemote與Tone需要的腳位中斷起衝突?
      你的紅外線接受器與蜂鳴器,接到哪個腳位?

      Delete
    5. 紅外線是11 tone 是8

      第258~260行是

      ISR(TIMER_INTR_NAME)
      {
      TIMER_RESET;

      uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);

      Delete
    6. 嗯,可能是有很多人都使用同一個timer吧,造成衝突。

      tone應該是使用timer 2,timer 2會影響腳位3跟11。
      所以試著換掉紅外線的腳位吧。

      另外,把Arduino路徑下的arduino-1.6.1\libraries\RobotIRremote整個砍掉試試看,這是Arduino自己內建的。

      Delete
    7. 還是不行
      請問一下如果改成使用analogWrite呢?

      case 0xA806A5B3:
      analogWrite(VoicePin,200);
      Serial.println("Emergency");
      digitalWrite(led,HIGH);
      delay(1000);
      digitalWrite(led,LOW);

      break;

      Delete
    8. This comment has been removed by the author.

      Delete
    9. 不知道為什麼 一樣是單獨的時候會發出聲音
      放進case裡後 雖然能編譯成功 可是卻不會響

      Delete
    10. 改成使用analogWrite呢? 當然不行。

      雖然能編譯成功 ,哦,那麼原本編譯失敗的原因是?

      Delete
    11. tone 編譯失敗 analogWrite 編譯成功
      analogWrite 不是能發出單頻的聲音嗎? 為何不行?

      按照你說的 我把 RECV_PIN 變為 10 且把RobotIRremote砍掉
      但他還是跑出

      Arduino:1.6.1 (Windows 8.1), 板子:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

      建置選項已變更,重建所有
      C:\Users\敬翰\AppData\Local\Temp\build1414386163229144798.tmp/core.a(Tone.cpp.o): In function `__vector_13':
      C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Tone.cpp:536: multiple definition of `__vector_13'
      IRremote\IRremote.cpp.o:C:\Users\敬翰\Documents\Arduino\libraries\IRremote/IRremote.cpp:259: first defined here
      c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.8.1/../../../../avr/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions
      collect2.exe: error: ld returned 1 exit status
      編譯時發生錯誤

      這份報告的詳情將會在
      "編譯時顯示詳細輸出資訊"
      在檔案 > 偏好設定裡啟用。

      的訊息

      Delete
    12. analogWrite 不是能發出單頻的聲音嗎?
      啊,可以,是我錯了。

      從錯誤訊息,就是Tone.cpp與IRremote.cpp都定義了同名稱的ISR。

      你的IRRemote是哪一版?

      試試底下這個不好的解法吧:
      到C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Tone.cpp
      找到
      #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

      #define AVAILABLE_TONE_PINS 1
      #define USE_TIMER2

      把USE_TIMER2改成USE_TIMER3或USE_TIMER5試試看。

      Delete
    13. 改了 他說
      Arduino:1.6.1 (Windows 8.1), 板子:"Arduino Uno"

      建置選項已變更,重建所有
      C:\Users\敬翰\AppData\Local\Temp\build3314314162315834644.tmp/core.a(Tone.cpp.o): In function `__vector_7':
      C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Tone.cpp:536: multiple definition of `__vector_7'
      IRremote\IRremote.cpp.o:C:\Users\敬翰\Documents\Arduino\libraries\IRremote/IRremote.cpp:259: first defined here
      collect2.exe: error: ld returned 1 exit status
      編譯時發生錯誤

      這份報告的詳情將會在
      "編譯時顯示詳細輸出資訊"
      在檔案 > 偏好設定裡啟用。

      如果 analogWrite 可以
      那為何放進case禮之後他就發不出聲音了呢?

      case 0xA806A5B3:
      analogWrite(VoicePin,200);
      Serial.println("Emergency");
      digitalWrite(led,HIGH);
      delay(1000);
      digitalWrite(led,LOW);

      break;

      Delete
    14. 我的IRRemote是你在紅外線提供的那一個版本

      Delete
    15. http://forum.arduino.cc/index.php?topic=120955.0

      他說改一下IRremoteInt.h 中的timer就好了

      Delete
    16. 還是`__vector_7'

      :C

      Delete
    17. > 我的IRRemote是你在紅外線提供的那一個版本
      是嗎?可是該版本第259行並不是ISR(TIMER_INTR_NAME)

      我自己試了一下,改了timer設定,就可以編譯成功。
      你再試試吧。

      Delete
    18. timer 有很多個 (4/5個吧)
      只需要改這個嗎
      #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

      #define AVAILABLE_TONE_PINS 1
      #define USE_TIMER2

      Delete
    19. 修改IRremoteInt.h
      #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      //#define IR_USE_TIMER1 // tx = pin 11
      #define IR_USE_TIMER2 // tx = pin 9
      //#define IR_USE_TIMER3 // tx = pin 5
      //#define IR_USE_TIMER4 // tx = pin 6
      //#define IR_USE_TIMER5 // tx = pin 46

      從IR_USE_TIMER2換成其他的

      Delete
    20. 換成你提共的
      在改成TIMER3
      變成這樣:


      Arduino: 1.6.3 (Windows 7), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

      Servo\avr\Servo.cpp.o: In function `__vector_32':
      C:\Program Files (x86)\Arduino\libraries\Servo\src\avr/Servo.cpp:88: multiple definition of `__vector_32'
      IRremote\IRremote.cpp.o:C:\Users\Ching-Han Kuan\Documents\Arduino\libraries\IRremote/IRremote.cpp:312: first defined here
      c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.8.1/../../../../avr/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions
      collect2.exe: error: ld returned 1 exit status
      Multiple libraries were found for "IRremote.h"
      Used: C:\Users\Ching-Han Kuan\Documents\Arduino\libraries\IRremote
      Not used: C:\Program Files (x86)\Arduino\libraries\RobotIRremote
      Not used: C:\Program Files (x86)\Arduino\libraries\IRremote
      Error compiling.

      This report would have more information with
      "Show verbose output during compilation"
      enabled in File > Preferences.

      第312行是
      ISR(TIMER_INTR_NAME)
      {
      TIMER_RESET;

      Delete
    21. 我是改C:\Users\Ching-Han Kuan\Documents\Arduino\libraries\IRremote 裡面的

      Delete
    22. 同樣的問題,
      繼續改成其他的試試看吧,
      TIMER4、TIMER5...

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. 你好请问如果我想播放一个声音文件呢?要怎样做?

    ReplyDelete
  6. 你好请问如果我想播放一个声音文件呢?要怎样做?

    ReplyDelete
    Replies
    1. 若是wav檔或mp3檔,通常需要加一塊擴充板(shield),譬如https://www.adafruit.com/products/1790

      若是以小喇叭播放簡單的樂音,請參考這篇
      http://yehnan.blogspot.com/2012/02/arduinoloudspeaker.html

      或是播放鈴聲格式RTTTL,請參考這篇
      http://yehnan.blogspot.tw/2015/03/arduinotonertttl.html

      Delete
  7. void play(int *melody, int *noteDurations, int num){
    for(int note = 0; note < num; note++){
    int noteDuration = 3000 / noteDurations[note];
    tone(8, melody[note], noteDuration);
    這是本文中提到3個定義的地方,請問num定義為什麼呢?

    ReplyDelete
    Replies
    1. melody陣列裡頭元素的個數。也應該等於noteDurations陣列的元素個數。

      Delete
  8. 請問紅外線啟動MP3擴板我該怎麼使用或撰寫程式呢?

    ReplyDelete
  9. 請問紅外線啟動MP3擴板我該怎麼使用或撰寫程式呢?

    ReplyDelete
  10. 你好,請問Arduino是否有支援兩個pin腳同時輸出的功能?
    目前想要用兩個蜂鳴器賴做出音樂和弦的功能,但又看到有人說Arduino不支援pin腳同時輸出(除非買兩塊Arduino的板子0.0)
    如果這個情報是正確的,那就算我找到能讓迴圈同時執行的功能也無法使用了ˊˋ

    ReplyDelete
    Replies
    1. Arduino內建函式tone,只使用一個硬體計時器,只能發出一個頻率,只能控制一個小喇叭。

      需使用另一套程式庫Tone,https://code.google.com/p/rogue-code/

      程式庫Tone的用法,請參考拙作《Arduino輕鬆入門:範例分析與實作設計》的6.4節「如何發出多個頻率」。

      Delete
  11. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. 如果燈泡亮滅跟tone發聲與否一樣,那麼就在play函式裡、delay呼叫附近,加入控制亮滅的程式碼。

      如果不一樣,那就難了,因為這篇的play會使用delay。

      Delete
  12. 老師 有何不同 的連結死掉了

    ReplyDelete
  13. 你好,請問能提供信箱嗎,我使用您寫的Tone.h中DTMFT的方式改寫一首曲調,但出現一些問題

    ReplyDelete
    Replies
    1. > 能提供信箱嗎
      不能。

      有問題請留言,盡量回答。

      Delete
    2. 我的程式碼如下
      #include
      #define BUZZER_1 11
      #define BUZZER_2 12

      Tone freq1;
      Tone freq2;
      int tempo = 300;
      unsigned long beats[]={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,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2};
      const int DTMF_freq[] = { 0, 65, 73, 82, 87, 98, 110, 123, //0~7
      0, 131, 147, 165, 175, 196, 220, 247, //8~15
      0, 262, 294, 330, 349, 392, 440, 494, //16~23
      0, 523, 587, 659, 698, 784, 880, 988, //24~31
      0, 1046, 1175, 1319, 1397, 1568, 1760, 1976}; //32~39
      void setup()
      {
      Serial.begin(9600);
      freq1.begin(BUZZER_1);
      freq2.begin(BUZZER_2);
      }

      void playDTMF(uint8_t number, unsigned long duration)
      {
      freq1.play(DTMF_freq[number], beats[number] * tempo);
      freq2.play(DTMF_freq[number], beats[number] * tempo);
      }
      void loop()
      {
      int i;
      uint8_t music_number[] = {17,17,21,21,22,22,21,20,20,19,19,18,18,17,21,21,20,20,19,19,18,21,21,20,20,19,19,18,17,17,21,21,22,22,21,20,20,19,19,18,18,17};

      for(i = 0; i < sizeof(music_number); i ++)
      {
      Serial.print(music_number[i], 10);
      Serial.print(' ');
      playDTMF(music_number[i], 300);
      delay(400);
      }
      Serial.println();
      delay(1000);
      }
      我的音樂在兩個20的中間沒有辦法斷音,要把tempo調到大約150的時候才勉強有辦法斷音,請問一下要怎麼解決

      Delete
    3. 插入不發聲的音符,作為休止符。

      Delete
    4. 是說在20之前插入一個0,將原本20位置改成21嗎

      Delete
    5. DTMF_freq 插入0,
      music_number 插入適當的值。

      Delete