اذهب إلى المحتوى

تخمين عدد مرات وميض الليد باستخدام الأردوينو Arduino


Mohammad Baher Karazeh

نستكمل في هذا المقال بناء المشروع الثالث من سلسلتنا التعليمية دليل أردوينو Arduino، سنتعلم في هذا المقال كيفية بناء مشروع إلكتروني تفاعلي من خلال تصميم وتنفيذ لعبة بسيطة لتخمين عدد مرات وميض ليد باستخدام لوحة أردوينو أونو Arduino Uno

فكرة مشروع تخمين عدد مرات وميض الليد

سنبني مشروعًا يحسب عدد مرات تشغيل وإطفاء ليد بفترات زمنية عشوائية ضمن مجال محدد عند الضغط على مفتاح الضغط اللحظي Push Button (سنشرحه لاحقًا في هذا المقال) بشكل مستمر، ويجب على المستخدم حساب أو تخمين هذا الرقم، في النهاية بعد إزالة الضغط عن المفتاح سيتوقف الليد عن الومض ويطبع عدد مرات تشغيل وإطفاء الليد على نافذة الاتصال التسلسلي Serial monitor.

سنتبع تسلسل الخطوات الآتية في آلية عمل المشروع:

  1. فحص حالة المفتاح (مضغوط أم لا) وإذا كان مضغوطًا تنفذ الخطوات من 2 إلى 5 وإلا تكرر الخطوة 1.
  2. يضيء الليد لفترة زمنية عشوائية ضمن مجال محدد.
  3. ينطفئ الليد لفترة زمنية عشوائية ضمن مجال محدد.
  4. تزداد قيمة العداد بمقدار 1.
  5. فحص حالة المفتاح (مضغوط أم لا) وإذا كان مضغوطًا تكرر الخطوات من 2 إلى 5 وإلا ينتقل إلى 6
  6. فحص قيمة العداد إذا كانت أكبر من 0 (ومض الليد مرة واحدة على الأقل) وإذا كان الشرط محققًا تنفيذ الخطوة 7 و 8 وإلا الرجوع إلى الخطوة 1.
  7.  طباعة قيمة العداد.
  8. تصفير قيمة العداد.

001_مخطط_تسلسل_عمل_المشروع.jpg.JPG

العناصر المستخدمة لمشروع تخمين عدد مرات وميض الليد

العناصر التي سنستخدمها لعمل هذا المشروع هي:

  • لوحة أردوينو أونو Arduino Uno.
  • كابل البرمجة USB Cable.
  • لوحة توصيل التجارب Breadboard.
  • ليد LED.
  • مفتاح الضغط اللحظي Push Button.
  • مقاومة بقيمة 220 أوم.
  • مقاومة بقيمة 10 كيلو أوم.
  • مجموعة أسلاك توصيل من نوع Male to Male.

ما هو مفتاح الضغط اللحظي Push Button

عبارة عن مفتاح ميكانيكي لحظي عند الضغط عليه تتصل أطرافه معًا مما يؤدي إلى إغلاق الدائرة الكهربائية المتصلة به، وعند إزالة الضغط يعود إلى حالته الأولى، يمكن أن يستخدم كعنصر للتحكم بالتشغيل والإيقاف بإعطاء إشارة رقمية Digital إلى الأردوينو Arduino من خلال توصيل أحد أطرافه مع 5v أو GND والطرف الآخر مع إحدى أقطاب الأردوينو الرقمية.

مفتاح الضغط اللحظي

مثلًا وصَّلنا الطرف الأول للمفتاح مع 5v والطرف الثاني مع القطب رقم 2 للأردوينو Arduino وضغطنا على المفتاح في هذه الحالة عند قراءة قيمة القطب ستكون HIGH أو 1 منطقي.

002 توصيل المفتاح مع التغذية

أو إذا كان الطرف الأول للمفتاح وصل مع GND بدلًا من 5v والطرف الثاني مع القطب رقم 2 للأردوينو Arduino فإنه عند الضغط على المفتاح ستكون قيمة القطب LOW أو 0 منطقي.

003 توصيل المفتاح مع الأرضي

