الثلاثاء، 20 أغسطس، 2013

ما لا تعلمه عن التعديل النبضي PWM Mode




التعديل النبضي PWM  هو من أهم المواضيع التي يهتم به المبرمجون في عالم المايكروكنترولر , و في تدوينة سابقة لي تحدثت عن التعديل النبضي و عن استخداماته الواسعة في المجالات العملية .

فكرة التعديل النبضي هو التحكم بعرض النبضة بحيث تعطي قيمة فولتية متغيرة اعتماداً على عرض هذه النبضة . 



المداخل Pins التي تعمل على توليد نبضات ذات تعديل نبضي هي D3,D5,D6,D9,D10,D11 و حيث أن أقل قيمة يمكن أن تكون 0 و أكبر قيمة هي 255 و الصورة أعلاه تبين قيم مختلفة اعتماداً على عرض النبضة .

تحسب الدورة Duty cycle بقسمة النبضة الفّعالة على طول النبضة الكلي  

duty cycle = ton/ttotal  .

أقصى تردد يمكن الحصول عليه هنا في الطريقة المباشرة هي 490 هيرتز , هي جيده للكثير من التطبيقات , لكن إذا أردنا التحكم بشكل أدق بالعمليات قد نحتاج لتردد أعلى . 

لكن هل من الممكن عمل ذلك بواسطة المتحكم Atmega 168/ 328 الموجود على بطاقة الأردوينو Arduino Board؟ هل من الممكن توليد موجه تعديل نبضي PWM Wave ذات تردد يصل ل 10كيلو هيرتز مثلاً  ؟

الجواب نعم , سنتحدث الأن في موضوعين متقدمين ألا و هما ال
Fast PWM and Phase correct PWM

و هما أحدى الخصائص الموجودة في المؤقتات Timers في المتحكم AVR Atmega328 و نستطيع من خلالهما استعمال أي من المؤقتات الثلاث Timer 0,1,2 لتوليد تعديل نبضي ذو مدى واسع من الترددات .

سأبدأ بنمط التوليد النبضي السريع fast PWM باستخدام المؤقت Timer 2 8bit  .

ستحتاج لمعرفة بعض المفاهيم الخاصة بالمؤقتات , حيث يمكنك مراجعة المقال هنا لكي تكون لك خلفية حول الموضوع .

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





لتبسيط الفكرة هناك مقارنين داخلين يسميان TCCRxA و TCCRxB و هما المتحكمان الأساسيان للمؤقت يتحكمان بمسجلات المداخل و المخارج output control register  OCRx و المقارنين  TCCRxA و TCCRxB  يتكونان من عدة بتات تتحكم بعدة أمور مثل 
wave form Generation Mode ( WGM) .
Compare Match Output A  (COMnA) .
Compare Match Output B  (COMnB).

كل عنصر منها يتحكم في طريقة عمل المسجل , التردد , و ايضاً التحكم  ب ال prescaler   .

لنأخذ مثال بسيط , نريد التحكم من خلال المؤقت Timer2 " D3, D11 " و توليد تعديل نبضي بتردد 7.81 كيلو هيرتز ! بحيث يكون احد المخارج بدورة مشغولية Duty cycle تساوي 30% و الأخرى 70% "طبعاً في هذا الوضع التردد في الحالتين متساوي " .

البرنامج :


void setup() {
  // put your setup code here, to run once:
   pinMode(3, OUTPUT);
   pinMode(11, OUTPUT);
   TCCR2A = (1<<COM2A1) | (1<<COM2B1) | (1<<WGM21) | (1<<WGM20);
   TCCR2B = (1<<CS21);// set prescale = 8 
//   output freq = 16*10^6 /(8*256) = 7.812KHz .
   OCR2A = 179; // calculated by (179+1)/256 = 70.3%
   OCR2B = 75;  // calculated by (76+1)/256 = 29.7%

}

void loop() {
  // put your main code here, to run repeatedly: 
  
}



الصورة للناتج على المدخلين D3,D11 باستخدام راسم الإشارة 



اذا أردنا تغيير التردد فقط نغير ال Prescaler حسب الجدول أعلاه . و تغيير دورة المشغولية duty cycle "OCR2A, OCR2B  " و الصور ادناه تبين الخرج على راسم الإشارة .

هذا برنامج آخر باستخدام المؤقت Timer0 8bit .
void setup() {
   // put your setup code here, to run once:
   pinMode(5, OUTPUT);
   pinMode(6, OUTPUT);
   TCCR0A = (1<<COM0A1) | (1<<COM0B1) | (1<<WGM01) | (1<<WGM00);
   TCCR0B = (1<<CS00);// set prescale = 1 
//   output freq = 16*10^6 /(1*256) = 62.5KHz .
   OCR0A = 179; // calculated by (179+1)/256 = 70.3%
   OCR0B = 75;  // calculated by (76+1)/256 = 29.7%

}
  // put your setup code here, to run once:
void loop() {
  // put your main code here, to run repeatedly: 
  
}



المؤقت Timer1 16bit يختلف في أننا نقسم التردد الكلي على 2 . بالإضافة لعمل المؤقت على 8,9,10bit  .




النمط الآخر هو Phase correct :

