آموزش آردوینو

آموزش Serial Monitor و عیب یابی مقدماتی (Debugging) در آردوینو

در این مستند با ابزار Serial Monitor در محیط Arduino IDE و کاربرد آن برای مشاهده اطلاعات، بررسی عملکرد برنامه و عیب یابی اولیه آردوینو آشنا می شوید. روش راه اندازی ارتباط سریال با Serial.begin()، نمایش متن و متغیرها با Serial.print() و Serial.println()، دریافت اطلاعات از کاربر و استفاده از پیام های Debug برای پیدا کردن خطاهای رایج را با مثال های عملی یاد می گیرید.

سطح مقدماتی

آموزش Serial Monitor و عیب یابی مقدماتی (Debugging) در آردوینو

مقدمه

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

برای مثال، ممکن است یک سنسور مقدار اشتباهی گزارش کند، کلید به درستی تشخیص داده نشود یا برنامه وارد بخشی از کد شود که انتظار آن را نداریم.

یکی از ساده ترین ابزارها برای بررسی چنین مشکلاتی، Serial Monitor در محیط Arduino IDE است. این ابزار به ما اجازه می دهد اطلاعاتی را از برد دریافت کنیم و در بعضی پروژه ها، فرمان یا داده ای را نیز از رایانه به آردوینو بفرستیم.

فرایند بررسی رفتار برنامه برای پیدا کردن و رفع خطاها را Debugging یا عیب یابی نرم افزاری می نامند.

در این آموزش با روش استفاده از Serial Monitor و تکنیک های مقدماتی Debugging آشنا می شویم.

۱. Serial Monitor چیست؟

Serial Monitor ابزاری در Arduino IDE است که اطلاعات ارسال شده از طریق ارتباط سریال را نمایش می دهد.

با کمک این ابزار می توانیم:

  • مقدار متغیرها را مشاهده کنیم.
  • خروجی سنسورها را بررسی کنیم.
  • از اجرای بخش های مختلف برنامه مطلع شویم.
  • وضعیت کلیدها و ورودی ها را کنترل کنیم.
  • خطاهای منطقی برنامه را پیدا کنیم.
  • از رایانه به برد فرمان یا داده بفرستیم.

برای استفاده از Serial Monitor، برد باید از یک رابط ارتباط سریال پشتیبانی کند و ارتباط آن به درستی راه اندازی شده باشد.

در بسیاری از بردهای آردوینو، ارتباط با رایانه از طریق USB انجام می شود؛ اما مسیر ارتباطی دقیق به مدل برد و نوع رابط USB آن بستگی دارد.

۲. راه اندازی ارتباط سریال

برای شروع ارتباط سریال در برنامه آردوینو از تابع زیر استفاده می کنیم:

Serial.begin(9600);

عدد 9600 نرخ انتقال اطلاعات یا Baud Rate را مشخص می کند.

مقدار ۹۶۰۰ برای بسیاری از مثال های آموزشی مناسب است. در پروژه های دیگر ممکن است از نرخ هایی مانند 115200 استفاده شود.

مهم است که نرخ ارتباط انتخاب شده در برنامه با نرخ تنظیم شده در Serial Monitor یکسان باشد.

مثال ساده

void setup() {
  Serial.begin(9600);
  Serial.println("Arduino is ready");
}

void loop() {
}

پس از بارگذاری برنامه و باز کردن Serial Monitor، باید پیام زیر را مشاهده کنید:

Arduino is ready

این پیام پس از راه اندازی برنامه ارسال می شود. در صورت ریست شدن برد، ممکن است دوباره نمایش داده شود.

۳. باز کردن Serial Monitor

برای مشاهده اطلاعات ارسالی از آردوینو:

  1. برد را با کابل مناسب به رایانه متصل کنید.
  2. در Arduino IDE، برد و درگاه ارتباطی صحیح را انتخاب کنید.
  3. برنامه را روی برد بارگذاری کنید.
  4. Serial Monitor را از منوی Tools باز کنید یا از آیکون مربوط به آن استفاده کنید.
  5. نرخ ارتباط را با مقدار استفاده شده در Serial.begin() هماهنگ کنید.

در Arduino IDE نسخه ۲، Serial Monitor معمولا از بخش بالایی محیط یا منوی Tools قابل دسترسی است. در نسخه های قدیمی تر، محل این ابزار ممکن است متفاوت باشد.

