برنامه نویسی

آموزش شرط ها در آردوینو

دستورهای شرطی یکی از بخش های اصلی برنامه نویسی آردوینو هستند و به برنامه اجازه می دهند بر اساس وضعیت ورودی ها، مقادیر سنسورها یا نتیجه یک مقایسه، تصمیم گیری کند. در این آموزش با شرط های if، if...else، else if، شرط های تو در تو، عملگرهای مقایسه ای و منطقی، دستور switch...case و عملگر شرطی آشنا می شوید. برای هر ساختار، مثال های کاربردی از پروژه های Arduino ارائه شده است.

سطح مقدماتی

شرط در آردوینو چیست؟

در برنامه نویسی آردوینو، همیشه نمی خواهیم دستورات به یک ترتیب ثابت اجرا شوند. گاهی لازم است برنامه بر اساس یک وضعیت مشخص تصمیم بگیرد و فقط در صورت برقرار بودن یک شرط، دستور خاصی را اجرا کند.

برای مثال:

  • اگر دمای سنسور از 30 درجه بیشتر شد، فن روشن شود.
  • اگر دکمه فشرده شد، LED روشن شود.
  • اگر ولتاژ باتری کاهش پیدا کرد، هشدار نمایش داده شود.
  • اگر فاصله جسم از سنسور کمتر از مقدار مشخصی شد، موتور متوقف شود.
  • اگر رمز وارد شده صحیح بود، قفل باز شود.

برای پیاده سازی چنین رفتارهایی از دستورهای شرطی استفاده می کنیم.

در این مستند با مهم ترین ساختارهای شرطی در Arduino آشنا می شویم و برای هر کدام مثال عملی ارائه می دهیم.

1. شرط if

ساده ترین دستور شرطی در آردوینو، if است.

این دستور یک شرط را بررسی می کند. اگر نتیجه شرط درست باشد، دستورهای داخل بلوک اجرا می شوند. اگر شرط برقرار نباشد، آن دستورات اجرا نمی شوند.

ساختار کلی:

if (condition) {
    // دستورهایی که در صورت درست بودن شرط اجرا می شوند
}

برای مثال، فرض کنید یک LED به پایه 13 متصل شده است و می خواهیم در صورت درست بودن یک شرط، آن را روشن کنیم.

int ledPin = 13;
int temperature = 35;

void setup() {
    pinMode(ledPin, OUTPUT);

    if (temperature > 30) {
        digitalWrite(ledPin, HIGH);
    }
}

void loop() {
}

در این برنامه مقدار temperature برابر 35 است. چون 35 از 30 بزرگ تر است، شرط برقرار می شود و LED روشن خواهد شد.

اگر مقدار دما 25 بود، شرط برقرار نمی شد و دستور روشن کردن LED اجرا نمی شد.

نکته: چون این بررسی در تابع setup() قرار دارد، فقط یک بار هنگام راه اندازی برد انجام می شود.

2. شرط if...else

گاهی لازم است برای هر دو حالت درست و نادرست بودن یک شرط، دستور مشخصی اجرا شود.

در چنین شرایطی از if...else استفاده می کنیم.

ساختار کلی:

if (condition) {
    // در صورت درست بودن شرط
} else {
    // در صورت نادرست بودن شرط
}

مثال: روشن کردن LED در صورت فشرده شدن دکمه و خاموش کردن آن در غیر این صورت.

const int buttonPin = 2;
const int ledPin = 13;

void setup() {
    pinMode(buttonPin, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);
}

void loop() {
    int buttonState = digitalRead(buttonPin);

    if (buttonState == LOW) {
        digitalWrite(ledPin, HIGH);
    } else {
        digitalWrite(ledPin, LOW);
    }
}

در این مثال از INPUT_PULLUP استفاده شده است. در این حالت، وقتی دکمه به پایه GND متصل و فشرده شود، مقدار خوانده شده LOW خواهد بود.

بنابراین:

  • اگر دکمه فشرده شود، LED روشن می شود.
  • اگر دکمه رها شود، LED خاموش می شود.