ولكن نلاحظ أنه في حال عدم الضغط على المفتاح فإنه يعطي قيم خاطئة أو عشوائية وذلك لأنه عند عدم الضغط على المفتاح لا يوجد أي إشارة على قطب الأردوينو (1 منطقي HIGH أو 0 منطقي LOW) وتسمى هذه الحالة بالحالة العائمة أو حالة مقاومة عالية (High-Z or High impedance).

004 مشكلة عدم الضغط على المفتاح

نحل هذه المشكلة من خلال إضافة مقاومة رفع Pull-Up Resistor من خلال توصيل مقاومة بين قطب الأردوينو و5v (تكون القيمة الافتراضية للقطب في حال عدم الضغط على المفتاح هي HIGH أو 1 منطقي أما عند الضغط على المفتاح فتكون قيمته LOW أو 0 منطقي) أو إضافة مقاومة خفض Pull-Down Resistor من خلال توصيل مقاومة بين قطب الأردوينو والأرضي GND (تكون القيمة الافتراضية للقطب في حال عدم الضغط على المفتاح هي LOW أو 0 منطقي أما عند الضغط على المفتاح فستكون قيمته HIGH أو 1 منطقي). توضح الصورة الآتية حالة قطب الدخل في لوحة الأردوينو أونو Arduino Uno في حال استخدام مقاومة رفع مع مفتاح الضغط اللحظي Push Button أو بدونها.

005_قيمة القطب مع مقاومة رفع وبدون.JPG

وتوضح الصورة الآتية طريقة توصيل مقاومة الرفع والخفض مع مفتاح الضغط اللحظي Push Button في لوحة الأردوينوأونو Arduino UNO

006_مقاومة الرفع والخفض مع الأردوينو.JPG

مخطط التوصيل لمشروع تخمين عدد مرات وميض الليد

اتبع الخطوات الآتية في عملية توصيل العناصر والأسلاك مع لوحة الأردوينو Arduino لتنفيذ فكرة المشروع:

  • صل أقطاب التغذية في لوحة الأردوينو أونو Arduino Uno مع لوحة توصيل التجارب BreadBoard، إذ يوصل القطب 5v في لوحة الأردوينو مع المسرى الموجب للوحة التجارب، والقطب GND في لوحة الأردوينو مع المسرى السالب للوحة التجارب من خلال أسلاك التوصيل.
  • صل الرِّجل الأطول (التي تمثل الطرف الموجب) لليد مع الرجل الأولى للمقاومة ذات القيمة 220 أوم، ثم الرجل الأخرى للمقاومة ذات القيمة 220 أوم مع القطب رقم 13 في لوحة الأردوينو أونو Arduino Uno.
  • صل الرجل الأقصر (التي تمثل الطرف السالب) لليد مع المسرى السالب في لوحة توصيل التجارب BreadBoard.
  • يوجد في مفتاح الضغط اللحظي Push Button أربعة أرجل أو أطراف كما ذكرنا سابقًا، كل اثنين منها متصلة ببعضها داخليًا ويمكن اعتبارها رجلًا واحدة، ولتجنب الخطأ أو التشتت في التوصيل سنعتمد أن نأخذ الأرجل القطرية (الأرجل المختلفة للمفتاح) دائمًا.

أقطاب مفتاح الضغط اللحظي.jpg

  • ثبت المفتاح بشكل جيد في منتصف لوحة توصيل التجارب BreadBoard، بحيث يكون نصف المفتاح في الجزء الأيمن للوحة التجارب BreadBoard والنصف الثاني للمفتاح في الجزء الأيسر للوحة التجارب BreadBoard.
  • صل الطرف الأول للمفتاح مع المسرى السالب للوحة التجارب BreadBoard، والطرف الثاني للمفتاح مع القطب رقم 2 في لوحة أردوينو أونو Arduino Uno.
  • صل الطرف الأول للمقاومة ذات القيمة 10 كيلو أوم مع الطرف الثاني للمفتاح (المتصل مع القطب رقم 2 في لوحة الأردوينو أونو Arduino Uno).
  • صل الطرف الثاني للمقاومة ذات القيمة 10 كيلو أوم مع المسرى الموجب للوحة توصيل التجارب BreadBoard.