يختلف هذا النمط عن سابقه بأنه يقوم بالعد من 0-255 و من ثم يقوم بالعد تنازلياً من 255 إلى أن يعود للصفر مجدداً , و تكون حالة المخرج Output واحد منطقي HIGH حتى تصل قيمة العد إلى القيمة المحددة في ال OCR فتتحول قيمة المخرج إلى الصفر المنطقي LOW  .

في هذا النمط يكون التردد الكلي مقسوماً على 2 و أيضاً تكون اشارة المخارج أكثر تماثلاً Symmetric  .

في لغة الأردوينو يتم استخدام هذا النمط عند استدعاء analogRead من أجل التعديل النبضي .



لحساب التردد نختار المعامل Prescale  , و نعوض في المعادلة :
f=clock /(256*prescale)
f=16*10^6/(256*
prescale)


مثال :
void setup() {
  // put your setup code here, to run once:
  pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = (1<<COM2A1) |(1<<COM2B1)|(1<<WGM20);
  TCCR2B = (1<<CS20);// prescale = 1
  // f = 16*10^6 /(256*1*2) = 31.32KHz 
  OCR2A = 225; // 88.23%
  OCR2B = 80;  //31.37%

}

void loop() {
  // put your main code here, to run repeatedly: 
  
}



التردد  على جهاز راسم الأشارة كما هو متوقع 31.32KHz


هذه أهم التقنيات التي تساعدك على بناء مشروعك و استخدام الموقتات لتوليد موجات تعديل نبضي PWM بترددات عالية لغاية 60 كيلو هيرتز .

7 التعليقات :

  1. شرح اكثر من رائع .. وتقنية PWM اصبحت محطة اهتمام لدى الكثير :)

    شكراً مهند :)

    ردحذف
  2. الله يعطيك العافية اخي ,,
    لكن عندي تساؤلات شوي بالموضوع ,, بتمنى يكون صدرك رحب :)
    اول اشي ,, بدي توضحلي ايش معنى هالجمل البرمجية ,, وكأني بعرفش برمجة :)
    TCCR2A = (1<<COM2A1) | (1<<COM2B1) | (1<<WGM21) | (1<<WGM20);
    TCCR2B = (1<<CS21);// set prescale = 8
    ثاني شغلة ,,, لنقل اني بدي اقيمة الPWM تبعا لمتغير ما ,, معين ,, اسأل لانها واجهتني مشكلة من قبل حيث كان المشروع يغير قيمة البلس ويدث موديوليشن تبعا لقيمة معينة تصله من سنسور ,,, وكنت بحاجة لتردد عالي لذلك ,,, كيف الطريقة لجعل الموضوع سلس وسهل برمجيا ,,,

    المهم ,, هل هذا التغيير في هذه القيم قد يؤثر على function مثل ال mills() وغيره من حيث الزمن ؟؟
    وشكرا جزيلا

    ردحذف
    الردود
    1. شكراً لتفاعلك ^_^

      هذه برمجة لغة الآلة Assembly و اذا سألتني كيف برمجة عليها ؟ ببساطة أنا لست علّامة كل ما قمت به هو قراءة النشرة الفنية للمتحكم atmega328 و برمجة الأوامر تبعاً لما ورد في الجداول التي أوردتها في المقال , بأختصار هي أوامر لتفعيل خانة من مسجل معين له وظيفة محددة في المؤقت .
      في العادة المؤقتات تعمل بشكل لاتزامني مع البرنامج الأصلي اي تعمل على التوازي معه , و لتغيير التردد تبعاً لقيمة معينة ما عليك سوى تغيير المسجل Timer counter control register TCCR2A و TCCR2B مثلاً لتناسب التردد المطلوب كلها عمليات حسابية بسيطة لا أكثر .

      حدد قيمة ال PRESCALE لنظامك لتعرف تردد المؤقت .
      حدد ال TCCRxA و TCCRxB المطلوب
      ثم استخدم راسم اشارة لترى التردد الناتج و تطابقه بحساباتك .

      الأوامر millis, micros, delay تستخدم المؤقت Timer0 في الأردوينو اي لا تؤثر على timer1 و لا تؤثر على Timer2

      حذف
    2. مشكور على ردك اخي ,,,
      نعم اعرف انها لغة الاسمبلي فقد سبق لي وتعاملت معها لبرمحة الPIC مايكروكونترولر في بداياتي تعلم الماكروكونترولر,,
      لكن سؤالي ما معنى (1<<COM2A1) | يعني ببساطة هاي الاشارة اكبر من لما تنحط مرتين شو معناها ,, ههه يمكن السؤال بسييط بس صدقا ما مرت علي ^_^

      وضحت فكرة التغيير في التردد والقيمة للبلص ويدث موديوليشن ,,, ولك الشكر فقد سبق ان بحثت بالموضوع قبل اشهر ,, وكنت مشوشا بالموضوع

      حذف
    3. العفو .

      عملية تفعيل للمسجل , معناه ببساطة ضع قيمة 1 في الخانة bit لهذا المسجل . ولو كتبنا (0<<COM2A1) معناه ضع قيمة 0 في الخانة bit لهذا المسجل

      حذف

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