الأربعاء، 14 أغسطس، 2013

المؤقتات في لغة أردوينو Arduino Timer

Arduino Timer

المؤقتات في لغة أردوينو


في التطبيقات المتقدمة من برمجة المتحكمات الأصغرية Microcontrollers تصبح التعليمات و الأوامر في الكود كثيرة و متداخلة , و قد يصادف استعمال العديد من جمل الdelay و while و for و احياناً قد تحتاج للاستجابة للعديد من الأشارات سواءاً القدامة من الحساسات أو من نفس البرنامج , لذلك تحتاج إلى تقنية جديدة في البرمجة تسمى المؤقتات Timers.


ما هي المؤقتات :

الفكرة العامة التي قد يعرف بها المؤقت , هو استخدامه لقياس فترة زمنية معطاة , الفكرة موجودة في المتحكمات الأصغرية , و هو أن تقوم بقدح"Trigger " أو مقاطعة " Interrupt "عمل مخرج , مدخل , تعليمة , في نقطة محددة في البرنامج , و يمكن تشبيهه بالتنبيه للمتحكم الصغري Microcontrollers بأن حدث ما تم حصوله ليقوم بدوره بتغيير سير عمل البرنامج .

المؤقتات تعمل بشكل لا تزامني Asynchronous و هذه ميزة مهمة لنتعامل مع المتغيرات بشكل متوازي , بحيث يستمر تنفيذ الأوامر في جملة الدوران Loop و تنفذ اوامر المقاطعة في نفس اللحظة .

فبدون الحاجة لجمل دوران و استخدام الأمر millis , نستطيع باستخدام المؤقتات الأستغناء عنها جميعاً .

كيف تعمل ؟

المؤقت يقوم بزيادة قيمة العد عند كل عملية , عبر مسجلات عدّ counter Registers , و هذه المسجلات Registers بدورها لها مقدار " قيمة معينة ", عندما تصل قيمة العد لهذه القيمة , تعود قيمة العداد إلى الصفر فيما يعرف بال Overflow و المسجل يقوم بتغيير قيمة Flag bit إلى الواحد ليبين لنا حدوث رجوع إلى الصفر Overflow هنا في هذه الحالة يمكننا جعل المؤقت يقوم بعملية مقاطعة لبرنامج معين في هذه اللحظة .

لذلك استخدام المؤقت Timer , لانه وسيلة سهلة و سريعة للتطبيقات العملية .

تعتمد المقاطعات Interrupt بشكل رئيسي على تردد ساعة المتحكم Crystal Clock source و أصغر قيمة يستطيع المتحكم قياسها هو قيمة تردد الساعة .
f= clock source (Hz).
t= Time Period (sec).

على سبيل المثال , بطاقة الأردوينو Arduino UNO لها كريستالة قيمتها 16,000,000هيرتز , و عليه تكون 

t=1/f = 1/16,000,000 = 62.5ns

من الآن سأتحدث حصراً على المتحكمين AVR ATmega168 /328 , نظراً لشيوعهما في بطاقات الأردوينوArduino Boards .

لنتعرف الآن على أنواع المؤقتات . 

Timer 0: هو مؤقت حجمه 8 bit و اقصى قيمة يستطيع هذا المؤقت الوصول إليها 255 , و هذا المؤقت يستعمل من برنامج الأردوينو لعمل جمل الmillis و delay 

Timer 1: و هذا المؤقت حجمه 16bit و أقصى قيمة يستطيع هذا المؤقت الوصول إليه هو 65535 , و هذا المؤقت يستعمل من برنامج الأردوينو في مكتبة محركات السيرفو Servo Library 

Timer 2هو مؤقت حجمه 8 bit و اقصى قيمة يستطيع هذا المؤقت الوصول إليها 255 , و هذا المؤقت يستعمل من برنامج الأردوينو في انشاء أوامر  ()Tone .

كيفية برمجة المؤقتات :

نستخدم هنا مسجلات في المتحكم الأصغري لتخزين إعدادات المؤقت فيها , هناك مسجلين لضبط الإعدادات و هما TCCRxB و TCCRxA أو ما يعرف اختصاراً ب ( Timer/Counter Control Register ) و قيمة x  هي رقم المؤقت (0,1,2 ) و نحدد قيمة ال Prescaler  من النشرة الفنية Datasheet للمتحكم .
سنأخذ هذا المثال , و فيه سنقوم بإضاءة و أطفاء الLED المربوط مع المخرج D2 في كل مرة يحصل فيها Overflow  لقيمة العداد , و الذي سيعمل بسرعة هزاز المتحكم "16MHz"و سنشغل الISR في كل مرة يحصل فيها Overflow  للعداد .

// avr-libc library  
//taken from www.engblaze.com
#include <avr/io.h> #include <avr/interrupt.h>   #define LEDPIN 13   void setup() {     pinMode(LEDPIN, OUTPUT);       // initialize Timer1     cli();             // disable global interrupts     TCCR1A = 0;        // set entire TCCR1A register to 0     TCCR1B = 0;       // enable Timer1 overflow interrupt:     TIMSK1 = (1 << TOIE1);     // Set CS10 bit so timer runs at clock speed:     TCCR1B |= (1 << CS10);     // enable global interrupts: 
    sei(); 
}
ISR(TIMER1_OVF_vect)
{
    digitalWrite(LEDPIN, !digitalRead(LEDPIN));
}
          void loop(){} 

في حال تطبيق هذا البرنامج فانه سيقوم بإضاءة و اطفاء الLED المربوط مع المدخل D2 بوقت منتظم بغض النظر عن البرنامج الرئيسي .

