الخميس، 9 يناير، 2014

المؤقتات الزمنية و التحكم اللحظي بالمنافذ

المؤقتات الزمنية و التحكم اللحظي بالمنافذ 





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


في البداية يجب أن أشير إلى أن المتحكمات الأصغرية MCU برمجتها تعتمد على الأوامر السلمية Ladder أي تنفيذ البرامج يكون بالترتيب حسب موضع التعليمة بالكود , من الأعلى للأسفل , هناك استثناءات الأ وهي المقاطعات Interrupts و المؤقتات Timers و لأهميتهما أفردت لهما مواضيع منفصلة في المدونة .


لكن نرجع للسؤال الأهم , هل يمكنهم كلهم العمل مع الأردوينو دون تأخير زمني ملحوظ ؟




 الجواب نعم

كيف ؟ هذا ما سنتعرف عليه سوية في  هذه التدوينة .

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

كأبسط مثال , برنامج Blink الذي يطبق على الباعث الضوئي LED المربوط على المدخل D13 يضيء لثانية واحده و يطفى لثانية واحدة .

/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.
 
  This example code is in the public domain.
 */
 
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}



هذا الأمر فيه عدة عيوب , منها أنه لا نستطيع عمل أي شيء خلال زمن التأخير , لا نستطيع مثلاً قراءة حالة مدخل معين خلال هذا الوقت او التحكم في حالة مدخل آخر , إلا بعد انتهاء زمن التأخير كما أن زمن التأخير لا يكون بالضبط بنفس القيمة المحددة , في المثل السابق التأخير الزمني هو 1000 ملي ثانية لكن فعلياً التأخير يزيد بقليل عن هذه القيمة , و اذا تم تشغيل هذا البرنامج لفترة طويلة سيكون واضحاً جداً ان التأخير الزمني بين عمليه الأنارة و الأطفاء تزيد عن 1000 ملي ثانية بوضوح تام !

الحل يكون باستخدام الأمر millis ففي الأردوينو يمكن تشغيل المؤقتات باستخدام هذا الأمر و ان يكون زمن الأضاءة و الأغلاق للباعث الضوئي LED بالضبط هو 1000ملي ثانية حتى و لو استمر البرنامج بالعمل لفترة طويلة , هذا رائع :)

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


/* Blink without Delay
 
 Turns on and off a light emitting diode(LED) connected to a digital  
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.
 
 The circuit:
 * LED attached from pin 13 to ground.
 * Note: on most Arduinos, there is already an LED on the board
 that's attached to pin 13, so no hardware is needed for this example.
 
 
 created 2005
 by David A. Mellis
 modified 8 Feb 2010
 by Paul Stoffregen
 
 This example code is in the public domain.

 
 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

// constants won't change. Used here to 
// set pin numbers:
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

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

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

هذه المكتبة تعتمد بشكل أساسي على الأمر millis و تسهل على المبرمج الحصول على برنامج يحتوي العديد من البرامج ذات تأخير زمني ثابت بين كل وظيفة و الأخرى .

اولاً يمكن تحميل المكتبة من هنا . 

أوامرها جداً سهلة و يمكن أن ترى عدة أمثلة مرفقه مع المكتبة .


مثلاً لو أردنا تشغيل 3 مداخل في الأردوينو بحيث يكون :

1)واحد منهم يعمل لأضاءة - اطفاء ضوء لمدة2000ملي ثانية 

2)يعمل كتعديل نبضي PWM بحيث يقوم بزيادة طول النبضة الفعالة  "زيادة توهج ال LED " مرة كل 10 ملي ثانية.

3) يعمل كمدخل قراءة لحساس تماثلي "مقاومة متغيرة" يقوم بالتحقق منها كل 200ملي ثانية و يزيد توهج LED مربوط على مدخل رقمي بتناسب طردي مع قيمة المقاومة المقروءة .

القطع المستخدمة في التجربة :

1) بطاقة أردوينو
2) مقاومة متغيرة Potentiometer

3) LED باعث ضوئي عدد 3
4)مقاومات عدد 3 "ان تكون قيمتها أقل من 1كيلو اوم"
5) اسلاك توصيل

6) Bread Board .

المخطط :



البرنامج :
// Metro Library code 
//Written By : Mohannad Rawashdeh 
//http://www.genotronex.com
// 1/4/2014 9:00 AM 
//....................................
#include <Metro.h> // Include the Metro library
//first , Blink Led for 150ms
Metro LED_flasher = Metro(2000);
boolean LEDState=true;
//second , Increase dimming For Led by 1 each time
Metro PWM_Cycle = Metro(10);
int i=0;
int Factor=1; //or -1
// third , Read Potentiometer and control the bright
//of led connect to another PWM Pin 
Metro Sensor=Metro(200);

const int LED=13;
const int pwmPin=6;
const int sensorPin=A0;
const int pwmPin2=3;
void setup() {
  // put your setup code here, to run once:
pinMode( LED ,OUTPUT);
pinMode( pwmPin ,OUTPUT);
pinMode( pwmPin2 ,OUTPUT);
pinMode( sensorPin ,INPUT);

}

void loop() {
  // put your main code here, to run repeatedly: 
   if (LED_flasher.check() == 1) { // check if the metro has passed its interval .
  digitalWrite(LED,LEDState);
  LEDState=!LEDState;
   }
  if (PWM_Cycle.check() == 1) { // check if the metro has passed its interval .
   analogWrite(pwmPin,i);
   if(i==0){Factor=1;}
   if(i>255){Factor=-1;}
   i+=Factor;
}
  if (Sensor.check() == 1) { // check if the metro has passed its interval .
  int SensorValue=analogRead(A0);
  analogWrite(pwmPin2,SensorValue/4);
}
}

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

أختم هنا بالقول أنه اذا اردت عمل برنامجك بصورة سريعة و في نفس الوقت و دون تأخير فخيارك الأمثل هو استخدام Arduino DUE و هو ما سأفرد له بنداً خاصاً في المدونة للحديث عن أمكانياتها . 




12 التعليقات :

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

    ردحذف
    الردود
    1. سهل جداً , قم فقط بوضع الزمن المطلوب في البداية , ثم قم بعمل جملة استدعاء خلال هذا الوقت ليقوم بأضاءته , و أوضحت الفكرة بالمثال الثاني لهذا النمط و اعيده في التعليق التالي

      حذف
    2. // Metro Library code
      //Written By : Mohannad Rawashdeh
      //http://www.genotronex.com
      // 1/4/2014 9:00 AM
      //....................................
      #include // Include the Metro library
      //first , Blink Led for 150ms
      Metro LED_flasher = Metro(2000);
      boolean LEDState=true;
      //second , Increase dimming For Led by 1 each time
      Metro PWM_Cycle = Metro(10);
      int i=0;
      int Factor=1; //or -1
      // third , Read Potentiometer and control the bright
      //of led connect to another PWM Pin
      Metro Sensor=Metro(200);
      boolean state2=false;
      const int LED=13;
      const int LED2=11;
      const int pwmPin=6;
      const int sensorPin=A0;
      const int pwmPin2=3;
      void setup() {
      // put your setup code here, to run once:
      pinMode( LED ,OUTPUT);
      pinMode( pwmPin ,OUTPUT);
      pinMode( pwmPin2 ,OUTPUT);
      pinMode( LED2 ,OUTPUT);
      pinMode( sensorPin ,INPUT);

      }

      void loop() {
      // put your main code here, to run repeatedly:
      if (LED_flasher.check() == 1) { // check if the metro has passed its interval .
      digitalWrite(LED,LEDState);
      LEDState=!LEDState;
      }
      if (PWM_Cycle.check() == 1) { // check if the metro has passed its interval .
      analogWrite(pwmPin,i);
      if(i==0){Factor=1;}
      if(i>255){Factor=-1;}
      i+=Factor;
      }
      if (Sensor.check() == 1) { // check if the metro has passed its interval .
      digitalWrite(LED2,state2);
      state2=!state2;
      }
      }

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

    ردحذف
    الردود
    1. بصراحة لم افهم المطلوب من البرنامج بشكل واضح , الرجاء التوضيح أكثر

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

      حذف
    3. اولاً الأشارة لا تأتي من ريلايه بل نحن من نعطيه اشارة .

      ما هي الأولوية المطلوبة ؟ ما اساسها ؟.

      ما المقصود بمرور الأشارات الأخرى , و إلى اين تمر ؟

      فكرة عمل النظام ككل فيها شيء مبهم و غير مترابط !!

      حذف
  3. الموضوع هو اريد ادخال اربع اشارات لتشغيل واحد من الاربع ريليات المستخدمة كمحارج بزمن معين يعني ادخل اشارة رقم 1 لتشغيل الريليه 1 بعد زمن معين ولاتعمل الريليات الباقية وعند عدم وجود الاشارة1 واعطينا اشارة 2 يعمل ريليه2 بعد زمن معين ولايعمل ريليه 3و4 وهكذا

    ردحذف
  4. اخي اذ اريد اشغل مصباحين على سبيل المثال بس مونفس الوقت بيناتهم فتره زمنية بس مااريد يتكرر تشغيلهم مره ثانية اكو حل لحلقة التكرار حتى ماتكرر العمل void loop()

    ردحذف
  5. ممكن الجواب على استفساري وهو اشتغال الحساسات في نفس الوقت

    ردحذف
  6. ممكن مساعدة عند اضافة Metro-Arduino-Wiring-master الى مكتبة الااردوينو وعملت vérifer خرج ا الخطا ما الحل رغم ان الملف موجود في مكتبة

    ردحذف
  7. Arduino : 1.6.5 (Windows 7), Carte : "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

    Specified folder/zip file does not contain a valid library

    Specified folder/zip file does not contain a valid lib
    الانسخة الاخيرة 1.5.6 لم يدخل الملف الى المكتبة

    ردحذف

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