برنامه نویسی

آموزش متغیرها و انواع داده در آردوینو (int, float, char, bool, String)

در این آموزش با مفهوم متغیر در آردوینو و انواع داده پرکاربرد شامل int، float، char، bool و String آشنا می شویم. همچنین نحوه تعریف و مقداردهی متغیرها، تغییر مقدار، تبدیل نوع داده، نمایش مقادیر در Serial Monitor و انتخاب نوع مناسب برای پروژه های آردوینو را با مثال های عملی یاد می گیریم.

سطح مقدماتی

آموزش متغیرها و انواع داده در آردوینو

مقدمه

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

این محل ذخیره سازی را متغیر (Variable) می نامیم.

هر متغیر یک نام و یک نوع داده دارد. نوع داده مشخص می کند چه نوع اطلاعاتی در متغیر ذخیره می شود و چه محدوده ای از مقادیر را می توان در آن نگهداری کرد.

در این آموزش با پنج نوع داده پرکاربرد در آردوینو آشنا می شویم:

  • int برای اعداد صحیح
  • float برای اعداد اعشاری
  • char برای یک کاراکتر
  • bool برای مقادیر منطقی
  • String برای متن

۱. متغیر چیست؟

متغیر فضایی در حافظه است که برنامه برای نگهداری یک مقدار از آن استفاده می کند.

برای مثال، اگر بخواهیم شماره پایه ای را که یک LED به آن متصل شده است ذخیره کنیم، می توانیم بنویسیم:

int ledPin = 13;

در این دستور:

  • int نوع داده متغیر را مشخص می کند.
  • ledPin نام متغیر است.
  • 13 مقدار اولیه متغیر است.
  • علامت = مقدار سمت راست را در متغیر سمت چپ قرار می دهد.
  • علامت ; پایان دستور را مشخص می کند.

پس از تعریف این متغیر، می توانیم به جای نوشتن عدد ۱۳ در تمام قسمت های برنامه، از نام ledPin استفاده کنیم.

مثال:

int ledPin = 13;

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
}

void loop() {
}

در این برنامه، پایه شماره ۱۳ به عنوان خروجی تنظیم و سپس روشن می شود.

استفاده از نام مناسب برای متغیرها باعث می شود برنامه خواناتر و اصلاح آن آسان تر شود.

۲. تعریف و مقداردهی متغیر

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

نوع_داده نام_متغیر = مقدار;

برای مثال:

int counter = 0;
float temperature = 25.5;
char grade = 'A';
bool ledState = true;
String message = "Hello Arduino";

در این مثال، پنج متغیر با انواع داده متفاوت تعریف شده اند.

توجه کنید که مقدار متنی در String داخل علامت نقل قول دوتایی قرار می گیرد، اما مقدار char داخل علامت نقل قول تکی نوشته می شود.

همچنین می توان ابتدا متغیر را تعریف و سپس مقدار آن را تعیین کرد:

int counter;
counter = 10;

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

۳. نوع داده int

نوع داده int برای نگهداری اعداد صحیح، یعنی اعدادی بدون بخش اعشاری، استفاده می شود.

مثال:

int age = 25;
int ledPin = 13;
int counter = 0;
int temperature = -5;

متغیرهای int می توانند مقادیر مثبت، منفی و صفر را نگهداری کنند؛ البته محدوده دقیق آن ها به معماری برد بستگی دارد.

در بسیاری از بردهای رایج آردوینو مانند Uno مبتنی بر ATmega328P، نوع int شانزده بیتی است و محدوده آن از ۳۲۷۶۸- تا ۳۲۷۶۷ است.

در بردهای ۳۲ بیتی مانند ESP32، نوع int معمولا ۳۲ بیتی است.

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

مثال کاربردی int

در این مثال، یک شمارنده هر ثانیه یک واحد افزایش پیدا می کند:

int counter = 0;

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

void loop() {
  counter++;

  Serial.println(counter);

  delay(1000);
}

عملگر ++ مقدار متغیر را یک واحد افزایش می دهد. خروجی Serial Monitor به صورت ۱، ۲، ۳ و ... خواهد بود.

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

۴. نوع داده float

نوع داده float برای نگهداری اعداد اعشاری استفاده می شود.

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

مثال:

float temperature = 24.7;
float batteryVoltage = 3.85;
float current = 0.25;

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

مثال کاربردی float

float voltage = 3.75;

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

void loop() {
  Serial.print("Voltage: ");
  Serial.print(voltage, 2);
  Serial.println(" V");

  delay(1000);
}

