تعلّم

An Arduino traffic light, with a crossing button that works

متوسط

أو تصفّح كل الدروس.

  • 503قطعة على المنضدة
  • 44لوحة تعمل الآن
  • 1.00xزمن حقيقي، على كل لوحة
Arduino Uno: معبر مشاةlive0.000 s 0.00x
اضغط الزر لتطلب العبور
مثال المرور، يعمل على ATmega328P محاكاة. اضغط الزر على لوحة التجارب لتطلب العبور.

إشارة المرور هي المشروع الذي يلجأ إليه كل مقرر Arduino تقريبًا في أسبوعه الثاني، لأنها ثلاثة LED وحفنة من التأخيرات ومع ذلك تبدو شيئًا حقيقيًا. والنسخة أعلاه تخطو خطوة أبعد من معظمها: إنها معبر مشاة، بمصباح للمشاة وزر طلب وقاعدة ألا ينتهي الأخضر أبكر مما ينبغي. وهي تعمل الآن على Arduino Uno محاكى، وبالكود نفسه الذي تستطيع قراءته أدناه في هذه الصفحة.

اضغط الزر على لوحة التجارب وراقب ما يحدث. يضيء مصباح WAIT الأزرق لحظة انغلاق التلامس، ويثبت الأخضر حتى ينال حده الأدنى من الوقت، ثم الكهرماني، ثم الأحمر مع مصباح المشي الأبيض، ثم مرحلة الوميض، ثم العودة إلى الأخضر. افتحه في المحرر لتغيير أي من التوقيتات وتشغيله مرة أخرى.

What you need

  • Arduino Uno
  • خمسة LED: أحمر وأصفر وأخضر وأبيض وأزرق
  • خمس مقاومات 220 ohm، واحدة لكل LED
  • زر ضغط واحد
  • عاكس سداسي 74HC04 لمصباح WAIT
  • لوحة تجارب وأسلاك توصيل

Wiring

القطعة والطرفيتصل بـملاحظة
LED أحمر، عبر 220 ohmالطرف 8أحمر المرور
LED أصفر، عبر 220 ohmالطرف 9كهرماني المرور
LED أخضر، عبر 220 ohmالطرف 10أخضر المرور
LED أبيض، عبر 220 ohmالطرف 11مصباح المشي
زر الضغط، أحد الجانبينالطرف 2الجانب الآخر إلى GND؛ يشغّل الكود مقاومة الرفع الداخلية
مدخل 74HC04خط الزريقود مخرجه مصباح WAIT الأزرق، دون أي كود
الطرفان 14 و7 في 74HC045 V وGNDلا تفعل الشريحة شيئًا حتى يوصَّل كلاهما

كيف يُبنى التسلسل

للمعبر حالة سكون واحدة، أخضر للمركبات، ولا يغادرها إلا عندما يطلب أحد ذلك. يكتب الكود ذلك في حلقة من أربع مراحل: أخضر حتى يصل طلب (لكن لا يقل عن ثلاث ثوانٍ ولا يزيد على تسع)، ثم كهرماني لثانية ونصف، ثم أحمر مع مصباح المشي لأربع ثوانٍ، ثم اثنتا عشرة وميضة كل نصف ثانية للكهرماني ومصباح المشي معًا، وهذا ما يفعله معبر مشاة حقيقي في نهاية مرحلة المشي.

كل مرحلة استدعاء لدالة مساعدة صغيرة اسمها lights() تضبط الأحمر والكهرماني والأخضر دفعة واحدة. كتابة المصابيح الثلاثة معًا في كل مرة هي ما يمنع أشهر عيب في إشارات المرور، وهو أن تنسى مرحلة إطفاء المصباح الذي قبلها فيضيء لونان معًا.

المراحل الأربع، من مثال المرور (مقتطع)
void loop() {
  lights(0, 0, 1);          // green
  waitForRequest();

  lights(0, 1, 0);          // amber
  delay(AMBER_MS);

  lights(1, 0, 0);          // red, and walk
  digitalWrite(WALK, HIGH);
  delay(WALK_MS);

  for (int i = 0; i < 12; i++) {   // the flashing phase
    int on = (i & 1) ? LOW : HIGH;
    digitalWrite(WALK, on);
    lights(0, on == HIGH, 0);
    delay(500);
  }
  digitalWrite(WALK, LOW);
}

لماذا الزر على مقاطعة

أول كود معبر يكتبه معظم الناس يفحص الزر بـdigitalRead() في مكان ما داخل loop(). يعمل عندما تختبره بإبقاء الزر مضغوطًا، ويفشل لحظة ينقر عليه أحدهم، لأن اللوحة تكون في معظم الدورة داخل delay() ولا تنظر إلى الطرف أصلًا. والنقرة أثناء المرحلة الحمراء ببساطة لا تُرى أبدًا.

يضع هذا الكود الزر على الطرف 2، وهو طرف INT0 في Uno، ويربط مقاطعة بحافته الهابطة. يفعل المعالج شيئًا واحدًا: يضبط علَمًا اسمه requested. وأيًّا كان ما تفعله الحلقة الرئيسية، حتى لو كانت داخل delay، تُلتقط الضغطة. ثم تقرأ الحلقة العلَم مع تعليق المقاطعات لحظة، فلا تقرأ قيمة مكتوبة نصفها أبدًا، وتمسحه في نهاية الدورة.