توضح الصورة الآتية مخطط التوصيل لمشروع تخمين عدد مرات وميض الليد:

007_مخطط توصيل المشروع الثالث.JPG 

الكود البرمجي لمشروع تخمين عدد مرات وميض الليد

نحتاج في البداية لتعريف متغيرات خاصة بأرقام أقطاب بالليد LED والمفتاح Push Button؛ فكما شرحنا في مخطط التوصيل سيوصل المفتاح مع القطب رقم 2 والليد مع القطب رقم 13، وبما أن هذه الأرقام صحيحة نخزنها في متغيرات من نوع int.

int led = 13;
int button = 2;

شرحنا في فكرة المشروع أن الليد سيضيء وينطفئ لمدة زمنية عشوائية ولكن هذه المدة ضمن مجال محدد لذلك نخزن مجال القيم العشوائية الخاصة بالتأخير الزمني في متغيرات من نوع int وسنختار أقل مدة هي 100 مللي ثانية وأكثر مدة هي 500 مللي ثانية.

int minDelay = 100;
int maxDelay = 500;

أخيرًا نحتاج إلى تعريف متغير من نوع int لتخزين قيمة العداد بقيمة ابتدائية 0.

int count = 0;

سنفعّل واجهة الاتصال التسلسلية Serial Communication داخل الدالة الرئيسية ()setup في البداية من أجل عرض قيمة العداد على نافذة الاتصال التسلسلي Serial Monitor الموجودة في بيئة الأردوينو البرمجية Arduino IDE وذلك من خلال التابع ()Serial.begin الذي تأخذ وسيطين: الأول أساسي وهو سرعة نقل البيانات Baud rate بمعدل بت في الثانية وسنختار 9600، والثاني اختياري خاص بضبط الإعدادات config الأخرى لواجهة الاتصال ويمكن تركه فارغًا حيث يأخذ الضبط الافتراضي في هذه الحالة. سنضبط بعدها القطب الخاص بالليد كقطب خرج OUTPUT والقطب الخاص بالمفتاح كقطب دخل INPUT من خلال الدالة المدمجة ()pinMode التي تأخذ وسيطين: الأول رقم القطب (الذي خُزن في المتغير) والثاني نوع القطب (إما خرج وإما دخل)

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

سنعرف في الدالة التكرارية ()loop في البداية متغيرًا خاصًا بتخزين قيمة القطب الموصول مع المفتاح بعد قراءتها من خلال الدالة ()digitalRead التي تأخذ وسيطًا واحدًا وهو رقم القطب وتعيد القيمة الفيزيائية الموجودة على القطب، وبما أن المفتاح موصول مع مقاومة رفع خارجية ستكون قيمة القطب LOW أو 0 منطقي في حالة الضغط على المفتاح وHIGH أو 1 منطقي عند إزالة الضغط عن المفتاح.

  int buttonStat = digitalRead(button);

سيومض الليد وتزداد قيمة العداد باستمرار ولكن بشرط استمرار الضغط على المفتاح؛ لذلك سنستخدم الحلقة التكرارية ()while والشرط الذي سنضعه هو أن تكون قيمة المتغير buttonStat هي 0.

while (buttonStat == 0) {
 }

سيضيء الليد وينطفئ داخل هذه الحلقة بتأخير زمني عشوائي ويتم التحكم بقيمة القطب من خلال الدالة ()digitalWrite التي تأخذ وسيطين: الأول رقم القطب (الذي خُزن في المتغير) والثاني حالة أو قيمة القطب (إما 1 منطقي HIGH للتشغيل وإما 0 منطقي LOW للإطفاء). لتحقيق التأخير الزمني نستخدم الدالة ()delay التي تحقق انتظار أو تأخير زمني في مكان كتابتها في الكود ويُكتب الزمن داخلها بواحدة المللي ثانية "ms" وللحصول على قيمة عشوائية نستخدم الدالة ()random التي يمكن أن تأخذ وسيطين الأول أقل قيمة والثاني أكبر قيمة وتعيد قيمة عشوائية ضمن هذا المجال.

    digitalWrite(led, HIGH);
    delay(random(minDelay, maxDelay));
    digitalWrite(led, LOW);
    delay(random(minDelay, maxDelay));

اكتملت مرة واحدة من تشغيل وإطفاء الليد في هذه الحالة لذلك سنزيد قيمة العداد count بمقدار 1، ومن ثَم سنحتاج إلى قراءة حالة المفتاح مرة أخرى كي لا تصبح الحلقة التكرارية غير منتهية فإذا تمت إزالة الضغط عن المفتاح سيخرج البرنامج من هذه الحلقة ويكمل تنفيذ باقي البرنامج.

    count++;
    buttonStat = digitalRead(button);

ليصبح الكود الخاص بالحلقة التكرارية ()while:

 while (buttonStat == 0) {
    digitalWrite(led, HIGH);
    delay(random(minDelay, maxDelay));
    digitalWrite(led, LOW);
    delay(random(minDelay, maxDelay));
    count++;
    buttonStat = digitalRead(button);
  }

سنطبع قيمة العداد count على نافذة الاتصال التسلسلي إن تحقق الشرط أن العداد count لا يساوي الصفر (المفتاح ضغط والليد اشتغل وانطفأ مرة واحدة على الأقل) وسبب استخدام هذا الشرط هو تجنب طباعة رقم 0 باستمرار في حالة عدم الضغط على المفتاح.

 if (count != 0) {
 }

بعد التأكد من أن قيمة العداد ليست صفرًا سنطبع العبارة ":Number of blinking" من خلال الدالة المدمجة ()Serial.print ونضع البيانات التي نريد طباعتها داخل الأقواس وبما أننا نريد طباعة نص نكتبه ضمن علامتي تنصيص " " وبجانبه نريد طباعة عدد مرات الوميض ثم النزول إلى سطر جديد؛ لذلك سنستخدم التابع ()Serial.println الذي يطبع البيانات ثم ينتقل إلى سطر جديد.

وفي النهاية نصفر قيمة العداد كي يبدأ العد من الصفر إذا ضُغط على المفتاح مرة أخرى.

 if (count != 0) {
    Serial.print("number of blinking: ");
    Serial.println(count);
    count = 0;
  }

تحسين الكود البرمجي للمشروع

من أكثر المشكلات التي تواجه المطورين في المشاريع الضخمة هي استهلاك ذاكرة البرنامج بشكل مفرط ولعل أهم أسباب هذه المشكلة هو العدد الكبير للمتغيرات الموجودة في الكود، ونلاحظ أن لدينا في هذا المشروع المتغيرات الآتية: led وbutton وminDelay وmaxDelay التي لم نعدل على القيمة المخزنة فيها مطلقًا خلال الكود على عكس المتغيرات الأخرى count buttonStat التي تتغير قيمها.

لهذا نستطيع الاستغناء عن المتغيرات التي لا نحتاج للتعديل عليها مثل led وbutton و minDelay وmaxDelay من أجل تقليل استهلاك ذاكرة البرنامج، واستبدال هذه المتغيرات بالماكرو Macro وهو عبارة عن طريقة لتعريف مجموعة من التعليمات البرمجية التي يمكن استخدامها مرارًا وتكرارًا في البرنامج دون استهلاك ذاكرة البرنامج، ويعرف الماكرو باستخدام الموجهات Directives وتبدأ بالكلمة المفتاحية define# ثم اسم الماكرو وبعدها القيمة الخاصة به مثال لاستبدال المتغيرات السابقة:

#define led 13
#define button 2
#define minDelay 100
#define maxDelay 500

لاحظ الفرق بين حجم استهلاك ذاكرة البرنامج في كلا الحالتين الأولى هي عند استخدام المتغيرات والثانية هي عند استبدالها بالماكرو

009 استهلاك الذاكرة في حالة المتغيرات

010 استهلاك الذاكرة في حالة الماكرو

ويمكن أن يكون الماكرو بسيطًا كاستبدال نص معين أو أرقام ويمكن أن يكون معقدًا أكثر مثل ماكرو الدالة، للاطلاع أكثر على الماكرو وأنواعه من خلال مقال الماكرو Macro والمعالج المسبق Preprocessor في لغة سي C.

رأينا سابقًا مشكلة الحالة العائمة floating الخاصة بالمداخل الرقمية Digital Input عندما لا يكون هناك قيمة محددة عليها واستطعنا حل هذه المشكلة من خلال التعرف على مفهوم مقاومة الرفع والخفض واستخدمنا مقاومة رفع خارجية في مشروعنا مع مفتاح الضغط اللحظي Push Button. تدعم بعض المتحكمات ومن بينها لوحات الأردوينو وجود مقاومة رفع داخلية نستطيع تفعيلها برمجيًا أثناء ضبط نوع القطب من خلال الدالة المدمجة ()pinMode التي نمرر لها رقم القطب ونوعه كما ذكرنا سابقًا وقد تعرفنا على حالتين لنوع القطب إما أن يكون خرج OUTPUT وإما دخل INPUT ولكن هناك حالة ثالثة وهي دخل مع تفعيل مقاومة رفع داخلية INPUT_PULLUP وبهذه الحالة نستطيع الإستغناء عن مقاومة الرفع الخارجية والتقليل من التوصيلات والعناصر التي قد تسبب تعقيدًا في تنفيذ المشروع للبعض بحل برمجي بسيط

  pinMode(button, INPUT_PULLUP);

يصبح الكود البرمجي النهائي للمشروع:

#define led 13
#define button 2
#define minDelay 100
#define maxDelay 500
int count = 0;

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop() {
  int buttonStat = digitalRead(button);

  while(buttonStat == 0){
    digitalWrite(led, HIGH);
    delay(random(minDelay, maxDelay));
    digitalWrite(led, LOW);
    delay(random(minDelay, maxDelay));
    count++;
    buttonStat = digitalRead(button);
  }

  if(count !=0){
    Serial.print("number of blinking: ");
    Serial.println(count);
    count = 0;
  }
}

محاكاة لمشروع تخمين عدد مرات وميض الليد

011 الصفحة الخاصة بمحاكاة المشروع

  • أضف العناصر الإلكترونية اللازمة للمشروع وهي Push Button LEDs و Resistors و BreadBoard.

012 إضافة العناصر في موقع وكوي

  • غير قيمة مقاومة الليد إلى 220 أوم ومقاومة المفتاح إلى 10 كيلو أوم (في حال استخدام مقاومة خارجية) من خلال الضغط عليها فتظهر لك نافذة في الأعلى تمكنك من تغير القيمة والواحدة.

013 تغيير قيمة المقاومة

  • بالطريقة نفسها يمكنك تغير ألوان الليد والمفتاح من خلال الضغط عليها فتظهر لك نافذة بالأعلى تستطيع من خلالها اختيار اللون.

014 تغير لون الليد والمفتاح

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

  • اكتب الكود البرمجي في الجزء الخاص به، ثم شغل المحاكاة، اضغط على المفتاح سيبدأ الليد بالوميض حاول أن تركز في عدد مرات تشغيل وإطفاء الليد انتظر قليلًا ثم أزل الضغط عن المفتاح سيظهر لك عدد مرات وميض الليد في الاسفل، هل استطعت تخمينها بشكل صحيح؟

015 النتيجة النهائية لمحاكاة المشروع الثالث

الخلاصة

شرحنا في هذا المشروع طريقة بناء مشروع لقياس وتخمين عدد مرات وميض الليد عند الضغط عليه باستخدام لوحة الأردوينو، واستعرضنا كيفية بناء المشروع وتوصيل العناصر والأدوات، بما في ذلك الأردوينو، الليد، المقاومات والمفتاح، بالإضافة إلى كيفية كتابة الكود الخاص ببرمجة الأردوينو باستخدام بيئة التطوير المتكاملة (IDE) الخاصة به وعمل محاكاة للمشروع من خلال منصة وكوي Wokwi وكيفية مواجهة المشاكل وحلها وتحسين المشروع للأفضل.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...