التعديل النبضي 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: }
شرح اكثر من رائع .. وتقنية PWM اصبحت محطة اهتمام لدى الكثير :)
ردحذفشكراً مهند :)
العفو أخي هيثم
حذفالله يعطيك العافية اخي ,,
ردحذفلكن عندي تساؤلات شوي بالموضوع ,, بتمنى يكون صدرك رحب :)
اول اشي ,, بدي توضحلي ايش معنى هالجمل البرمجية ,, وكأني بعرفش برمجة :)
TCCR2A = (1<<COM2A1) | (1<<COM2B1) | (1<<WGM21) | (1<<WGM20);
TCCR2B = (1<<CS21);// set prescale = 8
ثاني شغلة ,,, لنقل اني بدي اقيمة الPWM تبعا لمتغير ما ,, معين ,, اسأل لانها واجهتني مشكلة من قبل حيث كان المشروع يغير قيمة البلس ويدث موديوليشن تبعا لقيمة معينة تصله من سنسور ,,, وكنت بحاجة لتردد عالي لذلك ,,, كيف الطريقة لجعل الموضوع سلس وسهل برمجيا ,,,
المهم ,, هل هذا التغيير في هذه القيم قد يؤثر على function مثل ال mills() وغيره من حيث الزمن ؟؟
وشكرا جزيلا
شكراً لتفاعلك ^_^
حذفهذه برمجة لغة الآلة Assembly و اذا سألتني كيف برمجة عليها ؟ ببساطة أنا لست علّامة كل ما قمت به هو قراءة النشرة الفنية للمتحكم atmega328 و برمجة الأوامر تبعاً لما ورد في الجداول التي أوردتها في المقال , بأختصار هي أوامر لتفعيل خانة من مسجل معين له وظيفة محددة في المؤقت .
في العادة المؤقتات تعمل بشكل لاتزامني مع البرنامج الأصلي اي تعمل على التوازي معه , و لتغيير التردد تبعاً لقيمة معينة ما عليك سوى تغيير المسجل Timer counter control register TCCR2A و TCCR2B مثلاً لتناسب التردد المطلوب كلها عمليات حسابية بسيطة لا أكثر .
حدد قيمة ال PRESCALE لنظامك لتعرف تردد المؤقت .
حدد ال TCCRxA و TCCRxB المطلوب
ثم استخدم راسم اشارة لترى التردد الناتج و تطابقه بحساباتك .
الأوامر millis, micros, delay تستخدم المؤقت Timer0 في الأردوينو اي لا تؤثر على timer1 و لا تؤثر على Timer2
مشكور على ردك اخي ,,,
حذفنعم اعرف انها لغة الاسمبلي فقد سبق لي وتعاملت معها لبرمحة الPIC مايكروكونترولر في بداياتي تعلم الماكروكونترولر,,
لكن سؤالي ما معنى (1<<COM2A1) | يعني ببساطة هاي الاشارة اكبر من لما تنحط مرتين شو معناها ,, ههه يمكن السؤال بسييط بس صدقا ما مرت علي ^_^
وضحت فكرة التغيير في التردد والقيمة للبلص ويدث موديوليشن ,,, ولك الشكر فقد سبق ان بحثت بالموضوع قبل اشهر ,, وكنت مشوشا بالموضوع
العفو .
حذفعملية تفعيل للمسجل , معناه ببساطة ضع قيمة 1 في الخانة bit لهذا المسجل . ولو كتبنا (0<<COM2A1) معناه ضع قيمة 0 في الخانة bit لهذا المسجل
شكرا ,, جزيلا :)
حذفاستاذ في هذه الطريقة بالكتابة ماذا يعني الشكل التالي:
حذفUCSZ0>>3
طبعا هذا في برمجة ال USART
like
ردحذفاستاز من فظلك لو اردنا قياس النبظة بالنانوسيكند مثل التي في التراسونيك غير ان الالتراسونيك تقيس بالميكروسيكند فكيف سيكون الكود
ردحذفشرح
ردحذف