يُعلَن العلَم بـvolatile، وهذا يخبر المترجم أن شيئًا خارج التدفق العادي للبرنامج قد يغيّره. احذف هذه الكلمة وسيُسمح للمترجم المحسّن بقراءة المتغير مرة واحدة ثم لا ينظر إليه ثانية.

الطلب، يُلتقط أيًّا كان ما تفعله loop()
volatile bool requested = false;

static void onPress() { requested = true; }

void setup() {
  pinMode(BUTTON, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(BUTTON), onPress, FALLING);
}

المصباح الذي لا يحتاج إلى كود

مصباح WAIT الأزرق لا يقوده Uno على الإطلاق. إنه معلّق في إحدى بوابات عاكس 74HC04 موصول مباشرةً بخط الزر: يبقى الخط مرتفعًا عبر مقاومة الرفع، ويسحبه الزر إلى الأسفل، ويحوّل العاكس ذلك المنخفض إلى مرتفع، فيضيء المصباح. يتفاعل في نانو ثوانٍ، قبل أن تلاحظ الكود أي شيء.

وهو في الدائرة تذكير بأن ليست كل مهمة من نصيب المتحكم الدقيق. ويُظهر شيئًا عن المحاكي أيضًا: 74HC04 هنا شريحة حقيقية من 14 طرفًا، وتغذيتها على الطرفين 14 و7، وإذا حذفت أيًّا من سلكي التغذية في المحرر يتوقف المصباح عن العمل، تمامًا كما يحدث على مكتب.

جرّبه في المحرر

افتح الدائرة في المحرر وغيّر MIN_GREEN من 3000 إلى 500. اضغط الزر لحظة يضيء الأخضر، فيوقف المعبر المركبات الآن تقريبًا فورًا، وهذا بالضبط سبب وجود حد أدنى في المعابر الحقيقية.

ثم أفسده عمدًا. استبدل المقاطعة بـdigitalRead() عادية للطرف 2 داخل waitForRequest() وانقر الزر أثناء المرحلة الحمراء. تضيع الضغطة. أعد المقاطعة فتُلتقط في كل مرة.

وأخيرًا، اسحب محلل منطق من صندوق القطع وثبّت قنواته الأربع على الأطراف 8 و9 و10 و11. يظهر التسلسل كله كمخطط توقيت، ومرحلة الوميض صفًا أنيقًا من النبضات، وهذه طريقة أسرع بكثير لفحص التوقيتات من مراقبة المصابيح.

Common mistakes

LED دون مقاومة. لكل مصباح هنا مقاومة 220 ohm خاصة به، تحدّ التيار بنحو 14 ملي أمبير من طرف 5 فولت. والـLED الموصول مباشرةً بطرف يحاول أن يأخذ أكثر بكثير مما ينبغي للطرف أن يعطي.

قراءة الزر بين التأخيرات فقط، كما وُصف أعلاه. إذا تُجوهلت ضغطة أحيانًا، فهذا هو السبب في الغالب.

توقّع أن يقرأ الزر HIGH عند الضغط. مع INPUT_PULLUP يبقى الطرف مرتفعًا في السكون والضغطة تسحبه إلى الأرضي، فالضغط هو LOW. والمقاطعة على الحافة الهابطة للسبب نفسه.

لونان مضاءان معًا، لأن مرحلة أضاءت مصباحًا ولم تطفئه المرحلة التالية. ضبط الثلاثة معًا في دالة واحدة يزيل هذه الفئة من العيوب كلها.

الأسئلة

هل أستطيع بناء إشارة مرور بسيطة دون الزر؟

نعم. احذف الزر واستدعاء waitForRequest() وأعطِ الأخضر delay() ثابتة خاصة به. والنتيجة هي التسلسل الكلاسيكي بثلاثة LED. وتستحق نسخة الزر الأسطر القليلة الإضافية لأنها طريقة تصرف المعابر الحقيقية.

لماذا الطرف 2 للزر؟

في Uno، لا يملك مقاطعات خارجية خاصة بها إلا الطرفان 2 و3، INT0 وINT1. يمكن قراءة أي طرف بـdigitalRead()، لكن هذين الطرفين وحدهما يستدعيان دالة لحظة تغيّرهما.

هل يعمل هذا على Arduino Uno حقيقية دون تغيير؟

يستخدم الكود استدعاءات Arduino القياسية فقط: pinMode وdigitalWrite وdelay وmillis وattachInterrupt. إنه الكود نفسه الذي سترفعه من Arduino IDE.

كيف أجعلها تقاطعًا رباعيًا؟

أضف مجموعة ثانية من ثلاثة مصابيح على ثلاثة أطراف أخرى، وأعطِ كل مرحلة استدعاءين، واحدًا لكل طريق. وللتقاطع أيضًا مرحلة أحمر وكهرماني قبل الأخضر، وهذا لا يحتاجه معبر المشاة.

ابنِ هذا على أرض الواقع

افتح المحرر وغيّر قيمة وشاهد الرقم يتحرك معها. لا شيء لتثبّته ولا حاجة إلى حساب.