3. شرط else if

گاهی یک متغیر می تواند چند وضعیت مختلف داشته باشد و لازم است برای هر وضعیت، رفتار متفاوتی تعریف کنیم.

برای این کار از else if استفاده می کنیم.

ساختار کلی:

if (condition1) {
    // دستورهای حالت اول
} else if (condition2) {
    // دستورهای حالت دوم
} else if (condition3) {
    // دستورهای حالت سوم
} else {
    // در صورت برقرار نبودن هیچ کدام از شرط ها
}

مثال: تعیین وضعیت دما.

int temperature = 28;

void setup() {
    Serial.begin(9600);

    if (temperature < 15) {
        Serial.println("Cold");
    } else if (temperature < 25) {
        Serial.println("Normal");
    } else if (temperature < 35) {
        Serial.println("Warm");
    } else {
        Serial.println("Hot");
    }
}

void loop() {
}

با مقدار 28، پیام Warm نمایش داده می شود.

برنامه شرط ها را از بالا به پایین بررسی می کند و پس از پیدا کردن اولین شرط درست، بلوک مربوط به آن را اجرا می کند و از ادامه زنجیره شرط ها عبور می کند.

به همین دلیل، ترتیب شرط ها اهمیت دارد.

4. عملگرهای مقایسه ای

برای ساختن شرط ها، معمولا از عملگرهای مقایسه ای استفاده می کنیم.

عملگرمعنیمثال
==برابر است باx == 10
!=برابر نیست باx != 10
>بزرگ تر ازx > 10
<کوچک تر ازx < 10
>=بزرگ تر یا مساویx >= 10
<=کوچک تر یا مساویx <= 10

برای مثال:

int batteryVoltage = 3300;

if (batteryVoltage < 3500) {
    Serial.println("Battery is low");
}

در این مثال فرض شده است مقدار ولتاژ باتری بر حسب میلی ولت در متغیر ذخیره شده است. اگر مقدار کمتر از 3500 باشد، پیام هشدار نمایش داده می شود.

تفاوت == و =

یکی از خطاهای رایج در برنامه نویسی، اشتباه گرفتن عملگر مقایسه == با عملگر انتساب = است.

عملگر = برای اختصاص دادن مقدار به متغیر استفاده می شود:

x = 10;

اما عملگر == بررسی می کند که آیا دو مقدار برابر هستند یا خیر:

if (x == 10) {
    // ...
}

این دو عملگر کاربرد متفاوتی دارند و نباید با یکدیگر اشتباه گرفته شوند.

5. استفاده از عملگر منطقی AND

عملگر && به معنی «و» است.

زمانی که می خواهیم چند شرط هم زمان برقرار باشند، از این عملگر استفاده می کنیم.

ساختار:

if (condition1 && condition2) {
    // هر دو شرط باید درست باشند
}

مثال: روشن شدن LED فقط زمانی که دما در محدوده مشخصی باشد.

int temperature = 28;
const int ledPin = 13;

void setup() {
    pinMode(ledPin, OUTPUT);

    if (temperature >= 20 && temperature <= 30) {
        digitalWrite(ledPin, HIGH);
    } else {
        digitalWrite(ledPin, LOW);
    }
}

void loop() {
}

در این برنامه LED فقط زمانی روشن می شود که دما بین 20 تا 30 درجه، با احتساب دو حد، باشد.

اگر دما کمتر از 20 یا بیشتر از 30 باشد، LED خاموش می شود.

6. استفاده از عملگر منطقی OR

عملگر || به معنی «یا» است.

اگر حداقل یکی از شرط ها درست باشد، نتیجه عبارت منطقی درست خواهد بود.

مثال:

int temperature = 38;
int humidity = 80;

void setup() {
    Serial.begin(9600);

    if (temperature > 35 || humidity > 75) {
        Serial.println("Warning!");
    }
}

void loop() {
}

در این مثال اگر دما از 35 درجه بیشتر باشد یا رطوبت از 75 درصد بیشتر شود، پیام هشدار نمایش داده می شود.

در عملگر || لازم نیست هر دو شرط درست باشند؛ درست بودن یکی از آنها کافی است.

7. استفاده از عملگر منطقی NOT

عملگر ! نتیجه منطقی یک عبارت را معکوس می کند.

برای مثال:

bool doorOpen = false;

void setup() {
    Serial.begin(9600);

    if (!doorOpen) {
        Serial.println("Door is closed");
    }
}

void loop() {
}

چون مقدار doorOpen برابر false است، عبارت !doorOpen درست خواهد بود و پیام نمایش داده می شود.

این عملگر زمانی کاربرد دارد که بخواهیم برقرار نبودن یک وضعیت را بررسی کنیم.

8. ترکیب چند شرط

می توان از چند عملگر منطقی در یک عبارت شرطی استفاده کرد.

مثال: روشن شدن هشدار در صورت پایین بودن ولتاژ باتری و فعال بودن دستگاه.

float batteryVoltage = 3.2;
bool deviceActive = true;

void setup() {
    Serial.begin(9600);

    if (batteryVoltage < 3.4 && deviceActive) {
        Serial.println("Low battery warning");
    }
}

void loop() {
}

در این مثال، هر دو شرط باید درست باشند:

  • ولتاژ باتری کمتر از 3.4 ولت باشد.
  • دستگاه فعال باشد.

اگر یکی از این دو شرط برقرار نباشد، پیام هشدار نمایش داده نمی شود.

برای جلوگیری از ابهام در عبارت های پیچیده، بهتر است از پرانتز استفاده کنیم:

if ((temperature > 30 && humidity > 70) || emergencyMode) {
    // اجرای دستورها
}

در این مثال، شرط زمانی درست است که دما و رطوبت هر دو از حدود مشخص شده بیشتر باشند، یا حالت اضطراری فعال باشد.

9. شرط های تو در تو

گاهی لازم است پس از برقرار شدن یک شرط، شرط دیگری نیز بررسی شود. در این حالت می توان یک دستور if را داخل دستور if دیگر قرار داد.

مثال:

int temperature = 35;
bool fanEnabled = true;

void setup() {
    Serial.begin(9600);

    if (fanEnabled) {
        if (temperature > 30) {
            Serial.println("Fan ON");
        } else {
            Serial.println("Temperature is normal");
        }
    } else {
        Serial.println("Fan control is disabled");
    }
}

void loop() {
}

در این برنامه ابتدا بررسی می شود که کنترل فن فعال باشد. اگر این شرط برقرار بود، دما بررسی می شود.

اگر کنترل فن غیرفعال باشد، شرط دما بررسی نخواهد شد.

شرط های تو در تو برای کنترل فرایندهای چندمرحله ای مفید هستند، اما استفاده بیش از حد از آنها می تواند خوانایی برنامه را کاهش دهد.

10. دستور switch...case

ساختار switch...case زمانی کاربرد دارد که یک متغیر می تواند یکی از چند مقدار مشخص را داشته باشد و برای هر مقدار، دستور متفاوتی اجرا شود.

ساختار کلی:

switch (value) {
    case 1:
        // دستورهای حالت اول
        break;

    case 2:
        // دستورهای حالت دوم
        break;

    default:
        // در صورت تطبیق نداشتن با هیچ حالت
        break;
}

مثال: انتخاب حالت کاری دستگاه.

int mode = 2;

void setup() {
    Serial.begin(9600);

    switch (mode) {
        case 1:
            Serial.println("Mode: Manual");
            break;

        case 2:
            Serial.println("Mode: Automatic");
            break;

        case 3:
            Serial.println("Mode: Sleep");
            break;

        default:
            Serial.println("Unknown mode");
            break;
    }
}

void loop() {
}

چون مقدار mode برابر 2 است، پیام Mode: Automatic نمایش داده می شود.

چرا از break استفاده می کنیم؟

دستور break باعث می شود اجرای ساختار switch پس از اجرای حالت انتخاب شده پایان پیدا کند.

اگر break را حذف کنیم، ممکن است اجرای برنامه به حالت های بعدی نیز ادامه پیدا کند. این رفتار در بعضی برنامه ها عمدی است، اما اگر به آن توجه نکنیم می تواند باعث خطا شود.

بخش default نیز زمانی اجرا می شود که هیچ کدام از حالت های تعریف شده با مقدار متغیر تطبیق نداشته باشند.

11. عملگر شرطی سه تایی

در Arduino می توان از عملگر شرطی ?: برای نوشتن شرط های ساده در یک خط استفاده کرد.

ساختار کلی:

condition ? valueIfTrue : valueIfFalse;

مثال:

int temperature = 32;

void setup() {
    Serial.begin(9600);

    String status = (temperature > 30) ? "Hot" : "Normal";

    Serial.println(status);
}

void loop() {
}

اگر دما بیشتر از 30 باشد، مقدار Hot و در غیر این صورت مقدار Normal در متغیر status قرار می گیرد.

این عملگر برای انتخاب بین دو مقدار ساده مفید است. برای شرط های پیچیده، استفاده از if...else معمولا خواناتر است.

12. مثال کاربردی: کنترل LED با سنسور آنالوگ

فرض کنیم یک سنسور آنالوگ به پایه A0 متصل شده است و می خواهیم اگر مقدار خوانده شده از 500 بیشتر شد، LED روشن شود.

const int sensorPin = A0;
const int ledPin = 13;

void setup() {
    pinMode(ledPin, OUTPUT);
    Serial.begin(9600);
}

void loop() {
    int sensorValue = analogRead(sensorPin);

    Serial.println(sensorValue);

    if (sensorValue > 500) {
        digitalWrite(ledPin, HIGH);
    } else {
        digitalWrite(ledPin, LOW);
    }

    delay(100);
}

در این مثال:

  1. مقدار سنسور با analogRead() خوانده می شود.
  2. مقدار خوانده شده در Serial Monitor نمایش داده می شود.
  3. اگر مقدار بیشتر از 500 باشد، LED روشن می شود.
  4. در غیر این صورت، LED خاموش می شود.
  5. برنامه پس از یک مکث کوتاه، این مراحل را دوباره اجرا می کند.

مقدار 500 یک آستانه نمونه است و باید متناسب با سنسور و کاربرد واقعی انتخاب شود.

13. مثال کاربردی: هشدار کاهش ولتاژ باتری

یکی از کاربردهای مهم شرط ها در پروژه های باتری محور، بررسی ولتاژ باتری و نمایش هشدار هنگام کاهش ولتاژ است.

فرض کنیم ولتاژ باتری قبلا از طریق مدار تقسیم ولتاژ به ورودی ADC منتقل شده و مقدار آن با روش مناسب محاسبه شده است.

float batteryVoltage = 3.3;
const float lowBatteryLimit = 3.5;

void setup() {
    Serial.begin(9600);
}

void loop() {
    if (batteryVoltage < lowBatteryLimit) {
        Serial.println("Warning: Low battery!");
    } else {
        Serial.println("Battery voltage is OK");
    }

    delay(1000);
}

این مثال برای توضیح ساختار شرطی است. در یک پروژه واقعی باید ولتاژ باتری در هر دور از حلقه از ورودی ADC خوانده و محاسبه شود، نه اینکه مقدار آن فقط یک بار به صورت ثابت تعریف شود.

همچنین حد مجاز ولتاژ به نوع باتری و مشخصات آن وابسته است. برای باتری های لیتیومی، حد قطع ایمن باید بر اساس دیتاشیت باتری و مدار مدیریت آن انتخاب شود.

14. تفاوت if و switch

هر دو ساختار برای تصمیم گیری استفاده می شوند، اما کاربرد آنها یکسان نیست.

ویژگیif...elseswitch...case
بررسی شرط های مقایسه ایمناسببه طور مستقیم مناسب نیست
بررسی بازه عددیمناسبمناسب نیست
بررسی چند مقدار مشخصمناسببسیار مناسب
ترکیب شرط های منطقیمناسبمحدودتر
خوانایی در انتخاب حالت های متعددبسته به ساختارمعمولا بهتر

برای مثال، اگر بخواهیم بررسی کنیم دما کمتر از 20 یا بیشتر از 30 است، if انتخاب مناسبی است.

اما اگر متغیر mode فقط می تواند مقادیر 1، 2، 3 یا 4 را داشته باشد و هر مقدار نشان دهنده یک حالت کاری است، switch...case می تواند برنامه را خواناتر کند.

15. اشتباهات رایج در نوشتن شرط ها

هنگام استفاده از شرط ها در Arduino باید به چند نکته توجه کنیم.

اشتباه اول: استفاده از = به جای ==

کد نادرست برای مقایسه:

if (x = 10) {
    // ...
}

در این کد، مقدار 10 به متغیر x اختصاص داده می شود؛ این عبارت مقایسه برابری نیست.

روش درست:

if (x == 10) {
    // ...
}

اشتباه دوم: فراموش کردن آکولادها

برای خوانایی بهتر، مخصوصا در شرط هایی که چند دستور دارند، از آکولاد استفاده کنید.

if (temperature > 30) {
    digitalWrite(ledPin, HIGH);
    Serial.println("High temperature");
}

اشتباه سوم: استفاده نادرست از AND و OR

اگر می خواهیم هر دو شرط برقرار باشند، از && استفاده می کنیم.

اگر برقرار بودن حداقل یکی از شرط ها کافی باشد، از || استفاده می کنیم.

اشتباه چهارم: بررسی مقدار اشتباه ورودی

در بعضی مدارها مانند ورودی های دارای INPUT_PULLUP، فشرده شدن دکمه مقدار LOW ایجاد می کند، نه HIGH. همیشه باید نحوه اتصال قطعه و وضعیت منطقی ورودی را بررسی کنیم.

اشتباه پنجم: انتخاب آستانه نامناسب

در مثال های سنسورها و باتری، مقدار آستانه باید متناسب با قطعه و کاربرد واقعی انتخاب شود. اعداد مثال های آموزشی لزوما برای تمام پروژه ها مناسب نیستند.

جمع بندی

دستورهای شرطی به برنامه های Arduino امکان می دهند بر اساس وضعیت ورودی ها و مقادیر محاسبه شده تصمیم گیری کنند.

مهم ترین ساختارهای شرطی عبارت اند از:

  • if: اجرای دستورها در صورت درست بودن شرط
  • if...else: انتخاب بین دو مسیر
  • else if: بررسی چند حالت مختلف
  • &&: برقرار بودن هم زمان چند شرط
  • ||: برقرار بودن حداقل یکی از شرط ها
  • !: معکوس کردن نتیجه منطقی
  • switch...case: انتخاب بین چند مقدار مشخص
  • ?:: انتخاب یکی از دو مقدار با یک شرط ساده

در پروژه های واقعی، شرط ها در کنار ورودی های دیجیتال و آنالوگ، سنسورها، تایمرها و سایر بخش های برنامه به کار می روند.

با تسلط بر این ساختارها می توانید برنامه هایی بنویسید که به جای اجرای دستورات ثابت، به شرایط محیط واکنش نشان دهند و رفتار هوشمندانه تری داشته باشند.

نمونه کد :

const int sensorPin = A0;
const int ledPin = 13;

void setup() {
    pinMode(ledPin, OUTPUT);
    Serial.begin(9600);
}

void loop() {
    int sensorValue = analogRead(sensorPin);

    if (sensorValue > 500) {
        digitalWrite(ledPin, HIGH);
        Serial.println("Threshold exceeded");
    } else {
        digitalWrite(ledPin, LOW);
        Serial.println("Value is normal");
    }

    delay(100);
}

منبع و فایل های پروژه ↗