شرطها و حلقهها در آردوینو
تصمیمگیری و تکرار در C++ آردوینو؛ if و else، عملگرهای مقایسه و منطقی، switch، حلقههای for و while و do-while با یک پروژهٔ چراغ راهنما روی سه LED.
آنچه در این درس میآموزید
- با if و else و عملگرهای مقایسه و منطقی تصمیمگیری در کد را پیاده کنید
- انتخاب میان چند حالت مشخص را با switch انجام دهید و break را جا نیندازید
- حلقههای for و while و do-while را در جای درست بهکار ببرید
- یک توالی چراغ راهنما را با حلقه و شرط روی سه LED بسازید
فهرست مطالب
برنامههای تاکنون خطبهخط از بالا به پایین اجرا میشدند. برنامهٔ واقعی دو چیز بیشتر نمیخواهد: تصمیم (اگر چنین بود، آن کار را بکن) و تکرار (این کار را ده بار انجام بده). در این درس «دستور شرطی» (Conditional) و «حلقه» (Loop) را در زبان C++ یاد میگیرید و در پایان یک چراغ راهنمای سهرنگ با سه LED میسازید که توالیاش با حلقه و شرط نوشته شده است.
تصمیم با if و else
«دستور if» یک شرط میگیرد؛ اگر درست باشد، بلوک کد داخل آکولاد اجرا میشود:
if (count > 10) {
count = 0; // Reset the counter when it passes ten
}شرط با «عملگرهای مقایسه» (Comparison Operators) ساخته میشود:
| عملگر | معنی | مثال |
|---|---|---|
== |
برابر است با | x == 5 |
!= |
نابرابر است با | x != 0 |
< و > |
کوچکتر / بزرگتر | x < 100 |
<= و >= |
کوچکتر یا مساوی / بزرگتر یا مساوی | x >= 3 |
چند شرط را با «عملگرهای منطقی» (Logical Operators) ترکیب میکنید: && یعنی و (هر دو باید درست باشند)، || یعنی یا (دستکم یکی)، و ! یعنی نقیض. با else if و else هم زنجیرهٔ گزینهها میسازید:
if (temperature > 30) {
// Hot path
} else if (temperature > 15) {
// Mild path
} else {
// Cold path
}انتخاب چندگانه با switch
وقتی یک متغیر را با چند مقدار مشخص مقایسه میکنید، «دستور switch» از زنجیرهٔ بلند else if خواناتر است:
switch (mode) {
case 1:
// Fast mode
break;
case 2:
// Slow mode
break;
default:
// Unknown mode
break;
}هر case یک مقدار ممکن است و break اجرای switch را تمام میکند. بدون break، اجرا به case بعدی میریزد و همهٔ بلوکهای پایینی پشتسرهم اجرا میشوند — خطایی که کامپایلر نمیگیرد و فقط رفتار عجیب برنامه نشان میدهد. default هم جای حالتهای پیشبینینشده است.
تکرار با for و while و do-while
سه حلقه، یک هدف: تکرار. تفاوت در شرایط استفاده است:
- for — وقتی تعداد تکرار از قبل معلوم است. سرِ حلقه سه بخش دارد: مقدار اولیه، شرط ادامه و گام. مثلاً
for (int i = 1; i <= 5; i++)پنج بار اجرا میشود؛iاز ۱ شروع میشود، تا وقتی کوچکتر یا مساوی ۵ است ادامه مییابد و هر بار یکی زیاد میشود. دقت کنید حلقهٔi < 5با شروع از صفر هم پنج بار میزند؛ مرزِ شرط را همیشه دو بار چک کنید تا یکی کم یا زیاد نشود. - while — وقتی تعداد تکرار معلوم نیست و فقط شرط مهم است؛ شرط قبل از هر دور چک میشود و ممکن است اصلاً اجرا نشود.
- do-while — مثل while است، اما شرط بعد از هر دور چک میشود؛ پس دستکم یک بار حتماً اجرا میشود.
یک حالت خاص مهم است: while (true) یعنی حلقهٔ همیشگی. در برنامهٔ رایانهای این معمولاً باگ است، اما روی میکروکنترلر معنی دارد: دستگاه نباید خاموش شود و باید همیشه در حال پاسخدادن باشد. در واقع loop() در اسکچ آردوینو خودش همین حلقهٔ همیشگی است که پشتصحنه اجرا میشود؛ گاهی هم داخل کد از while (true) برای «ایست تا وقتی رویداد رخ دهد» استفاده میکنیم، مثل انتظار برای اتصال سنسور.
پروژه: چراغ راهنما با سه LED
ابزارهای مورد نیاز
| قطعه | مقدار / مشخصات | تعداد |
|---|---|---|
| برد آردوینو Uno | ATmega328P | ۱ |
| LED قرمز | ۵ میلیمتری | ۱ |
| LED زرد | ۵ میلیمتری | ۱ |
| LED سبز | ۵ میلیمتری | ۱ |
| مقاومت | ۲۲۰ اهم (هر LED یکی) | ۳ |
| برد سرهمبندی و سیم رابط | نری به نری | ۱ برد، حدود ۸ سیم |
هر LED مثل درس مدار خارجی به یک مقاومت ۲۲۰ اهم نیاز دارد؛ ولتاژ مستقیم هر سه رنگ حدود ۲ ولت است و با فرمول همان ۳۰۰ اهمِ حسابشده و انتخاب استاندارد ۲۲۰ اهم بهکار میآید.
سیمکشی، همان الگوی همیشگی:
| از | به |
|---|---|
| پین ۸ آردوینو | مقاومت ۲۲۰ اهم، سپس آند LED قرمز |
| پین ۹ آردوینو | مقاومت ۲۲۰ اهم، سپس آند LED زرد |
| پین ۱۰ آردوینو | مقاومت ۲۲۰ اهم، سپس آند LED سبز |
| کاتد هر سه LED | ریل زمین بردبورد |
| پین GND آردوینو | ریل زمین بردبورد |
اسکچ کامل:
const int RED_PIN = 8; // Red LED
const int YELLOW_PIN = 9; // Yellow LED
const int GREEN_PIN = 10; // Green LED
void setup() {
pinMode(RED_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
}
void loop() {
// Green phase: blink twice, then stay on longer
for (int i = 1; i <= 2; i++) {
digitalWrite(GREEN_PIN, HIGH);
if (i == 2) {
delay(1500); // The last flash stays on longer
} else {
delay(300);
}
digitalWrite(GREEN_PIN, LOW);
delay(300);
}
// Yellow phase: short warning
digitalWrite(YELLOW_PIN, HIGH);
delay(1000);
digitalWrite(YELLOW_PIN, LOW);
// Red phase: stop
digitalWrite(RED_PIN, HIGH);
delay(2500);
digitalWrite(RED_PIN, LOW);
}توضیح نکتههای کلیدی:
- سه ثابت با نام رنگ، شمارهٔ پینها را نگه میدارند؛ خواندن و تغییر کد را ساده میکند.
- حلقهٔ
for (int i = 1; i <= 2; i++)فاز سبز را دقیقاً دو بار تکرار میکند. - شرط
if (i == 2)در دور آخر حلقه، مدت روشنی را طولانیتر میکند؛ ترکیب حلقه و شرط در یک توالی واقعی. - دقت کنید
==مقایسه است، نه=؛ این دو را در بخش خطاها جدا میکنیم. - هر فاز با خاموشکردن LED خودش تمام میشود، پس در هر لحظه فقط یک رنگ روشن است.
نتیجهٔ فیزیکی: سبز دو بار کوتاه میزند و یکونیم ثانیه میماند، زرد یک ثانیه روشن میشود و بعد قرمز دوونیم ثانیه؛ سپس کل چرخه از اول. الگوی همان چراغهای خیابان، بهدست کد شما.
خطاهای رایج
سه خطای کلاسیک این درس:
=بهجای==— علامت=مقدار میدهد و==مقایسه میکند. شرطif (x = 5)همیشه درست از آب درمیآید، چون مقدار ۵ را درxمیریزد؛ متغیر شما بیسروصدا تغییر میکند و شرط بیمعنا میشود.- جا انداختن
breakدر switch — اجرا به caseهای بعدی میریزد و چند بلوک پشتسرهم اجرا میشوند؛ بدون هیچ پیام خطایی. - مرز حلقه (Off-by-one) —
for (int i = 0; i <= 5; i++)شش بار میزند، نه پنج بار؛ چون شرط شامل خود ۵ هم هست. تصمیم بگیرید شمارش از صفر است یا یک و شرط را با آن هماهنگ کنید.
اشتباهات رایج و عیبیابی
| خطا یا نشانه | علت رایج | راهحل |
|---|---|---|
| شرط همیشه درست به نظر میرسد و متغیر بیدلیل تغییر میکند | استفاده از = بهجای == داخل if |
مقایسه را با == بنویسید؛ بعضیها برای پیشگیری، عدد را سمت چپ میگذارند: if (2 == i) |
| چند حالتِ switch پشتسرهم اجرا میشوند | نبود break در انتهای هر case |
هر case را با break ببندید، مگر عمداً خواسته باشید سرریز شود |
| حلقه یک بار کم یا زیاد اجرا میشود | مرز اشتباه: <= بهجای < یا برعکس |
تعداد دقیق تکرار را با یک شمارنده در سریال مانیتور چاپ و شرط را اصلاح کنید |
| حلقه هیچوقت تمام نمیشود و بقیهٔ کد اجرا نمیشود | شرط حلقه هیچوقت غلط نمیشود (مثلاً متغیر داخل حلقه تغییر نمیکند) | مطمئن شوید متغیرِ شرط داخل حلقه بهروز میشود؛ i++ را حذف نکرده باشید |
| LEDها با هم روشن میشوند یا هیچکدام | خطای سیمکشی یا شمارهٔ پین نادرست | جدول سیمکشی را سطربهسطر چک کنید و شمارهٔ پینها را با ثابتهای کد تطبیق دهید |
تمرینها
تمرین
تمرین ۱ — فاز زرد دوم
در چراغ راهنمای واقعی پیش از سبزشدن، دوباره زرد روشن میشود. اسکچ را طوری تغییر دهید که پس از پایان فاز قرمز، LED زرد ۵۰۰ میلیثانیه روشن شود و بعد سبز بزند.
نمایش راهحل
فقط یک بلوک زرد دوم با زمانهای جدید، بین فاز قرمز و فاز سبز اضافه میشود؛ حلقهٔ سبز دست نمیخورد:
const int RED_PIN = 8;
const int YELLOW_PIN = 9;
const int GREEN_PIN = 10;
void setup() {
pinMode(RED_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
}
void loop() {
for (int i = 1; i <= 2; i++) {
digitalWrite(GREEN_PIN, HIGH);
if (i == 2) {
delay(1500);
} else {
delay(300);
}
digitalWrite(GREEN_PIN, LOW);
delay(300);
}
digitalWrite(YELLOW_PIN, HIGH);
delay(1000);
digitalWrite(YELLOW_PIN, LOW);
digitalWrite(RED_PIN, HIGH);
delay(2500);
digitalWrite(RED_PIN, LOW);
// Second yellow phase before green starts again
digitalWrite(YELLOW_PIN, HIGH);
delay(500);
digitalWrite(YELLOW_PIN, LOW);
}توالی تازه: سبز، زرد، قرمز، زردِ کوتاه، و بازگشت به سبز. چون loop() همیشه از اول اجرا میشود، چرخه بیپایان تکرار میشود.
:::
خلاصه
ifوelse ifوelseمسیر اجرا را بر پایهٔ شرط عوض میکنند؛ مقایسه با==است، نه=.&&و||و!شرطها را ترکیب میکنند وswitchانتخاب میان چند مقدار مشخص را خواناتر میکند؛ هر case بهbreakنیاز دارد.forبرای تعداد معلوم،whileبرای شرط-محور وdo-whileبرای اجرای دستکم یک بار؛ مرز حلقه را دوبار چک کنید.while (true)روی میکروکنترلر معنا دارد: دستگاه باید همیشه پاسخگو بماند؛loop()خودش همین حلقهٔ همیشگی است.- چراغ راهنمای شما ترکیب حلقه و شرط در یک پروژهٔ واقعی بود.
کد چراغ راهنما همهٔ منطقش در loop() بود و تکرار داشت؛ در درس بعدی یاد میگیرید چنین بخشهایی را به توابع منتقل کنید تا کد کوتاهتر، تمیزتر و قابلاستفادهتر شود.