التعديل النبضي 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
الجواب نعم , سنتحدث الأن في موضوعين متقدمين ألا و هما ال
Fast PWM and Phase correct PWM
و هما أحدى الخصائص الموجودة في المؤقتات Timers في المتحكم AVR Atmega328 و نستطيع من خلالهما استعمال أي من المؤقتات الثلاث Timer 0,1,2 لتوليد تعديل نبضي ذو مدى واسع من الترددات .
سأبدأ بنمط التوليد النبضي السريع fast PWM باستخدام المؤقت Timer 2 8bit .
ستحتاج لمعرفة بعض المفاهيم الخاصة بالمؤقتات , حيث يمكنك مراجعة المقال هنا لكي تكون لك خلفية حول الموضوع .
بالعموم هذه الجداول هي التي نستخدمها في البرمجة بشكل واسع يجب عليك أن تعود أليها كلما اردت البرمجة .
سأبدأ بنمط التوليد النبضي السريع 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% "طبعاً في هذا الوضع التردد في الحالتين متساوي " .
البرنامج :
اذا أردنا تغيير التردد فقط نغير ال Prescaler حسب الجدول أعلاه . و تغيير دورة المشغولية duty cycle "OCR2A, OCR2B " و الصور ادناه تبين الخرج على راسم الإشارة .
لنأخذ مثال بسيط , نريد التحكم من خلال المؤقت 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 من أجل التعديل النبضي .
مثال :
النمط الآخر هو Phase correct :
يختلف هذا النمط عن سابقه بأنه يقوم بالعد من 0-255 و من ثم يقوم بالعد تنازلياً من 255 إلى أن يعود للصفر مجدداً , و تكون حالة المخرج Output واحد منطقي HIGH حتى تصل قيمة العد إلى القيمة المحددة في ال OCR فتتحول قيمة المخرج إلى الصفر المنطقي LOW .
في هذا النمط يكون التردد الكلي مقسوماً على 2 و أيضاً تكون اشارة المخارج أكثر تماثلاً Symmetric .
في لغة الأردوينو يتم استخدام هذا النمط عند استدعاء analogRead من أجل التعديل النبضي .
لحساب التردد نختار المعامل Prescale , و نعوض في المعادلة :
f=clock /(256*prescale)
f=16*10^6/(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: }