الثلاثاء، 4 مارس، 2014

الأردوينو و توليد النغمات Arduino And Tones

الأردوينو و توليد النغمات 


Arduino And Tones


تتمتع الأردوينو بقدرات ممتازة على ربط القطع المختلفة و برمجتها بسهولة عبرها .

من اكثر الأمور متعة خلال استعمالي للمتحكمات الأصغرية MCU هي توليد نغمات موسيقية Tones مختلفة و جميلة .

تعتمد هذه النغمات على تقنية PWM في الأساس "التحكم بعرض نبضة الصوت" او بشكل ابسط تشغيل مؤقت لقياس عرض هذه النبضة "و هو ما نقوم به فعلياً في الأردوينو "



سأبدأ من البداية , الحديث عن توليد نغمات على الأردوينو يقودنا لامر مهم في لغة الأردوينو .

Tone


يقوم هذا الأمر بتوليد موجة مربعة ذات مشغولية duty cycle تساوي 50% عند اي تردد مطلوب .

هذه التقنية تعطينا اصواتاً مسموعة عند ترددات ما بين "20-20كيلو هيرتز " .

الألعاب القديمة التي كانت على اجهزة التلفزيون في منتصف الثمانينيات و التسعينيات "قبل ظهور الفيفا و المزرعة السعيدة :) " كانت هذه الألعاب تصدر اصوات رائعة نذكر منها اللعبة الأشهر "ماريو " هذه اللعبة تعتمد في اصدار الأصوات على نفس المبدأ الذي سنتعامل معه اليوم .


القطع التي سنحتاجها :

سنحتاج للقطع التالية :

1) بطاقة اردوينو
2) سماعة Speaker
3)مقاومة 470 اوم .
4)اسلاك توصيل 
5)BreadBoard

سنقوم في البداية بتوصيل الدارة كما في المخطط .




برنامج بسيط .
//Simple Tone Generator arduino
//Mohannad Rawashdeh
//http://www.genotronex.com/
//orginal Code taken from :
//http://arduino.cc/en/Tutorial/Tone
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_B3  247
#define NOTE_C4  262
int melody[] = {
  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  2, 4, 2, 2,2,2,2,2 };

void setup() {
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 8; thisNote++) {

    // to calculate the note duration, take one second 
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000/noteDurations[thisNote];
    tone(8, melody[thisNote],noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration *0.5;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(8);
  }
}

void loop() {
  // no need to repeat the melody.
}

البرنامج بسيط و يعتمد في فكرته على تحديد مخرج رقمي "D8 في برنامجنا " و وضع نوتات موسيقية ذات ترددات مختلفة على ايقاعات مختلفة "2,4,8,16" ثم توليد هذه النوتات بطولها المحدد على المخرج , يصدر لدينا هذا الصوت على السماعة .



RTTL 

قامت شركة نوكيا بتطوير لغة اطلقت عليها اسم RTTL"Ringtone Transfer Language" كانت وظيفتها تحويل النغمات إلى صيغ يفهمها الهاتف المحمول "هل تذكر مولد النغمات في الجهاز Nokia 3310 ؟ "




هذه اللغة تحتوي 3 اقسام رئيسية :
 name.
default value.
data

يكون الأسم مكوناً من 10 احرف , و تليه 3 قيم هي 


d - duration

o - octave

b - beat, tempo

هذه القيم تحدد الطول  و المدة و النغمة الموسيقية المراد تشغيلها .


هذا مثال بسيط لكيفية تشغيل صوت معين .

لو اردنا تشغيل صوت مثل موسيقى لعبة الماريو الشهيرة



هذا البرنامج يقوم بهذه المهمة .


/* This example uses a piezo speaker to play melodies.  It sends
 * a square wave of the appropriate frequency to the piezo, generating
 * the corresponding tone.
 *
 * The calculation of the tones is made following the mathematical
 * operation:
 *
 *       timeHigh = period / 2 = 1 / (2 * toneFrequency)
 *
 * where the different tones are described as in the table:
 *
 * note  frequency  period  timeHigh
 * c          261 Hz          3830  1915  
 * d          294 Hz          3400  1700  
 * e          329 Hz          3038  1519  
 * f          349 Hz          2864  1432  
 * g          392 Hz          2550  1275  
 * a          440 Hz          2272  1136  
 * b          493 Hz          2028 1014 
 * C         523 Hz         1912  956
 *
 * http://www.arduino.cc/en/Tutorial/Melody
 */
    
int speakerPin = 8;

