در آردوینو، String() یک تابع سازنده (constructor) است که انواع دادههای مختلف — از جمله اعداد صحیح، اعشاری، کاراکترها و آرایههای بایتی — را به یک شیء از نوع String تبدیل میکند.
این تابع به شما امکان میدهد به راحتی دادههای غیرمتنی را به متن تبدیل کرده و با آنها کار کنید — مثلاً برای نمایش روی سریال مانیتور یا نمایشگر.
آردوینو نمیتواند مستقیماً یک عدد را به یک رشته متصل کند. بدون تبدیل، کد زیر ممکن است خطا بدهد یا رفتار غیرمنتظرهای داشته باشد:
int value = 42;
String msg = "عدد: " + value; // ❌ خطرناک!
راه درست:
String msg = "عدد: " + String(value); // ✅ ایمن
int n = 255;
String s1 = String(n); // "255" (مبنای 10)
String s2 = String(n, HEX); // "ff"
String s3 = String(n, BIN); // "11111111"
String s4 = String(n, OCT); // "377"
float t = 23.456;
String s = String(t, 2); // "23.46" — فقط 2 رقم اعشار
int code = 72;
String s = String(code, BYTE); // "H"
char text[] = "آردوینو";
String s = String(text); // "آردوینو"
float temp = 23.456;
int humidity = 60;
String log = "دمای هوا: ";
log += String(temp, 1); // "23.5"
log += "°C | رطوبت: ";
log += String(humidity); // "60"
log += "%";
Serial.println(log);
// خروجی: دمای هوا: 23.5°C | رطوبت: 60%
پس از ساخت یک شیء String، میتوانید از توابع زیر استفاده کنید. هر کدام با مثال و خروجی واقعی آورده شده است:
کاراکتر در موقعیت n را برمیگرداند (از ۰ شروع میشود).
String s = "سلام";
char c = s.charAt(1); // c = ل
رشته را با رشتهٔ دیگر مقایسه میکند. اگر برابر باشد → ۰، اگر کوچکتر باشد → عدد منفی، اگر بزرگتر باشد → عدد مثبت.
String a = "آب";
int r = a.compareTo("آب"); // r = 0
مقدار دادهشده را به انتهای رشته اضافه میکند.
String s = "Hello";
s.concat(" World"); // s = "Hello World"
اشارهگر به رشتهٔ سنتی C (const char*) برمیگرداند.
String s = "test";
const char* p = s.c_str(); // p اشاره به "test" دارد
بررسی میکند آیا رشته با زیررشته پایان مییابد.
String s = "data.txt";
bool b = s.endsWith(".txt"); // b = true
بررسی میکند آیا دو رشته کاملاً برابرند (حساس به بزرگ/کوچکی).
String a = "Arduino";
bool b = a.equals("arduino"); // b = false
برابری را بدون در نظر گرفتن حروف بزرگ/کوچک بررسی میکند.
String a = "Arduino";
bool b = a.equalsIgnoreCase("ARDUINO"); // b = true
رشته را به آرایهای از بایتها کپی میکند.
String s = "AB";
byte buf[3];
s.getBytes(buf, 3); // buf = {65, 66, 0}
موقعیت اولین occurrence زیررشته را برمیگرداند.
String s = "hello";
int i = s.indexOf("l"); // i = 2
جستجو از موقعیت from شروع میشود.
String s = "hello";
int i = s.indexOf("l", 3); // i = 3
موقعیت آخرین occurrence زیررشته را برمیگرداند.
String s = "hello";
int i = s.lastIndexOf("l"); // i = 3
تعداد کاراکترهای رشته را برمیگرداند.
String s = "سلام";
int n = s.length(); // n = 4
تمام کاراکترها از موقعیت index به بعد را حذف میکند.
String s = "Arduino";
s.remove(4); // s = "Ardu"
count کاراکتر از موقعیت index حذف میشوند.
String s = "Arduino";
s.remove(2, 3); // s = "Ario"
تمام occurrenceهای old را با new جایگزین میکند.
String s = "I like cats";
s.replace("cats", "dogs"); // s = "I like dogs"
فضای حافظهٔ اولیه برای رشته رزرو میکند (بهینهسازی).
String s;
s.reserve(50); // فضای 50 بایتی رزرو شد
کاراکتر در موقعیت index را تغییر میدهد.
String s = "Hello";
s.setCharAt(0, J); // s = "Jello"
بررسی میکند آیا رشته با زیررشته شروع میشود.
String s = "HTTP/1.1";
bool b = s.startsWith("HTTP"); // b = true
زیررشته از موقعیت from تا انتها.
String s = "Arduino";
String r = s.substring(3); // r = "uino"
زیررشته از from تا قبل از to.
String s = "Arduino";
String r = s.substring(2, 5); // r = "dui"
رشته را در آرایهای از char کپی میکند.
String s = "Hi";
char buf[3];
s.toCharArray(buf, 3); // buf = {H,i,�}
رشته را به عدد اعشاری تبدیل میکند.
String s = "3.14";
double d = s.toDouble(); // d = 3.14
رشته را به عدد صحیح تبدیل میکند.
String s = "123";
int n = s.toInt(); // n = 123
تمام حروف را به کوچک تبدیل میکند.
String s = "Hello";
s.toLowerCase(); // s = "hello"
تمام حروف را به بزرگ تبدیل میکند.
String s = "Hello";
s.toUpperCase(); // s = "HELLO"
فاصلههای ابتدایی و انتهایی را حذف میکند.
String s = " Hello ";
s.trim(); // s = "Hello"
String a = "Hi"; // a = "Hi"
String a = "Hello" + " World"; // a = "Hello World"
String a = "Hi";
a += " there"; // a = "Hi there"
String a = "A";
bool b = (a == "A"); // b = true
String a = "A";
bool b = (a != "B"); // b = true
بر اساس کدهای ASCII کار میکنند. برای فارسی ممکن است رفتار غیرمنتظره داشته باشند.
String a = "Apple";
bool b = (a < "Banana"); // b = true
String s = "ABC";
char c = s[1]; // c = B
هر بار که یک String ایجاد یا تغییر میکند، حافظهٔ جدیدی در RAM اختصاص داده میشود. در آردوینو Uno (فقط ۲ کیلوبایت RAM)، این کار در loop() میتواند پس از چند دقیقه باعث ریست شدن برد شود.
راهکار: در پروژههای بلادرنگ، از char و sprintf() استفاده کنید.
اگر یک عدد بین ۰–۲۵۵ دارید که نمایندهٔ یک کاراکتر است (مثلاً از سنسور سریال)، با String(code, BYTE) مستقیماً آن را به کاراکتر تبدیل کنید — بدون نیاز به آرایههای پیچیده.
تابع String() و کلاس String ابزارهایی قدرتمند برای کار با متن در آردوینو هستند، اما: — در پروژههای آموزشی و کوتاه عالی عمل میکنند.
— در سیستمهای بلادرنگ یا صنعتی، با احتیاط استفاده شوند.
— همیشه از توابعی مثل trim()، toInt() و substring() برای پردازش ورودی استفاده کنید.
این مطلب بر اساس مستندات رسمی Arduino از بخش String() – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی String (با حرف بزرگ S) یک کلاس پیشرفته است که به شما امکان میدهد راحتتر با رشتههای متنی (مثل "سلام"، "دما: 25C") کار کنید.
برخلاف رشتههای سنتی C (که آرایهای از char هستند)، String عملیاتی مثل جمع کردن، مقایسه، جستجو و تغییر متن را بسیار ساده میکند.
مثال ساده:
String message = "درجه حرارت: ";
message += "25C";
Serial.println(message); // خروجی: درجه حرارت: 25C
در آردوینو دو مفهوم متفاوت وجود دارد: — String (با S بزرگ): یک کلاس هوشمند که توسط آردوینو فراهم شده است.
— char* یا char[] (گاهی به اشتباه "string" گفته میشود): رشتههای سنتی C که آرایهای از کاراکترها هستند.
تفاوت اصلی: — String راحتتر است، اما حافظهی بیشتری مصرف میکند و ممکن است باعث خرابی برنامه در پروژههای طولانیمدت شود.
— رشتههای char کارآمدتر هستند، اما نیاز به کدنویسی دقیقتر دارند.
// تعریف
String name = "آردوینو";
String version;
// ترکیب (concatenation)
version = "نسخه " + String(1) + "." + String(8);
// طول رشته
int len = name.length(); // len = 7
// مقایسه
if (name == "آردوینو") {
Serial.println("نام صحیح است.");
}
// جستجو
int pos = version.indexOf("1"); // pos = 5
در این مثال، یک پیام شامل دما و رطوبت ساخته میشود:
float temperature = 23.5;
float humidity = 60.0;
String displayMessage = "دمای هوا: ";
displayMessage += String(temperature, 1); // 1 رقم اعشار
displayMessage += "°C | رطوبت: ";
displayMessage += String(humidity, 0);
displayMessage += "%";
// فرض کنید تابعی برای نمایش وجود دارد
// lcd.print(displayMessage);
Serial.println(displayMessage);
هر بار که یک String را تغییر میدهید (مثلاً با +=)، آردوینو یک کپی جدید از کل رشته در حافظه میسازد.
در آردوینو Uno فقط ۲ کیلوبایت RAM وجود دارد. اگر از String در حلقهی loop() استفاده کنید، ممکن است پس از چند دقیقه، RAM پر شود و برنامه ریست شود یا رفتار عجیبی داشته باشد.
راهکار ایمن: — از String فقط در setup() یا برای پیامهای کوتاه و موقت استفاده کنید.
— در پروژههای حساس یا بلادرنگ، از رشتههای char و توابعی مثل sprintf() استفاده کنید.
اگر مستقیماً عدد را به String اضافه کنید، ممکن است نتیجه غیرمنتظره باشد:
int x = 25;
String s = "عدد: " + x; // ❌ اشتباه! x به عنوان آدرس تفسیر میشود
در عوض، همیشه عدد را ابتدا به String تبدیل کنید:
String s = "عدد: " + String(x); // ✅ درست
loop() بدون مدیریت حافظهاین مطلب بر اساس مستندات رسمی Arduino از بخش String – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، size_t یک نوع دادهی صحیح بدون علامت (unsigned integer) است که برای نگهداری اندازهها و تعدادها طراحی شده است.
این نوع داده هرگز نمیتواند عدد منفی باشد — چون منفی بودن برای «تعداد عناصر» یا «طول یک آرایه» معنی ندارد!
اندازهی دقیق size_t بسته به پلتفرم متفاوت است: — در بردهای AVR (مثل Uno): ۲ بایت → محدوده: ۰ تا ۶۵,۵۳۵
— در بردهای ۳۲ بیتی (مثل ESP32 یا Due): ۴ بایت → محدوده: ۰ تا ۴,۲۹۴,۹۶۷,۲۹۵
هدف اصلی size_t این است که کدها را قابل انتقالتر (portable) کند — چون همیشه به اندازهی طبیعی پردازنده برای ذخیرهی اندازهها تنظیم میشود.
بسیاری از توابع استاندارد آردوینو و کتابخانههای C++ (مثل strlen()، sizeof()، یا String.length()) مقدار بازگشتی خود را به عنوان size_t تعریف میکنند.
مثال:
String message = "سلام";
size_t len = message.length(); // len = 4 (تعداد کاراکترها)
اگر شما از int برای ذخیرهی این مقدار استفاده کنید، در بردهای ۳۲ بیتی ممکن است هشدار کامپایلر دریافت کنید یا در موارد نادر، سرریز رخ دهد.
اما با size_t، همیشه با نوع صحیح کار میکنید.
شما معمولاً size_t را در متغیرهایی میبینید که با حلقههای شمارشی یا اندازهی آرایهها سروکار دارند:
int values[] = {10, 20, 30, 40};
size_t count = sizeof(values) / sizeof(values[0]); // count = 4
for (size_t i = 0; i < count; i++) {
Serial.println(values[i]);
}
استفاده از size_t در حلقهها نهتنها منطقیتر است (چون شمارنده هرگز منفی نمیشود)، بلکه با استانداردهای برنامهنویسی مدرن هم هماهنگ است.
void printString(const char* str) {
size_t len = strlen(str); // strlen() از size_t استفاده میکند
for (size_t i = 0; i < len; i++) {
Serial.print("کاراکتر ");
Serial.print(i);
Serial.print(": ");
Serial.println(str[i]);
}
}
اگر شما مبتدی هستید، کاملاً میتوانید از int یا unsigned int برای شمارندهها استفاده کنید و مشکلی پیش نمیآید.
اما وقتی کد شما بزرگتر میشود یا میخواهید آن را با دیگران به اشتراک بگذارید، استفاده از size_t نشاندهندهی سبک برنامهنویسی حرفهای است — چون دقیقاً همان نوعی را به کار میبرید که سیستم استفاده میکند.
چون size_t بدون علامت است، اگر آن را با یک عدد منفی مقایسه کنید، نتیجه غیرمنتظره خواهد بود:
size_t x = 5;
if (x > -1) {
// این شرط FALSE است! چون -1 به عدد بسیار بزرگی تبدیل میشود
Serial.println("این چاپ نمیشود!");
}
بنابراین، هرگز size_t را با اعداد منفی مقایسه نکنید — و همیشه به یاد داشته باشید: این نوع فقط برای مقادیر ≥ ۰ طراحی شده است.
size_t = نوعی برای اندازهها و تعدادهاstrlen() و sizeof() از آن استفاده میکننداین مطلب بر اساس مستندات رسمی Arduino از بخش size_t – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی short یک نوع عدد صحیح است که دقیقاً ۲ بایت (۱۶ بیت) حافظه مصرف میکند.
این نوع داده در تمام پلتفرمهای آردوینو (از جمله Uno، Nano، ESP32 و Due) همیشه ۲ بایت است — برخلاف int که در برخی بردها ۴ بایت میشود.
محدودهی مقادیر قابل ذخیره در یک متغیر short:
−۳۲,۷۶۸ تا +۳۲,۷۶۷
جالب است بدانید که در بردهای مبتنی بر AVR (مثل Arduino Uno)، short و int کاملاً یکسان هستند — هر دو ۲ بایت و همان محدوده را دارند.
هدف اصلی short این است که یک نوع دادهی ثابتالاندازه برای اعداد کوچک فراهم کند.
اگر کد شما باید روی چندین پلتفرم مختلف (مثل Uno و ESP32) اجرا شود و میخواهید مطمئن باشید که متغیر شما همیشه ۲ بایت است، short گزینهی مناسبی است.
اما در عمل، برای اکثر پروژههای مبتدی، نیازی به استفاده از short نیست — چون int در AVR همان کار را انجام میدهد و در ESP32 هم معمولاً مشکلی ایجاد نمیکند.
short temperature = -15;
short sensorValue = 1023;
short counter = 0;
نحوهی استفاده آن دقیقاً مثل int است — فقط نامش کوتاهتر است!
فرض کنید میخواهید ۱۰۰۰ مقدار سنسور را در حافظه ذخیره کنید. اگر از int استفاده کنید و روی ESP32 باشید، هر مقدار ۴ بایت مصرف میکند (جمعًا ۴۰۰۰ بایت).
اما اگر مطمئن باشید که مقادیر سنسور بین ۰ تا ۱۰۲۳ هستند، میتوانید از short استفاده کنید تا حافظه را نصف کنید:
const int MAX_SAMPLES = 1000;
short sensorBuffer[MAX_SAMPLES]; // فقط 2000 بایت RAM مصرف میکند
void setup() {
for (int i = 0; i < MAX_SAMPLES; i++) {
sensorBuffer[i] = analogRead(A0);
delay(10);
}
}
چون در آردوینو Uno/Nano، short و int هر دو ۲ بایت هستند، استفاده از short فقط کد را طولانیتر میکند، نه کارآمدتر!
پس مگر اینکه نیاز به سازگاری چندپلتفرمی داشته باشید، بهتر است از int استفاده کنید — چون خواناتر و رایجتر است.
اگر مطمئن هستید که عدد شما همیشه مثبت است (مثل مقدار سنسور یا شماره پین)، میتوانید از unsigned short استفاده کنید:
— محدوده: ۰ تا ۶۵,۵۳۵
این محدوده برای بسیاری از سنسورهای ۱۰ بیتی (مثل آنالوگ آردوینو با محدوده ۰–۱۰۲۳) کاملاً کافی است و دو برابر فضای مثبت short عادی را فراهم میکند.
byte: ۱ بایت — فقط ۰ تا ۲۵۵short: ۲ بایت — −۳۲,۷۶۸ تا +۳۲,۷۶۷ (ثابت در تمام بردها)int: ۲ بایت در AVR، ۴ بایت در ESP32/Due — برای کاربردهای عمومیlong: ۴ بایت — برای اعداد بسیار بزرگبرای اکثر مبتدیها، استفاده از int کافی و توصیهشده است.
short فقط زمانی مفید است که نیاز به کنترل دقیق حجم حافظه یا سازگاری بین پلتفرمها دارید.
این مطلب بر اساس مستندات رسمی Arduino از بخش short – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی long برای ذخیرهی اعداد صحیح بسیار بزرگ (مثبت یا منفی) استفاده میشود.
این نوع داده در تمام بردهای رایج آردوینو (از جمله Uno، Nano، Mega، ESP32 و Due) دقیقاً ۴ بایت (۳۲ بیت) حافظه مصرف میکند.
محدودهی مقادیر قابل ذخیره در یک متغیر long:
−۲,۱۴۷,۴۸۳,۶۴۸ تا +۲,۱۴۷,۴۸۳,۶۴۷
این محدوده تقریباً ۶۵ هزار برابر بزرگتر از محدودهی int در آردوینو Uno است — پس برای کارهایی که نیاز به اعداد بزرگ دارند، گزینهی ایدهآلی است.
در بسیاری از پروژهها، اعدادی که استفاده میکنیم از محدودهی int (در AVR) فراتر میروند. مثالهای رایج:
millis() تعداد میلیثانیههای گذشته از روشن شدن آردوینو را برمیگرداند. این عدد پس از حدود ۹ ساعت از محدودهی int خارج میشود!long currentTime = millis(); // زمان فعلی سیستم
long latitude = 356892345; // مختصات جغرافیایی (به صورت fixed-point)
long counter = 0; // شمارندهی بزرگ
⚠️ نکته: برای تعریف یک عدد ثابت به عنوان long، بهتر است پسوند L یا l به آن اضافه کنید (ترجیحاً L بزرگ، چون l کوچک شبیه عدد ۱ است):
long bigNumber = 1000000L; // مشخص میکند که این عدد long است
تابع millis() خروجی unsigned long دارد. اگر آن را در یک int ذخیره کنید، پس از ۳۲ ثانیه سرریز میشود! اما با long (یا بهتر است unsigned long) مشکلی پیش نمیآید:
unsigned long startTime = millis();
void setup() {
Serial.begin(9600);
}
void loop() {
unsigned long currentTime = millis();
unsigned long elapsedTime = currentTime - startTime;
Serial.print("زمان سپریشده: ");
Serial.print(elapsedTime / 1000); // تبدیل به ثانیه
Serial.println(" ثانیه");
delay(1000);
}
اگر عدد شما هرگز منفی نمیشود (مثل زمان، شمارنده، ولتاژ)، از unsigned long استفاده کنید:
— long: −۲,۱۴۷,۴۸۳,۶۴۸ تا +۲,۱۴۷,۴۸۳,۶۴۷
— unsigned long: ۰ تا ۴,۲۹۴,۹۶۷,۲۹۵
یعنی با unsigned long، محدودهی مثبت شما دو برابر میشود!
اما اگر حتی یکبار نیاز به عدد منفی دارید، حتماً از long استفاده کنید.
در حالی که اندازهی int بسته به برد تغییر میکند، long در تمام پلتفرمهای آردوینو همیشه ۴ بایت است.
این ویژگی باعث میشود کدهای شما قابل انتقالتر (portable) باشند.
اگر به اطمینان نیاز دارید که متغیر شما ۴ بایت است، long گزینهی ایمنتری نسبت به int است.
| نوع داده | اندازه (بایت) | محدوده (در AVR) |
|---|---|---|
| byte | 1 | 0 تا 255 |
| int | 2 | −32,768 تا +32,767 |
| long | 4 | −2,147,483,648 تا +2,147,483,647 |
این مطلب بر اساس مستندات رسمی Arduino از بخش long – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی int (مخفف integer یا «عدد صحیح») یکی از پرکاربردترین انواع داده است.
این نوع برای ذخیرهی اعداد صحیح مثبت و منفی استفاده میشود — یعنی اعدادی بدون ممیز یا بخش اعشاری.
اما نکتهی بسیار مهم: اندازهی int در آردوینو همیشه یکسان نیست!
— در بردهای مبتنی بر تراشههای AVR (مثل Arduino Uno, Nano, Mega):
int = ۲ بایت → محدوده: −۳۲,۷۶۸ تا +۳۲,۷۶۷
— در بردهای مبتنی بر ARM یا ESP (مثل Arduino Due, ESP32):
int = ۴ بایت → محدوده: −۲,۱۴۷,۴۸۳,۶۴۸ تا +۲,۱۴۷,۴۸۳,۶۴۷
این تفاوت به دلیل استاندارد C++ است که اندازهی int را بر اساس «اندازهی طبیعی پردازنده» تعریف میکند.
چون بیشتر شمارهها در دنیای آردوینو در محدودهی −۳۲,۷۶۸ تا +۳۲,۷۶۷ قرار دارند:
— شماره پینها (۰ تا ۵۳)
— مقادیر سنسور آنالوگ (۰ تا ۱۰۲۳)
— زمانهای تأخیر (میلیثانیه)
— شمارندههای حلقه
بنابراین، int گزینهی «پیشفرض» برای اعداد صحیح در آردوینو است.
int counter = 0;
int sensorValue = analogRead(A0); // مقداری بین 0 تا 1023
int temperature = -10; // دما میتواند منفی باشد!
در این مثال، هر بار که دکمه فشرده میشود، یک شمارنده افزایش پیدا میکند:
const int buttonPin = 2;
int pressCount = 0;
int lastButtonState = HIGH;
int currentButtonState;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
currentButtonState = digitalRead(buttonPin);
if (lastButtonState == HIGH && currentButtonState == LOW) {
pressCount++; // افزایش شمارنده
Serial.print("دکمه ");
Serial.print(pressCount);
Serial.println(" بار فشرده شد.");
delay(50); // جلوگیری از نوسان (debounce)
}
lastButtonState = currentButtonState;
}
اگر مقدار یک int در AVR از +۳۲,۷۶۷ بیشتر شود، بهجای خطا دادن، به −۳۲,۷۶۸ بر میگردد!
این پدیده را «سرریز» (overflow) میگویند:
int x = 32767;
x = x + 1; // حالا x = -32768 !
این رفتار گاهی در انیمیشنها یا شمارندههای چرخشی مفید است، اما اغلب باعث باگهای پنهان میشود.
اگر نیاز به اعداد بزرگتر دارید، از long استفاده کنید.
اگر عدد شما همیشه مثبت است (مثل شماره پین یا مقدار سنسور)، ممکن است فکر کنید unsigned int بهتر است.
اما این نوع داده محدودهی بیشتری ندارد — فقط جهت منفی را حذف میکند:
— int: −۳۲,۷۶۸ تا +۳۲,۷۶۷
— unsigned int: ۰ تا ۶۵,۵۳۵
با این حال، استفاده از unsigned میتواند باعث سردرگمی در محاسبات (مثلاً وقتی یک عدد منفی غیرمنتظره ظاهر شود) شود.
برای مبتدیها، استفاده از int سادهتر و ایمنتر است — مگر اینکه واقعاً به محدودهی ۰–۶۵۵۳۵ نیاز داشته باشید.
byte: ۱ بایت، فقط ۰ تا ۲۵۵ — برای اعداد کوچک و مثبتint: ۲ بایت در AVR، منفی و مثبت — برای کاربردهای عمومیlong: ۴ بایت، محدودهی بسیار بزرگ — برای زمان (میلیثانیه)، GPS و...انتخاب درست نوع داده، هم حافظه را ذخیره میکند و هم کد را خواناتر میسازد.
این مطلب بر اساس مستندات رسمی Arduino از بخش int – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی float برای ذخیره و کار با اعداد اعشاری (اعدادی با ممیز متحرک) استفاده میشود.
این نوع داده میتواند اعدادی در محدودهی تقریبی ±3.4028235 × 10³⁸ را نگه دارد، اما فقط با دقتی حدود ۶ تا ۷ رقم معنیدار.
هر متغیر از نوع float دقیقاً ۴ بایت (۳۲ بیت) از حافظهی RAM را اشغال میکند.
وقتی با سنسورها کار میکنید، اغلب نیاز دارید مقادیری مثل دما (۲۳.۵ درجه)، ولتاژ (۳.۳ ولت) یا فاصله (۱۲.۷ سانتیمتر) را ذخیره کنید.
اعداد صحیح (int) نمیتوانند بخش اعشاری را نگه دارند، پس باید از float استفاده کنیم.
float temperature = 23.45;
float voltage = 3.3;
float pi = 3.14159;
شما میتوانید عملیات ریاضی معمولی را روی اعداد float انجام دهید:
float a = 5.2;
float b = 2.1;
float sum = a + b; // نتیجه: 7.3
float product = a * b; // نتیجه: 10.92
پینهای آنالوگ آردوینو مقداری بین ۰ تا ۱۰۲۳ برمیگردانند. برای تبدیل آن به ولتاژ واقعی (مثلاً برای نمایش روی سریال مانیتور)، از float استفاده میکنیم:
const float REF_VOLTAGE = 5.0; // ولتاژ مرجع آردوینو
int sensorRaw = analogRead(A0);
float voltage = sensorRaw * (REF_VOLTAGE / 1023.0);
Serial.print("ولتاژ اندازهگیری شده: ");
Serial.print(voltage);
Serial.println(" ولت");
به دلیل محدودیتهای نمایش اعداد اعشاری در سیستم باینری، برخی اعداد ساده مثل 0.1 را نمیتوان دقیقاً ذخیره کرد.
مثلاً این کد را امتحان کنید:
float x = 0.1 + 0.2;
Serial.println(x, 10); // خروجی: 0.3000000119 — نه 0.3 دقیق!
بنابراین، هرگز برای مقایسهی دو عدد float از == استفاده نکنید. به جای آن، اختلاف آنها را بررسی کنید:
float a = 0.1 + 0.2;
float b = 0.3;
if (abs(a - b) < 0.0001) {
Serial.println("تقریباً برابر هستند!");
}
تراشههای AVR (مثل آنچه در آردوینو Uno استفاده میشود) فاقد واحد پردازش اعشاری (FPU) هستند.
به همین دلیل، هر عملیات ریاضی با float چندین برابر کندتر از اعداد صحیح است.
اگر در حلقهی loop() محاسبات زیادی دارید، سعی کنید از اعداد صحیح استفاده کنید — مثلاً به جای ۲۳.۵ درجه، از ۲۳۵ دهمدرجه استفاده کنید!
در آردوینو Uno/Nano/Mega (تراشههای AVR):
— float = ۴ بایت
— double = همان ۴ بایت (یعنی هیچ تفاوتی ندارد!)
اما در بردهای ARM مثل Arduino Due:
— double = ۸ بایت و دقت بالاتر دارد.
پس در AVR، همیشه از float استفاده کنید — هم خواناتر است، هم سازگاری بهتری دارد.
این مطلب بر اساس مستندات رسمی Arduino از بخش float – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در بسیاری از زبانهای برنامهنویسی (مثل C++ روی کامپیوتر)، نوع دادهی double برای ذخیرهی اعداد اعشاری با دقت بالا (معمولاً ۸ بایت) استفاده میشود.
اما در آردوینو (مخصوصاً روی تراشههای AVR مثل Uno، Nano و Mega)، double دقیقاً همان float است!
یعنی: — هر دو ۴ بایت حافظه مصرف میکنند.
— هر دو دقتی حدود ۶ تا ۷ رقم اعشاری دارند.
— هیچ تفاوتی در عملکرد یا دقت بین آنها وجود ندارد.
این رفتار به دلیل محدودیتهای سختافزاری تراشههای AVR است — آنها واحد پردازش اعشاری (FPU) ندارند، پس همه محاسبات اعشاری بهصورت نرمافزاری و با دقت محدود انجام میشوند.
دو دلیل اصلی وجود دارد:
double استفاده میکنند. آردوینو این نام را پشتیبانی میکند تا کدها بدون خطا کامپایل شوند.double واقعاً ۸ بایت است و دقت بیشتری دارد. پس اگر کد شما قابل انتقال باشد، بهتر است از همان ابتدا درست بنویسید.استفاده از double دقیقاً مثل float است:
double temperature = 23.45;
double voltage = 3.3;
double pi = 3.14159265359;
اما به یاد داشته باشید: در آردوینو Uno، این متغیرها همان float هستند و دقت بیشتری ندارند!
وقتی از analogRead() استفاده میکنید، یک عدد بین ۰ تا ۱۰۲۳ دریافت میکنید. برای تبدیل آن به ولتاژ واقعی، نیاز به عدد اعشاری دارید:
const double REF_VOLTAGE = 5.0; // ولتاژ مرجع
int sensorValue = analogRead(A0);
double voltage = sensorValue * (REF_VOLTAGE / 1023.0);
Serial.print("ولتاژ: ");
Serial.print(voltage);
Serial.println(" ولت");
در اینجا استفاده از double کاملاً قابل قبول است — حتی اگر در پسزمینه float باشد، خوانایی کد را بالا میبرد.
چون double در AVR هیچ مزیتی نسبت به float ندارد، استفاده از آن فقط باعث سردرگمی میشود.
اگر روی بردی مثل Uno یا Nano کار میکنید، بهتر است همیشه از float استفاده کنید.
اما اگر کد شما باید روی برد Due هم اجرا شود و به دقت بالا نیاز دارد، آنگاه double منطقی است.
تراشههای AVR فاقد پردازندهی اعشاری هستند، پس هر عملیات ریاضی با float یا double بسیار کندتر از اعداد صحیح است.
اگر سرعت مهم است (مثل کنترل موتور یا پردازش سنسور بلادرنگ)، سعی کنید از اعداد صحیح استفاده کنید — مثلاً به جای ۲۳.۴۵ ولت، از ۲۳۴۵ میلیولت استفاده کنید!
این مطلب بر اساس مستندات رسمی Arduino از بخش double – Language Reference تهیه شده است، با توضیحات شفاف درباره تفاوت واقعی (یا عدم تفاوت) double و float در پلتفرمهای مختلف آردوینو.
در آردوینو، نوع دادهی char برای ذخیرهی یک کاراکتر منفرد (مثل A، 5 یا @) استفاده میشود.
هر متغیر از نوع char دقیقاً یک بایت (۸ بیت) از حافظه را اشغال میکند.
اما نکتهی جالب اینجاست: در پسزمینه، هر کاراکتر در واقع یک عدد است! این اعداد بر اساس جدول استاندارد ASCII تعریف شدهاند.
مثلاً: — کاراکتر A معادل عدد ۶۵ است.
— کاراکتر 0 معادل عدد ۴۸ است.
برای تعریف یک کاراکتر، از علامت نقل قول تکی () استفاده میشود (نه دابل کوتیشن!):
char myLetter = K;
char digit = 7;
char symbol = #;
⚠️ توجه: اگر از دابل کوتیشن استفاده کنید ("K")، آردوینو آن را به عنوان یک رشته (string) در نظر میگیرد — نه یک کاراکتر!
چون char در واقع یک عدد ۸ بیتی است، میتوانید مستقیماً یک عدد به آن نسبت دهید:
char c = 65; // معادل کاراکتر A
Serial.println(c); // خروجی: A
همچنین میتوانید یک کاراکتر را به عدد تبدیل کنید:
char letter = B;
int asciiValue = letter; // asciiValue = 66
هر دو char و byte یک بایت حافظه مصرف میکنند، اما:
— byte فقط اعداد مثبت از ۰ تا ۲۵۵ را پشتیبانی میکند.
— char اعدادی از -۱۲۸ تا +۱۲۷ را پشتیبانی میکند (چون بهصورت پیشفرض «علامتدار» است).
پس اگر قصد دارید فقط کاراکتر ذخیره کنید یا با اعداد مثبت ۰–۲۵۵ کار کنید، byte گزینهی شفافتری است.
اما اگر واقعاً نیاز به کاراکتر دارید (مثلاً برای ارسال داده به سریال مانیتور)، از char استفاده کنید.
در این مثال، آردوینو منتظر دریافت یک کاراکتر از کامپیوتر است و بر اساس آن LED را روشن یا خاموش میکند:
const int ledPin = 13;
char command;
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
Serial.println("دستور را وارد کنید: 1 برای روشن، 0 برای خاموش");
}
void loop() {
if (Serial.available() > 0) {
command = Serial.read(); // خواندن یک کاراکتر
if (command == 1) {
digitalWrite(ledPin, HIGH);
Serial.println("LED روشن شد.");
} else if (command == 0) {
digitalWrite(ledPin, LOW);
Serial.println("LED خاموش شد.");
}
}
}
بسیاری از مبتدیها این اشتباه را میکنند:
— A → یک کاراکتر (صحیح برای char)
— "A" → یک رشتهی ۲ بایتی (شامل A و یک بایت پایاندهنده �)
استفاده از دابل کوتیشن در جایی که باید تک کوتیشن باشد، باعث خطاهای عجیب و غریب میشود!
اگرچه char برای کاراکتر طراحی شده، اما چون یک بایت است، گاهی برای انتقال دادههای خام (مثل بایتهای دریافتی از سنسور I2C یا UART) هم استفاده میشود.
اما در این موارد، بهتر است از uint8_t یا byte استفاده کنید تا منظور شما از کد واضحتر باشد.
این مطلب بر اساس مستندات رسمی Arduino از بخش char – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی byte برای ذخیرهی اعداد صحیح در محدودهی ۰ تا ۲۵۵ استفاده میشود.
این نوع داده دقیقاً یک بایت (۸ بیت) از حافظه را اشغال میکند — همان حجمی که یک کاراکتر ساده مصرف میکند.
چرا این محدوده؟ چون ۸ بیت میتواند 2^8 = 256 حالت مختلف داشته باشد، یعنی از ۰ تا ۲۵۵.
در آردوینو، نوع دادهی int دو بایت حافظه مصرف میکند و میتواند اعداد منفی و مثبت را ذخیره کند (معمولاً از -۳۲۷۶۸ تا +۳۲۷۶۷).
اما اگر شما میدانید که دادهی شما همیشه بین ۰ تا ۲۵۵ است (مثل مقدار خروجی یک پین PWM یا خواندن یک سنسور آنالوگ پس از تبدیل)، استفاده از byte هوشمندانهتر است:
byte brightness = 150; // روشنایی LED (0 تا 255)
byte sensorValue = 0; // مقدار سنسور
byte pinNumber = 9; // شماره پین
مثال کاربردی با analogWrite که فقط اعداد ۰ تا ۲۵۵ را میپذیرد:
byte ledPin = 9;
byte brightness = 200;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
analogWrite(ledPin, brightness); // brightness باید بین 0 تا 255 باشد
}
اگر مقدار یک متغیر byte را کم کنید و از صفر پایینتر برود، به جای منفی شدن، به انتهای محدوده بر میگردد (این پدیده را «سرریز معکوس» یا underflow میگویند):
byte x = 0;
x = x - 1; // حالا x برابر است با 255!
این رفتار گاهی عمدی است (مثلاً در انیمیشنهای چرخشی)، اما اغلب باعث خطا میشود. همیشه قبل از کم کردن، بررسی کنید که متغیر از صفر بیشتر است:
if (x > 0) {
x--;
}
در آردوینو، هر دو نوع byte و char یک بایت حافظه مصرف میکنند.
اما تفاوت منطقی دارند: — byte برای اعداد ۰ تا ۲۵۵ طراحی شده.
— char برای کاراکترها (مثل A یا 5) است.
با این حال، در پشت صحنه، هر کاراکتر یک عدد است (مثلاً A = 65). پس گاهی میتوانید آنها را تبدیل کنید — اما فقط وقتی که واقعاً نیاز دارید!
یک رنگ RGB از سه مقدار قرمز، سبز و آبی تشکیل شده که هر کدام بین ۰ تا ۲۵۵ است:
byte red = 255;
byte green = 128;
byte blue = 0;
// ارسال به یک LED RGB (با PWM)
analogWrite(redPin, red);
analogWrite(greenPin, green);
analogWrite(bluePin, blue);
استفاده از byte در اینجا کاملاً منطقی است — چون هیچوقت نیازی به عدد منفی یا بزرگتر از ۲۵۵ نداریم.
این مطلب بر اساس مستندات رسمی Arduino از بخش byte – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی boolean دقیقاً همان bool است. این دو نام متفاوت برای یک نوع داده هستند که فقط دو مقدار میتوانند داشته باشند:
true → درست / فعال / بلهfalse → غلط / غیرفعال / خیرتفاوتی در عملکرد، حجم حافظه یا سرعت بین bool و boolean وجود ندارد. این دو کاملاً قابل جایگزینی هستند.
در زبان C++ (که آردوینو بر پایه آن ساخته شده)، نوع استاندارد bool است.
اما در نسخههای اولیهی آردوینو، برای راحتی کاربران غیرحرفهای، نام boolean هم اضافه شد — چون برای بسیاری از مبتدیها، کلمهی «boolean» شناختهتر از «bool» است.
در پسزمینه، آردوینو این دو را با این خط تعریف میکند:
typedef bool boolean;
یعنی: «هر جا boolean نوشتی، منظور همان bool است.»
شما میتوانید به جای bool، از boolean استفاده کنید — کد کاملاً یکسان کار میکند:
boolean isLightOn = false;
boolean buttonPressed = true;
if (isLightOn) {
digitalWrite(LED_PIN, HIGH);
}
فرض کنید یک سنسور درب (reed switch) دارید که وقتی درب باز است، خروجی LOW میدهد:
const int doorSensor = 3;
boolean doorOpen = false;
void setup() {
pinMode(doorSensor, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
doorOpen = !digitalRead(doorSensor); // اگر درب باز باشد، doorOpen = true
if (doorOpen) {
Serial.println("⚠️ هشدار: درب باز است!");
} else {
Serial.println("درب بسته است.");
}
delay(500);
}
هر دو صحیح هستند، اما:
— اگر کد شما برای جامعه جهانی است، از bool استفاده کنید (استاندارد C++).
— اگر کد شما فقط برای آموزش فارسیزبانان مبتدی است، boolean خواناتر و گویاتر است.
در پروژههای شخصی، هر کدام را که دوست دارید انتخاب کنید — ولی در یک پروژه، از یکی از آنها استفاده کنید تا کد یکدست باشد.
با وجود اینکه فقط یک بیت (0 یا 1) نیاز است، هر متغیر boolean در آردوینو یک بایت کامل RAM اشغال میکند. اگر بخواهید صدها وضعیت را ذخیره کنید، بهتر است از تکنیکهای فشردهسازی بیتی (مثل آرایهی byte و عملگرهای بیتی) استفاده کنید — اما این موضوع برای مبتدیها پیشرفته است.
این مطلب بر اساس مستندات رسمی Arduino از بخش boolean – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در دنیای آردوینو، گاهی فقط نیاز دارید بدانید یک چیز «روشن است یا خاموش؟»، «سنسور فعال است یا غیرفعال؟»، «شرایط برقرار است یا نه؟».
برای همین کارها، از نوع دادهی bool استفاده میشود.
این نوع داده فقط دو مقدار میتواند داشته باشد:
true → به معنی «درست» یا «بله»false → به معنی «غلط» یا «خیر»فرض کنید میخواهید بدانید آیا دکمه فشرده شده است یا نه. میتوانید از یک متغیر عددی استفاده کنید و عدد ۱ یا ۰ ذخیره کنید، اما این روش گیجکننده است.
اما با bool، کد شما خواناتر و منطقیتر میشود:
bool buttonPressed = false; // در ابتدا دکمه فشرده نشده
همین سادگی! حالا هر کس کد شما را بخواند، دقیقاً متوجه منظور شما میشود.
تعریف یک متغیر از نوع bool بسیار ساده است:
bool myState = true;
bool isDark = false;
شما میتوانید مقدار یک متغیر bool را در شرطها (مثل if) مستقیماً استفاده کنید:
bool lightOn = true;
if (lightOn) {
Serial.println("چراغ روشن است!");
} else {
Serial.println("چراغ خاموش است.");
}
نیازی نیست بنویسید if (lightOn == true) — چون خودِ lightOn یک مقدار منطقی است!
در این مثال، یک دکمه به پین ۲ متصل شده است. میخواهیم وضعیت آن را در یک متغیر bool ذخیره کنیم:
const int buttonPin = 2;
bool buttonState = false;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
buttonState = !digitalRead(buttonPin); // چون از PULLUP استفاده کردیم، LOW یعنی فشرده شده
if (buttonState) {
Serial.println("دکمه فشرده شد!");
} else {
Serial.println("دکمه آزاد است.");
}
delay(200);
}
بسیاری فکر میکنند چون bool فقط دو حالت دارد، پس باید کمتر از یک بایت حافظه بگیرد. اما در آردوینو (و بیشتر سیستمهای مبتنی بر C++)، هر متغیر bool دقیقاً یک بایت از RAM را اشغال میکند.
اگر RAM کم دارید (مثل آردوینو Uno با فقط ۲ کیلوبایت)، و نیاز به ذخیرهی صدها وضعیت دارید، بهتر است از بیتها در یک آرایه byte استفاده کنید — اما این موضوع برای مبتدیها پیچیده است و فعلاً نیازی به نگرانی نیست!
اگر یک عدد (مثلاً int) را در یک شرط if بگذارید، آردوینو آن را بهصورت خودکار به bool تبدیل میکند:
— هر عدد غیر از صفر → true
— عدد صفر → false
int sensorValue = 5;
if (sensorValue) {
// این بخش اجرا میشود، چون 5 غیرصفر است!
Serial.println("مقدار سنسور صفر نیست.");
}
اما استفاده از bool برای وضعیتهای منطقی، همیشه خوانایی کد را بالا میبرد و از اشتباهات جلوگیری میکند.
این مطلب بر اساس مستندات رسمی Arduino از بخش bool – Language Reference تهیه شده است، اما با توضیحات سادهتر، مثالهای کاربردی و نکات طلایی منحصربهفرد برای کاربران فارسیزبان.
تصور کنید یک جعبهی کفش دارید که داخلش چندتا کشوی کوچک هست — هر کدوم یه شماره دارن: کشوی ۰، کشوی ۱، کشوی ۲ و...
شما میتونید تو هر کشو یه چیز بریزید: یه عدد، یه ولتاژ سنسور، یه شماره پین LED و...
اسم این جعبهی هوشمند در برنامهنویسی، «آرایه» (Array) هست!
فرض کنید میخواید دمای ۵ اتاق رو بخونید و ذخیره کنید. بدون آرایه، باید بنویسید:
int temp1 = 22;
int temp2 = 24;
int temp3 = 21;
int temp4 = 23;
int temp5 = 20;
حالا اگر بخواید میانگین بگیرید؟ باید هر کدوم رو جداگانه جمع کنید!
اما با آرایه:
int temperatures[5] = {22, 24, 21, 23, 20};
همه دادهها در یک جا، با یک اسم، و قابل دسترسی با یک شماره!
این همون قدرت آرایههاست.
شما فقط میگید: «من یه آرایه از ۴ تا عدد میخوام»، ولی هنوز مقدار نمیریزید:
int myArray[4]; // آرایهای با 4 خانه — ولی محتوایش تصادفی است!
هشدار مهم: مقادیر داخل این آرایه تعریفنشده هستند! ممکنه عدد عجیبی مثل
-12345یا0باشن.
همیشه قبل از استفاده، مقداردهی کنید:myArray[0] = 10; myArray[1] = 20; // و الی آخر
اینجا همه چیز رو یکجا مینویسید — هم اندازه، هم مقادیر:
int myArray[] = {10, 20, 30, 40}; // آرایهای با 4 عنصر — کامپایلر خودش اندازه رو متوجه میشه!
نکته طلایی: وقتی از
{}استفاده میکنید، نیازی نیست عدد داخل براکت[ ]رو بنویسید. آردوینو خودش تعداد اعداد رو میشماره و آرایه رو درست میکنه!
در آرایهها، اولین خانه شمارهی ۰ دارد، نه ۱!
پس:
myArray[0] → اولین عدد (10)myArray[1] → دومین عدد (20)myArray[3] → چهارمین عدد (40)اگر بنویسید myArray[4]، خارج از محدوده هستید! چون آرایهی ما فقط خونههای ۰ تا ۳ رو داره.
این اشتباه، یکی از رایجترین دلایل خراب شدن برنامههای آردوینو است!
راهکار ایمن: همیشه از متغیری برای ذخیرهی اندازه آرایه استفاده کنید:
int values[] = {5, 10, 15, 20}; int size = sizeof(values) / sizeof(values[0]); // size = 4 for (int i = 0; i < size; i++) { Serial.println(values[i]); }
int ledPins[] = {2, 3, 4, 5}; // پینهای 4 تا LED
int numLeds = 4; // تعداد LEDها
void setup() {
for (int i = 0; i < numLeds; i++) {
pinMode(ledPins[i], OUTPUT);
}
}
void loop() {
for (int i = 0; i < numLeds; i++) {
digitalWrite(ledPins[i], HIGH);
delay(300);
digitalWrite(ledPins[i], LOW);
}
}
فرض کنید ۳ عدد سنسور فتوسل (LDR) به پینهای A0, A1, A2 وصل شدن:
int sensorPins[] = {A0, A1, A2};
int sensorValues[3]; // جایی برای ذخیره مقادیر
void setup() {
Serial.begin(9600);
}
void loop() {
for (int i = 0; i < 3; i++) {
sensorValues[i] = analogRead(sensorPins[i]); // مقدار هر سنسور رو بخون
Serial.print("Sensor ");
Serial.print(i);
Serial.print(": ");
Serial.println(sensorValues[i]);
}
delay(1000);
}
این کد نشون میده چطور آرایهها کمک میکنن کد رو انعطافپذیر و قابل گسترش کنید. فردا اگر ۱۰ تا سنسور اضافه کردید، فقط کافیه آرایه رو بزرگتر کنید — بقیه کد تغییری نمیکنه!
این مطلب بر اساس مستندات رسمی Arduino از بخش Array – Language Reference تهیه شده است، اما با توضیحات عمیقتر، مثالهای کاربردی و نکات منحصربهفرد برای جامعهی فارسیزبان.