สารบัญ:

เมนูใน Arduino และวิธีใช้ปุ่ม: 10 ขั้นตอน (พร้อมรูปภาพ)
เมนูใน Arduino และวิธีใช้ปุ่ม: 10 ขั้นตอน (พร้อมรูปภาพ)

วีดีโอ: เมนูใน Arduino และวิธีใช้ปุ่ม: 10 ขั้นตอน (พร้อมรูปภาพ)

วีดีโอ: เมนูใน Arduino และวิธีใช้ปุ่ม: 10 ขั้นตอน (พร้อมรูปภาพ)
วีดีโอ: สอนการสร้างเมนูแสดงผลบนจอ LCD 2024, พฤศจิกายน
Anonim
เมนูใน Arduino และวิธีใช้ปุ่ม
เมนูใน Arduino และวิธีใช้ปุ่ม

ในบทช่วยสอน Arduino 101 ของฉัน คุณจะได้รับการสอนวิธีตั้งค่าสภาพแวดล้อมของคุณใน Tinkercad ฉันใช้ Tinkercad เพราะเป็นแพลตฟอร์มออนไลน์ที่ทรงพลังมาก ซึ่งทำให้ฉันสามารถแสดงทักษะต่างๆ ให้กับนักเรียนในการสร้างวงจรได้ รู้สึกอิสระที่จะสร้างบทช่วยสอนทั้งหมดของฉันโดยใช้ Arduino IDE และ Arduino จริง!

ในบทช่วยสอนนี้ เราจะมาเรียนรู้เกี่ยวกับปุ่มต่างๆ กัน! เราจำเป็นต้องรู้:

  • วิธีการวางสาย
  • การอ่านค่า
  • Debounce และเหตุใดจึงสำคัญ
  • แอปพลิเคชั่นที่ใช้งานได้จริง (การสร้างเมนู)

คนส่วนใหญ่คิดว่าสิ่งที่เป็นประโยชน์ที่สุดในการทำปุ่มคือเปิดและปิดไฟ เราจะไม่ใช่ที่นี่! เราจะใช้เมนูของเราเพื่อสร้างเมนูและตั้งค่าตัวเลือกบางอย่างบน Arduino

พร้อม? มาเริ่มกันเลย!

ขั้นตอนที่ 1: ตั้งค่าบอร์ด

ติดตั้งบอร์ด
ติดตั้งบอร์ด
ติดตั้งบอร์ด
ติดตั้งบอร์ด

ขั้นตอนแรกคือการวาง Arduino และ Breadboard Small ลงบนพื้นที่สร้างต้นแบบ ตรวจสอบภาพด้านบนเพื่อดูวิธีการต่อสายไฟ

Breadboard Mini มีรางไฟฟ้าสองรางด้านบนและด้านล่าง เราเชื่อมต่อสิ่งเหล่านี้กับ Arduino เพื่อให้เราสามารถจ่ายพลังงานให้กับส่วนประกอบต่างๆ ได้มากขึ้น ต่อไปในบทช่วยสอนนี้ เราจะใช้ 3 ปุ่ม ดังนั้นเราจะต้องเพิ่มพลัง สิ่งที่ควรทราบคือบนเขียงหั่นขนมขนาดเล็ก รางไฟวิ่งข้ามกระดานในแนวนอน ซึ่งแตกต่างจากคอลัมน์ในพื้นที่สร้างต้นแบบหลักที่อยู่ตรงกลาง เหล่านี้ทำงานในแนวตั้ง คุณสามารถใช้พินเพาเวอร์ใดๆ เพื่อจ่ายไฟให้กับคอลัมน์ใดๆ ในพื้นที่หลักที่อยู่ตรงกลาง

เมื่อคุณเพิ่มกำลัง ให้ใช้สายสีดำและสีแดงกับขั้วลบและขั้วบวกตามลำดับ เพิ่มสายไฟที่ปลายสายไฟที่อีกด้านหนึ่งของบอร์ด เราจะไม่ใช้ด้านนั้น แต่เป็นการฝึกฝนที่ดี

ขั้นตอนที่ 2: เพิ่มปุ่มและตัวต้านทาน

เพิ่มปุ่มและตัวต้านทาน
เพิ่มปุ่มและตัวต้านทาน
เพิ่มปุ่มและตัวต้านทาน
เพิ่มปุ่มและตัวต้านทาน
เพิ่มปุ่มและตัวต้านทาน
เพิ่มปุ่มและตัวต้านทาน

เพิ่มปุ่มกดเล็กๆ จากถาดส่วนประกอบ ควรมีลักษณะเหมือนในภาพ ตรวจสอบให้แน่ใจว่าไม่ใช่สวิตช์! เพิ่มตัวต้านทานด้วย คลิกและตั้งค่าเป็น10kΩ นั่นก็เพียงพอแล้วที่จะดึงพินให้ต่ำเมื่อไม่ได้เชื่อมต่อ ซึ่งสำคัญมากในโค้ดในภายหลัง