نکته: در بعضی بردها، باز شدن درگاه سریال یا بارگذاری برنامه می تواند باعث ریست شدن برد شود. بنابراین اگر پیام ابتدایی دوباره ظاهر شد، لزوما به معنی اجرای چندباره غیرمنتظره کد نیست.

۴. تفاوت Serial.print و Serial.println

برای ارسال اطلاعات به Serial Monitor، دو تابع بسیار پرکاربرد وجود دارد.

تابع Serial.print()

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

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

  Serial.print("Temperature: ");
  Serial.print(25);
}

void loop() {
}

خروجی:

Temperature: 25

اگر چند دستور Serial.print() پشت سر هم اجرا شوند، خروجی آنها معمولا در یک خط کنار هم قرار می گیرد.

تابع Serial.println()

این تابع پس از ارسال اطلاعات، خط جدید ایجاد می کند.

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

  Serial.println("Arduino");
  Serial.println("Serial Monitor");
}

void loop() {
}

خروجی:

Arduino
Serial Monitor

مقایسه دو تابع

تابعکاربرد
Serial.print()ارسال اطلاعات بدون رفتن خودکار به خط بعد
Serial.println()ارسال اطلاعات و سپس رفتن به خط بعد

هر دو تابع می توانند برای نمایش متن، عدد و مقدار متغیرها استفاده شوند.

۵. نمایش مقدار متغیرها

یکی از کاربردهای مهم Serial Monitor، بررسی مقدار متغیرها هنگام اجرای برنامه است.

فرض کنید می خواهیم مقدار یک ورودی آنالوگ را بخوانیم:

const int sensorPin = A0;

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

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

  Serial.println(sensorValue);

  delay(500);
}

در این برنامه، مقدار خوانده شده از پایه A0 هر نیم ثانیه نمایش داده می شود.

در برد Arduino Uno کلاسیک، خروجی analogRead() با ADC ده بیتی معمولا عددی بین ۰ تا ۱۰۲۳ است.

اگر ورودی به درستی سیم کشی نشده باشد، مقدار نمایش داده شده ممکن است ثابت، متغیر یا غیرمنتظره باشد. این موضوع به نوع مدار ورودی و وضعیت پایه نیز بستگی دارد.

نمایش نام و مقدار متغیر

برای خواناتر شدن اطلاعات می توانیم نام متغیر را نیز نمایش دهیم:

const int sensorPin = A0;

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

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

  Serial.print("Sensor value: ");
  Serial.println(sensorValue);

  delay(500);
}

خروجی نمونه:

Sensor value: 512
Sensor value: 509
Sensor value: 514

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

۶. نمایش چند مقدار در یک خط

گاهی لازم است چند متغیر را هم زمان بررسی کنیم؛ برای مثال، مقدار خام سنسور و ولتاژ محاسبه شده از آن.

const int sensorPin = A0;

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

void loop() {
  int sensorValue = analogRead(sensorPin);
  float voltage = sensorValue * (5.0 / 1023.0);

  Serial.print("ADC: ");
  Serial.print(sensorValue);

  Serial.print(" | Voltage: ");
  Serial.print(voltage, 2);

  Serial.println(" V");

  delay(500);
}

خروجی نمونه:

ADC: 512 | Voltage: 2.50 V

در این مثال:

  • Serial.print(sensorValue) مقدار خام ADC را نمایش می دهد.
  • Serial.print(voltage, 2) عدد اعشاری را با دو رقم بعد از ممیز نمایش می دهد.
  • Serial.println(" V") واحد ولتاژ را اضافه می کند و به خط بعد می رود.

محاسبه ولتاژ در این مثال فرض می کند مرجع ADC برابر ۵ ولت است. برای بردها یا تنظیمات دارای مرجع متفاوت، فرمول باید متناسب با همان شرایط تغییر کند.

۷. Debugging چیست؟

Debugging فرایند بررسی و پیدا کردن علت رفتار نادرست یک برنامه است.

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

خطای کامپایل

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

نمونه علت ها:

  • فراموش کردن نقطه ویرگول
  • اشتباه نوشتن نام تابع
  • استفاده نادرست از متغیر
  • ناقص بودن آکولادها

این خطاها معمولا هنگام Verify یا Compile در Arduino IDE گزارش می شوند.

خطای زمان اجرا یا رفتار غیرمنتظره

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

برای مثال:

  • LED روشن نمی شود.
  • مقدار سنسور همیشه صفر است.
  • شرط برنامه به اشتباه اجرا می شود.
  • ارتباط با ماژول برقرار نمی شود.

