🎓 آزمون تخصصی

آزمون پیشرفته برنامه‌نویسی Arduino

سنجش مهارت‌های حرفه‌ای در طراحی سیستم‌های Embedded و Non-Blocking
⏱ مدت زمان ۱۲۰ دقیقه
📊 نمره کل 100
🎯 سطح آزمون پیشرفته
👤 نام و نام خانوادگی: ....................................................
📅 تاریخ: ..................................

دستورالعمل آزمون

  1. فرض بر این است که برد مورد استفاده Arduino UNO است، مگر اینکه خلاف آن ذکر شود.
  2. در قسمت‌های مربوط به طراحی سیستم، استفاده از delay() ممنوع است، مگر اینکه سؤال صراحتاً اجازه دهد.
  3. در سؤالات کدنویسی، فقط نوشتن کد بدون توضیح منطق ممکن است باعث کاهش نمره شود.
  4. در صورت استفاده از روش متفاوت ولی منطقی و صحیح، پاسخ قابل قبول است.
  5. در طراحی سیستم‌ها، Clean Code، تقسیم برنامه به توابع، استفاده صحیح از نوع داده‌ها و Non-Blocking بودن برنامه در نمره تأثیر دارد.
  6. در سؤالات مربوط به break و continue، فقط استفاده ظاهری از این دستورات کافی نیست و باید کاربرد آن‌ها از نظر منطقی صحیح باشد.

بخش اول: تحلیل عمیق کد و پیدا کردن Bug ۲۰ نمره

سؤال ۱ — millis و Overflow ۵ نمره

کد زیر را بررسی کنید:

unsigned long previous = 0;
const unsigned long interval = 1000;

void loop() {
  if (millis() == previous + interval) {
    Serial.println("EVENT");
    previous = millis();
  }
}
چرا ممکن است شرط if هیچ‌وقت اجرا نشود؟
Overflow در millis() چیست و چه مشکلی ممکن است ایجاد کند؟
کد را به شکل صحیح و مقاوم در برابر Overflow بازنویسی کنید.
توضیح دهید چرا روش زیر مناسب‌تر است: currentTime - previousTime >= interval
تفاوت زیر را توضیح دهید: previous = millis(); و previous += interval;

سؤال ۲ — مشکل uint8_t و Underflow ۵ نمره

کد زیر را بررسی کنید:

uint8_t i = 10;

while (i >= 0) {
  Serial.println(i);
  i--;
}
دقیقاً توضیح دهید این برنامه چه اتفاقی برای متغیر i ایجاد می‌کند.
چرا این حلقه ممکن است هیچ‌وقت تمام نشود؟
دو روش مختلف برای اصلاح برنامه ارائه دهید.
آیا استفاده از int همیشه بهترین راه‌حل است؟ دلیل خود را توضیح دهید.

سؤال ۳ — تحلیل Button و استفاده صحیح از break و continue ۵ نمره

کد زیر را بررسی کنید:

#define BUTTON 7
#define LED 13

int counter = 0;

void loop() {
  for (int i = 0; i < 10; i++) {
    if (digitalRead(BUTTON) == LOW) {
      continue;
    }
    if (counter >= 5) {
      break;
    }
    counter++;
    digitalWrite(LED, HIGH);
  }
  digitalWrite(LED, LOW);
}
دقیقاً توضیح دهید continue در این برنامه چه کاری انجام می‌دهد.
دقیقاً توضیح دهید break در این برنامه چه کاری انجام می‌دهد.
اگر counter برابر ۵ شود، چه اتفاقی برای حلقه for می‌افتد؟
حداقل سه مشکل یا نکته طراحی این برنامه را بیان کنید.
یک کاربرد مناسب برای break و یک کاربرد مناسب برای continue در برنامه‌های Arduino توضیح دهید.

سؤال ۴ — EEPROM و مشکل ذخیره‌سازی ۵ نمره

کد زیر را بررسی کنید:

void loop() {
  int value = analogRead(A0);
  EEPROM.write(10, value);
  delay(100);
}
حداقل چهار مشکل این برنامه را بیان کنید.
چرا EEPROM.write برای ذخیره مستقیم مقدار analogRead مناسب نیست؟
برنامه را با استفاده از EEPROM.put اصلاح کنید.
توضیح دهید EEPROM.update چه مشکلی را کاهش می‌دهد.
چرا حتی استفاده از EEPROM.update نیز به معنی حل کامل مشکل معماری EEPROM نیست؟

بخش دوم: طراحی و پیاده‌سازی حرفه‌ای ۲۵ نمره