วางส่วนประกอบไว้ตรงกลางของเขียงหั่นขนม วิธีการทำงานของปุ่มคือ:

  • มุมต่อมุม ปุ่มไม่ได้เชื่อมต่อ การกดปุ่มจะปิดหน้าสัมผัสและเชื่อมต่อมุมต่างๆ
  • ด้านข้างของปุ่มเชื่อมต่อกัน หากคุณต่อสายเข้ากับด้านซ้ายบนและด้านซ้ายล่าง วงจรจะถูกปิด

นี่คือเหตุผลที่เราวางองค์ประกอบข้ามช่องว่างตรงกลาง ทำให้แน่ใจว่ามุมต่างๆ ไม่ได้เชื่อมต่ออยู่ใต้หมุดในบอร์ด

ขั้นตอนต่อไปจะมีรูปภาพสองสามภาพที่แสดงให้เห็นประเด็นเหล่านี้

วางตัวต้านทานจากพินขวาล่างข้ามคอลัมน์ ให้วางในแนวนอน

ขั้นตอนที่ 3: การเชื่อมต่อปุ่ม

การเชื่อมต่อปุ่ม
การเชื่อมต่อปุ่ม
การเชื่อมต่อปุ่ม
การเชื่อมต่อปุ่ม

ภาพด้านบนทำให้เห็นได้ชัดเจนว่าปุ่มต่างๆ เชื่อมต่อกันอย่างไร เป็นเรื่องที่สับสนเสมอเมื่อคุณคิดว่ามีบางอย่างที่ดีและไม่ได้ผล!

ทีนี้มาเพิ่มสายไฟกัน

  • วางตะกั่วสีแดงจากพินพลังงานบวกไปยังคอลัมน์เดียวกันกับพินขวาล่างของปุ่ม
  • วางตะกั่วสีดำจากพินพลังงานลบไปยังคอลัมน์เดียวกันกับตัวต้านทาน
  • วางลวดสี (ไม่ใช่สีแดง/ดำ) จากพินซ้ายบนไปยัง Digital Pin 2 บน Arduino

ตรวจสอบภาพด้านบนเพื่อให้แน่ใจว่าการเดินสายของคุณถูกต้อง

ขั้นตอนที่ 4: รหัส…

รหัส…
รหัส…
รหัส…
รหัส…

มาดูรหัสสำหรับปุ่มพื้นฐานกัน

เปิดตัวแก้ไขโค้ดและเปลี่ยนจาก Blocks เป็น Text ล้างคำเตือนที่ขึ้นมา เราพอใจกับข้อความ!

คุณทราบการตั้งค่าพื้นฐานแล้ว มากำหนดปุ่มและอ่านพื้นฐานกัน เราจะพิมพ์ผลลัพธ์ไปยัง Serial

ฉันใส่ความคิดเห็นพิเศษสองสามข้อลงในโค้ดด้านล่างเพื่อให้อ่านง่ายกว่ารูปภาพ

// กำหนดค่าคงที่

#define ปุ่ม 2 การตั้งค่าเป็นโมฆะ () { pinMode (ปุ่ม, INPUT); Serial.begin(9600); } วงเป็นโมฆะ () { // อ่านพินดิจิทัลเพื่อตรวจสอบสถานะของปุ่ม int ที่กด = digitalRead (ปุ่ม); // ปุ่มจะคืนค่า HIGH หากกด LOW ถ้าไม่เช่นนั้นหาก (กด == HIGH){ Serial.println("Pressed!"); } }

โอเค ได้ผล!

โดยพื้นฐานแล้ว สิ่งที่เราทำคือการตรวจสอบสถานะของพินดิจิทัลทุกครั้งที่โค้ดวนซ้ำ หากคุณคลิก เริ่มการจำลอง และกดปุ่ม คุณจะเห็น Serial Monitor (คลิกปุ่มด้านล่างโค้ด) แสดง "Pressed!" ซ้ำแล้วซ้ำเล่า

คุณลักษณะหนึ่งที่คุณจะเห็นในโค้ดด้านบนคือการประเมินเงื่อนไข if() ที่เกิดขึ้น โค้ดทั้งหมดที่ทำคือการถามคำถามและประเมินว่าจริงหรือไม่ ในกรณีนี้ เราใช้ is equal (เครื่องหมายเท่ากับสองเท่า เช่น ==) เพื่อตรวจสอบว่าค่าของตัวแปรเท่ากับค่าหนึ่งหรือไม่ digitalRead() ส่งกลับค่า HIGH หรือ LOW

การใช้ if() else if / else เราสามารถตรวจสอบเงื่อนไขได้หลายอย่างหรือทุกเงื่อนไข และหากคุณกลับไปที่ Arduino Basics คุณจะเห็นการเปรียบเทียบบางอย่างที่คุณสามารถทำได้

ตอนนี้… รหัสของเราอาจดูสมบูรณ์… แต่เรามีปัญหา