Serial Monitor می تواند به بررسی این مشکلات کمک کند؛ اما همه خطاهای سخت افزاری یا زمان اجرا را به تنهایی تشخیص نمی دهد.

خطای سخت افزاری

گاهی مشکل از سیم کشی، تغذیه، قطعه معیوب یا ناسازگاری ولتاژ است.

برای مثال، اگر سنسور به پایه اشتباهی وصل شده باشد، حتی کد صحیح هم نمی تواند نتیجه مورد انتظار را ایجاد کند.

در این شرایط باید اطلاعات Serial Monitor را در کنار بررسی سیم کشی، ولتاژ و مشخصات قطعات ارزیابی کنیم.

۸. استفاده از پیام های Debug

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

مثال

const int ledPin = 8;

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

  Serial.println("Step 1: Starting setup");

  pinMode(ledPin, OUTPUT);

  Serial.println("Step 2: Pin configured");
}

void loop() {
  Serial.println("Step 3: Loop started");

  digitalWrite(ledPin, HIGH);
  delay(1000);

  digitalWrite(ledPin, LOW);
  delay(1000);
}

خروجی نمونه:

Step 1: Starting setup
Step 2: Pin configured
Step 3: Loop started
Step 3: Loop started
Step 3: Loop started

با مشاهده این پیام ها می توان فهمید کدام بخش های برنامه اجرا شده اند.

در این مثال، پیام های داخل setup() فقط در هر بار راه اندازی برنامه یک بار ارسال می شوند؛ اما پیام داخل loop() به طور پیوسته تکرار می شود.

نکته: برای جلوگیری از تولید خروجی بیش از حد، پیام های Debug را فقط در نقاط مورد نیاز قرار دهید.

۹. بررسی شرط ها با Serial Monitor

گاهی برنامه کامپایل می شود، اما یک شرط به شکلی اجرا می شود که انتظار نداریم.

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

مثال: بررسی یک ورودی دیجیتال

const int buttonPin = 2;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(9600);
}

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

  Serial.print("Button state: ");
  Serial.println(buttonState);

  if (buttonState == LOW) {
    Serial.println("Button pressed");
  }

  delay(300);
}

در این مثال، کلید بین پایه ۲ و GND متصل می شود.

به دلیل استفاده از INPUT_PULLUP:

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

اگر برنامه همیشه یک مقدار نشان دهد، باید وضعیت سیم کشی، اتصال GND و عملکرد کلید بررسی شود.

۱۰. دریافت اطلاعات از Serial Monitor

Serial Monitor فقط برای مشاهده اطلاعات نیست؛ در بسیاری از پروژه ها می توان از آن برای ارسال داده به آردوینو نیز استفاده کرد.

تابع Serial.available() تعداد بایت های دریافت شده و آماده خواندن را گزارش می کند. تابع Serial.read() یک بایت از داده های دریافتی را می خواند.

مثال: روشن و خاموش کردن LED با فرمان متنی

در این مثال، با ارسال حرف 1، LED روشن و با ارسال حرف 0، LED خاموش می شود.

const int ledPin = 8;

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

  Serial.begin(9600);
  Serial.println("Send 1 to turn ON");
  Serial.println("Send 0 to turn OFF");
}

void loop() {
  if (Serial.available() > 0) {
    char command = Serial.read();

    if (command == '1') {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED ON");
    }
    else if (command == '0') {
      digitalWrite(ledPin, LOW);
      Serial.println("LED OFF");
    }
  }
}

برای آزمایش:

  1. برنامه را روی برد بارگذاری کنید.
  2. Serial Monitor را باز کنید.
  3. نرخ ارتباط را روی ۹۶۰۰ قرار دهید.
  4. حرف 1 را ارسال کنید.
  5. سپس حرف 0 را ارسال کنید.

نکته: در تنظیمات ارسال، بهتر است گزینه پایان خط روی حالت بدون پایان خط قرار بگیرد. اگر گزینه Newline یا Both NL & CR انتخاب شده باشد، ممکن است کاراکترهای اضافی نیز ارسال شوند. برنامه بالا این کاراکترها را نادیده می گیرد.

۱۱. اشکال یابی ارتباط سریال

اگر اطلاعات مورد انتظار را در Serial Monitor نمی بینید، موارد زیر را بررسی کنید.

نرخ ارتباط یکسان نیست

اگر برنامه از Serial.begin(9600) استفاده می کند، نرخ Serial Monitor را نیز روی ۹۶۰۰ قرار دهید.

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

درگاه اشتباه انتخاب شده است

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