در دستور Serial.print(voltage, 2) عدد ۲ مشخص می کند که مقدار با دو رقم اعشار نمایش داده شود.

خروجی نمونه:

Voltage: 3.75 V

نکته مهم این است که float دقت نامحدود ندارد. بسیاری از اعداد اعشاری در حافظه به صورت تقریبی ذخیره می شوند. بنابراین، برای محاسبات حساس باید خطای گرد کردن و دقت مورد نیاز را در نظر گرفت.

همچنین اگر دو مقدار از نوع int را بر هم تقسیم کنیم، نتیجه تقسیم صحیح خواهد بود؛ حتی اگر آن را در متغیر float قرار دهیم.

برای مثال:

int a = 5;
int b = 2;

float result = (float)a / b;

در این حالت نتیجه 2.5 خواهد بود؛ زیرا یکی از عملوندها پیش از تقسیم به float تبدیل شده است.

۵. نوع داده char

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

مثال:

char letter = 'A';
char command = 'Y';
char digit = '7';

مقدار char با علامت نقل قول تکی مشخص می شود.

تفاوت این دو دستور را ببینید:

char digit = '7';
int number = 7;

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

مثال کاربردی char

char command = 'Y';

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

  if (command == 'Y') {
    Serial.println("Command accepted");
  }
}

void loop() {
}

در این برنامه، اگر مقدار command برابر با کاراکتر Y باشد، پیام مورد نظر نمایش داده می شود.

نوع char در بسیاری از بردهای آردوینو یک بایت حافظه اشغال می کند. برای نگهداری متن فارسی یا سایر نویسه های چندبایتی، یک متغیر char به تنهایی کافی نیست.

۶. نوع داده bool

نوع داده bool برای نگهداری یک مقدار منطقی استفاده می شود. این متغیر فقط دو مقدار دارد:

  • true به معنی درست
  • false به معنی نادرست

مثال:

bool ledState = true;
bool alarmEnabled = false;
bool buttonPressed = false;

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

مثال کاربردی bool

const int ledPin = 13;
bool ledState = false;

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

void loop() {
  ledState = !ledState;

  digitalWrite(ledPin, ledState);

  delay(1000);
}

در این مثال، عملگر ! مقدار منطقی را معکوس می کند. اگر ledState برابر false باشد، به true تبدیل می شود و برعکس.

در نتیجه LED هر ثانیه بین حالت روشن و خاموش تغییر می کند.

در این کد فرض شده است که LED با قرار گرفتن پایه در وضعیت HIGH روشن می شود. در مدارهایی که LED به شکل Active-Low متصل شده است، رفتار روشن و خاموش ممکن است برعکس باشد.

۷. نوع داده String

نوع داده String برای نگهداری متن و مجموعه ای از کاراکترها استفاده می شود.

مثال:

String deviceName = "ARDUnia";
String message = "Hello Arduino";
String status = "Ready";

برخلاف char که یک کاراکتر را نگهداری می کند، String می تواند یک متن کامل را در خود جای دهد.

مثال کاربردی String

String deviceName = "ARDUnia";

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

  Serial.print("Device: ");
  Serial.println(deviceName);
}

void loop() {
}

خروجی Serial Monitor:

Device: ARDUnia

ترکیب متن و متغیرها

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

String deviceName = "ARDUnia";
int version = 2;

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

  String message = deviceName + " Version ";
  message += version;

  Serial.println(message);
}

void loop() {
}

خروجی:

ARDUnia Version 2

نکته مهم درباره String

در بسیاری از هسته های آردوینو، کلاس String برای ساخت و تغییر متن از حافظه پویا استفاده می کند. در برنامه های طولانی یا بردهایی با حافظه محدود، استفاده مکرر از ترکیب و تغییر رشته ها ممکن است باعث تکه تکه شدن حافظه و بروز خطا شود.

در پروژه های کوچک، استفاده از String معمولا ساده و مناسب است؛ اما در پروژه های بزرگ یا حساس به حافظه، استفاده از آرایه کاراکتری با نوع char می تواند انتخاب قابل کنترل تری باشد.

نمونه آرایه کاراکتری:

char deviceName[] = "ARDUnia";

این آرایه شامل کاراکترهای متن و یک کاراکتر پایان رشته '\0' است.

همچنین String با حرف بزرگ آغاز می شود؛ زیرا نام یک کلاس در محیط آردوینو است، در حالی که int، float، char و bool نام نوع های داده زبان C++ هستند.

۸. مقایسه انواع داده