سؤال ۵ — سیستم هشدار Non-Blocking ۷ نمره

با استفاده از HC-SR04 یک سیستم هشدار طراحی کنید.

قوانین

شرطLEDBuzzer
فاصله بیشتر از ۱۰۰ سانتی‌مترخاموشخاموش
فاصله بین ۵۰ تا ۱۰۰ سانتی‌مترروشنفرکانس ۵۰۰Hz
فاصله کمتر از ۵۰ سانتی‌مترPWMفرکانس ۱۰۰۰Hz

شرایط

  1. استفاده از delay ممنوع است.
  2. HC-05 باید همزمان بتواند کار کند.
  3. از millis استفاده شود.
  4. از enum استفاده شود.
  5. از tone و noTone استفاده شود.
  6. حداقل سه تابع مستقل طراحی کنید.
  7. برنامه باید Non-Blocking باشد.

سؤال ۶ — کنترل حرفه‌ای L298N ۶ نمره

پین‌های زیر را در نظر بگیرید:

ENA = 5
IN1 = 7
IN2 = 8

تابع زیر را طراحی کنید:

void setMotor(int speed);

شرایط

توضیح دهید:

سؤال ۷ — map و constrain ۶ نمره

مقدار سنسور بین ۱۲۰ تا ۹۰۰ است. این مقدار باید به PWM بین ۴۰ تا ۲۲۰ تبدیل شود.

تابع زیر را کامل کنید:

uint8_t calculatePWM(int sensorValue);

شرایط

  1. مقدار ورودی خارج از محدوده کنترل شود.
  2. از map استفاده شود.
  3. خروجی خارج از محدوده PWM نشود.
  4. دلیل استفاده از constrain قبل یا بعد از map را توضیح دهید.

سؤال ۸ — تابع با Reference برای تحلیل چند مقدار ۶ نمره

تابعی به نام analyzeValues() طراحی کنید که سه عدد int را دریافت کند و موارد زیر را با استفاده از Reference برگرداند:

شرایط

  1. از Global Variable استفاده نکنید.
  2. حداقل چهار خروجی با Reference داشته باشید.
  3. Average باید float باشد.
  4. تقسیم صحیح نباید باعث حذف بخش اعشاری شود.
  5. ورودی‌های اصلی نباید تغییر کنند.

تابع باید به شکل زیر قابل استفاده باشد:

int minValue;
int maxValue;
float avgValue;
int rangeValue;

analyzeValues(10, 25, 17, minValue, maxValue, avgValue, rangeValue);

خروجی مورد انتظار:

Minimum = 10
Maximum = 25
Average = 17.33
Range = 15

بخش سوم: UART، HC-05 و State Machine ۲۰ نمره

سؤال ۹ — طراحی Command Parser با break و continue ۷ نمره

HC-05 دستورات زیر را دریافت می‌کند:

AUTO
MANUAL
MOTOR:150
MOTOR:-100
LED:80
BUZZER:1000

یک Command Parser طراحی کنید.

شرایط

  1. از enum برای Mode استفاده کنید.
  2. اطلاعات دریافتی ابتدا وارد Buffer شود.
  3. Command کامل از Command ناقص تشخیص داده شود.
  4. Command Parse شود.
  5. Command Validation شود.
  6. سپس اجرا شود.
  7. در صورت دریافت Characterهای غیرمجاز، با استفاده صحیح از continue آن Character نادیده گرفته شود.
  8. در صورت رسیدن به پایان Command یا پیدا شدن Delimiter مناسب، در صورت نیاز از break برای خروج از حلقه استفاده شود.
  9. توضیح دهید چرا دریافت اطلاعات و اجرای Command بهتر است در دو بخش جدا انجام شود.

سؤال ۱۰ — State Machine واقعی ۷ نمره

سیستم دارای Stateهای زیر است:

IDLE
WARNING
DANGER
ERROR

قوانین

شرطState
distance > 100IDLE
50 <= distance <= 100WARNING
distance < 50DANGER
distance نامعتبرERROR

شرایط

  1. از enum استفاده شود.
  2. State فعلی ذخیره شود.
  3. State جدید محاسبه شود.
  4. فقط در صورت تغییر State، Event مربوطه اجرا شود.
  5. ورود به WARNING باعث فعال شدن Buzzer شود.
  6. ورود به DANGER باعث تغییر فرکانس Buzzer شود.
  7. خروج از DANGER باعث اجرای noTone شود.
  8. LCD باید State فعلی را نمایش دهد.
  9. delay ممنوع است.