ارتباط سریال راه اندازی نشده است

مطمئن شوید Serial.begin() در تابع setup() اجرا می شود.

کابل USB مناسب نیست

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

پیام ها بسیار سریع ارسال می شوند

اگر درون loop() تعداد زیادی پیام بدون وقفه ارسال شود، خروجی Serial Monitor شلوغ می شود و بررسی آن دشوار خواهد شد.

برای آزمایش های ساده می توانید از delay() استفاده کنید؛ اما در برنامه های حساس به زمان بهتر است از روش های غیرمسدودکننده استفاده شود.

پایه های ارتباط سریال تداخل دارند

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

برای مثال، در Arduino Uno کلاسیک، پایه های دیجیتال ۰ و ۱ برای RX و TX سخت افزاری استفاده می شوند.

۱۲. تفاوت Debugging با پیام های سریال و دیباگر سخت افزاری

نمایش پیام در Serial Monitor یکی از روش های ساده عیب یابی است؛ اما با دیباگر سخت افزاری تفاوت دارد.

ویژگیپیام های Serialدیباگر سخت افزاری
مشاهده مقدار متغیرهابا افزودن دستور چاپمعمولا مستقیم در محیط دیباگر
بررسی مسیر اجرای برنامهبا پیام های موقتبا توقف و اجرای مرحله ای
توقف روی یک خط مشخصبه طور معمول ندارددر صورت پشتیبانی، با Breakpoint
نیاز به سخت افزار اضافیمعمولا خیرممکن است لازم باشد
مناسب برای شروع یادگیریبسیار مناسبوابسته به برد و ابزارهای موجود

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

۱۳. نکات مهم در استفاده از Serial Monitor

  1. پیام های واضح بنویسید. به جای چاپ یک عدد نامشخص، نام متغیر را نیز نمایش دهید.
  1. خروجی را بیش از حد شلوغ نکنید. فقط اطلاعات مورد نیاز برای پیدا کردن خطا را چاپ کنید.
  1. واحد اندازه گیری را مشخص کنید. برای مثال، مقدار ولتاژ را همراه با V نمایش دهید.
  1. به اثر چاپ سریال بر زمان اجرا توجه کنید. ارسال اطلاعات زمان می برد و در برنامه های حساس به زمان ممکن است رفتار سیستم را تغییر دهد.
  1. از چاپ مداوم در حلقه های سریع خودداری کنید. در صورت نیاز، زمان ارسال پیام ها را محدود کنید.
  1. محدودیت حافظه را در نظر بگیرید. در میکروکنترلرهای دارای حافظه کم، رشته های متنی طولانی می توانند بخشی از منابع محدود را مصرف کنند.
  1. پس از پایان عیب یابی، پیام های غیرضروری را حذف یا کنترل کنید. این کار باعث خواناتر شدن کد و کاهش بار ارتباطی می شود.

۱۴. تمرین عملی

یک پتانسیومتر را به صورت زیر به Arduino Uno متصل کنید:

  • پایه کناری اول به 5V
  • پایه کناری دوم به GND
  • پایه وسط به A0

سپس برنامه زیر را اجرا کنید:

const int potPin = A0;

void setup() {
  Serial.begin(9600);
  Serial.println("Potentiometer Debug Started");
}

void loop() {
  int value = analogRead(potPin);

  Serial.print("Raw value: ");
  Serial.println(value);

  delay(500);
}

حالا مراحل زیر را انجام دهید:

  1. Serial Monitor را باز کنید.
  2. مقدار نمایش داده شده را در حالت های مختلف پتانسیومتر مشاهده کنید.
  3. بررسی کنید که مقدار با چرخاندن پتانسیومتر چگونه تغییر می کند.
  4. سیم پایه وسط را از A0 جدا کنید و تغییر رفتار را مشاهده کنید.
  5. اتصال را دوباره برقرار کنید و نتیجه را با وضعیت قبلی مقایسه کنید.

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

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

جمع بندی

Serial Monitor یکی از ابزارهای پایه و بسیار کاربردی در برنامه نویسی آردوینو است. با استفاده از Serial.begin() ارتباط سریال را راه اندازی می کنیم و با Serial.print() و Serial.println() اطلاعات مورد نیاز را مشاهده می کنیم.

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

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

نمونه کد :

const int sensorPin = A0;

void setup() {
  Serial.begin(9600);
  Serial.println("Debug started");
}

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

  Serial.print("Sensor value: ");
  Serial.println(sensorValue);

  delay(500);
}