لكن لو فكرنا بتطبيق البرنامج ستلاحظ شيء مهم , هو أن الTIMER1 سعته 16Bit" اكبر قيمة 65535 
و يصل لقيمة الoverflow في هذا البرنامج سيحتاج 62.5ns لتزيد قيمة العداد 1 و عليه ستصل قيمة العداد لأقصى قيمة و سيحدث ال overflow بعد :


O.F= 65535* 62.5*10^-9 =0.0041s

هذه سرعة عالية جداً و لا يفيدنا بالعديد من التطبيقات العملية , فما العمل لو أردنا عمل مؤقت يقوم بالعملية بشكل منتظم كل ثانية أو عدة ثواني و ليس أجزاء الثانية ! لذلك سنتكلم في الجزء الثاني عن الCTC Timer .

CTC Mode and Prescaling :


في حالة الoverflow يكون الprescaling فيها قيمة اقصاها 1024 وكما اوضحت في الفقرة السابقة فأنه لمؤقت بسرعة 62.5ns فإن للمؤقت دورة مقدارها تقريباً 0.0041 , لذلك هناك طريقة طورها مهندسو شركة اتميل Atmel نمط مؤقت يسمى clear timer or Compare match "CTC , فعوضاً عن انتظار العداد ليصل لقيمته القصوى و من ثم يعود للصفرOverflow يقوم المؤقت بمقارنة قيمة العدّ بقيمة نحددها و تحفظ في المسجل و عندما يصل عدّاد المؤقت  للقيمة التي نحددها للمؤقت , فيقوم المتحكم اما بضبط الflag reg =1 أو بقدح المخارج Output triggering.

كيفية استخدام الCTC Mode :
في البداية يجب ضبط ال (prescale (1,2,8,64,256,1024
و الحسابات المطلوبة هي  :

target time =timer resolution *(Number of timer count +1 ).

timer count = (target time/timer resolution ) - 1 .

target time : هو الوقت الذي نريد المقاطعة عنده 

timer resolution : (1,2,8,64,256,1024) 

سأكتب كود بسيط يقوم باضاءة و اطفاء الباعث الضوئي LED المربوط مع المدخل D13  .

و الكود كالآتي :
//taken from www.engblaze.com
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>
  int ledpin=13;
void setup()
{
    pinMode(ledpin, OUTPUT);
 
    // initialize Timer1
    cli();          // disable global interrupts
    TCCR1A = 0x00;     // set entire TCCR1A register to 0
    TCCR1B = 0x00;     // same for TCCR1B
    // set compare match register to desired timer count:
    OCR1A = 31249; // two seconds
    // turn on CTC mode:
    TCCR1B |= (1 << WGM12);
    //    TCCR1B=0x05 ;// prescaler 1/1024
    TCCR1B |= (1 << CS10);
    TCCR1B |= (1 << CS12);
    // enable timer compare interrupt:
    TIMSK1 |= (1 << OCIE1A);
    // enable global interrupts:
    sei();
}
 
void loop()
{
    // do some crazy stuff while my LED keeps blinking
}
 
ISR(TIMER1_COMPA_vect)
{
    digitalWrite(ledpin, !digitalRead(ledpin));
}

Picture for oscillscope wave form 



5 التعليقات :

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

    ولاكن اوجة مشكلة في تطبيق بعض الامثلة المطروحة بسبب عدم توفر القطع عندنا في المملكة فهل القطع متوفره عندكم بالاردن وهل يوجد سوق عربي لهذة القطع لان اغلب القطع اشتريها من امزون ويكلف علي سعر الشحن

    ردحذف
  2. و عليكم السلام .

    نعم هناك متاجر لدينا في الأردن , و انا شخصياً لدي أحدها .

    يمكنك مراسلتي على بريدي الألكتروني genotronex@gmail.com للتفاصيل كاملة .

    ردحذف
  3. يعطيك العافية اخوي ,,, بارك الله فيك
    عندي تعليق ,, ممكن توضح بعض المتخصرات عشان يزيد الفهم للموضوع : مثلا TCCR1B |= (1 << WGM12);

    شو ال WGM
    وشو ال CS12 في TCCR1B |= (1 << CS10);

    هاي الامور رغم بساطتها بتعيق الفهم ,,, وكل الشكر لك

    كمان بالنسبة لتحديد زمن العد ::: انا بعرف انه بينقسم التردد على اربعة ؟ هيك بعرف كنا نعمل في الpic يعني في الاتمل بيختلف الموضوع ؟

    ردحذف
    الردود
    1. اهلاً بك .

      TCCR1B عبارة عن عداد داخلي وظيفته هو العد و مقارنة النتائج مع TCCR1A و ضبط انماط التشغيل المطلوبة .

      في ال AVR أكثر من نمط للعمل بالنسبة للمؤقتات :
      1)WGM او ما يعرف ب Waveform Generation mode و يستخدم لتفعيل نمط ال CTC , و شتغيل المؤقت عند التردد المطلوب
      2)الوضع الأخر Fast PWM و وظيفته واضحة من اسمه توليد فولتيات بتعديل نبضي عالي التردد .
      هناك وضع Brown out detcetor لكن لا يستخدم بكثرة في الأردوينو لعدة محددات .

      CS اختصار ل Counter select و هي عبارة عن 3 بتات bit وظيفتها ضبط تردد الساعة للمؤقت ل 5 اوضاع مختلفة تجدهم في جدول في النشرة الفنية .

      ما يختلف عن ال pic هو انه نستطيع ضبط التردد حسب prescale بحيث يقسم التردد على 1,2,8,64,256,1024 و ليس على 4 فقط كما في ال pic

      حذف
    2. كل الشكر اخي ,, جزاك الله خيرا
      في الPIC نستطيع ضبط البريسكيلر حقا :) ,,, لكن لا اذكر الطريقة بالضبط
      بس بشكل عام فش مثل الاردوينو :)

      حذف

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