در آردوینو، true و false دو ثابت منطقی پیشتعریفشده هستند که برای نشان دادن مقادیر بولی (Boolean) استفاده میشوند.
این ثابتها بخشی از زبان برنامهنویسی آردوینو هستند و نیازی به تعریف آنها نیست — همیشه در دسترس هستند.
true = درست / فعال / بلهfalse = غلط / غیرفعال / خیرتوضیح برای مبتدیها: فکر کنید یک سؤال ساده پرسیده میشود: «آیا دکمه فشرده شده است؟» پاسخ فقط دو حالت دارد: «بله» یا «خیر». در دنیای آردوینو،
trueیعنی «بله» وfalseیعنی «خیر». این دو مقدار پایهی تمام تصمیمگیریهای منطقی در کد شما هستند.
استفاده از این ثابتها به جای اعداد خام (مثل ۱ و ۰) چند مزیت دارد: — خوانایی کد: کد شما شبیه زبان انسانی میشود.
— کاهش خطا: جلوی استفاده از مقادیر نامناسب (مثل ۲ یا -۱) در متغیرهای منطقی را میگیرد.
— سازگاری: در همه سیستمهای آردوینو یکسان رفتار میکنند.
متغیرهایی از نوع bool یا boolean فقط میتوانند یکی از این دو مقدار را بپذیرند:
bool isLightOn = false;
boolean buttonPressed = true;
در شرطها، میتوانید مستقیماً از متغیرهای بولی یا ثابتها استفاده کنید:
bool alarmActive = true;
if (alarmActive) { // معادل if (alarmActive == true)
Serial.println("هشدار فعال است!");
}
if (!alarmActive) { // معادل if (alarmActive == false)
Serial.println("هشدار غیرفعال است.");
}
توضیح برای مبتدیها: نوشتن
if (alarmActive)کافی است — نیازی نیست بنویسیدif (alarmActive == true). این سبک نوشتن کوتاهتر، خواناتر و حرفهایتر است.
const int DOOR_SENSOR = 2;
bool doorOpen = false;
void setup() {
pinMode(DOOR_SENSOR, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
// اگر درب باز باشد، سنسور LOW برمیگرداند
doorOpen = (digitalRead(DOOR_SENSOR) == LOW);
if (doorOpen) {
Serial.println("⚠️ درب باز است!");
} else {
Serial.println("درب بسته است.");
}
delay(1000);
}
در این مثال، متغیر doorOpen همیشه یکی از دو مقدار true یا false را دارد.
در واقع، false معادل عدد 0 و true معادل عدد 1 است. اما: — هرگز نباید بنویسید if (x == 1) وقتی منظورتان وضعیت منطقی است.
— همیشه از true و false استفاده کنید تا کد شما منطقیتر باشد.
اگر یک عدد (مثلاً int) را در یک شرط if بگذارید، آردوینو آن را بهصورت خودکار به مقدار منطقی تبدیل میکند: — هر عدد غیر از صفر → true
— عدد صفر → false
int sensorValue = 5;
if (sensorValue) {
// این بخش اجرا میشود، چون 5 غیرصفر است!
}
اما برای وضوح بیشتر، بهتر است همیشه از متغیرهای bool برای وضعیتهای منطقی استفاده کنید.
true = درست / فعال / بلهfalse = غلط / غیرفعال / خیرbool و شرطها استفاده میشونداین مطلب بر اساس مستندات رسمی Arduino از بخش true, false – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، LED_BUILTIN یک ثابت پیشتعریفشده است که بهطور خودکار شماره پین متصل به LED داخلی برد را مشخص میکند.
این ثابت به شما اجازه میدهد بدون نیاز به دانستن شماره دقیق پین، LED داخلی را کنترل کنید — چه روی Arduino Uno، Nano، Mega یا هر برد دیگری.
توضیح برای مبتدیها: بیشتر بردهای آردوینو یک LED کوچک روی خودشان دارند که معمولاً به یکی از پینها متصل است (مثلاً پین ۱۳ در Uno). به جای اینکه همیشه عدد ۱۳ را به یاد داشته باشید، میتوانید از
LED_BUILTINاستفاده کنید. آردوینو خودش میداند که روی برد شما این LED به کدام پین وصل است!
استفاده از این ثابت چند مزیت مهم دارد: — قابلیت انتقال کد: کد شما روی هر برد آردوینو بدون تغییر کار میکند.
— خوانایی بهتر: هر کس کد شما را بخواند، متوجه میشود که منظور شما LED داخلی برد است.
— کاهش خطا: دیگر نیازی نیست شماره پین را برای هر برد جداگانه بررسی کنید.
نکته مهم: شما نیازی به حفظ این اعداد ندارید! کافی است همیشه از LED_BUILTIN استفاده کنید.
استفاده از LED_BUILTIN دقیقاً مثل استفاده از یک شماره پین است:
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // تنظیم LED داخلی به عنوان خروجی
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // LED روشن
delay(1000);
digitalWrite(LED_BUILTIN, LOW); // LED خاموش
delay(1000);
}
اولین برنامهای که بسیاری از مبتدیها مینویسند، چشمک زدن LED داخلی است. با LED_BUILTIN، این کد روی هر بردی کار میکند:
// این کد روی هر برد آردوینو بدون تغییر کار میکند!
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // تغییر وضعیت
delay(500);
}
توضیح برای مبتدیها: تابع
digitalRead(LED_BUILTIN)وضعیت فعلی LED را میخواند. علامت!آن را معکوس میکند (اگر روشن بود، خاموش میشود و بالعکس). این روش هوشمندانهتر از نوشتن دو خط جداگانه برای روشن و خاموش کردن است.
برخی بردهای آردوینو (مثل بردهای کوچک یا ماژولهای خاص) LED داخلی ندارند. در این موارد، LED_BUILTIN معمولاً به یک پین مجازی یا پین -۱ تعریف میشود.
کد شما بدون خطا کامپایل میشود، اما LED چشمک نمیزند — چون فیزیکی وجود ندارد. این رفتار کاملاً طبیعی است و نشاندهندهی خطا نیست.
LED داخلی برد فقط برای تست و آموزش مناسب است. چون: — روشنایی آن کم است.
— ممکن است در برد شما بهصورت معکوس متصل باشد (روشن = LOW).
— در پروژههای واقعی، نیاز به LED در جای خاصی دارید — نه روی برد.
پس برای پروژههای نهایی، حتماً از LED خارجی با مقاومت مناسب استفاده کنید.
LED_BUILTIN = ثابتی برای دسترسی به LED داخلی بردpinMode() و digitalWrite() استفاده میشوداین مطلب بر اساس مستندات رسمی Arduino از بخش LED_BUILTIN – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، ثابت صحیح (Integer Constant) به هر عددی گفته میشود که بهصورت مستقیم در کد نوشته شود و فاقد نقطه اعشاری باشد.
این اعداد بهطور خودکار توسط کامپایلر به عنوان نوع دادهی int در نظر گرفته میشوند — مگر اینکه با پسوند یا مقدار بزرگتر، نوع دیگری مشخص شود.
توضیح برای مبتدیها: وقتی شما در کد عددی مثل
100،-5یا0مینویسید، آردوینو آن را یک «ثابت صحیح» میداند. این اعداد فقط برای مقادیر کامل (بدون اعشار) استفاده میشوند — مثل تعداد دفعات تکرار، شماره پین یا مقدار سنسور دیجیتال.
در پروژههای آردوینو، بیشتر محاسبات و کنترلها با اعداد صحیح انجام میشوند: — شماره پینها (مثل ۱۳)
— تعداد تکرار حلقه (مثل for (int i = 0; i < 10; i++))
— مقادیر سنسور دیجیتال (مثل digitalRead() که ۰ یا ۱ برمیگرداند)
— زمان تأخیر (مثل delay(1000))
ثابتهای صحیح سادهترین و کارآمدترین راه برای نوشتن این اعداد در کد هستند.
در آردوینو، میتوانید اعداد صحیح را در سه مبنای رایج بنویسید:
اعداد معمولی بدون هیچ پیشوندی:
int a = 1024;
int b = -255;
int c = 0;
برای نمایش اعداد بهصورت بیتبهبیت (مثلاً برای کنترل مستقیم بیتها):
int d = 0b1111; // معادل 15 در دهدهی
int e = 0b10101010; // معادل 170
توضیح برای مبتدیها:
0b1111یعنی ۱×۸ + ۱×۴ + ۱×۲ + ۱×۱ = ۱۵. این روش برای کار با رجیسترها یا سنسورهایی که داده را بهصورت بیتی ارسال میکنند بسیار مفید است.
برای نمایش فشردهتر اعداد بزرگ یا رنگها:
int f = 0xFF; // معادل 255
int g = 0x1A3; // معادل 419
در این مبنا، ارقام A تا F بهترتیب معادل ۱۰ تا ۱۵ هستند.
⚠️ هشدار: اگر عددی با صفر شروع شود، آردوینو آن را بهعنوان مبنای هشت در نظر میگیرد:
int h = 010; // ❌ این 10 نیست! این معادل 8 در دهدهی است
این رفتار گاهی باعث خطاهای پنهان میشود. پس مگر اینکه واقعاً نیاز داشته باشید، از اعدادی که با صفر شروع میشوند خودداری کنید.
در این مثال، از ثابتهای شانزدهشانزدهی برای نمایش رنگها استفاده میشود:
const int RED_PIN = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN = 11;
// رنگ سفید: #FFFFFF → قرمز=255, سبز=255, آبی=255
const byte RED_VALUE = 0xFF;
const byte GREEN_VALUE = 0xFF;
const byte BLUE_VALUE = 0xFF;
void setup() {
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
}
void loop() {
analogWrite(RED_PIN, RED_VALUE);
analogWrite(GREEN_PIN, GREEN_VALUE);
analogWrite(BLUE_PIN, BLUE_VALUE);
// LED سفید میشود
}
شما میتوانید بنویسید -10، اما نمیتوانید بنویسید -0xFF یا -0b1010. اگر نیاز به عدد منفی در مبناهای دیگر دارید، ابتدا مقدار مثبت را بنویسید، سپس علامت منفی را اضافه کنید:
int negativeHex = -(0xFF); // -255
کامپایلر آردوینو نوع ثابت صحیح را بر اساس مقدار آن انتخاب میکند: — اگر عدد بین -۳۲,۷۶۸ تا +۳۲,۷۶۷ باشد → int (۲ بایت در Uno)
— اگر عدد بزرگتر باشد → long (۴ بایت)
اگر میخواهید مجبور کنید که یک عدد کوچک بهعنوان long در نظر گرفته شود، از پسوند L استفاده کنید:
long bigNumber = 100L; // مجبور به long شدن
0b)، شانزدهشانزدهی (0x)، هشتهشتی (0 — با احتیاط!)0x برای رنگها و آدرسها، از 0b برای کار با بیتها استفاده کنید010) خودداری کنید — مگر نیاز واقعی داشته باشیداین مطلب بر اساس مستندات رسمی Arduino از بخش Integer Constants – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، INPUT، INPUT_PULLUP و OUTPUT سه ثابت پیشتعریفشده هستند که برای تعیین حالت یک پین دیجیتال با تابع pinMode() استفاده میشوند.
این تنظیم مشخص میکند که آیا پین برای خواندن سیگنال (ورودی) است یا برای ارسال سیگنال (خروجی)، و در صورت ورودی بودن، آیا نیاز به مقاومت بالاکش داخلی دارد یا خیر.
توضیح برای مبتدیها: فکر کنید هر پین آردوینو مثل یک دریچه دو طرفه است. با
pinMode()تصمیم میگیرید این دریچه فقط ورودی باشد (مثل گوش دادن به دکمه)، فقط خروجی باشد (مثل فرمان دادن به LED)، یا ورودی با یک «کمککننده داخلی» (مقاومت بالاکش) برای جلوگیری از سیگنالهای نامشخص.
وقتی یک پین را به عنوان OUTPUT تنظیم میکنید، آردوینو میتواند ولتاژ آن را کنترل کند:
— با digitalWrite(pin, HIGH) ولتاژ پین را به ۵ ولت (یا ۳.۳ ولت) میرساند.
— با digitalWrite(pin, LOW) ولتاژ پین را به ۰ ولت (زمین) متصل میکند.
pinMode(13, OUTPUT); // پین 13 خروجی است
digitalWrite(13, HIGH); // LED روشن میشود
این حالت برای کنترل LED، رله، بوزر و سایر قطعات فعال استفاده میشود.
در حالت INPUT، پین فقط ولتاژ خارجی را میخواند. اما اگر پین به هیچ چیز متصل نباشد، مقدار آن «شناور» (floating) است — یعنی ممکن است بهصورت تصادفی بین HIGH و LOW تغییر کند.
pinMode(2, INPUT); // پین 2 ورودی ساده است
int state = digitalRead(2);
توضیح برای مبتدیها: «شناور بودن» مثل این است که یک میکروفون را بدون پوشش روشن کنید — صداهای نامربوط (سر و صدا) گرفته میشود. برای جلوگیری از این مشکل، معمولاً از
INPUT_PULLUPاستفاده میشود.
در این حالت، آردوینو یک مقاومت داخلی (معمولاً ۲۰ تا ۵۰ کیلو اهم) بین پین و ولتاژ مثبت فعال میکند. این کار باعث میشود: — وقتی دکمه فشرده نشده باشد، پین به ولتاژ متصل است → digitalRead() مقدار HIGH برمیگرداند.
— وقتی دکمه فشرده شود (و به زمین وصل شود)، پین به زمین متصل میشود → مقدار LOW برمیگرداند.
pinMode(2, INPUT_PULLUP); // فعالسازی مقاومت بالاکش داخلی
int button = digitalRead(2); // اگر دکمه فشرده شود، LOW برمیگرداند
این روش رایجترین و سادهترین راه برای خواندن دکمههاست — چون نیازی به مقاومت فیزیکی خارجی ندارد.
// پین 13: خروجی (LED)
pinMode(13, OUTPUT);
// پین 2: ورودی با مقاومت بالاکش (دکمه)
pinMode(2, INPUT_PULLUP);
// پین 3: ورودی ساده (نیاز به مقاومت خارجی دارد)
pinMode(3, INPUT);
void loop() {
// کنترل LED
digitalWrite(13, HIGH);
// خواندن دکمه با INPUT_PULLUP
if (digitalRead(2) == LOW) {
Serial.println("دکمه فشرده شد!");
}
// خواندن سنسور با INPUT (فرض کنید مقاومت خارجی وجود دارد)
if (digitalRead(3) == HIGH) {
Serial.println("سنسور فعال است.");
}
}
مگر اینکه نیاز خاصی داشته باشید، همیشه از INPUT_PULLUP برای دکمهها و سوئیچها استفاده کنید. این کار: — از نیاز به مقاومت فیزیکی جلوگیری میکند.
— از خطاهای ناشی از پینهای شناور جلوگیری میکند.
— مدار شما را سادهتر و قابل اعتمادتر میکند.
پینهای خروجی آردوینو میتوانند حداکثر ۴۰ میلیآمپر جریان تأمین کنند. اگر LED یا قطعهای نیاز به جریان بیشتری دارد، حتماً از ترانزیستور یا درایور استفاده کنید — در غیر این صورت، آردوینو آسیب میبیند.
OUTPUT: برای کنترل قطعات (LED، رله)INPUT: ورودی ساده — نیاز به مقاومت خارجی داردINPUT_PULLUP: ورودی با مقاومت داخلی — ایدهآل برای دکمههاdigitalRead() یا digitalWrite()، پین را با pinMode() تنظیم کنیداین مطلب بر اساس مستندات رسمی Arduino از بخش INPUT, INPUT_PULLUP, OUTPUT – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، HIGH و LOW دو ثابت پیشتعریفشده هستند که برای نشان دادن وضعیت منطقی یک پین دیجیتال استفاده میشوند.
این ثابتها بخشی از زبان آردوینو هستند و نیازی به تعریف آنها نیست — همیشه در دسترس هستند.
HIGH = ولتاژ بالا (معمولاً ۵ ولت یا ۳.۳ ولت بسته به برد)LOW = ولتاژ پایین (۰ ولت یا زمین)توضیح برای مبتدیها: فکر کنید یک سوئیچ دارید که فقط دو حالت دارد: «روشن» و «خاموش». در دنیای آردوینو،
HIGHیعنی «روشن» (ولتاژ وجود دارد) وLOWیعنی «خاموش» (بدون ولتاژ). این دو کلمه ساده، پل ارتباطی بین کد شما و دنیای فیزیکی هستند.
استفاده از این ثابتها به جای اعداد خام (مثل ۱ و ۰) چند مزیت دارد: — خوانایی کد: هر کس کد شما را بخواند، بلافاصله متوجه منظور شما میشود.
— قابلیت انتقال: در سیستمهای مختلف، ممکن است HIGH به ۳.۳ ولت یا ۵ ولت اشاره کند، اما کد شما بدون تغییر کار میکند.
— کاهش خطا: جلوی استفاده اشتباه از اعداد دیگر (مثل ۲ یا -۱) را میگیرد.
برای روشن یا خاموش کردن یک LED یا رله:
digitalWrite(13, HIGH); // LED روشن میشود
digitalWrite(13, LOW); // LED خاموش میشود
برای بررسی فشرده شدن دکمه:
int buttonState = digitalRead(2);
if (buttonState == HIGH) {
// دکمه فشرده شده (بسته به مدار)
}
توضیح برای مبتدیها: وضعیت واقعی دکمه بستگی به نحوهی سیمکشی دارد. اگر از
INPUT_PULLUPاستفاده کنید، دکمه فشردهنشدهHIGHو فشردهشدهLOWاست. همیشه مدار خود را بررسی کنید!
هرچند pinMode() معمولاً از INPUT، OUTPUT و INPUT_PULLUP استفاده میکند، اما در برخی کتابخانههای پیشرفته، HIGH و LOW برای تنظیمات اولیه ولتاژ هم به کار میروند.
const int BUTTON_PIN = 2;
const int LED_PIN = 13;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); // دکمه با مقاومت داخلی
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState == LOW) { // دکمه فشرده شده
digitalWrite(LED_PIN, HIGH); // LED روشن
} else {
digitalWrite(LED_PIN, LOW); // LED خاموش
}
}
در این مثال، LOW نشان میدهد دکمه فشرده شده است (به دلیل استفاده از INPUT_PULLUP)، و HIGH LED را روشن میکند.
در واقع، LOW معادل عدد 0 و HIGH معادل عدد 1 است. اما: — هرگز نباید بنویسید digitalWrite(13, 1) — چون خوانایی کد را کم میکند.
— در شرطها، بهتر است مستقیماً از HIGH/LOW استفاده کنید، نه از اعداد.
این ثابتها برای پینهای آنالوگ (مثل A0) یا اعداد محاسباتی معنی ندارند. برای پینهای آنالوگ، از مقادیر عددی (۰ تا ۱۰۲۳ برای ورودی، ۰ تا ۲۵۵ برای خروجی PWM) استفاده میشود.
HIGH = ولتاژ بالا (روشن / ۱)LOW = ولتاژ پایین (خاموش / ۰)digitalWrite() و digitalRead() استفاده میشونداین مطلب بر اساس مستندات رسمی Arduino از بخش Variables – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، ثابت اعشاری (Floating Point Constant) به هر عددی گفته میشود که شامل یک نقطه اعشاری (.) باشد و بهصورت مستقیم در کد نوشته شود.
این اعداد بهطور خودکار توسط کامپایلر به عنوان نوع دادهی float در نظر گرفته میشوند — مگر اینکه مشخصاً به عنوان double تعریف شوند (که در آردوینو AVR همان float است).
توضیح برای مبتدیها: وقتی شما در کد عددی مثل
3.14یا0.001مینویسید، آردوینو آن را بهعنوان یک «ثابت اعشاری» تشخیص میدهد. این عدد در حافظه بهصورت خاصی ذخیره میشود که بتواند بخش اعشاری را هم نگه دارد — برخلاف اعداد صحیح مثل5که فقط برای اعداد کامل طراحی شدهاند.
در پروژههای آردوینو، اغلب با مقادیری سروکار داریم که نیاز به دقت اعشاری دارند: — دما (مثل ۲۳.۵ درجه)
— ولتاژ (مثل ۳.۳ ولت)
— فاصله (مثل ۱۲.۷ سانتیمتر)
— ثابتهای ریاضی (مثل π = ۳.۱۴۱۵۹)
بدون استفاده از ثابتهای اعشاری، نمیتوانیم این مقادیر را بهدرستی در کد بنویسیم.
در آردوینو، ثابت اعشاری را میتوان به چند شکل نوشت:
float pi = 3.14159;
float voltage = 5.0;
float small = 0.001;
⚠️ نکته مهم: برای اعداد صحیحی که میخواهید بهعنوان اعشاری در نظر گرفته شوند، حتماً .0 اضافه کنید:
float a = 5; // ممکن است به عنوان int در نظر گرفته شود (سپس تبدیل شود)
float b = 5.0; // قطعاً به عنوان float در نظر گرفته میشود
برای اعداد بسیار کوچک یا بسیار بزرگ، میتوانید از نماد علمی استفاده کنید:
float micro = 1e-6; // معادل 0.000001
float mega = 1e6; // معادل 1000000.0
float avogadro = 6.022e23;
در اینجا، e یا E به معنی «ضرب در ۱۰ به توان» است.
توضیح برای مبتدیها:
1e-6یعنی «۱ ضرب در ۱۰ به توان منفی ۶» = ۰٫۰۰۰۰۰۱. این روش برای نوشتن اعداد خیلی کوچک (مثل ثابت پلانک) یا خیلی بزرگ (مثل جمعیت جهان) بسیار راحتتر از نوشتن صفرهای زیاد است.
در این مثال، از یک ثابت اعشاری برای تبدیل مقدار خام سنسور به ولتاژ استفاده میشود:
const float REFERENCE_VOLTAGE = 5.0; // ولتاژ مرجع آردوینو
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A0);
float voltage = sensorValue * (REFERENCE_VOLTAGE / 1023.0);
Serial.print("ولتاژ: ");
Serial.print(voltage, 2); // نمایش با 2 رقم اعشار
Serial.println(" ولت");
delay(1000);
}
در اینجا، 5.0 و 1023.0 هر دو ثابتهای اعشاری هستند تا محاسبه بهدرستی بهصورت اعشاری انجام شود.
اگر عددی مثل 5 را بهعنوان مقدار اولیه برای یک float استفاده کنید، کامپایلر ابتدا آن را بهعنوان int در نظر میگیرد، سپس آن را به float تبدیل میکند. این کار معمولاً مشکلی ایجاد نمیکند، اما در محاسبات پیچیده یا هنگام استفاده از ماکروها ممکن است باعث خطاهای ظریف شود.
بنابراین، عادت کنید همیشه برای اعداد اعشاری از .0 استفاده کنید — حتی اگر بخش اعشاری صفر باشد.
ثابتهای اعشاری در آردوینو (مثل همه اعداد float) فقط دقتی حدود ۶ تا ۷ رقم معنیدار دارند. پس نوشتن 3.14159265358979323846 بیفایده است — چون فقط 3.141592 ذخیره میشود.
برای اجتناب از سردرگمی، ثابتها را با دقت واقعیشان بنویسید:
const float PI = 3.141592; // کافی است — بیشتر از این ذخیره نمیشود
float در نظر گرفته میشود.0 استفاده کنید1e-6) برای اعداد بسیار کوچک یا بزرگ استفاده کنیداین مطلب بر اساس مستندات رسمی Arduino از بخش Floating Point Constants – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، کلمهی کلیدی volatile برای تعریف متغیرهایی استفاده میشود که ممکن است توسط عوامل خارج از جریان عادی کد تغییر کنند — مثلاً توسط قطعات وقفه (Interrupts) یا سختافزار.
وقتی یک متغیر را volatile اعلام میکنید، به کامپایلر میگویید: «هر بار که این متغیر را استفاده میکنم، حتماً مقدار واقعی آن را از حافظه بخوان — آن را بهینهسازی نکن!»
توضیح برای مبتدیها: کامپایلر آردوینو گاهی برای سرعت بیشتر، مقادیر متغیرها را در ثباتهای داخلی پردازنده نگه میدارد و دوباره از RAM نمیخواند. این کار معمولاً خوب است، اما اگر یک وقفه (مثل فشردن دکمه) مقدار متغیر را عوض کند، کامپایلر متوجه نمیشود! با
volatile، مجبور میشود هر بار مقدار واقعی را بررسی کند — مثل این است که بگویید: «این متغیر زنده است، همیشه نگهش دار!»
بدون volatile، در دو موقعیت رایج با خطا مواجه میشوید: — وقتی یک متغیر در تابع وقفه (ISR) تغییر میکند و در loop() خوانده میشود.
— وقتی یک متغیر توسط سختافزار (مثل تایمر یا ماژول خارجی) بهروزرسانی میشود.
در این موارد، کامپایلر فکر میکند مقدار متغیر ثابت است و آن را بهینهسازی میکند — در نتیجه کد شما رفتار عجیبی دارد یا اصلاً کار نمیکند.
برای تعریف یک متغیر volatile، کافی است قبل از نوع داده، کلمهی volatile را بنویسید:
volatile int buttonPressCount = 0;
در این مثال، هر بار که دکمه فشرده میشود، یک وقفه فعال شده و شمارنده افزایش مییابد. این شمارنده باید volatile باشد:
const byte INTERRUPT_PIN = 2;
volatile int pressCount = 0; // ⚠️ حتماً volatile باشد!
void setup() {
pinMode(INTERRUPT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), countPress, FALLING);
Serial.begin(9600);
}
void countPress() {
pressCount++; // این تابع وقفه است — pressCount را تغییر میدهد
}
void loop() {
static int lastCount = 0;
if (pressCount != lastCount) {
Serial.print("دکمه فشرده شد: ");
Serial.println(pressCount);
lastCount = pressCount;
}
}
توضیح برای مبتدیها: اگر
pressCountراvolatileنکنید، ممکن است برنامه هرگز متوجه افزایش آن نشود — چون کامپایلر فکر میکند مقدار آن درloop()همیشه همان مقدار اولیه است! این یکی از رایجترین باگهای پنهان در پروژههای وقفه است.
اگر متغیری فقط در loop() یا توابع معمولی تغییر میکند، نیازی به volatile نیست. این کلمه کلیدی فقط زمانی لازم است که: — تابع وقفه (ISR) آن را تغییر میدهد، یا
— سختافزار مستقیماً به آن دسترسی دارد (مثل رجیسترها در برنامهنویسی پایینسطح).
استفاده بیدلیل از volatile باعث کاهش سرعت و افزایش حجم کد میشود — چون کامپایلر نمیتواند بهینهسازیهای معمول را انجام دهد.
شما میتوانید یک متغیر را هم const و هم volatile تعریف کنید:
const volatile byte* hardwareRegister = (byte*)0x1234;
این معمولاً در برنامهنویسی سطح پایین (مثل دسترسی مستقیم به رجیستر سختافزار) استفاده میشود — جایی که مقدار یک آدرس ثابت است، اما محتوای آن توسط سختافزار تغییر میکند. برای اکثر پروژههای مبتدی، نیازی به این ترکیب نیست.
volatile برای متغیرهایی است که توسط وقفه یا سختافزار تغییر میکننداین مطلب بر اساس مستندات رسمی Arduino از بخش volatile – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، کلمهی کلیدی static برای تعریف متغیرهایی استفاده میشود که محلی هستند (یعنی فقط در یک تابع قابل دسترسیاند)، اما مقدارشان بین فراخوانیهای متوالی تابع حفظ میشود.
بدون static، متغیرهای محلی هر بار که تابع فراخوانی میشود، دوباره ساخته و مقدار اولیهشان تنظیم میشود. اما با static، مقدار قبلی ذخیره میماند.
توضیح برای مبتدیها: تصور کنید یک دفترچه یادداشت شخصی دارید که فقط شما میتوانید به آن نگاه کنید (مثل یک متغیر محلی). بدون
static، هر بار که وارد اتاق میشوید، دفترچه را پاک میکنید و دوباره شروع میکنید. اما باstatic، دفترچه همانطور که بود باقی میماند — پس میتوانید از آخرین یادداشت خود ادامه دهید!
در بسیاری از پروژهها، نیاز داریم یک تابع بتواند «خاطرهای» از فراخوانی قبلی داشته باشد — مثلاً: — شمارش تعداد دفعاتی که یک تابع فراخوانی شده است.
— ذخیره آخرین وضعیت یک سنسور برای مقایسه با مقدار جدید.
— پیادهسازی تایمرهای ساده بدون استفاده از متغیرهای سراسری.
استفاده از static به شما امکان میدهد این کار را بدون ایجاد متغیر سراسری (که RAM را اشغال میکند و کد را شلوغ میکند) انجام دهید.
برای تبدیل یک متغیر محلی به متغیر static، کافی است قبل از نوع داده، کلمهی static را بنویسید:
void myFunction() {
static int counter = 0; // فقط یک بار مقداردهی میشود
counter++;
Serial.println(counter);
}
اولین بار که myFunction() فراخوانی میشود، counter برابر ۱ میشود.
دومین بار: ۲، سومین بار: ۳ و همینطور ادامه مییابد — چون مقدار قبلی حفظ شده است.
void checkSensor() {
static unsigned long lastCheck = 0;
static int callCount = 0;
callCount++;
unsigned long now = millis();
if (now - lastCheck > 5000) { // هر ۵ ثانیه یک بار
int value = analogRead(A0);
Serial.print("بررسی شماره ");
Serial.print(callCount);
Serial.print(" — مقدار سنسور: ");
Serial.println(value);
lastCheck = now;
}
}
void loop() {
checkSensor(); // هر بار که فراخوانی میشود، callCount افزایش مییابد
delay(100);
}
توضیح برای مبتدیها: بدون
static، هر بار کهcheckSensor()فراخوانی میشد،callCountدوباره صفر میشد و همیشه فقط «۱» چاپ میکرد. اما باstatic، این متغیر فقط یک بار ساخته میشود و مقدارش بین فراخوانیها زنده میماند.
| ویژگی | متغیر static (محلی) | متغیر سراسری |
|---|---|---|
| دامنه | فقط داخل یک تابع | در تمام کد قابل دسترسی |
| عمر (Lifetime) | تا پایان برنامه | تا پایان برنامه |
| مصرف RAM | مثل سراسری (در RAM ثابت) | در RAM ثابت |
| امنیت و سازماندهی | عالی — فقط تابع میتواند آن را ببیند | ضعیف — هر تابعی میتواند آن را تغییر دهد |
خط مقداردهی اولیه (مثل static int x = 0;) فقط اولین بار که تابع اجرا میشود، انجام میشود. در فراخوانیهای بعدی، این خط نادیده گرفته میشود — حتی اگر مقدار را تغییر داده باشید!
void test() {
static int x = 10; // فقط اولین بار اجرا میشود
x++;
Serial.println(x);
}
اولین فراخوانی: ۱۱
دومین فراخوانی: ۱۲
سومین فراخوانی: ۱۳
... و هرگز دوباره به ۱۰ بازنمیگردد.
بسیاری از مبتدیها برای ذخیره وضعیت، متغیرهای سراسری تعریف میکنند. این کار RAM را اشغال میکند و کد را شلوغ میکند.
اما با static، میتوانید همان کار را درون تابع انجام دهید — بدون اینکه نام متغیر در بقیه کد دیده شود. این روش، کد شما را ماژولار، ایمن و حرفهای میکند.
static متغیرهای محلی را «حافظهدار» میکنداین مطلب بر اساس مستندات رسمی Arduino از بخش static – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، دامنه (Scope) به معنی محدودهی دید یک متغیر در کد است — یعنی بخشی از برنامه که در آن متغیر قابل استفاده و شناختهشده است.
هر متغیر فقط در دامنهای که تعریف شده، «زنده» است. خارج از آن دامنه، گویی وجود ندارد!
توضیح برای مبتدیها: فرض کنید یک اسم دوست دارید، مثل «سارا». اگر این اسم را فقط داخل یک اتاق فریاد بزنید، کسی بیرون از اتاق آن را نمیشنود. در برنامهنویسی هم همینطور است: اگر متغیری را داخل یک تابع تعریف کنید، فقط در همان تابع قابل استفاده است — نه در جاهای دیگر کد.
درک دامنه به شما کمک میکند: — از خطاهای «متغیر تعریف نشده» جلوگیری کنید.
— کدهای تمیزتر و سازمانیافتهتر بنویسید.
— از تداخل ناخواسته بین متغیرها جلوگیری کنید.
— حافظه را بهینهتر مدیریت کنید (چون متغیرهای محلی پس از پایان تابع از حافظه پاک میشوند).
اگر متغیری را خارج از هر تابع (معمولاً در بالای کد، قبل از setup()) تعریف کنید، آن متغیر سراسری است.
یعنی در همه جای کد — چه در setup() و چه در loop() و چه در سایر توابع — قابل دسترسی است.
int globalCounter = 0; // متغیر سراسری
void setup() {
globalCounter = 10; // قابل دسترسی
}
void loop() {
globalCounter++; // قابل دسترسی
}
اگر متغیری را داخل یک تابع یا داخل یک بلوک کد (مثل داخل حلقه یا شرط) تعریف کنید، آن متغیر محلی است.
یعنی فقط در همان بلوک قابل استفاده است و خارج از آن «نامرئی» است.
void setup() {
int localVar = 5; // متغیر محلی — فقط در setup قابل دسترسی
Serial.println(localVar);
}
void loop() {
// Serial.println(localVar); // ❌ خطا: localVar was not declared in this scope
}
حتی داخل یک بلوک کوچک هم دامنه جداگانهای وجود دارد:
void loop() {
if (true) {
int temp = 100; // فقط داخل این بلوک if زنده است
}
// Serial.println(temp); // ❌ خطا: temp خارج از دامنه است
}
توضیح برای مبتدیها: هر بار که یک متغیر محلی تعریف میشود، آردوینو برای آن فضایی در RAM اختصاص میدهد. وقتی از آن بلوک خارج میشوید (مثلاً تابع تمام میشود)، آن فضا آزاد میشود. این باعث میشود RAM شما برای کارهای بعدی آماده بماند — خصوصاً در آردوینو Uno که فقط ۲ کیلوبایت RAM دارد!
در این مثال، یک شمارندهی سراسری برای کل سیستم و یک متغیر محلی برای محاسبهی موقت استفاده شده است:
const int SENSOR_PIN = A0;
int totalReadings = 0; // سراسری — برای ذخیره مجموع خواندنها
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(SENSOR_PIN); // محلی — فقط برای این خواندن
totalReadings += sensorValue;
Serial.print("مقدار فعلی: ");
Serial.println(sensorValue); // ✅ در دامنه است
delay(1000);
}
// sensorValue اینجا وجود ندارد — پس RAM آزاد شده است
اگرچه متغیرهای سراسری راحت هستند، اما: — کد شما را پیچیده میکنند (هر تابعی میتواند آنها را تغییر دهد).
— خطاگیری را سخت میکنند (نمیدانید کدام تابع مقدار را عوض کرده).
— RAM را همیشه اشغال نگه میدارند.
قانون طلایی: هر متغیری را در کوچکترین دامنهی ممکن تعریف کنید — ترجیحاً محلی.
گاهی ممکن است یک متغیر محلی و یک متغیر سراسری نام یکسان داشته باشند. در این صورت، متغیر محلی متغیر سراسری را پنهان میکند (shadowing):
int value = 10; // سراسری
void loop() {
int value = 20; // محلی — سراسری را پنهان میکند
Serial.println(value); // چاپ میکند: 20
}
این رفتار گاهی عمدی است، اما اغلب باعث سردرگمی میشود. پس از نامهای متفاوت استفاده کنید یا از قراردادهای نامگذاری (مثل g_value برای سراسری) کمک بگیرید.
این مطلب بر اساس مستندات رسمی Arduino از بخش scope – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، کلمهی کلیدی const برای تعریف متغیرهای ثابت استفاده میشود — یعنی متغیرهایی که پس از مقداردهی اولیه، دیگر قابل تغییر نیستند.
این کار باعث میشود کد شما خواناتر، ایمنتر و کمخطاتر شود، چون جلوی تغییر تصادفی مقادیر مهم را میگیرد.
توضیح برای مبتدیها: فرض کنید یک عدد مهم دارید، مثل شماره پین LED که همیشه ۱۳ است. اگر این عدد را در یک متغیر معمولی ذخیره کنید، ممکن است بعداً در کد اشتباهی آن را تغییر دهید. اما اگر از
constاستفاده کنید، کامپایلر هر تلاش برای تغییر آن را به عنوان خطا نشان میدهد — مثل این است که بگویید: «این عدد مقدس است، دست نزن!»
استفاده از const چند مزیت دارد: — جلوگیری از خطا: تغییر تصادفی مقادیر ثابت جلوگیری میشود.
— بهبود خوانایی کد: هر کس کد شما را بخواند، میفهمد که این مقدار قرار نیست تغییر کند.
— بهینهسازی حافظه: در آردوینو، متغیرهای const معمولاً در حافظهی برنامه (Flash) ذخیره میشوند، نه در RAM — پس RAM شما آزاد میماند.
برای تعریف یک متغیر ثابت، کافی است قبل از نوع داده، کلمهی const را بنویسید:
const int ledPin = 13;
const float pi = 3.14159;
const char version = A;
اگر سعی کنید بعداً مقدار آن را تغییر دهید، کامپایلر خطا میدهد:
const int sensorPin = A0;
sensorPin = A1; // ❌ خطای کامپایل: assignment of read-only variable
در اکثر پروژههای آردوینو، پینها و مقادیر آستانه (threshold) ثابت هستند. استفاده از const برای آنها استاندارد صنعتی است:
const int BUTTON_PIN = 2;
const int LED_PIN = 13;
const int TEMP_THRESHOLD = 30; // آستانه دما برای هشدار
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
}
void loop() {
int temperature = readTemperature();
if (temperature > TEMP_THRESHOLD) {
digitalWrite(LED_PIN, HIGH);
Serial.println("هشدار دما!");
}
}
توضیح برای مبتدیها: توجه کنید که نام متغیرهای
constمعمولاً با حروف بزرگ نوشته میشود (مثلLED_PIN). این یک قرارداد استاندارد در برنامهنویسی است که به خواننده کد نشان میدهد: «این یک مقدار ثابت است».
در آردوینو، دو راه برای تعریف ثابت وجود دارد: — #define NAME value (پیشپردازنده)
— const type NAME = value; (متغیر ثابت)
تفاوتهای کلیدی: — const نوع داده دارد (مثل int یا float)، اما #define نوع ندارد.
— const فقط در محدودهی خودش (مثلاً داخل یک تابع یا سراسری) قابل دسترسی است، اما #define همیشه سراسری است.
— const ایمنتر است، چون کامپایلر میتواند خطاهای نوعگذاری را تشخیص دهد.
مثال مقایسهای:
// روش قدیمی (کمتر توصیه میشود)
#define PI 3.14159
// روش مدرن و ایمن (توصیه شده)
const float PI = 3.14159;
در آردوینو، متغیرهای const بهطور خودکار در حافظهی برنامه (Flash) ذخیره میشوند، نه در RAM محدود. این ویژگی بسیار مهم است، چون: — RAM آردوینو Uno فقط ۲ کیلوبایت است.
— با استفاده از const برای مقادیر ثابت، RAM را برای دادههای پویا (مثل سنسورها یا شمارندهها) آزاد نگه میدارید.
اگر آرایهای دارید که هیچوقت تغییر نمیکند (مثل لیست رنگها یا پیامهای ثابت)، آن را با const تعریف کنید:
const char* messages[] = {
"آماده",
"در حال کار",
"خطا!"
};
این کار هم RAM را ذخیره میکند و هم جلوی تغییر تصادفی پیامها را میگیرد.
const برای تعریف مقادیر ثابت استفاده میشودconst در Flash ذخیره میشوند — نه در RAM#define استاین مطلب بر اساس مستندات رسمی Arduino از بخش const – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی word یک نوع عدد صحیح است که دقیقاً ۲ بایت (۱۶ بیت) حافظه مصرف میکند و فقط اعداد مثبت یا صفر را ذخیره میکند.
محدودهی مقادیر قابل ذخیره در آن:
۰ تا ۶۵,۵۳۵
این نوع داده در تمام بردهای رایج آردوینو (از جمله Uno، Nano، Mega، ESP32 و Due) همیشه ۲ بایت است — برخلاف int که در برخی بردها ۴ بایت میشود.
توضیح برای مبتدیها: کلمهی «word» در دنیای کامپیوتر به معنی «یک واحد دادهی ۱۶ بیتی» است. در آردوینو، این کلمه بهصورت یک نوع داده تعریف شده تا به شما امکان دهد اعداد مثبت ۱۶ بیتی را بدون نگرانی از تغییر اندازه در بردهای مختلف ذخیره کنید. فکر کنید مثل یک جعبهی ۱۶ تکهای که همهی تکهها فقط برای عدد استفاده میشوند — پس بیشترین عدد ممکن (۶۵,۵۳۵) جا میشود، اما هیچوقت نمیتواند منفی باشد.
در آردوینو، چند نوع داده وجود دارد که ممکن است شبیه word به نظر برسند:
unsigned int: در بردهای AVR (مثل Uno) همان word است (۲ بایت، ۰–۶۵,۵۳۵). اما در ESP32 یا Due، unsigned int ۴ بایت است — پس با word فرق میکند!uint16_t: این نوع از کتابخانههای استاندارد C++ آمده و دقیقاً همان word است. در واقع، در آردوینو: typedef uint16_t word;int: میتواند منفی باشد و در Uno محدودهی کوچکتری دارد (−۳۲,۷۶۸ تا +۳۲,۷۶۷).بنابراین، اگر نیاز دارید که متغیر شما همیشه ۲ بایت باشد و فقط اعداد مثبت ذخیره کند، word گزینهی ایمنتری نسبت به unsigned int است — چون اندازهاش در تمام بردها ثابت است.
word sensorValue = 1023; // حداکثر مقدار آنالوگ
word pwmValue = 255; // مقدار PWM
word counter = 50000; // شمارندهی بزرگ (کمتر از 65535)
بعضی سنسورها (مثل سنسورهای فشار یا دما با دقت بالا) دادههای ۱۶ بیتی ارسال میکنند. برای ذخیرهی این داده، word گزینهی طبیعی است:
// فرض کنید دو بایت از سنسور خوانده شدهاند
byte highByte = 0x12;
byte lowByte = 0x34;
// ترکیب دو بایت به یک عدد 16 بیتی
word sensorData = (highByte << 8) | lowByte; // sensorData = 0x1234 = 4660
Serial.println(sensorData);
توضیح برای مبتدیها: عبارت
(highByte << 8)یعنی «بایت بالا را ۸ بیت به چپ منتقل کن» — یعنی آن را در جای دهگان بایت قرار بده. سپس با|(یا بیتی) بایت پایین را اضافه میکنیم. نتیجه یک عدد ۱۶ بیتی کامل است که دقیقاً در یکwordجا میشود.
اگر کد شما باید هم روی Arduino Uno و هم روی ESP32 اجرا شود، استفاده از word تضمین میکند که متغیر شما همیشه ۲ بایت باشد. در مقابل، unsigned int در Uno ۲ بایت است، اما در ESP32 ۴ بایت — که میتواند باعث خطا در ارتباطات سریال یا ذخیرهسازی داده شود.
چون word بدون علامت است، اگر مقدار آن را کم کنید و از صفر پایینتر برود، به انتهای محدوده بر میگردد (سرریز معکوس):
word x = 0;
x = x - 1; // حالا x = 65535!
بنابراین، در حلقههای کاهشی یا محاسباتی که ممکن است نتیجه منفی شود، از word استفاده نکنید — یا حتماً قبل از کم کردن، مقدار را بررسی کنید.
word = ۲ بایت، فقط ۰ تا ۶۵,۵۳۵uint16_t است — ولی نام سادهتری برای کاربران آردوینو داردunsigned int استاین مطلب بر اساس مستندات رسمی Arduino از بخش word – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، کلمهی کلیدی void یک نوع دادهی خاص است که به معنی «هیچ چیز» یا «بیمقدار» است.
این نوع داده هرگز برای تعریف متغیر استفاده نمیشود. بلکه فقط در تعریف توابع به کار میرود تا نشان دهد آن تابع هیچ مقداری را برنمیگرداند.
توضیح برای مبتدیها: تصور کنید یک دستور العمل دارید که میگوید: «چراغ را روشن کن». این دستور یک کار انجام میدهد، اما پاسخی مثل «چراغ روشن شد» یا عددی به شما نمیدهد. در برنامهنویسی، چنین دستوری با
voidتعریف میشود — یعنی فقط کاری انجام میدهد، ولی چیزی برنمیگرداند.
در زبانهای برنامهنویسی، هر تابع باید مشخص کند که چه نوع خروجیای دارد. اگر تابعی خروجی نداشته باشد، باید از void استفاده کرد تا کامپایلر بداند که انتظار مقدار بازگشتی نداشته باشد.
این کار باعث میشود کد شما منطقیتر، خواناتر و کمخطاتر باشد.
در آردوینو، دو تابع اصلی setup() و loop() هر دو از نوع void هستند:
void setup() {
// تنظیمات اولیه — هیچ چیزی برنمیگرداند
pinMode(13, OUTPUT);
}
void loop() {
// حلقه اصلی — هیچ چیزی برنمیگرداند
digitalWrite(13, HIGH);
delay(1000);
}
همچنین میتوانید توابع شخصی خود را با void تعریف کنید:
void blinkLED(int pin, int duration) {
digitalWrite(pin, HIGH);
delay(duration);
digitalWrite(pin, LOW);
delay(duration);
// این تابع فقط یک کار انجام میدهد — چیزی برنمیگرداند
}
int, float, String و...: تابع مقداری را محاسبه کرده و برمیگرداند.void: تابع فقط یک کار انجام میدهد (مثل روشن کردن LED، ارسال داده، تنظیم پین) و هیچ مقداری برنمیگرداند.مثال مقایسهای:
// تابعی که مقدار برمیگرداند
int add(int a, int b) {
return a + b; // یک عدد صحیح برمیگرداند
}
// تابعی که چیزی برنمیگرداند
void printSum(int a, int b) {
Serial.println(a + b); // فقط چاپ میکند — return ندارد
}
توضیح برای مبتدیها: اگر در تابعی از دستور
returnاستفاده میکنید، باید نوع دادهی تابع را مشخص کنید (مثلint). اما اگر تابع شما فقط کاری انجام میدهد و نیازی به بازگرداندن مقدار نیست، حتماً ازvoidاستفاده کنید. در توابعvoidنمیتوانید ازreturn value;استفاده کنید — فقط میتوانید باreturn;از تابع خارج شوید (اختیاری).
void resetSensor() {
digitalWrite(sensorResetPin, LOW);
delay(10);
digitalWrite(sensorResetPin, HIGH);
Serial.println("سنسور ریست شد.");
// هیچ مقداری برنمیگرداند — فقط یک سری دستور اجرا میکند
}
void loop() {
// ... خواندن داده ...
if (errorDetected) {
resetSensor(); // فراخوانی تابع void
}
}
شما نمیتوانید متغیری از نوع void تعریف کنید:
void x = 5; // ❌ خطای کامپایل! void برای متغیر نیست
اگر چنین کدی بنویسید، کامپایلر خطایی مانند «variable or field x declared void» نشان میدهد.
در آردوینو، دو تابع اصلی setup() و loop() بخشی از ساختار پایهی هر اسکچ هستند. این توابع حتماً باید از نوع void باشند — چون سیستم آردوینو انتظار ندارد آنها مقداری را بازگردانند. اگر نوع دیگری قرار دهید، کد کامپایل نمیشود.
void یک نوع داده برای «عدم بازگشت مقدار» استsetup() و loop() همیشه void هستندvoid استفاده کنیداین مطلب بر اساس مستندات رسمی Arduino از بخش void – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی unsigned long یک نوع عدد صحیح است که فقط اعداد مثبت یا صفر را ذخیره میکند و در تمام بردهای رایج آردوینو (از جمله Uno، Nano، ESP32 و Due) دقیقاً ۴ بایت (۳۲ بیت) حافظه مصرف میکند.
محدودهی مقادیر قابل ذخیره در یک متغیر unsigned long:
۰ تا ۴,۲۹۴,۹۶۷,۲۹۵
این محدوده تقریباً دو برابر بزرگتر از محدودهی long (که شامل اعداد منفی هم میشود) است و برای کارهایی که نیاز به اعداد بسیار بزرگ و فقط مثبت دارند، گزینهی ایدهآلی است.
توضیح برای مبتدیها: فکر کنید یک شمارنده دارید که میخواهد ثانیههای گذشته از سال ۲۰۰۰ را بشمارد. این عدد خیلی بزرگ میشود — بیشتر از ۲ میلیارد! اگر از
longاستفاده کنید، نصف فضای عددی شما برای اعداد منفی هدر میرود. اما باunsigned long، همهی فضای ۴ بایتی فقط برای اعداد مثبت استفاده میشود — پس شمارندهتان تا ۴ میلیارد ثانیه (بیش از ۱۳۶ سال!) کار میکند.
در بسیاری از پروژهها، اعدادی که استفاده میکنیم همیشه مثبت هستند و از محدودهی unsigned int (در Uno: ۰–۶۵,۵۳۵) فراتر میروند. مثالهای رایج:
millis() بعد از ۴۹ روز سرریز میشود — اما تا آن زمان، مقدار آن در محدودهی unsigned long است.unsigned long currentTime = millis(); // زمان فعلی سیستم
unsigned long totalEvents = 1000000UL; // شمارندهی بزرگ
unsigned long deviceId = 3487294823UL; // شناسه دستگاه
توجه: برای تعریف یک عدد ثابت به عنوان unsigned long، بهتر است پسوند UL یا ul به آن اضافه کنید (ترجیحاً UL بزرگ):
unsigned long bigNumber = 4000000000UL; // مشخص میکند که این عدد unsigned long است
تابع millis() خروجی 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);
}
توضیح برای مبتدیها: چرا
elapsedTimeهمیشه مثبت است؟ چون هر دوcurrentTimeوstartTimeاز نوعunsigned longهستند وcurrentTimeهمیشه بزرگتر یا مساویstartTimeاست. حتی اگرmillis()سرریز کند (بعد از ۴۹ روز)، تفریق بهدرستی کار میکند — چون حساب پیمانهای (modulo) انجام میشود.
| نوع داده | اندازه | محدوده (در تمام بردها) |
|---|---|---|
| unsigned int | 2 بایت (در Uno) | 0 تا 65,535 |
| long | 4 بایت | −2,147,483,648 تا +2,147,483,647 |
| unsigned long | 4 بایت | 0 تا 4,294,967,295 |
توابع millis() و micros() همیشه unsigned long برمیگردانند. اگر خروجی آنها را در یک int یا حتی long ذخیره کنید، ممکن است: — در Uno، پس از ۳۲ ثانیه سرریز شود (اگر از int استفاده کنید)
— در محاسبات، عدد منفی تولید شود (اگر از long استفاده کنید و مقدار از ۲ میلیارد بیشتر شود)
بنابراین، همیشه از unsigned long برای ذخیرهی زمان استفاده کنید.
در حالی که unsigned int در بردهای مختلف اندازهی متفاوتی دارد، unsigned long در تمام پلتفرمهای آردوینو همیشه ۴ بایت است.
این ویژگی باعث میشود کدهای شما قابل انتقالتر (portable) باشند. اگر به اطمینان نیاز دارید که متغیر شما ۴ بایت است و فقط مثبت باشد، unsigned long گزینهی ایمنتری نسبت به unsigned int است.
unsigned long = ۴ بایت، فقط ۰ تا ۴,۲۹۴,۹۶۷,۲۹۵millis() و micros() استفاده شوداین مطلب بر اساس مستندات رسمی Arduino از بخش unsigned long – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی unsigned int یک نوع عدد صحیح است که فقط میتواند اعداد مثبت یا صفر را ذخیره کند — هیچوقت نمیتواند عدد منفی باشد.
این نوع داده در بردهای مختلف آردوینو اندازهی متفاوتی دارد:
تفاوت اصلی آن با int این است که unsigned int فضای علامت (sign bit) را برای ذخیرهی مقدار عددی استفاده میکند — پس محدودهی مثبت آن دو برابر بزرگتر از int است.
توضیح برای مبتدیها: فرض کنید یک عدد ۲ بایتی دارید. در
int، یکی از بیتها فقط برای تشخیص «مثبت یا منفی» استفاده میشود، پس فقط ۱۵ بیت برای عدد باقی میماند. اما درunsigned int، همهی ۱۶ بیت برای عدد استفاده میشود — پس میتوانید اعداد بزرگتری ذخیره کنید، اما هیچوقت نمیتوانید عدد منفی داشته باشید.
از unsigned int زمانی استفاده میشود که: — مطمئن هستید عدد شما هرگز منفی نخواهد شد (مثل تعداد دور موتور، زمان سپریشده، مقدار سنسور)
— نیاز به محدودهی بزرگتری نسبت به int دارید (مثلاً در Uno، تا ۶۵ هزار به جای ۳۲ هزار)
— میخواهید منظور خود را بهوضوح در کد نشان دهید: «این عدد همیشه مثبت است».
unsigned int counter = 0;
unsigned int sensorValue = 1023; // حداکثر مقدار آنالوگ در آردوینو
unsigned int elapsedTime = 50000; // میلیثانیه — بیشتر از محدوده int در Uno
فرض کنید میخواهید تعداد بارهایی که یک سنسور فعال میشود را در یک روز بشمارید. این عدد ممکن است از ۳۲,۷۶۷ بیشتر شود — پس از unsigned int استفاده میکنیم:
unsigned int activationCount = 0;
void loop() {
if (digitalRead(sensorPin) == HIGH) {
activationCount++; // میتواند تا 65535 برسد (در Uno)
delay(100); // جلوگیری از نوسان
}
}
| نوع داده | اندازه (Uno) | محدوده (Uno) |
|---|---|---|
| int | 2 بایت | −32,768 تا +32,767 |
| unsigned int | 2 بایت | 0 تا 65,535 |
| long | 4 بایت | −2,147,483,648 تا +2,147,483,647 |
توضیح برای مبتدیها: اگر عدد شما همیشه مثبت است و در Uno از ۳۲ هزار بیشتر میشود، اما از ۶۵ هزار کمتر است،
unsigned intگزینهی ایدهآلی است. اگر از ۶۵ هزار هم بیشتر شد، باید ازlongیاunsigned longاستفاده کنید.
اگر یک متغیر unsigned int را کم کنید و به صفر برسد، دوباره به بزرگترین مقدار خود برمیگردد (سرریز معکوس):
unsigned int x = 0;
x = x - 1; // حالا x = 65535! (در Uno)
بنابراین، در حلقههایی مثل for (unsigned int i = 10; i >= 0; i--)، شرط i >= 0 همیشه true است — چون unsigned int هرگز منفی نمیشود! این یکی از رایجترین باگهای مبتدیهاست.
اگر کد شما را روی Uno مینویسید و بعد روی ESP32 اجرا میکنید، ممکن است متوجه نشوید که unsigned int در ESP32 ۴ بایت است. این میتواند باعث مشکلات ظریفی در حافظه یا محاسبات شود.
اگر به اندازهی دقیق نیاز دارید، بهتر است از انواع ثابتالاندازه مثل uint16_t یا uint32_t استفاده کنید.
unsigned int فقط اعداد ≥ ۰ را ذخیره میکندintاین مطلب بر اساس مستندات رسمی Arduino از بخش unsigned int – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
در آردوینو، نوع دادهی unsigned char یک نوع عددی است که دقیقاً یک بایت (۸ بیت) حافظه مصرف میکند و فقط میتواند اعداد مثبت یا صفر را ذخیره کند.
محدودهی مقادیر قابل ذخیره در آن:
۰ تا ۲۵۵
برای درک بهتر: چون ۸ بیت داریم، میتوانیم 2^8 = 256 حالت مختلف داشته باشیم — از ۰ تا ۲۵۵.
در آردوینو دو نوع char وجود دارد:
char (معمولی): میتواند اعداد منفی و مثبت را ذخیره کند → محدوده: −۱۲۸ تا +۱۲۷unsigned char: فقط اعداد مثبت یا صفر → محدوده: ۰ تا ۲۵۵چرا این تفاوت وجود دارد؟ چون در char معمولی، یکی از ۸ بیت برای نشان دادن «علامت» (مثبت یا منفی) استفاده میشود. اما در unsigned char، همهی ۸ بیت برای ذخیرهی مقدار عددی استفاده میشوند — پس میتواند اعداد بزرگتری را نگه دارد، اما هیچوقت منفی نیست.
توضیح برای مبتدیها: فکر کنید یک جعبهی ۸ تکهای دارید که هر تکه میتواند ۰ یا ۱ باشد. اگر بخواهید عدد منفی هم نشان دهید، یکی از تکهها را فقط برای «علامت» استفاده میکنید (مثلاً ۰ = مثبت، ۱ = منفی). اما اگر فقط عدد مثبت نیاز دارید، همهی ۸ تکه را برای عدد استفاده میکنید — پس عدد بزرگتری جا میشود!
زمانی از unsigned char استفاده میکنیم که: — مطمئن هستیم عدد هرگز منفی نمیشود (مثل مقدار سنسور، شدت نور LED، ولتاژ)
— نیاز به ذخیرهی عددی بین ۰ تا ۲۵۵ داریم
— میخواهیم حافظه را ذخیره کنیم (چون فقط ۱ بایت مصرف میکند)
در واقع، unsigned char در آردوینو همان نوع دادهی byte است! این دو کاملاً قابل جایگزینی هستند و هیچ تفاوتی در عملکرد یا حجم حافظه ندارند.
unsigned char value1 = 200;
byte value2 = 200; // دقیقاً همان چیزی است!
توضیح برای مبتدیها: چرا دو نام برای یک چیز؟ چون
byteبرای کاربران آردوینو طراحی شده (خواناتر است)، اماunsigned charاز استاندارد زبان C++ آمده است. هر دو یکی هستند — مثل اینکه یک چیز را هم «سیب» و هم «میوه» صدا کنید!
unsigned char brightness = 150; // روشنایی LED (0 تا 255)
unsigned char sensorValue = 0; // مقدار سنسور
unsigned char red = 255; // مولفه قرمز در رنگ RGB
تابع analogWrite() فقط اعداد ۰ تا ۲۵۵ را میپذیرد. پس استفاده از unsigned char کاملاً منطقی است:
unsigned char ledPin = 9;
unsigned char brightness = 200;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
analogWrite(ledPin, brightness); // brightness باید بین 0 تا 255 باشد
}
هر دو یکسان هستند، اما: — اگر کد شما برای آموزش یا پروژههای فارسیزبان است، از byte استفاده کنید — چون خواناتر و سادهتر است.
— اگر کد شما باید با کتابخانههای استاندارد C++ سازگار باشد، unsigned char گزینهی بهتری است.
در پروژههای شخصی، هر کدام را که دوست دارید انتخاب کنید — اما در یک پروژه، از یکی از آنها استفاده کنید تا کد یکدست باشد.
وقتی با سنسورهای دیجیتال (مثل سنسورهای I2C یا UART) کار میکنید، اغلب دادهها به صورت بایتهای خام دریافت میشوند. در این موارد، unsigned char یا byte گزینهی طبیعی برای ذخیرهی هر بایت است:
unsigned char receivedData = Wire.read(); // خواندن یک بایت از سنسور I2C
unsigned char = ۱ بایت، فقط ۰ تا ۲۵۵byte است — فقط نام متفاوتی دارداین مطلب بر اساس مستندات رسمی Arduino از بخش unsigned char – Language Reference تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.