🔵 Arduino · درس ۴

زمان‌بندی بدون delay با millis

یاد می‌گیری برنامه را بدون توقف طولانی اجرا کنی تا چند کار هم‌زمان جلو برود.

⏱ ۱۶ دقیقه 🌱 آسان ⭐ +۳۰ XP 🧠 کوئیز الزامی
🎯
بعد از این درس

قراره چی یاد بگیری؟

  • مشکل blocking بودن delay را توضیح بدهی.
  • با millis چند کار دوره‌ای را بدون توقف طولانی زمان‌بندی کنی.
  • الگوی تفاضل زمان با unsigned long را به جای مقایسه مستقیم مطلق بفهمی.

مشکل delay

delay(1000) ساده است ولی در آن یک ثانیه، کد اصلی هیچ کار دیگری انجام نمی‌دهد. برای Blink ساده اشکالی ندارد؛ اما ربات باید همزمان دکمه اضطراری، سنسور و موتور را بررسی کند.

راه بهتر برای بسیاری از کارهای دوره‌ای استفاده از millis() است:

unsigned long previousBlink = 0;
const unsigned long interval = 500;
bool ledState = false;

void loop() {
  unsigned long now = millis();

  if (now - previousBlink >= interval) {
    previousBlink = now;
    ledState = !ledState;
    digitalWrite(LED_BUILTIN, ledState);
  }

  readEmergencyButton();
  readSensors();
}

برنامه منتظر نمی‌ماند؛ هر دور loop سریع بررسی می‌کند آیا زمان کار دوره‌ای رسیده یا نه.

چرا تفاضل زمان؟

millis() بعد از مدت طولانی سرریز (wrap around) می‌کند. الگوی now - previous >= interval با نوع unsigned در بسیاری از کاربردهای Arduino این سرریز را درست تحمل می‌کند؛ مقایسه‌های ساده مثل now > previous + interval می‌توانند در مرز سرریز مشکل‌ساز شوند.

چند تایمر نرم‌افزاری

برای Blink، خواندن سنسور و ارسال Log می‌توانی سه previous... مستقل داشته باشی. هر کار interval خودش را دارد:

LED:      هر 500ms
Sensor:   هر 50ms
Telemetry:هر 1000ms

این هنوز سیستم‌عامل چندوظیفه‌ای نیست؛ همه کارها در همان loop اجرا می‌شوند. اگر یکی از توابع خودش ۳ ثانیه Block کند، بقیه هم دیر می‌شوند.

محدودیت مهم: کارهای طولانی هنوز Block می‌کنند

استفاده از millis() فقط وقتی مفید است که خود کارهایی که در loop() صدا می‌زنی کوتاه باشند. اگر تابعی داخل خودش چند ثانیه منتظر بماند، فایل بزرگی بخواند یا یک حلقه طولانی بدون خروج اجرا کند، بقیه زمان‌بندی‌ها باز هم دیر می‌شوند. برای پروژه‌های ساده تلاش کن هر دور loop() سریع تمام شود و وضعیت کارهای طولانی را در چند مرحله نگه داری. این طرز فکر بعدا مقدمه خوبی برای State Machine است؛ یعنی به جای «صبر کن تا کار تمام شود»، وضعیت فعلی را نگه می‌داریم و در دور بعد ادامه می‌دهیم.

تمرین

برنامه‌ای طراحی کن که LED هر ۵۰۰ms تغییر کند ولی سنسور هر ۱۰۰ms خوانده شود. روی کاغذ Timeline دو ثانیه‌ای بکش و زمان اجرای هر کار را علامت بزن. سپس کد را با دو متغیر previous مستقل پیاده کن و از Serial برای ثبت زمان نمونه سنسور استفاده کن.

🃏
مرور سریع

فلش کارت‌ها

۱ / ۳
🧠
برای تکمیل درس لازمه

آزمون کوتاه همین درس

حد نصاب ۷۰٪

برای عبور از درس، مفهوم را روی یک موقعیت واقعی به کار ببر؛ جواب‌ها از حفظ یک جمله نیستند.

۱

مشکل اصلی delay(3000) در رباتی که باید دکمه اضطراری را سریع بخواند چیست؟

۲ امتیاز
۲

الگوی now - previous >= interval برای زمان‌بندی غیرمسدودکننده رایج است.

۱ امتیاز
۳

جای خالی را برای تست رسیدن زمان کامل کن.

۲ امتیاز
if (now - previous _____ interval) { جای خالی 
  previous = now;
}
۳ سوال هنوز جواب نداره.
🔗
برای عمیق‌تر شدن

منابع تکمیلی