جدول المحتويات:

قائمة في Arduino ، وكيفية استخدام الأزرار: 10 خطوات (بالصور)
قائمة في Arduino ، وكيفية استخدام الأزرار: 10 خطوات (بالصور)

فيديو: قائمة في Arduino ، وكيفية استخدام الأزرار: 10 خطوات (بالصور)

فيديو: قائمة في Arduino ، وكيفية استخدام الأزرار: 10 خطوات (بالصور)
فيديو: طريقة برمجة الأردوينو للمبتدئين | شرح برنامج Arduino IDE 2024, يوليو
Anonim
قائمة في Arduino ، وكيفية استخدام الأزرار
قائمة في Arduino ، وكيفية استخدام الأزرار

في برنامج Arduino 101 التعليمي الخاص بي ، ستتعلم كيفية إعداد بيئتك في Tinkercad. أستخدم Tinkercad لأنها منصة قوية جدًا على الإنترنت تتيح لي عرض مجموعة من المهارات للطلاب لبناء الدوائر. لا تتردد في إنشاء جميع دروسي التعليمية باستخدام Arduino IDE و Arduino حقيقي!

في هذا البرنامج التعليمي ، سنتعرف على الأزرار! نحتاج أن نعرف:

  • كيفية ربطهم
  • قراءة قيمتها
  • Debounce ولماذا هو مهم
  • تطبيق عملي (إنشاء قائمة)

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

مستعد؟ هيا بنا نبدأ!

الخطوة 1: إعداد المجلس

إعداد المجلس
إعداد المجلس
إعداد المجلس
إعداد المجلس

تتمثل الخطوة الأولى في وضع Arduino و Breadboard Small في منطقة النماذج الأولية. تحقق من الصور أعلاه لمعرفة كيفية توصيل قضبان الطاقة.

يحتوي Breadboard Mini على قضبان كهربائية أعلى وأسفل. نقوم بتوصيلها بأردوينو حتى نتمكن من توفير الطاقة لمزيد من المكونات. في وقت لاحق من هذا البرنامج التعليمي ، سنستخدم 3 أزرار لذلك سنحتاج إلى مزيد من الطاقة. الشيء الذي يجب ملاحظته هو أنه على لوح صغير ، تعمل قضبان الطاقة عبر اللوح ، أفقيًا. هذا يختلف عن الأعمدة الموجودة في منطقة النماذج الأولية الرئيسية في المنتصف ؛ هذه تعمل عموديا. يمكنك استخدام أي من دبابيس الطاقة لتوفير الطاقة لأي عمود في المنطقة الرئيسية في المنتصف.

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

الخطوة 2: أضف الزر والمقاوم

أضف الزر والمقاوم
أضف الزر والمقاوم
أضف الزر والمقاوم
أضف الزر والمقاوم
أضف الزر والمقاوم
أضف الزر والمقاوم

أضف زر ضغط صغير من درج المكونات. يجب أن يبدو مثل الموجود في الصورة. تأكد من أنه ليس مفتاحًا! أضف المقاوم أيضًا. انقر فوقه ، واضبط قيمته على 10kΩ. هذا يكفي لسحب الدبوس منخفضًا عندما لا يكون متصلاً ، وهو أمر مهم جدًا لاحقًا في الكود.

ضع المكون في منتصف اللوح. الطريقة التي يعمل بها الزر هي:

  • من الزاوية إلى الزاوية ، الزر غير متصل. يؤدي الضغط على الزر إلى إغلاق جهات الاتصال وربط الزوايا.
  • جوانب الزر متصلة. إذا قمت بتوصيل سلك بأعلى اليسار وأسفل اليسار ، فسيتم إغلاق الدائرة.

هذا هو السبب في أننا وضعنا المكون عبر المساحة في المنتصف. يتأكد من عدم توصيل الزوايا أسفل المسامير في اللوحة.

تقدم الخطوة التالية صورتين توضحان هذه النقاط.