int length = 295; // the number of notes
char notes[] = "EE E CE G  g  C  g e  a b ia gEGA FG E CDb C  g e  a b ia gEGA FG E CDb  GNFR E uaC aCD GNFR E 1 11   GNFR E uaC aCD L  D C   CC C CD EC ag  CC C CDE  CC C CD EC ag  EE E CE G  g  C  g e  a b ia gEGA FG E CDb C  g e  a b ia gEGA FG E CDb EC g u aF Fa  bAAAGFEC ag  EC g u aF Fa  bF FFEDCe ec  "; // a space represents a rest
float beats[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, //Page 1
                2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 4, //Page 2
                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, //Page4
                1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, //Page 5
                1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1.3, 1.3, 1.3, 1, 1, 1, 1, 1, 1, 2 }; //Page 6
                
int tempo = 95;

void playTone(int ton1, int duration) {
  for (long i = 0; i < duration * 1000L; i += ton1) {
    tone(speakerPin, ton1);
    delayMicroseconds(ton1);
  }
  noTone(speakerPin);
}

void playNote(char note, int duration) {
//                        c    c#   d    d#   e    f    f#   g    g#   a    a#   b
  char names[] = { ' ',  '!', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C', 'D', 'E', 'F', 'G', 'A', 'B', 'i', 'N', 'R', 'u',  '1', 'L', 'k'}; // [i = b flat] [N = G flat] [R = D#] [u = g#] [1 = C oct. 5] [L = E flat]
  int tones[] =  {   0, 1046, 138, 146, 155, 164, 174, 184, 195, 207, 220, 233, 246, 261, 293, 329, 349, 391, 440, 493, 523, 587, 659, 698, 783, 880, 987, 466, 740, 622, 415, 1046, 622u, 227};
  
  // play the tone corresponding to the note name
  for (int i = 0; i < 34; i++) {
    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); 
  }
}


الكود قد يكون معقداً بعض الشيء , أليس كذلك ؟

حسناً هنا نحتاج لمكتبة لتنظيم كل هذه الأسطر من البرنامج في شكل سهل و بسيط قابل للدمج مع مشاريع اخرى .


سنستعمل مكتبة RTTL يمكن تحميلها من هنا  .

هذه المكتبة تتيح لنا سهولة اكبر في الأستخدام و اضافة اصوات جديدة و بشكل مرتب .

كتبت هذا الكود لتوليد أكثر من نغمة موسيقية مشهورة متنوعة .

بعد ان تفك ضغط المكتبة و تضعها في مسار المكتبات في برنامج الأردوينو , يمكنك تحميل البرنامج ادناه .



//Simple Tone Generator arduino
//Mohannad Rawashdeh
//http://www.genotronex.com/
//this code under Licence CC by-nc-sa
//http://creativecommons.org/licenses/by-nc-sa/4.0/
//...................................................
#include <Tone.h> //the external Tone library is used 
#include <rtttl.h>

const int pinSpeaker = 8;
const int octave = 0;

