الدرس 7 - المصفوفات و حلقات for والشرط if للتحكم في LEDs

محمد صلاح الدينمنذ 4 سنوات

في هذا الدرس سنقوم بالتحكم بأربعة مصابيح من النوع LED ، كل مصباح سيتم التحكم به عن طريق مفتاح push button. ما سنتعلمه هنا هو كيفية وضع المنافذ المتصلة مع الـ LEDs في متغير واحد هو عبارة عن مصفوفة (Array) ، وكذلك الأمر بالنسبة الى المفاتيح هي أيضا ً سيتم وضعها في مصفوفة واحدة. بهذه الكيفية سيكون الكود مختزلاً وأكثر احترافية. يتطرق الدرس أيضاً الى كيفية استخدام حلقات for للوصول الى عناصر المصفوفة والقيم المحفوظة بها ، كذلك سيتم توضيح كيفية تنفيذ أمر ما بناءً على تحقق شرط محدد.

 

 

تصميم الدائرة على بروتيوس

افتح برنامج بروتيوس وقم بتصميم الدائرة كما هو موضح بالشكل التالي

شرح الدائرة

تم توصيل أربعة push buttons مع منافذ الأردوينو من المنفذ رقم 1 وحتى المنفذ رقم 4 ، تم ضبط المنافذ لتحتوي داخليا ً على مقاومة من النوع pull up لذلك لن تكون هناك أي حوجة لتوصيل مقاومات أو مصدر فولتية مع الـ push buttons وعليه سيعمل عن طريق المنطق المعكوس فعندما يتم الضغط على زر محدد سيقرأ ذلك المنفذ المنطق LOW وعندما لايتم الضغط على زر سيقرأ ذلك المنفذ المنطق HIGH وهذا ما يجب اعتباره في الكود (يمكنك مراجعة الدرس السادس فهناك تجربة كاملة لفهم هذه الطريقة). بالنسبة لمصابيح LEDs تم توصيلها مع المنافذ من 9 وحتى 12 عبر مقاومة 220 أوم تستخدم لتخفيف التيار. في الكود سنجعل كل زر يقوم بإنارةLED  واحد فقط.

 

كتابة الكود على برنامج أردوينو

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

int pushButtons[4] = {1,2,3,4};
int ledPins[4]= {9,10,11,12};


void setup() {
  // put your setup code here, to run once:
  for(int i=0; i<4; i++)
  {
    pinMode(pushButtons[i], INPUT);
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(pushButtons[i], HIGH); //activate pullup resistor
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  for (int i=0; i<4; i++)
  {
    int val = digitalRead(pushButtons[i]);
    if (val == 0)
      digitalWrite(ledPins[i], HIGH);
    else
      digitalWrite(ledPins[i], LOW);
  }
}

 

شرح الكود

يبدأ الكود بتعريف المتغيرات العامة (Global variables) التي ستعمل داخل مجالي الـ setup و الـ loop. عرفنا مصفوفتين من النوع العددي integer كل مصفوفة تتكون من أربعة عناصر ، ففي المصفوفة الأولى والتي سُميت بـ pushButtons تم اسناد أرقام المنافذ المتصلة مع الـ pushButtons وهي المنافذ من 1 وحتى 4. كذلك بالنسبة للمصفوفة الثانية والتي سُميت ledPins تم وضع أرقام المنافذ المتصلة مع LEDs داخل المصفوفة وهي المنافذ من 9 وحتى 12. علينا أن نلاحظ أن بعد إسم المصفوفة يتم وضع عدد عناصر المصفوفة بين قوسين مثل  [4].

int pushButtons[4] = {1,2,3,4};
int ledPins[4]= {9,10,11,12};

بالنسبة الى الكود الموجود بداخل منطقة الـ setup فكما تعلمنا سابقا ً غالبا مايُستخدم لضبط وضع المنافذ (ports) لكي تكون إما في حالة الدخل أو الخرج. ولكن قبل شرح الكود الموجود بداخل مجال الـ setup سنتطرق أولاً لتوضيح بعض المفاهيم الأساسية المتعلقة بالمصفوفات.

يبدأ ترقيم العناصر داخل المصوفات بالرقم 0 ، فعلى سبيل المثال أول عنصرٍ في المصفوفة ledPins هو [0]ledPins والذي يحوي القيمة 9 ومن ذلك نستنتج أن العنصر الثاني في المصفوفة هو العنصر رقم 1 وهكذا. إذاً [0]ledPins هو عبارة عن متغير يحتوي على القيمة 9 واذا ماقمنا باستدعاءه في أي وقت فهو يعني أننا استدعينا القيمة الموجودة بداخله وهي 9 مالم يتم تغييرها. وبما أن المنفذ رقم 9 متصل بـ LED يجب ضبطه ليعمل كمنفذ خرج ، الكود التالي يوضح هذه الخطوة:

pinMode(ledPins[0], OUTPUT);

لاحظ وجود الرقم 0 داخل المصفوفة ledPins والذي يؤشر الى العنصر رقم صفر والذي قيمته 9. الآن نحن نريد أن نضبط جميع المنافذ ابتداءً من 9 وحتى 12 لكي تعمل كمنافذ خرج لأنها متصلة مع LEDs. يمكننا تنفيذ ذلك من خلال الكود التالي بداخل دالة الـ setup.

void setup() {
    pinMode(ledPins[0], OUTPUT);
    pinMode(ledPins[1], OUTPUT);
    pinMode(ledPins[2], OUTPUT);
    pinMode(ledPins[3], OUTPUT);
}

في الكود أعلاه قمنا باستدعاء الدالة  pinMode في كل سطر لضبط المنافذ لتعمل إما في حالة الخرج أو الدخل ، المدخلات (Arguments) التي سيتم تمريرها الى الدالة هي رقم المنفذ والحالة التي يجب أن يعمل عليها (دخل / خرج) ، وبما أننا نتعامل مع المنافذ المتصلة بالـ LEDs ستكون الحالة هي الخرج دائماً. أما بالنسبة لأرقام المنافذ فقد تم تعريفها مسبقا داخل المصفوفة ledPins لذلك في كل سطر سيتم وضع اسم المصفوفة مع رقم العنصر داخل الدالة pinMode. هذا الكود صحيح مائة بالمائة الا أنه يفتقد للإحترافية ويوضح أن كاتبه ضعيف بالبرمجة بعض الشيء ولكن لماذا؟ تخيل لو كان عدد المنافذ داخل المصفوفة هو 10 فذلك يعني أننا سنقوم بكتابة 10 أسطر لتعريف نوع المنفذ ليعمل كمنفذ خرج. ولكن ماهي الطريقة الاحترافية؟ من الأفضل إستخدام الحلقات التكرارية لتقليص الكود وجعله أكثر احترافية ومرونة. سنقوم باستخدام حلقة for كما هو موضح بالكود التالي.

for(int i=0; i<4; i++)
  {
    pinMode(ledPins[i], OUTPUT);
  }

 

في الكود أعلاه قمنا باستخدام حلقة for وداخل تعريف for عرفنا المتغير i وهو من النوع العددي integer وأسندنا اليه القيمة الابتدائية 0 وذلك لأن أول عنصر في المصفوفة يبدأ بصفر. والآن لننفذ for loop معاً ، في الدورة الأولى ستكون قيمة i تساوي 0 سيتم تعويض هذه القيمة داخل الكود الموجود داخل مجال الـ for loop وعليه سيكون الكود كالتالي (pinMode(ledPins[0], OUTPUT ، بعد تنفيذ كل الكود الموجود داخل مجال الـ for loop ستقوم الـ for  بتنفيذ جزئية الكود الذي سيؤثر على قيمة i وفي هذا الكود هي ++i وهذا يعني أن المتغير i ستصبح قيمته تساوي الواحد ، الآن ستقوم الـ for باختبار الشرط i < 4 وبالتاكيد سيتحقق الشرط لأن قيمة i الآن هي واحد وهي فعلا ً أقل من أربعة. وبما أن الشرط تحقق يمكننا الآن تنفيذ مابداخل حلقة for وفي هذه المرة لاتنسى أن قيمة i أصبحت واحد وعليه سيتم تعويض المتغير i بواحد ليصبح الكود (pinMode(ledPins[1], OUTPUT وبتنفيذه سيتم ضبط المنفذ رقم عشرة ليصبح في حالة الخرج ، ستستمر دالة for في العمل حتى الوصول الى حالة انتفاء الشرط والتي فيها ستكون قيمة i ليست أقل من 4 وعندها ستتوقف الـ for عن العمل.

بنفس الكيفية يمكننا ضبط مصفوفة منافذ الدخل التي تمتد من المنفذ رقم 1 وحتى 4 ويمكن إضافة الكود المختص بها الى داخل حلقة for التي احتوت ضبط منافذ الخرج. من المهم جدا ً أن تلاحظ أن أرقام المنافذ من 1 وحتى 4 هي أرقام موجودة بداخل المصفوفة بينما المصفوفة نفسها تبدأ من العنصر رقم 0 وستنتهي بالعنصر رقم 3 لأن بها أربعة عناصر. 

void setup() {
  for(int i=0; i<4; i++)
  {
    pinMode(pushButtons[i], INPUT);
    pinMode(ledPins[i], OUTPUT);
  }
}

 

في النهاية سنقوم بإضافة جزئية الكود الذي سيجعل منافذ الدخل ترتبط بمقاومة pull up الداخلية الى الحلقة التكرارية حيث سيعمل بنفس المفهوم السابق.

void setup() {
  for(int i=0; i<4; i++)
  {
    pinMode(pushButtons[i], INPUT);
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(pushButtons[i], HIGH); //activate pullup resistor
  }
}

 

حتى الآن انتهينا من الكود المختص بضبط حالة المنافذ (port mode) ولكن ماذا عن الكود الموجود بداخل الدالة loop؟ كما تعلمون الكود بداخل loop هو الكود المسؤول عن تنفيذ الفكرة الأساسية.

الكود الموجود بداخل الدالة loop هو كود يتم تنفيذه باستمرار الى مالانهاية فعند الوصول الى السطر الأخير من الدالة تبدأ الدالة في العمل مرة أخرى ابتداءً من السطر الأول. الجدير بالذكر هنا أن المايكروكونترولر الموجود ببورد الأردوينو أونو هو من النوع ATMEGA328P متصل مع مصدر clock يعمل بسرعة 16 ميجاهيرتز وتقريبا ً يقوم المايكروكونترولر بتنفيذ تعملية واحدة كل نبضة clock أي يمكننا القول أن المايكروكونترولر يستطيع تنفيذ 16 مليون تعليمة في الثانية الواحدة ! تعمدت ذكر هذه المعلومة الآن لأن الكود الموجود بداخل loop في هذا الدرس يعتمد على هذه الخاصية ولن تستطيع فهمه حتى تستشعر السرعة التي يعمل بها المايكروكونترولر.

void loop() {
  // put your main code here, to run repeatedly:
  for (int i=0; i<4; i++)
  {
    int val = digitalRead(pushButtons[i]);
    if (val == 0)
      digitalWrite(ledPins[i], HIGH);
    else
      digitalWrite(ledPins[i], LOW);
  }
}

 

يبدأ الكود بحلقة for تعمل من 0 الى 3 ، ستبدأ بوضع القيمة 0 في المتغير i وسيتم تنفيذ الكود الموجود داخل الحلقة. في السطر الأول داخل الحلقة عرفنا المتغير val من النوع العددي integer والذي سيتم فيه قراءة القيمة الموجودة بالمنفذ رقم 1 أي [push button[0 ، فاذا كان الـ push button مضغوطا ً ستقرأ الدالة digitalRead القيمة 0 وفي الحالة المعاكسة ستقرأ القيمة 1 ثم سيتم وضع هذه القيمة في المتغير val. بعد ذلك سيقوم المايكروكونترولر بتنفيذ دالة الشرط if else وستقوم باختبار الشرط اذا ما كان المتغير val يحتوي القيمة 0 أو LOW فاذا تحقق الشرط سيتم وضع القيمة HIGH على المنفذ المرتبط بالمتغير [ledPins[0 وإن لم يتحقق الشرط سيتم وضع القيمة LOW على المنفذ المرتبط بالمتغير [ledPins[0 وبذلك نكون قد نفذنا أول حلقة تكرارية والتي كانت فيها قيمة المتغير i تساوي صفر. ستواصل الدالة العمل وستقوم في كل مرة بزيادة قيمة i بواحد ثم تنفيذ الكود بقيمة i الجديدة حتى تصبح i تساوي 3 فيتم تنفيذ الكود بناءً على هذه القيمة ثم تعود قيمة i مرة أخرى الى 0.

والآن لنفترض أنك قد قمت بتنفيذ الكود وقمت بتحميله الى الأردوينو ثم قمت بالضغط على الزر المتصل مع المنفذ رقم 3 والموجود بـ [pushbutton[2. فعلياً سيقوم الكود الموجود بدالة loop باختبار كل الـ pushbuttons ابتداءً من [pushbutton[0 حتى الوصول الى [pushbutton[3 ولكن سيتم تنفيذ ذلك بسرعة شديدة وفي كل مرة عندما يمر باختبار الشرط المتعلق بـ [pushbutton[2 والذي سيقوم باضاءة LED المتصل مع المنفذ رقم 11.

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !