نستكمل في هذا المقال بناء المشروع الثالث من سلسلتنا التعليمية دليل أردوينو Arduino، سنتعلم في هذا المقال كيفية بناء مشروع إلكتروني تفاعلي من خلال تصميم وتنفيذ لعبة بسيطة لتخمين عدد مرات وميض ليد باستخدام لوحة أردوينو أونو Arduino Uno
فكرة مشروع تخمين عدد مرات وميض الليد
سنبني مشروعًا يحسب عدد مرات تشغيل وإطفاء ليد بفترات زمنية عشوائية ضمن مجال محدد عند الضغط على مفتاح الضغط اللحظي Push Button (سنشرحه لاحقًا في هذا المقال) بشكل مستمر، ويجب على المستخدم حساب أو تخمين هذا الرقم، في النهاية بعد إزالة الضغط عن المفتاح سيتوقف الليد عن الومض ويطبع عدد مرات تشغيل وإطفاء الليد على نافذة الاتصال التسلسلي Serial monitor.
سنتبع تسلسل الخطوات الآتية في آلية عمل المشروع:
- فحص حالة المفتاح (مضغوط أم لا) وإذا كان مضغوطًا تنفذ الخطوات من 2 إلى 5 وإلا تكرر الخطوة 1.
- يضيء الليد لفترة زمنية عشوائية ضمن مجال محدد.
- ينطفئ الليد لفترة زمنية عشوائية ضمن مجال محدد.
- تزداد قيمة العداد بمقدار 1.
- فحص حالة المفتاح (مضغوط أم لا) وإذا كان مضغوطًا تكرر الخطوات من 2 إلى 5 وإلا ينتقل إلى 6
- فحص قيمة العداد إذا كانت أكبر من 0 (ومض الليد مرة واحدة على الأقل) وإذا كان الشرط محققًا تنفيذ الخطوة 7 و 8 وإلا الرجوع إلى الخطوة 1.
- طباعة قيمة العداد.
- تصفير قيمة العداد.
العناصر المستخدمة لمشروع تخمين عدد مرات وميض الليد
العناصر التي سنستخدمها لعمل هذا المشروع هي:
- لوحة أردوينو أونو Arduino Uno.
- كابل البرمجة USB Cable.
- لوحة توصيل التجارب Breadboard.
- ليد LED.
- مفتاح الضغط اللحظي Push Button.
- مقاومة بقيمة 220 أوم.
- مقاومة بقيمة 10 كيلو أوم.
- مجموعة أسلاك توصيل من نوع Male to Male.
ما هو مفتاح الضغط اللحظي Push Button
عبارة عن مفتاح ميكانيكي لحظي عند الضغط عليه تتصل أطرافه معًا مما يؤدي إلى إغلاق الدائرة الكهربائية المتصلة به، وعند إزالة الضغط يعود إلى حالته الأولى، يمكن أن يستخدم كعنصر للتحكم بالتشغيل والإيقاف بإعطاء إشارة رقمية Digital إلى الأردوينو Arduino من خلال توصيل أحد أطرافه مع 5v أو GND والطرف الآخر مع إحدى أقطاب الأردوينو الرقمية.
مثلًا وصَّلنا الطرف الأول للمفتاح مع 5v والطرف الثاني مع القطب رقم 2 للأردوينو Arduino وضغطنا على المفتاح في هذه الحالة عند قراءة قيمة القطب ستكون HIGH
أو 1 منطقي.
أو إذا كان الطرف الأول للمفتاح وصل مع GND بدلًا من 5v والطرف الثاني مع القطب رقم 2 للأردوينو Arduino فإنه عند الضغط على المفتاح ستكون قيمة القطب LOW
أو 0 منطقي.
ولكن نلاحظ أنه في حال عدم الضغط على المفتاح فإنه يعطي قيم خاطئة أو عشوائية وذلك لأنه عند عدم الضغط على المفتاح لا يوجد أي إشارة على قطب الأردوينو (1 منطقي HIGH
أو 0 منطقي LOW
) وتسمى هذه الحالة بالحالة العائمة أو حالة مقاومة عالية (High-Z or High impedance).
نحل هذه المشكلة من خلال إضافة مقاومة رفع Pull-Up Resistor من خلال توصيل مقاومة بين قطب الأردوينو و5v (تكون القيمة الافتراضية للقطب في حال عدم الضغط على المفتاح هي HIGH
أو 1 منطقي أما عند الضغط على المفتاح فتكون قيمته LOW
أو 0 منطقي) أو إضافة مقاومة خفض Pull-Down Resistor من خلال توصيل مقاومة بين قطب الأردوينو والأرضي GND (تكون القيمة الافتراضية للقطب في حال عدم الضغط على المفتاح هي LOW
أو 0 منطقي أما عند الضغط على المفتاح فستكون قيمته HIGH
أو 1 منطقي). توضح الصورة الآتية حالة قطب الدخل في لوحة الأردوينو أونو Arduino Uno في حال استخدام مقاومة رفع مع مفتاح الضغط اللحظي Push Button أو بدونها.
وتوضح الصورة الآتية طريقة توصيل مقاومة الرفع والخفض مع مفتاح الضغط اللحظي Push Button في لوحة الأردوينوأونو Arduino UNO
مخطط التوصيل لمشروع تخمين عدد مرات وميض الليد
اتبع الخطوات الآتية في عملية توصيل العناصر والأسلاك مع لوحة الأردوينو Arduino لتنفيذ فكرة المشروع:
- صل أقطاب التغذية في لوحة الأردوينو أونو Arduino Uno مع لوحة توصيل التجارب BreadBoard، إذ يوصل القطب 5v في لوحة الأردوينو مع المسرى الموجب للوحة التجارب، والقطب GND في لوحة الأردوينو مع المسرى السالب للوحة التجارب من خلال أسلاك التوصيل.
- صل الرِّجل الأطول (التي تمثل الطرف الموجب) لليد مع الرجل الأولى للمقاومة ذات القيمة 220 أوم، ثم الرجل الأخرى للمقاومة ذات القيمة 220 أوم مع القطب رقم 13 في لوحة الأردوينو أونو Arduino Uno.
- صل الرجل الأقصر (التي تمثل الطرف السالب) لليد مع المسرى السالب في لوحة توصيل التجارب BreadBoard.
- يوجد في مفتاح الضغط اللحظي Push Button أربعة أرجل أو أطراف كما ذكرنا سابقًا، كل اثنين منها متصلة ببعضها داخليًا ويمكن اعتبارها رجلًا واحدة، ولتجنب الخطأ أو التشتت في التوصيل سنعتمد أن نأخذ الأرجل القطرية (الأرجل المختلفة للمفتاح) دائمًا.
- ثبت المفتاح بشكل جيد في منتصف لوحة توصيل التجارب BreadBoard، بحيث يكون نصف المفتاح في الجزء الأيمن للوحة التجارب BreadBoard والنصف الثاني للمفتاح في الجزء الأيسر للوحة التجارب BreadBoard.
- صل الطرف الأول للمفتاح مع المسرى السالب للوحة التجارب BreadBoard، والطرف الثاني للمفتاح مع القطب رقم 2 في لوحة أردوينو أونو Arduino Uno.
- صل الطرف الأول للمقاومة ذات القيمة 10 كيلو أوم مع الطرف الثاني للمفتاح (المتصل مع القطب رقم 2 في لوحة الأردوينو أونو Arduino Uno).
- صل الطرف الثاني للمقاومة ذات القيمة 10 كيلو أوم مع المسرى الموجب للوحة توصيل التجارب BreadBoard.
توضح الصورة الآتية مخطط التوصيل لمشروع تخمين عدد مرات وميض الليد:
الكود البرمجي لمشروع تخمين عدد مرات وميض الليد
نحتاج في البداية لتعريف متغيرات خاصة بأرقام أقطاب بالليد 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
لاحظ الفرق بين حجم استهلاك ذاكرة البرنامج في كلا الحالتين الأولى هي عند استخدام المتغيرات والثانية هي عند استبدالها بالماكرو
ويمكن أن يكون الماكرو بسيطًا كاستبدال نص معين أو أرقام ويمكن أن يكون معقدًا أكثر مثل ماكرو الدالة، للاطلاع أكثر على الماكرو وأنواعه من خلال مقال الماكرو 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; } }
محاكاة لمشروع تخمين عدد مرات وميض الليد
- اتبع الخطوات التي تعلمناها في المقال السابق للوصول الى الصفحة الخاصة بمحاكاة مشروعك على موقع وكوي Wokwi .تستطيع الرجوع إليها من خلال مقال التحكم بتشغيل وإطفاء ليد LED باستخدام الأردوينو Arduino
- أضف العناصر الإلكترونية اللازمة للمشروع وهي Push Button LEDs و Resistors و BreadBoard.
- غير قيمة مقاومة الليد إلى 220 أوم ومقاومة المفتاح إلى 10 كيلو أوم (في حال استخدام مقاومة خارجية) من خلال الضغط عليها فتظهر لك نافذة في الأعلى تمكنك من تغير القيمة والواحدة.
- بالطريقة نفسها يمكنك تغير ألوان الليد والمفتاح من خلال الضغط عليها فتظهر لك نافذة بالأعلى تستطيع من خلالها اختيار اللون.
-
رتب العناصر على لوحة التجارب بالشكل الذي تراه مناسبًا، ثم صل العناصر بعضها ببعض حسب مخطط التوصيل الذي عرضناه سابقًا.
-
اكتب الكود البرمجي في الجزء الخاص به، ثم شغل المحاكاة، اضغط على المفتاح سيبدأ الليد بالوميض حاول أن تركز في عدد مرات تشغيل وإطفاء الليد انتظر قليلًا ثم أزل الضغط عن المفتاح سيظهر لك عدد مرات وميض الليد في الاسفل، هل استطعت تخمينها بشكل صحيح؟
الخلاصة
شرحنا في هذا المشروع طريقة بناء مشروع لقياس وتخمين عدد مرات وميض الليد عند الضغط عليه باستخدام لوحة الأردوينو، واستعرضنا كيفية بناء المشروع وتوصيل العناصر والأدوات، بما في ذلك الأردوينو، الليد، المقاومات والمفتاح، بالإضافة إلى كيفية كتابة الكود الخاص ببرمجة الأردوينو باستخدام بيئة التطوير المتكاملة (IDE) الخاصة به وعمل محاكاة للمشروع من خلال منصة وكوي Wokwi وكيفية مواجهة المشاكل وحلها وتحسين المشروع للأفضل.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.