أهلاً بكم في الدرس الثاني من سلسلة "أساسيات لغة C++ للمتحكمات"! في هذا الدرس، سنتعمق في فهم واستخدام الحلقات التكرارية for و while، وهما أداتان أساسيتان للتحكم المستمر في مشاريع المتحكمات الدقيقة مثل الأردوينو.
سنتعلم اليوم كيفية استخدام الحلقات لتنفيذ المهام بشكل متكرر، سواء لعدد محدد من المرات أو طالما أن شرطاً معيناً صحيحاً، مما يتيح لنا بناء أنظمة تحكم ديناميكية ومتجاوبة.
1. مقدمة إلى الحلقات التكرارية وأهميتها
في برمجة المتحكمات، نحتاج غالباً إلى تكرار مجموعة من التعليمات لعدد معين من المرات، أو الاستمرار في تنفيذها طالما أن شرطاً معيناً صحيحاً. هنا يأتي دور الحلقات التكرارية (Loops). إنها تتيح لنا كتابة كود فعال ينجز مهام متكررة دون الحاجة لإعادة كتابة نفس الأسطر مراراً وتكراراً.
ملاحظة تقنية: وظيفة
loop()في الأردوينو هي بحد ذاتها حلقةwhile(true)ضخمة، حيث يتم تنفيذ التعليمات بداخلها بشكل مستمر بعد انتهاءsetup().
لنبدأ بمثال بسيط يوضح كيف يمكن لحلقة for أن تكرر عملية إضاءة وإطفاء مصباح LED لعدد محدد من المرات عند بدء تشغيل المتحكم.
// تعريف منفذ الـ LED
const int ledPin = 13;
void setup() {
// تهيئة منفذ الـ LED كخرج
pinMode(ledPin, OUTPUT);
// حلقة for لتكرار عملية إضاءة وإطفاء الـ LED 5 مرات
for (int i = 0; i < 5; i++) {
digitalWrite(ledPin, HIGH); // إضاءة الـ LED
delay(100); // انتظار 100 مللي ثانية
digitalWrite(ledPin, LOW); // إطفاء الـ LED
delay(100); // انتظار 100 مللي ثانية
}
}
void loop() {
// هذه الدالة ستكون فارغة مؤقتاً
// سيتم إضافة الكود الخاص بالتحكم المستمر هنا لاحقاً
}
في هذا الجزء، تقوم حلقة for بتكرار عملية وميض الـ LED خمس مرات فور تشغيل المتحكم، ثم تتوقف. هذا يوضح كيف يمكن استخدام for لمهام ذات عدد تكرارات معروف ومحدد.
2. التحكم المستمر باستخدام حلقة for (تطبيق عملي: تلاشي الإضاءة)
لتحقيق تحكم مستمر وديناميكي، غالباً ما نضع الحلقات التكرارية داخل دالة loop(). سنستخدم حلقة for لإنشاء تأثير تلاشي (Fading) لمصباح LED، حيث تزداد إضاءته تدريجياً ثم تتناقص، وتتكرر هذه العملية باستمرار.
// تعريف منفذ الـ LED (يجب أن يكون منفذ PWM مثل 3, 5, 6, 9, 10, 11 على معظم لوحات الأردوينو)
const int ledPin = 9; // اختر منفذ PWM
void setup() {
// تهيئة منفذ الـ LED كخرج
pinMode(ledPin, OUTPUT);
}
void loop() {
// حلقة for لزيادة إضاءة الـ LED تدريجياً (Fade In)
// تبدأ قيمة السطوع من 0 وتزيد حتى 255
for (int brightness = 0; brightness <= 255; brightness++) {
analogWrite(ledPin, brightness); // تطبيق قيمة السطوع على الـ LED
delay(10); // انتظار 10 مللي ثانية بين كل زيادة
}
// حلقة for لتقليل إضاءة الـ LED تدريجياً (Fade Out)
// تبدأ قيمة السطوع من 255 وتقل حتى 0
for (int brightness = 255; brightness >= 0; brightness--) {
analogWrite(ledPin, brightness); // تطبيق قيمة السطوع على الـ LED
delay(10); // انتظار 10 مللي ثانية بين كل نقصان
}
delay(500); // انتظار نصف ثانية قبل تكرار عملية التلاشي
}
هنا، تعمل دالة loop() باستمرار، وداخلها، تقوم حلقتي for بتغيير سطوع الـ LED من 0 إلى 255 ثم العودة من 255 إلى 0. هذا يخلق تأثيراً بصرياً سلساً يتكرر بلا نهاية، وهو مثال ممتاز للتحكم المستمر باستخدام for.
3. حلقة while للتحكم الشرطي والانتظار
تُستخدم حلقة while عندما نريد تكرار مجموعة من التعليمات طالما أن شرطاً معيناً صحيحاً. إنها مثالية للانتظار حتى يحدث شيء ما، أو لتنفيذ مهمة معينة طالما أن حالة معينة قائمة. في هذا المثال، سنجعل المتحكم ينتظر داخل حلقة while حتى يتم "استيفاء" شرط معين (مثل مرور فترة زمنية أو قراءة مستشعر).
// تعريف منفذ الـ LED
const int ledPin = 13;
// متغير لتتبع عدد التكرارات أو ليكون بمثابة شرط
int counter = 0;
// متغير لتحديد عدد التكرارات المطلوبة قبل الخروج من حلقة while
const int maxCount = 10;
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600); // تهيئة الاتصال التسلسلي لعرض الرسائل
Serial.println("بدء تشغيل المتحكم.");
}
void loop() {
Serial.print("العداد: ");
Serial.println(counter);
// إضاءة الـ LED كإشارة
digitalWrite(ledPin, HIGH);
// حلقة while: تستمر طالما أن counter أقل من maxCount
while (counter < maxCount) {
Serial.println("داخل حلقة while... العداد يزداد.");
delay(500); // انتظار نصف ثانية
counter++; // زيادة العداد
// يمكن هنا وضع كود يراقب مستشعر أو ينتظر حدثاً معيناً
}
// بعد الخروج من حلقة while
Serial.println("خرجنا من حلقة while! العداد وصل إلى الحد الأقصى.");
digitalWrite(ledPin, LOW); // إطفاء الـ LED
delay(2000); // انتظار ثانيتين قبل إعادة تعيين العداد
// إعادة تعيين العداد لبدء دورة جديدة في loop()
counter = 0;
Serial.println("إعادة تعيين العداد. بدء دورة جديدة.");
}
في هذا المثال، تظل حلقة while نشطة وتكرر زيادة العداد وطباعة الرسالة طالما أن counter أقل من maxCount. بمجرد أن يصل العداد إلى maxCount، تتوقف الحلقة ويستمر تنفيذ الكود بعدها، مما يدل على التحكم الشرطي الفعال.
ملاحظة حول
do-while: هناك أيضاً حلقةdo-while، والتي تشبهwhileلكنها تضمن تنفيذ كتلة التعليمات مرة واحدة على الأقل قبل التحقق من الشرط. صيغتها:do { // code } while (condition);
الكود النهائي الكامل
هذا الكود يجمع الأمثلة السابقة ليوضح كيف يمكن للحلقات التكرارية أن تعمل معاً في مشروع واحد. سيقوم الـ LED بالوميض 5 مرات عند البدء، ثم يبدأ في التلاشي صعوداً وهبوطاً باستمرار. بعد كل دورة تلاشي كاملة، ستتوقف الدائرة مؤقتًا في حلقة while حتى يكتمل عداد معين، محاكياً انتظار حدث ما قبل تكرار دورة التلاشي.
// تعريف منفذ الـ LED (يجب أن يكون منفذ PWM للمثال الثاني)
const int ledPin = 9; // استخدم منفذ PWM مثل 9 لتلاشي الإضاءة
// متغير للتحكم في حلقة while
int waitCounter = 0;
const int maxWaitCount = 3; // عدد مرات الانتظار في حلقة while
void setup() {
// تهيئة منفذ الـ LED كخرج
pinMode(ledPin, OUTPUT);
Serial.begin(9600); // تهيئة الاتصال التسلسلي
Serial.println("بدء تشغيل المتحكم: اختبار الوميض الأولي.");
// حلقة for للوميض الأولي (5 مرات)
for (int i = 0; i < 5; i++) {
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
delay(100);
}
Serial.println("انتهاء الوميض الأولي.");
delay(1000); // انتظار ثانية قبل بدء التلاشي
}
void loop() {
Serial.println("بدء دورة تلاشي جديدة.");
// حلقة for لزيادة إضاءة الـ LED تدريجياً (Fade In)
for (int brightness = 0; brightness <= 255; brightness++) {
analogWrite(ledPin, brightness);
delay(10);
}
// حلقة for لتقليل إضاءة الـ LED تدريجياً (Fade Out)
for (int brightness = 255; brightness >= 0; brightness--) {
analogWrite(ledPin, brightness);
delay(10);
}
Serial.println("انتهاء دورة التلاشي.");
// حلقة while للانتظار الشرطي
Serial.print("الدخول إلى حلقة الانتظار while... العداد: ");
Serial.println(waitCounter);
while (waitCounter < maxWaitCount) {
Serial.print("انتظار... العداد: ");
Serial.println(waitCounter);
digitalWrite(ledPin, HIGH); // إضاءة الـ LED للإشارة إلى حالة الانتظار
delay(500);
digitalWrite(ledPin, LOW);
delay(500);
waitCounter++; // زيادة العداد
}
Serial.println("الخروج من حلقة الانتظار while.");
waitCounter = 0; // إعادة تعيين العداد لدورة جديدة
delay(1000); // انتظار ثانية قبل بدء دورة تلاشي جديدة
}
النتيجة المتوقعة
عند تحميل الكود على لوحة الأردوينو:
- عند تشغيل المتحكم، سيومض الـ LED المتصل بالمنفذ 9 (أو 13 إذا لم يكن هناك منفذ PWM متاح) خمس مرات بسرعة.
- بعد الوميض الأولي، سيبدأ الـ LED المتصل بالمنفذ 9 في التلاشي تدريجياً من الإطفاء إلى أقصى سطوع، ثم يتلاشى مرة أخرى إلى الإطفاء. ستتكرر هذه العملية.
- بعد كل دورة تلاشي كاملة (صعوداً وهبوطاً)، سيومض الـ LED ثلاث مرات (بمعدل وميض واحد في الثانية) أثناء وجوده في "حلقة الانتظار" (
whileloop). - بعد انتهاء الومضات الثلاثة، ستتكرر دورة التلاشي والانتظار مرة أخرى إلى ما لا نهاية.
- ستظهر رسائل توضيحية على الشاشة التسلسلية (Serial Monitor) تشرح حالة المتحكم، مثل "بدء تشغيل المتحكم"، "بدء دورة تلاشي جديدة"، "الدخول إلى حلقة الانتظار while..."، وغيرها.