const char Barbie[] PROGMEM ="Barbie girl:d=4,o=5,b=125:8g#,8e,8g#,8c#6,a,p,8f#,8d#,8f#,8b,g#,8f#,8e,p,8e,8c#,f#,c#,p,8f#,8e,g#,f#";
const char Indiana[] PROGMEM ="Indiana:d=4,o=5,b=250:e,8p,8f,8g,8p,1c6,8p.,d,8p,8e,1f,p.,g,8p,8a,8b,8p,1f6,p,a,8p,8b,2c6,2d6,2e6,e,8p,8f,8g,8p,1c6,p,d6,8p,8e6,1f.6,g,8p,8g,e.6,8p,d6,8p,8g,e.6,8p,d6,8p,8g,f.6,8p,e6,8p,8d6,2c6";
const char Coca_cola[] PROGMEM ="Coca-cola:d=4,o=5,b=125:8f#6,8f#6,8f#6,8f#6,g6,8f#6,e6,8e6,8a6,f#6,d6,2p";
const char KnightRider[] PROGMEM ="KnightRider:d=4,o=5,b=125:16e,16p,16f,16e,16e,16p,16e,16e,16f,16e,16e,16e,16d#,16e,16e,16e,16e,16p,16f,16e,16e,16p,16f,16e,16f,16e,16e,16e,16d#,16e,16e,16e,16d,16p,16e,16d,16d,16p,16e,16d,16e,16d,16d,16d,16c,16d,16d,16d,16d,16p,16e,16d,16d,16p,16e,16d,16e,16d,16d,16d,16c,16d,16d,16d";
const char PinkPanther[] PROGMEM ="PinkPanther:d=4,o=5,b=160:8d#,8e,2p,8f#,8g,2p,8d#,8e,16p,8f#,8g,16p,8c6,8b,16p,8d#,8e,16p,8b,2a#,2p,16a,16g,16e,16d,2e";
const char final_countdown[] PROGMEM ="The final countdown: :d=4,o=5,b=125:p,8p,16b,16a,b,e,p,8p,16c6,16b,8c6,8b,a,p,8p,16c6,16b,c6,e,p,8p,16a,16g,8a,8g,8f#,8a,g.,16f#,16g,a.,16g,16a,8b,8a,8g,8f#,e,c6,2b.,16b,16c6,16b,16a,1b ";
const char ScoobyDoo[] PROGMEM ="ScoobyDoo:d=4,o=5,b=160:8e6,8e6,8d6,8d6,2c6,8d6,e6,2a,8a,b,g,e6,8d6,c6,8d6,2e6,p,8e6,8e6,8d6,8d6,2c6,8d6,f6,2a,8a,b,g,e6,8d6,2c6";
const char Song1[] PROGMEM ="Song1:d=4,o=5,b=100:2p,8p,16f#6,16f#6,16f#6,16e6,16d6,16c#6,b,8f#6,e6,16e6,16e6,16e6,16d6,16c#6,16b,a,8f#6,d6,16f#6,16f#6,16f#6,16e6,16d6,16c#6,b,8f#6,e6,8d6,8c#6,2d6";
const char Mario[] PROGMEM ="smb:d=4,o=5,b=100:16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,8g,8p,8c6,16p,8g,16p,8e,16p,8a,8b,16a#,8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,16c6,16d6,8b,16p,8c6,16p,8g,16p,8e,16p,8a,8b,16a#,8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,16c6,16d6,8b,8p,16g6,16f#6,16f6,16d#6,16p,16e6,16p,16g#,16a,16c6,16p,16a,16c6,16d6,8p,16g6,16f#6,16f6,16d#6,16p,16e6,16p,16c7,16p,16c7,16c7,p,16g6,16f#6,16f6,16d#6,16p,16e6,16p,16g#,16a,16c6,16p,16a,16c6,16d6,8p,16d#6,8p,16d6,8p,16c6";
Rtttl player;

void setup(void)
{
 player.begin(pinSpeaker);
        player.play_P(Mario, octave);
        delay(1000);
 player.play_P(Barbie, octave);
        delay(1000);
        player.play_P(Indiana, octave);
        delay(1000);
 player.play_P(Coca_cola, octave);
        delay(1000);
 player.play_P(KnightRider, octave);
        delay(1000);
 player.play_P(PinkPanther, octave);
        delay(1000);
 player.play_P(final_countdown, octave);
        delay(1000);
 player.play_P(ScoobyDoo, octave);
        delay(1000);
        player.play_P(Song1, octave);
        delay(1000);
}

void loop(void)
{
}



كل ما عليك هو بناء المصفوفة و وضع النوتة الموسيقية داخله فقط ان اردت اضافة صوت جديد . 


و في النهاية هذا الفيديو يوضح الأصوات التي ستسمعها .


5 التعليقات :

  1. السلام عليكم هذه الكودات الصوتية كيف نصنعها مثلا اذا اردنا صوت يناسب حركة سيارة ربوت كيف نصنع هذا الصوت وعلى اي اساس يتم صنعه

    ردحذف
    الردود
    1. هناك برامج tone RTTL Generator على الأنترنت تقوم بذلك , تحتاج لمعرفة بالنوتات الموسيقية لعمل نوتة كما تريد

      حذف
  2. السلام عليكم اخي الكريم
    يظهر عندي خطأ عند تطبيق الكود الأخير الخاص بمكتبة Rttl وبالتحديد عند ايعاز
    ;Rtttl player
    ارجو الرد على استفساري وشكرا

    ردحذف
    الردود
    1. تثبيتك للمكتبة في مسار المكتبات الخاص بالأردوينو خاطئ .

      حذف
  3. السلام عليكم
    انا اذا جيت ارفع الكود تجيني مشكله
    أردوينو 1.7.11 (Windows 8.1), لوحة:"Arduino Uno"

    Sketch uses 3,360 bytes (10%) of program storage space. Maximum is 32,256 bytes.

    Global variables use 64 bytes (3%) of dynamic memory, leaving 1,984 bytes for local variables. Maximum is 2,048 bytes.

    avrdude: ser_open(): can't open device "\\.\COM1": The system cannot find the file specified.




    مشكلة في الرفع الى البورد. راجع http://www.arduino.cc/en/Guide/Troubleshooting#upload كـ اقتراح .

    This report would have more information with
    "Show verbose output during compilation"
    مفعل في ملف> تفضيلات.

    ردحذف

 
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.