نوع دادهکاربردنمونه تعریفنکته
intاعداد صحیحint count = 10;اندازه و محدوده به برد بستگی دارد
floatاعداد اعشاریfloat voltage = 3.7;دقت آن محدود است
charیک کاراکترchar letter = 'A';از نقل قول تکی استفاده می کند
boolمقدار منطقیbool enabled = true;فقط true یا false
StringمتنString name = "Arduino";استفاده از حافظه پویا ممکن است هزینه داشته باشد

۹. تغییر مقدار متغیر

پس از تعریف متغیر، در صورت نیاز می توانیم مقدار آن را تغییر دهیم.

مثال:

int counter = 0;

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

void loop() {
  counter = counter + 1;

  Serial.println(counter);

  delay(1000);
}

عبارت زیر:

counter = counter + 1;

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

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

counter++;

برای افزایش دو واحدی می توان نوشت:

counter += 2;

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

مثال:

int temperature = 25;

if (temperature == 25) {
  // شرط برقرار است
}

۱۰. ثابت ها با const

گاهی مقدار یک متغیر نباید در طول اجرای برنامه تغییر کند. در این حالت می توانیم از const استفاده کنیم.

مثال:

const int ledPin = 13;
const float referenceVoltage = 5.0;

کلمه const مشخص می کند که مقدار این متغیر از طریق روش های معمول برنامه قابل تغییر نیست.

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

۱۱. محدوده دسترسی متغیرها

محل تعریف متغیر تعیین می کند کدام بخش های برنامه می توانند به آن دسترسی داشته باشند.

متغیر محلی

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

void setup() {
  int localValue = 10;
}

در این مثال، localValue خارج از تابع setup() قابل استفاده نیست.

متغیر سراسری

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

int counter = 0;

void setup() {
}

void loop() {
  counter++;
}

در این مثال، counter هم در setup() و هم در loop() قابل دسترسی است.

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

۱۲. اشتباهات رایج

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

int voltage = 3.7;

این متغیر مقدار اعشاری را به صورت دقیق نگهداری نمی کند و بخش اعشاری از بین می رود. برای نگهداری مقدار اعشاری از float استفاده کنید.

اشتباه دوم: استفاده نادرست از نقل قول

char letter = "A";

این دستور برای تعریف یک کاراکتر منفرد درست نیست. شکل صحیح آن:

char letter = 'A';

برای متن از String یا آرایه کاراکتری استفاده می کنیم:

String letterText = "A";

اشتباه سوم: اشتباه گرفتن = و ==

  • = برای مقداردهی است.
  • == برای مقایسه دو مقدار است.

اشتباه چهارم: فرض یکسان بودن اندازه int در تمام بردها

محدوده int در همه بردهای آردوینو یکسان نیست. هنگام کار با مقادیر بزرگ، نوع داده و معماری برد را بررسی کنید.

اشتباه پنجم: استفاده بی رویه از String

در بردهای دارای حافظه محدود، ترکیب مکرر رشته ها ممکن است مصرف حافظه را افزایش دهد. برای پروژه های حساس به حافظه، آرایه های کاراکتری و روش های مدیریت حافظه را نیز بررسی کنید.

جمع بندی

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

  • از int برای اعداد صحیح استفاده کنید.
  • از float برای اعداد اعشاری استفاده کنید.
  • از char برای یک کاراکتر استفاده کنید.
  • از bool برای وضعیت های درست و نادرست استفاده کنید.
  • از String برای نگهداری متن استفاده کنید؛ در پروژه های محدود از نظر حافظه، هزینه آن را نیز در نظر بگیرید.

پیشنهاد تمرین: برنامه ای بنویسید که نام دستگاه را در یک متغیر String، شماره پایه LED را در یک متغیر int، ولتاژ باتری را در یک متغیر float، وضعیت LED را در یک متغیر bool و یک فرمان تک کاراکتری را در یک متغیر char ذخیره کند. سپس همه این مقادیر را در Serial Monitor نمایش دهید.

نمونه کد :

const int ledPin = 13;
float batteryVoltage = 3.75;
char command = 'Y';
bool ledState = false;
String deviceName = "ARDUnia";

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

  Serial.print("Device: ");
  Serial.println(deviceName);

  Serial.print("Battery voltage: ");
  Serial.println(batteryVoltage, 2);

  Serial.print("Command: ");
  Serial.println(command);

  ledState = true;
  digitalWrite(ledPin, ledState);

  Serial.print("LED state: ");
  Serial.println(ledState);
}

void loop() {
}