ضع المقاوم من الدبوس الأيمن السفلي عبر الأعمدة ، بحيث يكون أفقيًا.

الخطوة 3: اتصالات الأزرار

اتصالات الزر
اتصالات الزر
اتصالات الزر
اتصالات الزر

توضح الصور أعلاه إلى حد ما كيفية اتصال الأزرار. لقد كانت دائمًا نقطة ارتباك عندما تعتقد أن شيئًا ما جيدًا ولا يعمل!

الآن ، دعنا نضيف الأسلاك.

  • ضع سلكًا أحمر من دبوس طاقة موجب إلى نفس العمود مثل الدبوس الأيمن السفلي على الزر
  • ضع سلكًا أسود من دبوس طاقة سالب إلى نفس العمود مثل المقاوم.
  • ضع سلكًا ملونًا (ليس أحمر / أسود) من أعلى الدبوس الأيسر إلى Digital Pin 2 على Arduino

تحقق من الصور أعلاه للتأكد من صحة الأسلاك الخاصة بك.

الخطوة 4: الكود …

الرمز…
الرمز…
الرمز…
الرمز…

دعنا نلقي نظرة على الكود الخاص بالزر الأساسي.

افتح محرر التعليمات البرمجية وقم بالتغيير من Blocks إلى Text. امسح التحذير الذي يأتي. نحن سعداء بالرسائل النصية!

أنت تعرف الإعداد الأساسي ، لذلك دعنا نحدد الزر ونقوم بقراءة أساسية. سنقوم بطباعة الإخراج إلى المسلسل.

أضع بعض التعليقات الإضافية في الكود أدناه ، لذا من الأسهل قراءتها من الصورة.

// تحديد الثوابت

#define button 2 void setup () {pinMode (button، INPUT)؛ Serial.begin (9600) ؛ } void loop () {// اقرأ الدبوس الرقمي للتحقق من حالة الزر int pressed = digitalRead (button)؛ // يعود الزر "مرتفع" إذا تم الضغط عليه ، ومنخفض إذا لم يكن (تم الضغط عليه == مرتفع) {Serial.println ("Pressed!") ؛ }}

حسنًا ، هذا يعمل جيدًا!

في الأساس ، كل ما نقوم به هو التحقق من حالة الدبوس الرقمي في كل مرة يتم فيها تكرار الكود. إذا قمت بالنقر فوق Start Simulation والضغط على الزر ، فسترى Serial Monitor (انقر فوق الزر الموجود أسفل الرمز) يعرض "Pressed!" مرارا وتكرارا.

إحدى الميزات التي ستراها في الكود أعلاه هي إجراء تقييم الحالة (). كل ما تفعله الكود هو طرح سؤال وتقييم ما إذا كان صحيحًا ، في هذه الحالة. نستخدم تساوي (علامات تساوي مزدوجة ، مثل هذا: ==) للتحقق مما إذا كانت قيمة المتغير تساوي قيمة معينة. تقوم digitalRead () بإرجاع إما HIGH أو LOW.

باستخدام if () else if / آخر يمكننا التحقق من العديد من الشروط أو جميع الشروط ، وإذا عدت إلى أساسيات Arduino ، فسترى بعض المقارنات التي يمكنك إجراؤها.

الآن … قد تبدو التعليمات البرمجية الخاصة بنا مكتملة … ولكن لدينا مشكلة.

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

دعونا نصلحه!

الخطوة 5: القليل من Debounce

القليل من الجزم
القليل من الجزم

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

لنلقِ نظرة على الكود:

#define button 2 # حدد debounceTimeout 100

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

طويل int lastDebounceTime ؛

تم التصريح عن هذا المتغير أسفل الثوابت. هذا هو نوع int طويل ، والذي يسمح لنا بشكل أساسي بتخزين أرقام طويلة في الذاكرة. أطلقنا عليه اسم lastDebounceTime.