ดูสิ มันใช้งานได้ดีจริงๆ เมื่ออยู่ในเครื่องจำลอง แต่ไฟฟ้าจริงมีสัญญาณรบกวน โดยเฉพาะอุปกรณ์ไฟฟ้ากระแสตรง ดังนั้นปุ่มของเราอาจส่งคืนการอ่านที่ผิดพลาดในบางครั้ง และนั่นคือปัญหา เนื่องจากโครงการของคุณอาจไม่ตอบสนองในทางที่ถูกต้องสำหรับผู้ใช้

มาแก้ไขกันเถอะ!

ขั้นตอนที่ 5: การโต้เถียงเล็กน้อย

Debounce เล็กน้อย
Debounce เล็กน้อย

เราใช้ขั้นตอนที่เรียกว่า debounce เพื่อแก้ปัญหาปุ่มของเรา โดยพื้นฐานแล้วจะรอตามระยะเวลาที่กำหนดระหว่างเวลาที่กดปุ่มและตอบสนองต่อการกดจริง ผู้ใช้ยังคงรู้สึกเป็นธรรมชาติ (เว้นแต่คุณจะใช้เวลานานเกินไป) คุณยังสามารถใช้เพื่อตรวจสอบความยาวของการกด คุณจึงสามารถตอบสนองได้แตกต่างกันในแต่ละครั้ง ไม่ต้องเปลี่ยนสายไฟ!

ลองดูรหัส:

#define ปุ่ม 2#define debounceTimeout 100

การเปลี่ยนแปลงครั้งแรกอยู่ในขอบเขตทั่วโลก คุณจะจำได้ว่าเป็นที่ที่เรากำหนดตัวแปรที่ฟังก์ชันจำนวนมากของเราอาจใช้หรือตัวแปรที่ไม่สามารถรีเซ็ตได้ในแต่ละครั้งที่ลูปเริ่มทำงาน ดังนั้นเราจึงเพิ่ม debounceTimeout ให้กับค่าคงที่ที่กำหนดไว้ เราสร้าง 100 รายการนี้ (ซึ่งจะแปลเป็น 100 มิลลิวินาทีในภายหลัง) แต่อาจสั้นกว่านี้ อีกต่อไปและมันจะรู้สึกผิดธรรมชาติ

ยาว int lastDebounceTime;

ตัวแปรนี้ถูกประกาศไว้ด้านล่างค่าคงที่ นี่เป็นประเภท int แบบยาว ซึ่งช่วยให้เราสามารถเก็บตัวเลขที่ยาวไว้ในหน่วยความจำได้ เราเรียกมันว่า LastDebounceTime

เราไม่จำเป็นต้องเปลี่ยนแปลงอะไรในฟังก์ชัน void setup() ปล่อยอันนั้นไปเถอะ

วงเป็นโมฆะ () {// อ่านพินดิจิทัลเพื่อตรวจสอบสถานะของปุ่ม int ที่กด = digitalRead (ปุ่ม); ยาว int currentTime = millis(); // รหัสปุ่ม }

การเปลี่ยนแปลงครั้งแรกที่เราทำในฟังก์ชัน loop() อยู่ภายใต้การเรียกเพื่ออ่านปุ่ม เราจำเป็นต้องติดตามเวลาปัจจุบัน ฟังก์ชัน millis() จะคืนค่าเวลาปัจจุบันของนาฬิกาตั้งแต่ Arduino บูทขึ้นในหน่วยมิลลิวินาที เราจำเป็นต้องเก็บไว้ในตัวแปรชนิด int แบบยาว

ตอนนี้ เราต้องแน่ใจว่าเราทราบเวลาตั้งแต่กดปุ่ม ดังนั้นเราจึงรีเซ็ตตัวจับเวลาเมื่อไม่ได้กดปุ่ม ลองดูสิ:

วงเป็นโมฆะ () {// อ่านพินดิจิทัลเพื่อตรวจสอบสถานะของปุ่ม int ที่กด = digitalRead (ปุ่ม); ยาว int currentTime = millis(); ถ้า (กด == ต่ำ) {// รีเซ็ตเวลานับในขณะที่ไม่ได้กดปุ่ม lastDebounceTime = currentTime; } // รหัสปุ่ม }

อัลกอริทึม if(pressed == LOW) จะตรวจสอบว่าไม่ได้กดปุ่มหรือไม่ หากไม่เป็นเช่นนั้น รหัสจะจัดเก็บเวลาปัจจุบันตั้งแต่การดีบักครั้งล่าสุด ด้วยวิธีนี้ ทุกครั้งที่กดปุ่ม เราจะมีจุดที่เราสามารถตรวจสอบว่าปุ่มนั้นถูกกดเมื่อใด จากนั้นเราสามารถคำนวณทางคณิตศาสตร์อย่างรวดเร็วเพื่อดูว่ามีการกดปุ่มนานเท่าใดและตอบสนองอย่างถูกต้อง มาดูโค้ดที่เหลือกัน:

วงเป็นโมฆะ () {// อ่านพินดิจิทัลเพื่อตรวจสอบสถานะของปุ่ม int ที่กด = digitalRead (ปุ่ม); ยาว int currentTime = millis(); ถ้า (กด == ต่ำ) {// รีเซ็ตเวลานับในขณะที่ไม่ได้กดปุ่ม lastDebounceTime = currentTime; } // มีการกดปุ่มในช่วงเวลาที่กำหนด if(((currentTime - lastDebounceTime) > debounceTimeout)){ // หากหมดเวลาแล้ว ให้กดปุ่ม! Serial.println("กด!"); } }

บล็อกสุดท้ายของโค้ดใช้เวลาปัจจุบัน ลบเวลา debounce ล่าสุด และเปรียบเทียบกับระยะหมดเวลาที่เราตั้งไว้ หากมีค่ามากกว่า โค้ดจะถือว่ามีการกดปุ่มในช่วงเวลานั้นและตอบสนอง ประณีต!

เรียกใช้รหัสของคุณและตรวจสอบว่าใช้งานได้ หากคุณมีข้อผิดพลาด ตรวจสอบรหัสของคุณ!

ทีนี้มาดูตัวอย่างการใช้งานจริงกัน

ขั้นตอนที่ 6: การสร้างเมนู

การทำเมนู
การทำเมนู

ปุ่มนั้นน่าสนใจเพราะมีความเป็นไปได้มากมายกับมัน! ในตัวอย่างนี้ เราจะทำเมนู สมมติว่าคุณได้สร้างอุปกรณ์ที่ยอดเยี่ยมจริงๆ เครื่องนี้ และต้องการให้ผู้ใช้สามารถเปลี่ยนตัวเลือกเพื่อเปิดหรือปิดบางสิ่ง หรือตั้งค่าเฉพาะสำหรับการตั้งค่า การออกแบบปุ่มสามปุ่มนี้สามารถทำได้!

ดังนั้น สำหรับโครงการนี้ เราต้องการ:

  • สามปุ่ม
  • ตัวต้านทานสามตัวตั้งค่าเป็น10kΩ

เรามีหนึ่งในนี้แล้ว เราแค่ต้องการอีกสองตัว เพื่อเพิ่มสิ่งเหล่านั้นลงในกระดาน การเดินสายไฟนั้นซับซ้อนกว่าเล็กน้อย แต่เพียงเพราะฉันต้องการให้มันกะทัดรัดจริงๆ คุณสามารถทำตามรูปแบบเดียวกันสำหรับปุ่มแรกหรือทำตามภาพด้านบน

ปุ่มสามปุ่มคือตัวเลือกเปิด/ถัดไปของเมนู ตัวเลือกการเปลี่ยนแปลง (เช่น เปลี่ยนการตั้งค่า) และปุ่มบันทึก/ปิดเมนู

วางสาย มาดูโค้ดกันเลย!

ขั้นตอนที่ 7: การแยกโค้ด - Global

ตกลง นี่จะเป็นขั้นตอนที่ยาวนาน แต่ฉันจะอธิบายแต่ละส่วนของโค้ด

อันดับแรก มาดูตัวแปรส่วนกลางที่จำเป็นกันก่อน

// กำหนดค่าคงที่#define menuButton 2 #define menuSelect 3#define menuSave 4 #define debounceTimeout 50 // กำหนดตัวแปร int menuButtonPreviousState = LOW; int menuSelectPreviousState = ต่ำ; int menuSavePreviousState = ต่ำ; ยาว int lastDebounceTime; // ตัวเลือกเมนู char * menuOptions = {"Check Temp", "Check Light"}; bool featureSetting = {เท็จ เท็จ}; bool menuMode = เท็จ; เมนูบูลNeedsPrint = false; int optionSelected = 0;

สามช่วงตึกนี้ค่อนข้างคล้ายกับที่เราเคยเห็นมาก่อน ในตอนแรก ฉันได้กำหนดปุ่มสามปุ่มและระยะหมดเวลา สำหรับส่วนนี้ของโปรเจ็กต์ ฉันได้ตั้งค่าไว้ที่ 50 มิลลิวินาที ดังนั้นจึงต้องมีการกดอย่างรอบคอบเพื่อให้ใช้งานได้

บล็อกที่สองคือตัวแปรทั้งหมด เราจำเป็นต้องติดตาม buttonPreviousState และเราต้องติดตาม LastDebounceTime ตัวแปรเหล่านี้เป็นตัวแปรประเภท int ทั้งหมด แต่ตัวสุดท้ายเป็นตัวแปรแบบยาว เพราะฉันคิดว่าเราต้องการพื้นที่ในหน่วยความจำ

บล็อกตัวเลือกเมนูมีคุณสมบัติใหม่บางอย่าง อย่างแรก อักขระ * (ใช่ นั่นคือเครื่องหมายดอกจันโดยเจตนา) ซึ่งเป็นตัวแปรตามตัวอักษร/สตริงตามตัวอักษร เป็นตัวชี้ไปยังที่เก็บข้อมูลแบบคงที่ในหน่วยความจำ คุณไม่สามารถเปลี่ยนแปลงได้ (เช่น ใน Python เป็นต้น) char *menuOptions บรรทัดนี้สร้างอาร์เรย์ของตัวอักษรสตริง คุณสามารถเพิ่มรายการเมนูได้มากเท่าที่คุณต้องการ

ตัวแปร bool featureSetting เป็นเพียงอาร์เรย์ของค่าที่แสดงถึงแต่ละรายการในเมนู ได้ คุณสามารถเก็บอะไรก็ได้ที่คุณชอบ เพียงแค่เปลี่ยนประเภทตัวแปร (ตัวแปรทั้งหมดต้องเป็นประเภทเดียวกัน) ตอนนี้ อาจมีวิธีที่ดีกว่าในการจัดการสิ่งนี้ เช่น พจนานุกรมหรือ tuples แต่วิธีนี้ง่ายสำหรับแอปพลิเคชันนี้ ฉันอาจจะสร้างหนึ่งในแอปพลิเคชันที่ปรับใช้

ฉันได้ติดตามเมนูโหมด ดังนั้นหากฉันต้องการสิ่งอื่นบนจอแสดงผลของฉัน ฉันสามารถทำได้ นอกจากนี้ หากฉันมีตรรกะของเซ็นเซอร์ ฉันอาจหยุดการทำงานนั้นชั่วคราวระหว่างการทำงานของเมนู เผื่อในกรณีที่มีบางอย่างขัดแย้งกัน ฉันมีตัวแปร menuNeedsPrint เพราะฉันต้องการพิมพ์เมนูตามเวลาที่กำหนด ไม่ใช่แค่ตลอดเวลา สุดท้าย ฉันมีตัวแปร optionSelected ดังนั้นฉันจึงสามารถติดตามตัวเลือกที่เลือกเมื่อฉันเข้าถึงได้ในหลายที่

มาดูฟังก์ชันชุดต่อไปกัน

ขั้นตอนที่ 8: การแยกย่อยโค้ด - การตั้งค่าและฟังก์ชันที่กำหนดเอง

ฟังก์ชัน setup() นั้นง่ายเพียงพอ เพียงสามการประกาศอินพุต:

การตั้งค่าเป็นโมฆะ () { pinMode (menuSelect, INPUT); โหมดพิน (menuSave, INPUT); pinMode (เลือกเมนู, อินพุต); Serial.begin(9600); }

ถัดไปคือฟังก์ชันแบบกำหนดเองสามแบบ ลองดูสองอันแรกแล้วอันสุดท้ายแยกกัน

เราต้องการสองฟังก์ชันที่ส่งคืนข้อมูลบางอย่าง เหตุผลก็คือ เราต้องการให้แน่ใจว่าสิ่งนี้สามารถอ่านได้โดยมนุษย์ นอกจากนี้ยังช่วยในการดีบักโค้ดหากเรามีปัญหา รหัส:

// ฟังก์ชันเพื่อคืนค่า optionchar ที่เลือกในปัจจุบัน *ReturnOptionSelected(){ ถ่าน *menuOption = menuOptions[optionSelected]; // Return option เมนูส่งคืนที่เลือก ตัวเลือก; } // ฟังก์ชันส่งคืนสถานะของตัวเลือกที่เลือกในปัจจุบัน ถ่าน *ReturnOptionStatus(){ bool optionSetting = featureSetting[optionSelected]; ถ่าน *ตัวเลือกSettingVal; ถ้า (optionSetting == false) { optionSettingVal = "False"; }อื่น{ optionSettingVal = "จริง"; } // Return optionSetting return optionSettingVal; }

ฟังก์ชัน char *ReturnOptionSelected() จะตรวจสอบตัวเลือกที่เลือก (หากคุณเห็นด้านบน เราจะตั้งค่าตัวแปรเพื่อติดตามสิ่งนั้น) และดึงสตริงตามตัวอักษรจากอาร์เรย์ที่เราสร้างไว้ก่อนหน้านี้ จากนั้นส่งคืนเป็นประเภทอักขระ เราทราบสิ่งนี้เนื่องจากฟังก์ชันระบุประเภทการส่งคืน

ฟังก์ชันที่สอง char *ReturnOptionStatus() จะอ่านสถานะของตัวเลือกที่บันทึกไว้ในอาร์เรย์และส่งกลับสตริงตัวอักษรที่แสดงค่า ตัวอย่างเช่น หากการตั้งค่าที่เราเก็บไว้เป็น false ฉันจะคืนค่าเป็น "False" นี่เป็นเพราะเราแสดงให้ผู้ใช้เห็นตัวแปรนี้ และเป็นการดีกว่าที่จะรวมตรรกะทั้งหมดนี้ไว้ด้วยกัน ฉันสามารถทำได้ในภายหลัง แต่มันสมเหตุสมผลกว่าที่จะทำที่นี่

// ฟังก์ชันเพื่อสลับตัวเลือกปัจจุบัน ToggleOptionSelected (){ featureSetting[optionSelected] = !featureSetting[optionSelected]; คืนค่าจริง; }

ฟังก์ชัน bool ToggleOptionSelected() เป็นฟังก์ชันอำนวยความสะดวกในการเปลี่ยนค่าของการตั้งค่าที่เราได้เลือกไว้ในเมนู มันแค่พลิกค่า หากคุณมีชุดตัวเลือกที่ซับซ้อนกว่านี้ อาจแตกต่างกันมาก ฉันคืนค่า true ในฟังก์ชันนี้ เนื่องจากการโทรกลับของฉัน (การโทรในภายหลังในโค้ดที่เรียกใช้ฟังก์ชันนี้) คาดว่าจะมีการตอบกลับจริง/เท็จ ฉันแน่ใจ 100% ว่าจะใช้งานได้ ดังนั้นฉันจึงไม่ได้พิจารณาว่ามันไม่ทำงาน แต่ฉันจะทำในแอปพลิเคชันที่ปรับใช้ (ในกรณีนี้)

ขั้นตอนที่ 9: วนรอบ…

ฟังก์ชัน loop() ค่อนข้างยาว ดังนั้นเราจะทำเป็นส่วนๆ คุณสามารถสมมติทุกอย่างด้านล่างซ้อนกันภายในฟังก์ชันนี้:

วงเป็นโมฆะ () {

// ทำงานที่นี่ <----- }

ตกลง เราเห็นสิ่งนี้มาก่อน:

// อ่านปุ่ม int menuButtonPressed = digitalRead(menuButton); int menuSelectPressed = digitalRead(menuSelect); int menuSavePressed = digitalRead (menuSave); // รับเวลาปัจจุบัน long int currentTime = millis(); if(menuButtonPressed == LOW && menuSelectPressed == LOW && menuSavePressed == LOW){ //รีเซ็ตเวลานับในขณะที่ไม่ได้กดปุ่ม lastDebounceTime = currentTime; menuButtonPreviousState = ต่ำ; menuSelectPreviousState = ต่ำ; menuSavePreviousState = ต่ำ; }

ทั้งหมดที่ฉันต้องทำคือเพิ่มการเรียก digitalRead() สามครั้ง และตรวจดูให้แน่ใจว่าฉันได้คำนึงถึงข้อเท็จจริงที่ว่าหากปุ่มทั้งหมดเหลือน้อย เราควรรีเซ็ตตัวจับเวลา (lastDebounceTime = currentTime) และตั้งค่าสถานะก่อนหน้าทั้งหมดเป็นต่ำ ฉันยังเก็บ millis() ใน currentTime

ส่วนถัดไปซ้อนอยู่ภายในเส้น

if(((currentTime - lastDebounceTime) > debounceTimeout)){

//ทำงานที่นี่ <---- }

มีสามส่วน ใช่ ฉันสามารถย้ายพวกมันไปยังฟังก์ชันของตัวเองได้ แต่เพื่อความเรียบง่าย ฉันจึงเก็บอัลกอริธึมปุ่มหลักสามปุ่มไว้ที่นี่

if((menuButtonPressed == HIGH) && (menuButtonPreviousState == LOW)){ if(menuMode == false){ menuMode = true; // แจ้งให้ผู้ใช้ทราบ Serial.println("เมนูใช้งานได้"); } else if (menuMode == true && optionSelected = 1){ // รีเซ็ตตัวเลือก optionSelected = 0; } // พิมพ์เมนู menuNeedsPrint = true; // สลับปุ่มก่อนหน้า กำหนดให้แสดงเฉพาะเมนู // หากปล่อยปุ่มแล้วกดอีกครั้ง menuButtonPreviousState = menuButtonPressed; // น่าจะสูง }

อันแรกนี้จะจัดการเมื่อ menuButtonPressed เป็น HIGH หรือเมื่อกดปุ่มเมนู นอกจากนี้ยังตรวจสอบเพื่อให้แน่ใจว่าสถานะก่อนหน้าเป็น LOW เพื่อให้ต้องปล่อยปุ่มก่อนที่จะกดอีกครั้ง ซึ่งจะทำให้โปรแกรมหยุดการทำงานของเหตุการณ์เดิมซ้ำแล้วซ้ำอีก

จากนั้นจะตรวจสอบว่าถ้าเมนูไม่ทำงานก็จะเปิดใช้งาน มันจะพิมพ์ตัวเลือกแรกที่เลือก (ซึ่งเป็นรายการแรกในอาร์เรย์ menuOptions โดยค่าเริ่มต้น หากคุณกดปุ่มครั้งที่สองหรือสาม (อื่นๆ) คุณจะได้รับตัวเลือกถัดไปในรายการ สิ่งที่ฉันแก้ไขได้คือ ที่เมื่อถึงจุดสิ้นสุด มันจะวนกลับมาที่จุดเริ่มต้น สิ่งนี้สามารถอ่านความยาวของอาร์เรย์และทำให้การวนกลับง่ายขึ้นหากคุณเปลี่ยนจำนวนตัวเลือก แต่ตอนนี้ ง่ายสำหรับตอนนี้

ส่วนเล็ก ๆ สุดท้าย (// พิมพ์เมนู) จะพิมพ์เมนูอย่างชัดเจน แต่ยังตั้งค่าสถานะก่อนหน้าเป็น HIGH ดังนั้นฟังก์ชันเดียวกันจะไม่วนซ้ำ (ดูหมายเหตุของฉันด้านบนเกี่ยวกับการตรวจสอบว่าปุ่มก่อนหน้านี้เป็น LOW หรือไม่)

// กด menuSelect ให้ logicif((menuSelectPressed == HIGH) && (menuSelectPreviousState == LOW)){ if(menuMode){ // เปลี่ยนตัวเลือกที่เลือก // ในขณะนี้ นี่เป็นเพียง true/false // แต่ อาจเป็นอะไรก็ได้ สลับบูล = ToggleOptionSelected(); ถ้า (สลับ) { menuNeedsPrint = true; }อื่น{ Serial.println("มีบางอย่างผิดพลาด โปรดลองอีกครั้ง"); } } // สลับสถานะเป็นสลับเฉพาะเมื่อปล่อยและกดอีกครั้ง menuSelectPreviousState = menuSelectPressed; }

โค้ดบิตนี้จัดการปุ่ม menuSelectPressed ในลักษณะเดียวกัน ยกเว้นเวลานี้ เราเพิ่งเรียกใช้ฟังก์ชัน ToggleOptionSelected() อย่างที่ฉันพูดไปก่อนหน้านี้ คุณสามารถเปลี่ยนฟังก์ชันนี้เพื่อให้ทำงานได้มากขึ้น แต่นั่นคือทั้งหมดที่ฉันต้องทำ

สิ่งสำคัญที่ควรทราบคือตัวแปรสลับ ซึ่งติดตามความสำเร็จของการโทรกลับและพิมพ์เมนูหากเป็นจริง หากไม่ส่งคืนสิ่งใดหรือเป็นเท็จ ระบบจะพิมพ์ข้อความแสดงข้อผิดพลาด นี่คือที่ที่คุณสามารถใช้การโทรกลับเพื่อทำสิ่งอื่นได้

if((menuSavePressed == HIGH) && (menuSavePreviousState == LOW)){ // ออกจากเมนู // คุณสามารถจัดระเบียบอะไรก็ได้ // หรือบันทึกลงใน EEPROM menuMode = false; Serial.println("ออกจากเมนู"); // สลับสถานะเพื่อให้เมนูออกเพียงครั้งเดียว menuSavePreviousState = menuSavePressed; } }

ฟังก์ชันนี้จัดการปุ่ม menuSave ซึ่งเพิ่งออกจากเมนู นี่คือที่ที่คุณสามารถมีตัวเลือกในการยกเลิกหรือบันทึก อาจทำการล้างข้อมูลหรือบันทึกลงใน EEPROM ฉันเพิ่งพิมพ์ "ออกจากเมนู" และตั้งค่าสถานะปุ่มเป็น HIGH เพื่อไม่ให้วนซ้ำ

if(menuMode && menuNeedsPrint){ // เราพิมพ์เมนูแล้ว เว้นแต่จะมีอะไรเกิดขึ้น // ไม่จำเป็นต้องพิมพ์ใหม่อีกครั้ง menuNeedsPrint = false; ถ่าน *optionActive = ReturnOptionSelected(); ถ่าน *optionStatus = ReturnOptionStatus(); Serial.print("เลือกแล้ว: "); Serial.print (optionActive); Serial.print(": "); Serial.print (ตัวเลือกสถานะ); Serial.println(); }

นี่คืออัลกอริธึมของ menuPrint ซึ่งจะเริ่มทำงานเฉพาะเมื่อเมนูเปิดใช้งานอยู่และเมื่อตัวแปร menuNeedsPrint ถูกตั้งค่าเป็น true

สิ่งนี้สามารถย้ายไปยังฟังก์ชั่นของตัวเองได้อย่างแน่นอน แต่เพื่อความเรียบง่าย..!

แค่นั้นแหละ! ดูขั้นตอนถัดไปสำหรับบล็อกโค้ดทั้งหมด

ขั้นตอนที่ 10: Final Code Block

// กำหนดค่าคงที่

#define menuปุ่ม 2 #define menuSelect 3 #define menuSave 4 #define debounceTimeout 50 int menuButtonPreviousState = LOW; int menuSelectPreviousState = ต่ำ; int menuSavePreviousState = ต่ำ; // กำหนดตัวแปร long int lastDebounceTime; bool lightSensor = จริง; bool tempSensor = จริง; // ตัวเลือกเมนู char * menuOptions = {"Check Temp", "Check Light"}; bool featureSetting = {เท็จ เท็จ}; bool menuMode = เท็จ; เมนูบูลNeedsPrint = false; int optionSelected = 0; // ฟังก์ชั่นการตั้งค่า

การตั้งค่าเป็นโมฆะ () { pinMode (menuSelect, INPUT); โหมดพิน (menuSave, INPUT); pinMode (เลือกเมนู, อินพุต); Serial.begin(9600); }

// ฟังก์ชันเพื่อคืนค่าตัวเลือกที่เลือกในปัจจุบัน ถ่าน *ReturnOptionSelected(){ ถ่าน *menuOption = menuOptions[optionSelected]; // Return option เมนูส่งคืนที่เลือก ตัวเลือก; } // ฟังก์ชันส่งคืนสถานะของตัวเลือกที่เลือกในปัจจุบัน ถ่าน *ReturnOptionStatus(){ bool optionSetting = featureSetting[optionSelected]; ถ่าน *ตัวเลือกSettingVal; ถ้า (optionSetting == false) { optionSettingVal = "False"; }อื่น{ optionSettingVal = "จริง"; } // Return optionSetting return optionSettingVal; } // ฟังก์ชันเพื่อสลับบูลตัวเลือกปัจจุบัน ToggleOptionSelected(){ featureSetting[optionSelected] = !featureSetting[optionSelected]; คืนค่าจริง; } // ลูปหลัก

วงเป็นโมฆะ () { // อ่านปุ่ม int menuButtonPressed = digitalRead (menuButton); int menuSelectPressed = digitalRead(menuSelect); int menuSavePressed = digitalRead (menuSave); // รับเวลาปัจจุบัน long int currentTime = millis(); if(menuButtonPressed == LOW && menuSelectPressed == LOW && menuSavePressed == LOW){ //รีเซ็ตเวลานับในขณะที่ไม่ได้กดปุ่ม lastDebounceTime = currentTime; menuButtonPreviousState = ต่ำ; menuSelectPreviousState = ต่ำ; menuSavePreviousState = ต่ำ; } if(((currentTime - lastDebounceTime) > debounceTimeout)){ // หากหมดเวลา ให้กดปุ่ม!

// กดเมนูแล้วให้ตรรกะ

// ยิงเฉพาะเมื่อปุ่มถูกปล่อยออกมาก่อนหน้านี้ if((menuButtonPressed == HIGH) && (menuButtonPreviousState == LOW)){ if(menuMode == false){ menuMode = true; // แจ้งให้ผู้ใช้ทราบ Serial.println("เมนูใช้งานได้"); } else if (menuMode == true && optionSelected = 1){ // รีเซ็ตตัวเลือก optionSelected = 0; } // พิมพ์เมนู menuNeedsPrint = true; // สลับปุ่มก่อนหน้า กำหนดให้แสดงเฉพาะเมนู // หากปล่อยปุ่มแล้วกดอีกครั้ง menuButtonPreviousState = menuButtonPressed; // จะสูง } // กด menuSelect ให้ตรรกะ if((menuSelectPressed == HIGH) && (menuSelectPreviousState == LOW)){ if(menuMode){ // เปลี่ยนตัวเลือกที่เลือก // ในขณะนี้คือ แค่ true/false // แต่อาจเป็นอะไรก็ได้ที่สลับบูล = ToggleOptionSelected(); ถ้า (สลับ) { menuNeedsPrint = true; }อื่น{ Serial.print("มีบางอย่างผิดพลาด โปรดลองอีกครั้ง"); } } // สลับสถานะเป็นสลับเฉพาะเมื่อปล่อยและกดอีกครั้ง menuSelectPreviousState = menuSelectPressed; } if((menuSavePressed == HIGH) && (menuSavePreviousState == LOW)){ // ออกจากเมนู // คุณสามารถจัดระเบียบอะไรก็ได้ // หรือบันทึกลงใน EEPROM menuMode = false; Serial.println("ออกจากเมนู"); // สลับสถานะเพื่อให้เมนูออกเพียงครั้งเดียว menuSavePreviousState = menuSavePressed; } } // พิมพ์ตัวเลือกเมนูปัจจุบันที่เปิดใช้งาน แต่พิมพ์เพียงครั้งเดียวหาก (menuMode && menuNeedsPrint){ // เราพิมพ์เมนูแล้ว ดังนั้นเว้นแต่จะมีอะไรเกิดขึ้น // ไม่จำเป็นต้องพิมพ์อีกครั้ง menuNeedsPrint = false; ถ่าน *optionActive = ReturnOptionSelected(); ถ่าน *optionStatus = ReturnOptionStatus(); Serial.print("เลือกแล้ว: "); Serial.print (optionActive); Serial.print(": "); Serial.print (ตัวเลือกสถานะ); Serial.println(); } } }

วงจรมีอยู่ในเว็บไซต์ Tinkercad ได้ฝังวงจรด้านล่างมาให้ชมกันด้วย!

เช่นเคย หากคุณมีคำถามหรือปัญหา โปรดแจ้งให้เราทราบ!

แนะนำ: