برنامه نویسی

آموزش حلقه for در Arduino

حلقه for یکی از پرکاربردترین ساختارهای برنامه نویسی در Arduino است و برای اجرای تکراری یک بخش از کد استفاده می شود. در این مستند با ساختار حلقه for، نحوه تعریف شمارنده، شرط ادامه حلقه و تغییر مقدار شمارنده آشنا می شویم و با استفاده از چند LED، یک مثال عملی از اجرای حلقه در جهت رفت و برگشت را بررسی می کنیم.

سطح مقدماتی

حلقه for چیست؟

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

برای مثال، فرض کنید 8 عدد LED به پایه های 6 تا 13 یک برد Arduino متصل شده اند و می خواهیم LEDها را یکی پس از دیگری روشن و خاموش کنیم.

می توانیم برای هر LED به صورت جداگانه کد بنویسیم، اما این روش باعث طولانی شدن برنامه می شود.

حلقه for به ما اجازه می دهد یک بخش از برنامه را چندین بار و بر اساس یک شرط مشخص اجرا کنیم.

ساختار کلی حلقه for به صورت زیر است:

for (مقداردهی اولیه; شرط; تغییر شمارنده) {
    // دستورهایی که باید تکرار شوند
}

سه بخش اصلی حلقه for عبارتند از: 1- مقداردهی اولیه 2- شرط ادامه حلقه 3- تغییر مقدار شمارنده

بخش اول: مقداردهی اولیه

در اولین قسمت حلقه for معمولا مقدار اولیه یک متغیر شمارنده مشخص می شود.

برای مثال:

for (index = 0; ...; ...) {
}

در اینجا متغیر index مقدار 0 می گیرد.

این متغیر مشخص می کند که در هر مرحله از حلقه با کدام عنصر یا کدام مرحله کار می کنیم.

بخش دوم: شرط ادامه حلقه

قسمت دوم مشخص می کند که حلقه تا چه زمانی باید ادامه پیدا کند.

برای مثال:

index < 8

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

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

بخش سوم: تغییر شمارنده

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

برای مثال:

index++

یعنی بعد از هر بار اجرای حلقه، مقدار index یک واحد افزایش پیدا کند.

بنابراین:

  • 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

مقادیر شمارنده در این مثال خواهند بود.

یک مثال ساده

فرض کنید می خواهیم یک LED را 5 بار روشن و خاموش کنیم.

کد زیر یک نمونه ساده از حلقه for است:

for (int i = 0; i < 5; i++) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);

    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
}

در این برنامه، حلقه از i = 0 شروع می شود.

تا زمانی که i < 5 باشد، دستورات داخل حلقه اجرا می شوند.

پس از هر بار اجرای دستورات، i یک واحد افزایش پیدا می کند.

در نتیجه حلقه در مجموع 5 بار اجرا می شود.

استفاده از for برای کنترل چند LED

یکی از کاربردهای بسیار مناسب حلقه for در Arduino، کنترل چند قطعه مشابه است.

فرض کنید 8 LED به پایه های زیر متصل شده اند:

  • 13
  • 12
  • 11
  • 10
  • 9
  • 8
  • 7
  • 6

به جای اینکه برای هر LED یک مجموعه دستور جداگانه بنویسیم، می توانیم پایه ها را داخل یک آرایه قرار دهیم:

 int ledPin[] = {13, 12, 11, 10, 9, 8, 7, 6};

در اینجا ledPin یک آرایه است که شماره پایه های LEDها را در خود نگه می دارد.

آرایه چیست؟

آرایه مجموعه ای از چند مقدار مشابه است که با یک نام مشخص نگهداری می شوند.

در مثال ما:

int ledPin[] = {13, 12, 11, 10, 9, 8, 7, 6};

داریم:

ledPin[0] = 13
ledPin[1] = 12
ledPin[2] = 11
ledPin[3] = 10
ledPin[4] = 9
ledPin[5] = 8
ledPin[6] = 7
ledPin[7] = 6

نکته مهم این است که شماره گذاری آرایه از 0 شروع می شود.

بنابراین آرایه 8 عضوی دارای اندیس های 0 تا 7 است.

استفاده از for برای تنظیم پایه ها

اکنون می توانیم به جای نوشتن 8 دستور pinMode، از یک حلقه for استفاده کنیم:

for (index=0; index<8; index++) {
    pinMode(ledPin[index], OUTPUT);
}

در اولین اجرای حلقه:

index = 0

بنابراین:

pinMode(ledPin[0], OUTPUT);

اجرا می شود.

از آنجا که:

ledPin[0] = 13

در واقع دستور زیر اجرا شده است:

pinMode(13, OUTPUT);

در اجرای بعدی:

index = 1

و دستور زیر اجرا می شود:

pinMode(ledPin[1], OUTPUT);

که معادل است با:

pinMode(12, OUTPUT);

این روند تا رسیدن index به 8 ادامه پیدا می کند.

وقتی index برابر 8 شود، شرط زیر دیگر برقرار نیست:

index < 8

بنابراین حلقه پایان پیدا می کند.

مثال کامل: حرکت LEDها از چپ به راست

در برنامه زیر LEDها یکی پس از دیگری روشن می شوند.

int ledPin[] = {13, 12, 11, 10, 9, 8, 7, 6};
int index = 0;

void setup() {
    for (index=0; index<8; index++) {
        pinMode(ledPin[index], OUTPUT);
    }
}

void loop() {

    for (index=0; index<8; index++) {
        digitalWrite(ledPin[index], HIGH);
        delay(100);

        digitalWrite(ledPin[index], LOW);
        delay(100);
    }
}

در این قسمت:

for (index=0; index<8; index++)

حلقه از LED شماره صفر شروع می شود و تا LED شماره 7 ادامه پیدا می کند.

به دلیل اینکه آرایه ما شامل 8 عضو است، آخرین اندیس آن 7 است.

حرکت LEDها در جهت معکوس

می توانیم همین کار را در جهت مخالف انجام دهیم.

برای این کار شمارنده را به جای افزایش، کاهش می دهیم:

for (index=7; index>=0; index--) {
    digitalWrite(ledPin[index], HIGH);
    delay(100);

    digitalWrite(ledPin[index], LOW);
    delay(100);
}

در این حالت مقادیر index به ترتیب زیر خواهند بود:

  • 7
  • 6
  • 5
  • 4
  • 3
  • 2
  • 1
  • 0

بنابراین LEDها از پایه 6 به سمت پایه 13 کنترل خواهند شد.

ترکیب حرکت رفت و برگشت

اکنون می توانیم دو حلقه را پشت سر هم قرار دهیم تا LEDها ابتدا در یک جهت و سپس در جهت مخالف حرکت کنند.

کد کامل:

int ledPin[] = {13, 12, 11, 10, 9, 8, 7, 6};
int index = 0;

void setup() {
    for (index=0; index<8; index++) {
        pinMode(ledPin[index], OUTPUT);
    }
}

void loop() {

    for (index=0; index<8; index++) {
        digitalWrite(ledPin[index], HIGH);
        delay(100);

        digitalWrite(ledPin[index], LOW);
        delay(100);
    }

    for (index=7; index>=0; index--) {
        digitalWrite(ledPin[index], HIGH);
        delay(100);

        digitalWrite(ledPin[index], LOW);
        delay(100);
    }
}

در نتیجه LEDها ابتدا از یک طرف به طرف دیگر حرکت می کنند:

13 → 12 → 11 → 10 → 9 → 8 → 7 → 6

و سپس در جهت مخالف حرکت می کنند:

6 → 7 → 8 → 9 → 10 → 11 → 12 → 13

چون این کد در تابع loop() قرار دارد، پس از پایان حرکت برگشتی، دوباره از ابتدا اجرا می شود.

بررسی دقیق حلقه اول

حلقه اول این است:

for (index=0; index<8; index++) {
    digitalWrite(ledPin[index], HIGH);
    delay(100);
    digitalWrite(ledPin[index], LOW);
    delay(100);
}

می توان مراحل آن را به صورت زیر نمایش داد:

مقدار indexLED مورد استفادهپایه Arduino
0ledPin[0]13
1ledPin[1]12
2ledPin[2]11
3ledPin[3]10
4ledPin[4]9
5ledPin[5]8
6ledPin[6]7
7ledPin[7]6

بنابراین یک حلقه کوتاه توانسته است هر 8 LED را کنترل کند.

بررسی دقیق حلقه دوم

حلقه دوم از مقدار 7 شروع می شود:

for (index=7; index>=0; index--) {
    digitalWrite(ledPin[index], HIGH);
    delay(100);
    digitalWrite(ledPin[index], LOW);
    delay(100);
}

در اینجا به جای:

index++

از:

index--

استفاده شده است.

علامت -- به معنی کاهش یک واحدی مقدار متغیر است.

بنابراین ترتیب حرکت به شکل زیر خواهد بود:

7 → 6 → 5 → 4 → 3 → 2 → 1 → 0

تفاوت ++ و --

دو عملگر بسیار پرکاربرد در حلقه های for عبارتند از:

index++

و:

index--

عملگر ++ مقدار متغیر را یک واحد افزایش می دهد.

عملگر -- مقدار متغیر را یک واحد کاهش می دهد.

برای مثال:

index++;

معادل افزایش یک واحدی است.

و:

index--;

معادل کاهش یک واحدی است.

چرا در حلقه اول از index < 8 استفاده شده است؟

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

آرایه ما 8 عضو دارد:

int ledPin[] = {13, 12, 11, 10, 9, 8, 7, 6};

اما آخرین اندیس آن 7 است.

بنابراین باید بنویسیم:

index < 8

و نه:

index <= 8

اگر از index <= 8 استفاده کنیم، در آخرین مرحله برنامه تلاش می کند به این عضو دسترسی پیدا کند:

ledPin[8]

در حالی که چنین عضوی در آرایه وجود ندارد.

کاربردهای حلقه for در پروژه های Arduino

حلقه for فقط برای کنترل LEDها استفاده نمی شود.

این ساختار در پروژه های مختلف کاربرد زیادی دارد.

برای مثال:

  • خواندن چند سنسور
  • کنترل چند LED
  • پیمایش آرایه ها
  • ارسال چند مقدار به Serial Monitor
  • کنترل چند رله یا MOSFET
  • پردازش داده های ذخیره شده در آرایه
  • ایجاد افکت های نوری
  • پیمایش پیکسل های یک نمایشگر
  • انجام محاسبات تکراری
  • جستجو در مجموعه ای از داده ها

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

for با متغیر تعریف شده داخل حلقه

در بسیاری از برنامه ها می توان متغیر شمارنده را مستقیما در حلقه تعریف کرد:

for (int i = 0; i < 8; i++) {
    Serial.println(i);
}

در این حالت متغیر i فقط در محدوده همین حلقه قابل استفاده است.

این روش معمولا باعث خواناتر شدن برنامه می شود.

در مثال این مستند از متغیر:

int index = 0;

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

جمع بندی

حلقه for یکی از مهم ترین ساختارهای برنامه نویسی در Arduino است.

این حلقه از سه بخش اصلی تشکیل می شود:

for (مقداردهی اولیه; شرط; تغییر شمارنده) {
    // دستورات
}

با استفاده از حلقه for می توان بدون تکرار دستی کد، یک عملیات را چندین بار اجرا کرد.

در مثال این مستند، یک آرایه شامل شماره پایه های 8 LED ایجاد کردیم و با استفاده از حلقه for ابتدا LEDها را از پایه 13 تا پایه 6 و سپس از پایه 6 تا پایه 13 کنترل کردیم.

ترکیب حلقه for با آرایه ها یکی از الگوهای بسیار کاربردی در برنامه نویسی Arduino است و در پروژه های بزرگ تر نیز به دفعات مورد استفاده قرار می گیرد.

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

کد نمونه :

int ledPin[] = {13, 12, 11, 10, 9, 8, 7, 6};
int index = 0;

void setup() {
    for (index=0; index<8; index++) {
        pinMode(ledPin[index], OUTPUT);
    }
}

void loop() {
    for (index=0; index<8; index++) {
        digitalWrite(ledPin[index], HIGH);
        delay(100);
        digitalWrite(ledPin[index], LOW);
        delay(100);
    }

    for (index=7; index>=0; index--) {
        digitalWrite(ledPin[index], HIGH);
        delay(100);
        digitalWrite(ledPin[index], LOW);
        delay(100);
    }
}