لا نحتاج إلى تغيير أي شيء في وظيفة الإعداد الباطل (). دعونا نترك هذا.

void loop () {// اقرأ الدبوس الرقمي للتحقق من حالة الزر int pressed = digitalRead (button) ؛ وقت طويل int CurrentTime = مللي () ؛ // رمز الزر}

التغيير الأول الذي نجريه في وظيفة loop () يكون تحت المكالمة لقراءة الزر. نحن بحاجة لتتبع الوقت الحالي. تُرجع الدالة millis () الوقت الحالي للساعة منذ بدء تشغيل Arduino بالمللي ثانية. نحتاج إلى تخزين هذا في متغير طويل من النوع int.

الآن ، نحتاج إلى التأكد من أننا على دراية بالوقت منذ الضغط على الزر ، لذلك نقوم بإعادة ضبط المؤقت عند عدم الضغط عليه. إلق نظرة:

void loop () {// اقرأ الدبوس الرقمي للتحقق من حالة الزر int pressed = digitalRead (button) ؛ وقت طويل int CurrentTime = مللي () ؛ إذا (تم الضغط عليه == منخفض) {// إعادة ضبط وقت العد أثناء عدم الضغط على الزر lastDebounceTime = currentTime ؛ } // رمز الزر}

تتحقق خوارزمية if (الضغط == LOW) من عدم الضغط على الزر. إذا لم يكن كذلك ، فسيخزن الرمز الوقت الحالي منذ آخر خصم. بهذه الطريقة ، في كل مرة يتم فيها الضغط على الزر ، لدينا نقطة زمنية يمكننا من خلالها التحقق من وقت الضغط على الزر. يمكننا بعد ذلك إجراء عملية حسابية سريعة لمعرفة المدة التي تم الضغط خلالها على الزر ، والاستجابة بشكل صحيح. دعنا نلقي نظرة على بقية الكود:

void loop () {// اقرأ الدبوس الرقمي للتحقق من حالة الزر int pressed = digitalRead (button) ؛ وقت طويل int CurrentTime = مللي () ؛ إذا (تم الضغط عليه == منخفض) {// إعادة ضبط وقت العد أثناء عدم الضغط على الزر lastDebounceTime = currentTime ؛ } // تم الضغط على الزر لوقت معين إذا (((currentTime - lastDebounceTime)> debounceTimeout)) {// إذا تم الوصول إلى المهلة ، فاضغط الزر! Serial.println ("Pressed!") ؛ }}

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

قم بتشغيل الكود الخاص بك وتحقق من أنه يعمل. إذا كان لديك أخطاء ، تحقق من الرمز الخاص بك!

الآن ، دعونا نلقي نظرة على مثال عملي.

الخطوة 6: صنع قائمة الطعام

صنع قائمة الطعام
صنع قائمة الطعام

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

لذلك ، بالنسبة لهذا المشروع ، نحتاج إلى:

  • ثلاثة أزرار
  • ثلاثة مقاومات مضبوطة على 10kΩ

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

الأزرار الثلاثة هي فتح القائمة / الخيار التالي ، وخيار التغيير (كما هو الحال في ، تغيير الإعداد) ، وزر قائمة حفظ / إغلاق.

اربطها ، دعنا نلقي نظرة على الكود!

الخطوة 7: تقسيم الكود - عام

حسنًا ، ستكون هذه خطوة طويلة ، لكنني سأستعرض كل قسم من أجزاء الكود.

أولاً ، دعونا نلقي نظرة على المتغيرات العامة المطلوبة.

// تحديد الثوابت # تحديد القائمة الزر 2 # تحديد القائمة حدد 3 # تحديد القائمة حفظ 4 # تعريف debounceTimeout 50 // تحديد المتغيرات int menuButtonPreviousState = LOW؛ القائمة int menuSelectPreviousState = LOW ؛ int menuSavePreviousState = LOW ؛ طويل int lastDebounceTime ؛ // خيارات القائمة char * menuOptions = {"Check Temp"، "Check Light"}؛ bool featureSetting = {خطأ ، خطأ} ؛ قائمة منطقية = خطأ ؛ قائمة منطقية NeedsPrint = خطأ ؛ int optionSelected = 0 ؛

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

الكتلة الثانية هي كل المتغيرات. نحن بحاجة إلى تتبع الزر PreviousState ، ونحتاج إلى تتبع lastDebounceTime. هذه كلها متغيرات من النوع int ، لكن الأخير هو نوع طويل لأنني أفترض أننا بحاجة إلى مساحة في الذاكرة.

تحتوي مجموعة خيارات القائمة على بعض الميزات الجديدة. أولاً ، الحرف * (نعم ، هذا هو علامة النجمة المتعمدة) ، وهو متغير حرفي للحرف / السلسلة. إنه مؤشر إلى وحدة تخزين ثابتة في الذاكرة. لا يمكنك تغييره (كما هو الحال في Python ، على سبيل المثال). ينشئ سطر char * menuOptions مجموعة من السلاسل الحرفية. يمكنك إضافة العديد من عناصر القائمة كما تريد.

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

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

لنلقِ نظرة على مجموعة الوظائف التالية.

الخطوة 8: تقسيم الكود - الإعداد والوظائف المخصصة

وظيفة الإعداد () سهلة بما فيه الكفاية ، فقط ثلاثة تصريحات إدخال:

إعداد باطل () {pinMode (menuSelect ، INPUT) ؛ pinMode (menuSave ، INPUT) ؛ pinMode (menuSelect ، INPUT) ؛ Serial.begin (9600) ؛ }

فيما يلي الوظائف الثلاث المخصصة. لنلقِ نظرة على أول اثنين ، ثم آخرهما بشكل منفصل.

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

// Function لإرجاع خيار optionchar المحدد الحالي * ReturnOptionSelected () {char * menuOption = menuOptions [optionSelected] ؛ // خيار العودة اختيار قائمة العودة المختارة ؛ } // وظيفة لإرجاع حالة char للخيار المحدد الحالي * ReturnOptionStatus () {bool optionSetting = featureSetting [optionSelected] ؛ شار * optionSettingVal ؛ إذا (optionSetting == false) {optionSettingVal = "False" ؛ } else {optionSettingVal = "True"؛ } // إرجاع optionSetting return optionSettingVal؛ }

تقوم وظيفة char * ReturnOptionSelected () بفحص الخيار المحدد (إذا رأيت أعلاه ، فسنقوم بتعيين متغير لتتبع ذلك) ، وسحب السلسلة الحرفية من المصفوفة التي أنشأناها سابقًا. ثم تقوم بإعادته كنوع حرف. نحن نعلم هذا لأن الوظيفة تشير إلى نوع الإرجاع.

الدالة الثانية char * ReturnOptionStatus () تقرأ حالة الخيار المحفوظ في المصفوفة وترجع سلسلة حرفية تمثل القيمة. على سبيل المثال ، إذا كان الإعداد الذي قمنا بتخزينه خاطئًا ، فسأعيد "False". هذا لأننا نظهر للمستخدم هذا المتغير ومن الأفضل الاحتفاظ بكل هذا المنطق معًا. يمكنني القيام بذلك لاحقًا ، لكن من المنطقي فعل ذلك هنا.

// وظيفة لتبديل مجلد الخيارات الحالية ToggleOptionSelected () {featureSetting [optionSelected] =! featureSetting [optionSelected] ؛ العودة صحيح }

وظيفة منطقية ToggleOptionSelected () هي وظيفة ملائمة لتغيير قيمة الإعداد الذي حددناه في القائمة. إنها تقلب القيمة فقط. إذا كانت لديك مجموعة أكثر تعقيدًا من الخيارات ، فقد يكون هذا مختلفًا تمامًا. أعود صحيحًا في هذه الوظيفة ، لأن رد الاتصال الخاص بي (المكالمة لاحقًا في الكود الذي يقوم بتشغيل هذه الوظيفة) يتوقع ردًا صحيحًا / خاطئًا. أنا متأكد بنسبة 100 ٪ من أن هذا سيعمل ، لذلك لم أعتبر أنه لا يعمل ، لكنني سأفعل ذلك في تطبيق تم نشره (فقط في حالة).

الخطوة 9: الحلقة …

الدالة loop () طويلة نسبيًا ، لذا سنفعلها على أجزاء. يمكنك أن تفترض أن كل شيء أدناه أعشاش ضمن هذه الوظيفة:

حلقة فارغة() {

// هل العمل هنا <-----}

حسنًا ، لقد رأينا هذه الأشياء من قبل:

// اقرأ الأزرار int menuButtonPressed = digitalRead (menuButton) ؛ int menuSelectPressed = digitalRead (menuSelect) ؛ int menuSavePressed = digitalRead (menuSave) ؛ // احصل على الوقت الحالي طويلاً int currentTime = millis () ؛ if (menuButtonPressed == LOW && menuSelectPressed == LOW && menuSavePressed == LOW) {// إعادة ضبط وقت العد أثناء عدم الضغط على الزر lastDebounceTime = currentTime ؛ menuButtonPreviousState = LOW ؛ menuSelectPreviousState = منخفضة ؛ menuSavePreviousState = منخفضة ؛ }

كل ما كان علي فعله هنا هو إضافة مكالمات digitalRead () الثلاثة ، والتأكد من أنني أدركت حقيقة أنه إذا كانت جميع الأزرار منخفضة ، فيجب علينا إعادة ضبط المؤقت (lastDebounceTime = currentTime) وضبط جميع الحالات السابقة على منخفضة. أقوم أيضًا بتخزين millis () في currentTime.

القسم التالي يعشش داخل الخط

إذا (((currentTime - lastDebounceTime)> debounceTimeout)) {

// هل العمل هنا <----}

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

إذا ((menuButtonPressed == HIGH) && (menuButtonPreviousState == LOW)) {if (menuMode == false) {menuMode = true؛ // دع المستخدم يعرف Serial.println ("القائمة نشطة") ؛ } else if (menuMode == true && optionSelected = 1) {// Reset option optionSelected = 0؛ } // طباعة menuNeedsPrint = صحيح ؛ // تبديل الزر prev. حالة لعرض القائمة فقط // إذا تم تحرير الزر والضغط عليه مرة أخرى menuButtonPreviousState = menuButtonPressed ؛ // سيكون مرتفعًا}

يتم التعامل مع هذا الخيار الأول عندما يكون menuButtonPressed مرتفعًا ، أو عند الضغط على زر القائمة. يقوم أيضًا بالتحقق للتأكد من أن الحالة السابقة كانت منخفضة ، بحيث يجب تحرير الزر قبل الضغط عليه مرة أخرى ، مما يوقف البرنامج عن إطلاق نفس الحدث باستمرار مرارًا وتكرارًا.

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

من الواضح أن القسم الأخير الصغير (// يطبع القائمة) يطبع القائمة ، لكنه أيضًا يعين الحالة السابقة على HIGH حتى لا تتكرر نفس الوظيفة (انظر ملاحظتي أعلاه حول التحقق مما إذا كان الزر سابقًا منخفضًا).

تم الضغط على // menuSelect ، وتوفير logicif ((menuSelectPressed == HIGH) && (menuSelectPreviousState == LOW)) {if (menuMode) {// قم بتغيير الخيار المحدد // في الوقت الحالي ، هذا فقط صحيح / خطأ // ولكن يمكن أن يكون أي شيء bool toggle = ToggleOptionSelected () ؛ إذا (تبديل) {menuNeedsPrint = صحيح ؛ } else {Serial.println ("حدث خطأ ما. يرجى المحاولة مرة أخرى") ؛ }} // تبديل الحالة للتبديل فقط إذا تم إطلاقه والضغط عليه مرة أخرى menuSelectPreviousState = menuSelectPressed؛ }

يتعامل هذا الجزء من الكود مع زر menuSelectPressed بنفس الطريقة ، إلا أننا في هذه المرة نطلق وظيفة ToggleOptionSelected (). كما قلت من قبل ، يمكنك تغيير هذه الوظيفة حتى تقوم بالمزيد ، ولكن هذا كل ما أحتاجه للقيام به.

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

إذا ((menuSavePressed == HIGH) && (menuSavePreviousState == LOW)) {// الخروج من القائمة // هنا يمكنك القيام بأي ترتيب // أو الحفظ في EEPROM menuMode = false ؛ Serial.println ("تم الخروج من القائمة") ؛ // تبديل الحالة بحيث تخرج القائمة مرة واحدة فقط menuSavePreviousState = menuSavePressed ؛ }}

تتعامل هذه الوظيفة مع زر menuSave ، الذي يخرج للتو من القائمة. هذا هو المكان الذي يمكن أن يكون لديك فيه خيار الإلغاء أو الحفظ ، ربما تقوم ببعض التنظيف أو الحفظ في EEPROM. أنا فقط أطبع "تم الخروج من القائمة" واضبط حالة الزر على "عالية" حتى لا تتكرر.

إذا (menuMode && menuNeedsPrint) {// لقد قمنا بطباعة القائمة ، لذلك ما لم يحدث شيء // ، لا حاجة لطباعتها مرة أخرى menuNeedsPrint = false؛ char * optionActive = ReturnOptionSelected () ، char * optionStatus = ReturnOptionStatus () ، Serial.print ("المحدد:") ؛ Serial.print (خيار نشط) ؛ Serial.print (":") ؛ Serial.print (optionStatus) ؛ Serial.println () ، }

هذه هي خوارزمية menuPrint ، والتي تنشط فقط عندما تكون القائمة نشطة وعندما يكون متغير menuNeedsPrint مضبوطًا على القيمة true.

يمكن بالتأكيد نقل هذا إلى وظيفته الخاصة ، ولكن من أجل البساطة..!

حسنًا ، هذا كل شيء! انظر الخطوة التالية لكامل التعليمات البرمجية.

الخطوة 10: الكتلة البرمجية النهائية

// تحديد الثوابت

# تعريف القائمة الزر 2 # تحديد القائمة حدد 3 # تحديد القائمة حفظ 4 # تحديد debounceTimeout 50 int menuButtonPreviousState = LOW ؛ القائمة int menuSelectPreviousState = LOW ؛ int menuSavePreviousState = LOW ؛ // تحديد المتغيرات long int lastDebounceTime ؛ منطقي lightSensor = صحيح ؛ bool tempSensor = صحيح ؛ // خيارات القائمة char * menuOptions = {"Check Temp"، "Check Light"}؛ bool featureSetting = {خطأ ، خطأ} ؛ قائمة منطقية = خطأ ؛ قائمة منطقية NeedsPrint = خطأ ؛ int optionSelected = 0 ؛ // وظيفة الإعداد

إعداد باطل () {pinMode (menuSelect ، INPUT) ؛ pinMode (menuSave ، INPUT) ؛ pinMode (menuSelect ، INPUT) ؛ Serial.begin (9600) ؛ }

// دالة لإرجاع حرف الخيار المحدد الحالي * ReturnOptionSelected () {char * menuOption = menuOptions [optionSelected] ؛ // خيار العودة اختيار قائمة العودة المختارة ؛ } // وظيفة لإرجاع حالة char للخيار المحدد الحالي * ReturnOptionStatus () {bool optionSetting = featureSetting [optionSelected] ؛ شار * optionSettingVal ؛ إذا (optionSetting == false) {optionSettingVal = "False" ؛ } else {optionSettingVal = "True"؛ } // إرجاع optionSetting return optionSettingVal؛ } // وظيفة لتبديل منطقية الخيار الحالي ToggleOptionSelected () {featureSetting [optionSelected] =! featureSetting [optionSelected] ؛ العودة صحيح } // الحلقة الرئيسية

حلقة باطلة () {// اقرأ الأزرار int menuButtonPressed = digitalRead (menuButton) ؛ int menuSelectPressed = digitalRead (menuSelect) ؛ int menuSavePressed = digitalRead (menuSave) ؛ // احصل على الوقت الحالي طويلاً int currentTime = millis () ؛ if (menuButtonPressed == LOW && menuSelectPressed == LOW && menuSavePressed == LOW) {// إعادة ضبط وقت العد أثناء عدم الضغط على الزر lastDebounceTime = currentTime ؛ menuButtonPreviousState = LOW ؛ menuSelectPreviousState = منخفضة ؛ menuSavePreviousState = منخفضة ؛ } if (((currentTime - lastDebounceTime)> debounceTimeout)) {// إذا تم الوصول إلى المهلة ، يتم الضغط على الزر!

// menuButton مضغوط ، توفير المنطق

// يعمل فقط عند تحرير الزر مسبقًا إذا ((menuButtonPressed == HIGH) && (menuButtonPreviousState == LOW)) {if (menuMode == false) {menuMode = true؛ // دع المستخدم يعرف Serial.println ("القائمة نشطة") ؛ } else if (menuMode == true && optionSelected = 1) {// Reset option optionSelected = 0؛ } // طباعة menuNeedsPrint = صحيح ؛ // تبديل الزر prev. حالة لعرض القائمة فقط // إذا تم تحرير الزر والضغط عليه مرة أخرى menuButtonPreviousState = menuButtonPressed ؛ // Would be HIGH} // تم الضغط على menuSelect ، وتوفير المنطق إذا ((menuSelectPressed == HIGH) && (menuSelectPreviousState == LOW)) {if (menuMode) {// Change the selected option // في الوقت الحالي ، هذا هو فقط صحيح / خطأ // ولكن يمكن أن يكون أي شيء تبديل منطقي = ToggleOptionSelected () ؛ إذا (تبديل) {menuNeedsPrint = صحيح ؛ } else {Serial.print ("حدث خطأ ما. يرجى المحاولة مرة أخرى") ؛ }} // تبديل الحالة للتبديل فقط إذا تم إطلاقه والضغط عليه مرة أخرى menuSelectPreviousState = menuSelectPressed؛ } إذا ((menuSavePressed == HIGH) && (menuSavePreviousState == LOW)) {// الخروج من القائمة // هنا يمكنك القيام بأي ترتيب // أو الحفظ في EEPROM menuMode = false؛ Serial.println ("تم الخروج من القائمة") ؛ // تبديل الحالة بحيث تخرج القائمة مرة واحدة فقط menuSavePreviousState = menuSavePressed ؛ }} // اطبع خيار القائمة الحالي نشطًا ، ولكن اطبعه مرة واحدة فقط إذا (menuMode && menuNeedsPrint) {// قمنا بطباعة القائمة ، لذلك ما لم يحدث شيء // ، فلا داعي لطباعته مرة أخرى menuNeedsPrint = false؛ char * optionActive = ReturnOptionSelected () ، char * optionStatus = ReturnOptionStatus () ، Serial.print ("المحدد:") ؛ Serial.print (خيار نشط) ؛ Serial.print (":") ؛ Serial.print (optionStatus) ؛ Serial.println () ، }}}

الدائرة متاحة على موقع Tinkercad. لقد قمت بتضمين الدائرة أدناه لتراها أيضًا!

كما هو الحال دائمًا ، إذا كانت لديك أسئلة أو مشكلات ، فيرجى إبلاغي بذلك!

موصى به: