
در آردوینو، کلمهی کلیدی 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 تهیه شده است، با توضیحات سادهشده، مثالهای کاربردی و نکات طلایی منحصربهفرد برای جامعه فارسیزبان.
برچسب های مهم