Πίνακας περιεχομένων:

Ένα μενού στο Arduino και πώς να χρησιμοποιήσετε τα κουμπιά: 10 βήματα (με εικόνες)
Ένα μενού στο Arduino και πώς να χρησιμοποιήσετε τα κουμπιά: 10 βήματα (με εικόνες)

Βίντεο: Ένα μενού στο Arduino και πώς να χρησιμοποιήσετε τα κουμπιά: 10 βήματα (με εικόνες)

Βίντεο: Ένα μενού στο Arduino και πώς να χρησιμοποιήσετε τα κουμπιά: 10 βήματα (με εικόνες)
Βίντεο: How to use up to 10 push button switch with 1 Arduino input pin ANPB-V1 2024, Ιούλιος
Anonim
Ένα μενού στο Arduino και πώς να χρησιμοποιήσετε τα κουμπιά
Ένα μενού στο Arduino και πώς να χρησιμοποιήσετε τα κουμπιά

Στο σεμινάριο μου στο Arduino 101, θα διδαχτείτε πώς να ρυθμίσετε το περιβάλλον σας στο Tinkercad. Χρησιμοποιώ το Tinkercad επειδή είναι μια αρκετά ισχυρή διαδικτυακή πλατφόρμα που μου επιτρέπει να επιδείξω μια σειρά δεξιοτήτων στους μαθητές για την κατασκευή κυκλωμάτων. Μη διστάσετε να δημιουργήσετε όλα τα σεμινάρια μου χρησιμοποιώντας το Arduino IDE και ένα πραγματικό Arduino!

Σε αυτό το σεμινάριο, θα μάθουμε για τα κουμπιά! Πρέπει να ξέρουμε:

  • Πώς να τα συνδέσετε
  • Διαβάζοντας την αξία τους
  • Debounce και γιατί είναι σημαντικό
  • Μια πρακτική εφαρμογή (δημιουργία μενού)

Οι περισσότεροι άνθρωποι πιστεύουν ότι το πιο πρακτικό πράγμα που πρέπει να κάνετε με ένα κουμπί είναι να ανάψετε και να σβήσετε ένα φως. Εμείς, όχι εδώ! Θα χρησιμοποιήσουμε το δικό μας για να δημιουργήσουμε ένα μενού και να ορίσουμε μερικές επιλογές στο Arduino.

Ετοιμος? Ας αρχίσουμε!

Βήμα 1: Ρύθμιση του πίνακα

Ρύθμιση του πίνακα
Ρύθμιση του πίνακα
Ρύθμιση του πίνακα
Ρύθμιση του πίνακα

Το πρώτο βήμα είναι να τοποθετήσετε ένα Arduino και ένα Breadboard Small στην περιοχή πρωτοτύπων. Ελέγξτε τις παραπάνω εικόνες για να δείτε πώς να συνδέσετε τις ράγες τροφοδοσίας.

Ένα Breadboard Mini έχει δύο ράγες ισχύος πάνω και κάτω. Τα συνδέουμε με το Arduino, ώστε να μπορούμε να παρέχουμε ενέργεια σε περισσότερα εξαρτήματα. Αργότερα σε αυτό το σεμινάριο θα χρησιμοποιήσουμε 3 κουμπιά, οπότε θα χρειαστούμε περισσότερη ενέργεια. Αυτό που πρέπει να σημειωθεί είναι ότι σε μια μικρή σανίδα ψωμιού, οι ράγες τροφοδοσίας περνούν παντού, οριζόντια. Αυτό είναι διαφορετικό από τις στήλες στην κύρια περιοχή πρωτοτύπων στη μέση. αυτά τρέχουν κάθετα. Μπορείτε να χρησιμοποιήσετε οποιαδήποτε από τις ακίδες τροφοδοσίας για να παρέχετε ισχύ σε οποιαδήποτε στήλη στην κύρια περιοχή στη μέση.

Όταν προσθέτετε ισχύ, χρησιμοποιήστε μαύρα και κόκκινα καλώδια στα αρνητικά και θετικά αντίστοιχα. Προσθέστε καλώδια στο τέλος που τρέχουν ισχύ στην άλλη πλευρά του πίνακα. Δεν θα χρησιμοποιήσουμε αυτήν την πλευρά, αλλά είναι καλή πρακτική.

Βήμα 2: Προσθέστε το κουμπί και την αντίσταση

Προσθέστε το κουμπί και την αντίσταση
Προσθέστε το κουμπί και την αντίσταση
Προσθέστε το κουμπί και την αντίσταση
Προσθέστε το κουμπί και την αντίσταση
Προσθέστε το κουμπί και την αντίσταση
Προσθέστε το κουμπί και την αντίσταση

Προσθέστε ένα μικρό κουμπί από το δίσκο εξαρτημάτων. Θα πρέπει να μοιάζει με αυτό της εικόνας. Βεβαιωθείτε ότι δεν είναι διακόπτης! Προσθέστε επίσης μια αντίσταση. Κάντε κλικ σε αυτό και ορίστε την τιμή του στα 10kΩ. Αυτό είναι αρκετό για να τραβήξει τον πείρο χαμηλά όταν δεν είναι συνδεδεμένος, κάτι που είναι πολύ σημαντικό αργότερα στον κώδικα.

Τοποθετήστε το συστατικό στη μέση της σανίδας. Ο τρόπος λειτουργίας ενός κουμπιού είναι:

  • Γωνία σε γωνία, το κουμπί δεν είναι συνδεδεμένο. Πατώντας το κουμπί κλείνουν οι επαφές και συνδέονται οι γωνίες.
  • Οι πλευρές του κουμπιού είναι συνδεδεμένες. Εάν συνδέσετε ένα καλώδιο πάνω αριστερά και κάτω αριστερά, το κύκλωμα θα είναι κλειστό.

Αυτός είναι ο λόγος για τον οποίο βάζουμε το στοιχείο σε όλο το χώρο στη μέση. Βεβαιώνεται ότι οι γωνίες δεν είναι συνδεδεμένες κάτω από τους πείρους στον πίνακα.

Το επόμενο βήμα παρέχει μερικές εικόνες που απεικονίζουν αυτά τα σημεία.

Τοποθετήστε την αντίσταση από τον κάτω δεξιό πείρο κατά μήκος των στηλών, έτσι ώστε να κάθεται οριζόντια.

Βήμα 3: Συνδέσεις κουμπιών

Συνδέσεις κουμπιού
Συνδέσεις κουμπιού
Συνδέσεις κουμπιού
Συνδέσεις κουμπιού

Οι παραπάνω εικόνες καθιστούν αρκετά σαφή τον τρόπο σύνδεσης των κουμπιών. Alwaysταν πάντα ένα σημείο σύγχυσης όταν πιστεύεις ότι κάτι είναι καλό και δεν λειτουργεί!

Τώρα, ας προσθέσουμε τα καλώδια.

  • Τοποθετήστε ένα κόκκινο καλώδιο από μια θετική καρφίτσα ισχύος στην ίδια στήλη με την κάτω δεξιά ακίδα στο κουμπί
  • Τοποθετήστε ένα μαύρο καλώδιο από έναν πείρο αρνητικής ισχύος στην ίδια στήλη με την αντίσταση.
  • Τοποθετήστε ένα χρωματιστό σύρμα (όχι κόκκινο/μαύρο) από την επάνω αριστερή καρφίτσα στο Digital Pin 2 στο Arduino

Ελέγξτε τις παραπάνω εικόνες για να βεβαιωθείτε ότι η καλωδίωση είναι σωστή.

Βήμα 4: Ο Κώδικας…

Ο κώδικας…
Ο κώδικας…
Ο κώδικας…
Ο κώδικας…

Ας ρίξουμε μια ματιά στον κώδικα για ένα βασικό κουμπί.

Ανοίξτε τον επεξεργαστή κώδικα και αλλάξτε από Blocks σε Text. Διαγράψτε την προειδοποίηση που εμφανίζεται. Είμαστε ευχαριστημένοι με το κείμενο!

Γνωρίζετε τη βασική ρύθμιση, οπότε ας ορίσουμε το κουμπί και κάνουμε μια βασική ανάγνωση. Θα εκτυπώσουμε την έξοδο σε Serial.

Έβαλα μερικά επιπλέον σχόλια στον παρακάτω κώδικα, ώστε να είναι ευκολότερο να διαβαστεί από την εικόνα.

// Ορισμός σταθερών

#define button 2 void setup () {pinMode (button, INPUT); Serial.begin (9600); } void loop () {// Διαβάστε την ψηφιακή καρφίτσα για να ελέγξετε την κατάσταση του κουμπιού int πατημένο = digitalRead (κουμπί); // Το κουμπί επιστρέφει HIGH αν πατηθεί, LOW αν όχι αν (πατημένο == HIGH) {Serial.println ("Pressed!"); }}

Εντάξει, καλά λειτουργεί!

Ουσιαστικά, το μόνο που κάνουμε είναι να ελέγχουμε την κατάσταση του ψηφιακού pin κάθε φορά που ο κώδικας βρόχος. Εάν κάνετε κλικ στο κουμπί Έναρξη προσομοίωσης και πατήσετε το κουμπί, θα δείτε την οθόνη Serial Monitor (κάντε κλικ στο κουμπί κάτω από τον κώδικα) "Πατημένο!" κατ 'επανάληψη.

Ένα χαρακτηριστικό που θα δείτε στον παραπάνω κώδικα είναι η εκτίμηση της κατάστασης if (). Το μόνο που κάνει ο κώδικας είναι να κάνει μια ερώτηση και να αξιολογεί αν είναι αληθινός, σε αυτή την περίπτωση. Χρησιμοποιούμε το ίσο (διπλά σημάδια ισότητας, όπως αυτό: ==) για να ελέγξουμε αν η τιμή της μεταβλητής είναι ίση με μια συγκεκριμένη τιμή. Ένα digitalRead () επιστρέφει είτε Υ HIGHΗΛΟ είτε ΧΑΜΗΛΟ.

Χρησιμοποιώντας το if () else if / else μπορούμε να ελέγξουμε πολλές συνθήκες ή όλες τις συνθήκες και αν επιστρέψετε στα βασικά του Arduino, θα δείτε μερικές από τις συγκρίσεις που μπορείτε να κάνετε.

Τώρα… Ο κωδικός μας μπορεί να φαίνεται πλήρης… Αλλά έχουμε ένα πρόβλημα.

Βλέπετε, αυτό λειτουργεί πολύ καλά όταν βρίσκεστε στον προσομοιωτή. Αλλά ο πραγματικός ηλεκτρισμός έχει θόρυβο, ειδικά τα ηλεκτρονικά DC. Έτσι, το κουμπί μας μπορεί μερικές φορές να επιστρέψει μια λανθασμένη ανάγνωση. Και αυτό είναι ένα πρόβλημα, επειδή το έργο σας ενδέχεται να μην ανταποκρίνεται με τον σωστό τρόπο για τον χρήστη.

Ας το φτιάξουμε!

Βήμα 5: Μικρή απογείωση

Μια μικρή ντεμπούτα
Μια μικρή ντεμπούτα

Χρησιμοποιούμε μια διαδικασία που ονομάζεται debounce για να ξεπεράσουμε το πρόβλημα του κουμπιού μας. Αυτό ουσιαστικά περιμένει ένα συγκεκριμένο χρονικό διάστημα μεταξύ της ώθησης του κουμπιού και της πραγματικής απόκρισης στο πάτημα. Εξακολουθεί να είναι φυσικό για τον χρήστη (εκτός εάν κάνετε πολύ χρόνο). Μπορείτε επίσης να το χρησιμοποιήσετε για τον έλεγχο της διάρκειας του πιεστηρίου, ώστε να μπορείτε να απαντάτε διαφορετικά κάθε φορά. Δεν χρειάζεται να αλλάξετε καμία από τις καλωδιώσεις!

Ας δούμε τον κώδικα:

#καθορίστε το κουμπί 2#καθορίστε το debounceTimeout 100

Η πρώτη αλλαγή αφορά την παγκόσμια εμβέλεια. Θα θυμάστε ότι εκεί ορίζουμε μεταβλητές που μπορούν να χρησιμοποιούν πολλές από τις λειτουργίες μας ή εκείνες που δεν μπορούν να επαναρυθμιστούν κάθε φορά που ενεργοποιείται ο βρόχος. Έτσι, προσθέσαμε το debounceTimeout στις καθορισμένες σταθερές. Φτιάξαμε αυτό το 100 (το οποίο αργότερα θα μεταφραστεί σε 100ms), αλλά θα μπορούσε να είναι συντομότερο. Πλέον και θα είναι αφύσικο.

long int lastDebounceTime;

Αυτή η μεταβλητή δηλώνεται κάτω από τις σταθερές. Αυτός είναι ένας μεγάλος τύπος int, ο οποίος μας επιτρέπει βασικά να αποθηκεύσουμε μεγάλους αριθμούς στη μνήμη. Το ονομάσαμε lastDebounceTime.

Δεν χρειάζεται να αλλάξουμε τίποτα στη συνάρτηση void setup (). Ας το αφήσουμε αυτό.

void loop () {// Διαβάστε την ψηφιακή καρφίτσα για να ελέγξετε την κατάσταση του κουμπιού int πατημένο = digitalRead (κουμπί); long int currentTime = millis (); // Κωδικός κουμπιού}

Η πρώτη αλλαγή που κάνουμε στη συνάρτηση βρόχου () είναι κάτω από την κλήση για ανάγνωση του κουμπιού. Πρέπει να παρακολουθούμε την τρέχουσα ώρα. Η συνάρτηση millis () επιστρέφει την τρέχουσα ώρα του ρολογιού από την εκκίνηση του Arduino σε χιλιοστά του δευτερολέπτου. Πρέπει να το αποθηκεύσουμε σε μια μεταβλητή τύπου int.

Τώρα, πρέπει να βεβαιωθούμε ότι γνωρίζουμε την ώρα από το πάτημα του κουμπιού, οπότε επαναφέρουμε το χρονόμετρο όταν δεν πατηθεί. Ρίξε μια ματιά:

void loop () {// Διαβάστε την ψηφιακή καρφίτσα για να ελέγξετε την κατάσταση του κουμπιού int πατημένο = digitalRead (κουμπί); long int currentTime = millis (); εάν (πατημένο == LOW) {// Επαναφορά του χρόνου καταμέτρησης ενώ το κουμπί δεν πατάτε lastDebounceTime = currentTime. } // Κωδικός κουμπιού}

Ο αλγόριθμος if (πατημένος == LOW) ελέγχει εάν δεν πατηθεί το κουμπί. Εάν δεν είναι, τότε ο κώδικας αποθηκεύει την τρέχουσα ώρα από την τελευταία αποκήρυξη. Με αυτόν τον τρόπο, κάθε φορά που πατάτε το κουμπί, έχουμε ένα χρονικό σημείο από το οποίο μπορούμε να ελέγξουμε πότε πατήθηκε το κουμπί. Στη συνέχεια, μπορούμε να κάνουμε έναν γρήγορο μαθηματικό υπολογισμό για να δούμε πόσο καιρό πατήθηκε το κουμπί και να απαντήσουμε σωστά. Ας δούμε τον υπόλοιπο κώδικα:

void loop () {// Διαβάστε την ψηφιακή καρφίτσα για να ελέγξετε την κατάσταση του κουμπιού int πατημένο = digitalRead (κουμπί); long int currentTime = millis (); εάν (πατημένο == LOW) {// Επαναφορά του χρόνου καταμέτρησης ενώ το κουμπί δεν πατάτε lastDebounceTime = currentTime; } // Το κουμπί έχει πατηθεί για μια δεδομένη χρονική στιγμή εάν (((currentTime - lastDebounceTime)> debounceTimeout)) {// Εάν επιτευχθεί το χρονικό όριο, πατήστε το κουμπί! Serial.println ("Πατημένο!"); }}

Το τελευταίο μπλοκ κώδικα παίρνει τον τρέχοντα χρόνο, αφαιρεί τον τελευταίο χρόνο αποσύνδεσης και τον συγκρίνει με το χρονικό όριο που έχουμε ορίσει. Εάν είναι μεγαλύτερο, ο κώδικας υποθέτει ότι το κουμπί έχει πατηθεί για εκείνη τη στιγμή και αποκρίνεται. Καθαρός!

Εκτελέστε τον κωδικό σας και ελέγξτε ότι λειτουργεί. Εάν έχετε σφάλματα, ελέγξτε τον κωδικό σας!

Τώρα, ας δούμε ένα πρακτικό παράδειγμα.

Βήμα 6: Η δημιουργία ενός μενού

Η παρασκευή ενός μενού
Η παρασκευή ενός μενού

Τα κουμπιά είναι ενδιαφέροντα, γιατί υπάρχουν τόσες πολλές δυνατότητες μαζί τους! Σε αυτό το παράδειγμα, θα φτιάξουμε ένα μενού. Ας υποθέσουμε ότι έχετε δημιουργήσει αυτήν την πραγματικά υπέροχη συσκευή και χρειάζεστε χρήστες για να μπορούν να αλλάζουν επιλογές για να ενεργοποιήσουν ή να απενεργοποιήσουν ορισμένα πράγματα ή να ορίσουν μια συγκεκριμένη τιμή για μια ρύθμιση. Αυτός ο σχεδιασμός με τρία κουμπιά μπορεί να το κάνει!

Έτσι, για αυτό το έργο χρειαζόμαστε:

  • Τρία κουμπιά
  • Τρεις αντιστάσεις ρυθμισμένες στα 10kΩ

Έχουμε ήδη ένα από αυτά, χρειαζόμαστε μόνο τα άλλα δύο. Προσθέστε τα λοιπόν στον πίνακα. Η καλωδίωση είναι λίγο πιο περίπλοκη, αλλά μόνο επειδή ήθελα να το κρατήσω πραγματικά συμπαγές. Μπορείτε να ακολουθήσετε το ίδιο μοτίβο για το πρώτο κουμπί ή να ακολουθήσετε την παραπάνω εικόνα.

Τα τρία κουμπιά είναι μια επιλογή ανοίγματος μενού/επόμενη, μια επιλογή αλλαγής (όπως στο, αλλάξτε τη ρύθμιση) και ένα κουμπί αποθήκευσης/κλεισίματος μενού.

Συνδέστε το, ας δούμε τον κωδικό!

Βήμα 7: Ανάλυση κώδικα - Παγκόσμιο

Εντάξει, αυτό θα είναι ένα μακρύ βήμα, αλλά θα περάσω από κάθε τμήμα του κώδικα.

Αρχικά, ας δούμε τις συνολικές μεταβλητές που απαιτούνται.

// Ορισμός σταθερών #καθορισμός μενούΠλήκτρο 2 #καθορισμός μενούΕπιλογή 3 #καθορισμός μενούΑποθήκευση 4 #καθορισμός debounceTimeout 50 // Ορισμός μεταβλητών int menuButtonPreviousState = LOW; int menuSelectPreviousState = LOW; int menuSavePreviousState = LOW; long int lastDebounceTime; // Επιλογές μενού char * menuOptions = {"Check Temp", "Check Light"}; bool featureSetting = {false, false}; bool menuMode = false; bool menuNeedsPrint = false; int optionSelected = 0;

Αυτά τα τρία μπλοκ είναι αρκετά παρόμοια με αυτά που έχουμε δει στο παρελθόν. Στο πρώτο, έχω ορίσει τα τρία κουμπιά και το χρονικό όριο. Για αυτό το μέρος του έργου, το έχω θέσει στα 50ms, οπότε χρειάζεται μια σκόπιμη πίεση για να λειτουργήσει.

Το δεύτερο μπλοκ είναι όλες οι μεταβλητές. Πρέπει να παρακολουθούμε το κουμπίPreviousState και πρέπει να παρακολουθούμε το τελευταίοDebounceTime. Αυτές είναι όλες μεταβλητές τύπου int, αλλά η τελευταία είναι μακράς τύπου επειδή υποθέτω ότι χρειαζόμαστε το χώρο στη μνήμη.

Το μπλοκ επιλογών μενού έχει μερικές νέες δυνατότητες. Πρώτον, το char * (ναι, πρόκειται για σκόπιμο αστερίσκο), το οποίο είναι κυριολεκτική μεταβλητή χαρακτήρα/συμβολοσειράς. Είναι ένας δείκτης για μια στατική αποθήκευση στη μνήμη. Δεν μπορείτε να το αλλάξετε (όπως μπορείτε για παράδειγμα στην Python). Αυτή η γραμμή char *menuOptions δημιουργεί μια σειρά κυριολεκτικών συμβολοσειρών. Μπορείτε να προσθέσετε όσα στοιχεία μενού θέλετε.

Η μεταβλητή bool featureSetting είναι απλώς ο πίνακας τιμών που αντιπροσωπεύει κάθε στοιχείο μενού. Ναι, θα μπορούσατε να αποθηκεύσετε οτιδήποτε σας αρέσει, απλώς αλλάξτε τον τύπο της μεταβλητής (όλες πρέπει να είναι του ίδιου τύπου). Τώρα, μπορεί να υπάρχουν καλύτεροι τρόποι διαχείρισης, όπως λεξικά ή πλειάδες, αλλά αυτό είναι απλό για αυτήν την εφαρμογή. Πιθανότατα θα δημιουργούσα ένα από τα τελευταία σε μια εκτεταμένη εφαρμογή.

Έχω παρακολουθήσει το menuMode, οπότε αν ήθελα άλλα πράγματα στην οθόνη μου θα μπορούσα να το κάνω. Επίσης, αν είχα λογική αισθητήρα, θα μπορούσα να το διακόψω κατά τη λειτουργία του μενού, σε περίπτωση που κάτι συγκρούεται. Έχω μια μεταβλητή menuNeedsPrint επειδή θέλω να εκτυπώσω το μενού σε συγκεκριμένες ώρες, όχι μόνο όλη την ώρα. Τέλος, έχω μια μεταβλητή optionSelected, ώστε να μπορώ να παρακολουθώ την επιλεγμένη επιλογή καθώς έχω πρόσβαση σε αυτήν σε πολλά σημεία.

Ας δούμε το επόμενο σύνολο συναρτήσεων.

Βήμα 8: Ανάλυση κώδικα - Ρύθμιση και προσαρμοσμένες λειτουργίες

Η λειτουργία εγκατάστασης () είναι αρκετά εύκολη, μόνο τρεις δηλώσεις εισόδου:

void setup () {pinMode (menuSelect, INPUT); pinMode (menuSave, INPUT); pinMode (menuSelect, INPUT); Serial.begin (9600); }

Ακολουθούν οι τρεις προσαρμοσμένες συναρτήσεις. Ας δούμε τα δύο πρώτα, μετά το τελευταίο ξεχωριστά.

Χρειαζόμαστε δύο συναρτήσεις που επιστρέφουν κάποιες πληροφορίες. Ο λόγος είναι ότι θέλουμε να βεβαιωθούμε ότι αυτό είναι ένα είδος ανθρώπινης ανάγνωσης. Θα βοηθήσει επίσης με τον εντοπισμό σφαλμάτων του κώδικα εάν έχουμε κάποιο πρόβλημα. Κώδικας:

// Λειτουργία επιστροφής του τρέχοντος επιλεγμένου optionchar *ReturnOptionSelected () {char *menuOption = menuOptions [optionSelected]; // Επιλογή επιστροφήςΕπιλεγμένο μενού επιστροφήςΕπιλογή; } // Λειτουργία για την επιστροφή της κατάστασης της τρέχουσας επιλεγμένης επιλογής char *ReturnOptionStatus () {bool optionSetting = featureSetting [optionSelected]; char *optionSettingVal; if (optionSetting == false) {optionSettingVal = "Λάθος"; } else {optionSettingVal = "True"; } // Return optionSetting return optionSettingVal; }

Η συνάρτηση char *ReturnOptionSelected () ελέγχει την επιλεγμένη επιλογή (αν βλέπετε παραπάνω, ορίζουμε μια μεταβλητή για να την παρακολουθούμε) και τραβά τη συμβολοσειρά κυριολεκτικά από τον πίνακα που δημιουργήσαμε νωρίτερα. Στη συνέχεια το επιστρέφει ως τύπος κάρτας. Το γνωρίζουμε επειδή η συνάρτηση υποδεικνύει τον τύπο επιστροφής.

Η δεύτερη συνάρτηση, char *ReturnOptionStatus () διαβάζει την κατάσταση της επιλογής που είναι αποθηκευμένη στον πίνακα και επιστρέφει μια συμβολοσειρά κυριολεκτική που αντιπροσωπεύει την τιμή. Για παράδειγμα, εάν η ρύθμιση που έχουμε αποθηκεύσει είναι ψευδής, θα επέστρεφα "False". Αυτό συμβαίνει επειδή δείχνουμε στον χρήστη αυτήν τη μεταβλητή και είναι καλύτερα να διατηρήσουμε όλη αυτή τη λογική μαζί. Θα μπορούσα να το κάνω αργότερα, αλλά είναι πιο λογικό να το κάνω εδώ.

// Λειτουργία για εναλλαγή της τρέχουσας optionbool ToggleOptionSelected () {featureSetting [optionSelected] =! FeatureSetting [optionSelected]; επιστροφή αληθινός? }

Η λειτουργία bool ToggleOptionSelected () είναι μια συνάρτηση ευκολίας για να αλλάξετε την τιμή της ρύθμισης που έχουμε επιλέξει στο μενού. Απλώς ανατρέπει την αξία. Εάν είχατε ένα πιο σύνθετο σύνολο επιλογών, αυτό μπορεί να είναι πολύ διαφορετικό. Επιστρέφω true σε αυτήν τη συνάρτηση, επειδή η επανάκλησή μου (η κλήση αργότερα στον κώδικα που ενεργοποιεί αυτήν τη λειτουργία) αναμένει μια αληθινή/ψευδή απάντηση. Είμαι 100% σίγουρος ότι αυτό θα λειτουργήσει, οπότε δεν έδωσα λογαριασμό ότι δεν λειτουργεί, αλλά θα το έκανα σε μια ανεπτυγμένη εφαρμογή (για κάθε περίπτωση).

Βήμα 9: Ο βρόχος…

Η συνάρτηση βρόχου () είναι αρκετά μεγάλη, οπότε θα το κάνουμε τμηματικά. Μπορείτε να υποθέσετε τα πάντα κάτω από τις φωλιές σε αυτήν τη συνάρτηση:

void 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 = LOW; menuSelectPreviousState = LOW; menuSavePreviousState = LOW; }

Το μόνο που έπρεπε να κάνω εδώ ήταν να προσθέσω τις τρεις κλήσεις 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) {// Reset option optionSelected = 0; } // Εκτύπωση του μενού menuNeedsPrint = true; // Εναλλαγή κουμπιού προηγούμενο. κατάσταση μόνο για εμφάνιση του μενού // εάν το κουμπί απελευθερωθεί και πατηθεί ξανά menuButtonPreviousState = menuButtonPressed; // Θα ήταν Υ HIGHΗΛΟ}

Αυτό το πρώτο χειρίζεται όταν το menuButtonPressed είναι Υ HIGHΗΛΟ ή όταν πατάτε το κουμπί μενού. Ελέγχει επίσης για να βεβαιωθεί ότι η προηγούμενη κατάσταση ήταν ΧΑΜΗΛΗ, έτσι ώστε το κουμπί να πρέπει να απελευθερωθεί πριν πατηθεί ξανά, γεγονός που εμποδίζει το πρόγραμμα να ενεργοποιεί συνεχώς το ίδιο συμβάν ξανά και ξανά.

Στη συνέχεια, ελέγχει ότι εάν το μενού δεν είναι ενεργό, το ενεργοποιεί. Θα εκτυπώσει την πρώτη επιλογή που είναι επιλεγμένη (το οποίο είναι το πρώτο στοιχείο στο μενού) Ο πίνακας επιλογών από προεπιλογή. Εάν πατήσετε το κουμπί για δεύτερη ή τρίτη (κλπ) φορά, θα λάβετε την επόμενη επιλογή στη λίστα. Κάτι που θα μπορούσα να διορθώσω είναι ότι όταν φτάσει στο τέλος, επιστρέφει στην αρχή. Αυτό θα μπορούσε να διαβάσει το μήκος του πίνακα και να κάνει την ποδηλασία πιο εύκολη αν αλλάξετε τον αριθμό των επιλογών, αλλά αυτό ήταν απλό προς το παρόν.

Το τελευταίο μικρό τμήμα (// Εκτυπώνει το μενού) εκτυπώνει προφανώς το μενού, αλλά ορίζει επίσης την προηγούμενη κατάσταση σε Υ HIGHΗΛΗ, έτσι ώστε η ίδια λειτουργία να μην κάνει βρόχο (δείτε την παραπάνω σημείωσή μου σχετικά με τον έλεγχο αν το κουμπί ήταν προηγουμένως ΧΑΜΗΛΟ).

// menuSelect πιέζεται, παρέχετε το logicif ((menuSelectPressed == HIGH) && (menuSelectPreviousState == LOW)) {if (menuMode) {// Αλλάξτε την επιλεγμένη επιλογή // Προς το παρόν, αυτό είναι απλώς αληθές/λάθος // αλλά θα μπορούσε να είναι οτιδήποτε bool toggle = ToggleOptionSelected (); if (εναλλαγή) {menuNeedsPrint = true; } else {Serial.println ("Κάτι πήγε στραβά. Δοκιμάστε ξανά"); }} // Εναλλαγή κατάστασης για εναλλαγή μόνο εάν απελευθερωθεί και πατηθεί ξανά menuSelectPreviousState = menuSelectPressed; }

Αυτό το κομμάτι κώδικα χειρίζεται το κουμπί menuSelectPressed με τον ίδιο τρόπο, εκτός από αυτήν τη φορά που απλώς ενεργοποιούμε τη λειτουργία ToggleOptionSelected (). Όπως είπα και πριν, μπορείτε να αλλάξετε αυτήν τη λειτουργία ώστε να κάνει περισσότερα, αλλά αυτό είναι το μόνο που χρειάζομαι για να κάνω.

Το κύριο πράγμα που πρέπει να σημειωθεί είναι η μεταβλητή εναλλαγής, η οποία παρακολουθεί την επιτυχία της επανάκλησης και τυπώνει το μενού εάν είναι αληθές. Εάν δεν επιστρέψει τίποτα ή λάθος, θα εκτυπώσει το μήνυμα σφάλματος. Εδώ μπορείτε να χρησιμοποιήσετε την επανάκλησή σας για να κάνετε άλλα πράγματα.

εάν ((menuSavePressed == HIGH) && (menuSavePreviousState == LOW)) {// Βγείτε από το μενού // Εδώ μπορείτε να κάνετε οποιαδήποτε τακτοποίηση // ή να αποθηκεύσετε στο μενού EEPROMMode = false; Serial.println ("Έξοδος από το μενού"); // Εναλλαγή κατάστασης ώστε το μενού να εξέρχεται μόνο μία φορά από το menuSavePreviousState = menuSavePressed; }}

Αυτή η λειτουργία χειρίζεται το κουμπί "Αποθήκευση μενού", το οποίο μόλις βγαίνει από το μενού. Εδώ θα μπορούσατε να έχετε επιλογή ακύρωσης ή αποθήκευσης, ίσως να κάνετε κάποιο καθάρισμα ή να αποθηκεύσετε στο EEPROM. Απλώς εκτυπώνω "Έξοδος από το μενού" και ορίζω την κατάσταση του κουμπιού σε Υ HIGHΗΛΗ για να μην κάνει βρόχο.

εάν (menuMode && menuNeedsPrint) {// Έχουμε εκτυπώσει το μενού, επομένως, εκτός εάν συμβεί κάτι //, δεν χρειάζεται να το εκτυπώσετε ξανά menuNeedsPrint = false; char *optionActive = ReturnOptionSelected (); char *optionStatus = ReturnOptionStatus (); Serial.print ("Επιλεγμένα:"); Serial.print (optionActive); 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; bool lightSensor = true; bool tempSensor = true; // Επιλογές μενού char * menuOptions = {"Check Temp", "Check Light"}; bool featureSetting = {false, false}; bool menuMode = false; bool menuNeedsPrint = false; int optionSelected = 0; // Λειτουργία εγκατάστασης

void setup () {pinMode (menuSelect, INPUT); pinMode (menuSave, INPUT); pinMode (menuSelect, INPUT); Serial.begin (9600); }

// Λειτουργία επιστροφής της τρέχουσας επιλεγμένης επιλογής char *ReturnOptionSelected () {char *menuOption = menuOptions [optionSelected]; // Επιλογή επιστροφήςΕπιλεγμένο μενού επιστροφήςΕπιλογή; } // Λειτουργία για την επιστροφή της κατάστασης της τρέχουσας επιλεγμένης επιλογής char *ReturnOptionStatus () {bool optionSetting = featureSetting [optionSelected]; char *optionSettingVal; if (optionSetting == false) {optionSettingVal = "Λάθος"; } else {optionSettingVal = "True"; } // Return optionSetting return optionSettingVal; } // Λειτουργία εναλλαγής τρέχουσας επιλογής bool ToggleOptionSelected () {featureSetting [optionSelected] =! FeatureSetting [optionSelected]; επιστροφή αληθινός? } // Ο κύριος βρόχος

void 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 = LOW; menuSelectPreviousState = LOW; menuSavePreviousState = LOW; } 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 = true; // Εναλλαγή κουμπιού προηγούμενο. κατάσταση μόνο για εμφάνιση του μενού // εάν το κουμπί απελευθερωθεί και πατηθεί ξανά menuButtonPreviousState = menuButtonPressed; // Θα ήταν HIGH} // menuSelect είναι πατημένο, παρέχετε λογική εάν ((menuSelectPressed == HIGH) && (menuSelectPreviousState == LOW)) {if (menuMode) {// Αλλάξτε την επιλεγμένη επιλογή // Προς το παρόν, αυτό είναι απλώς true/false // αλλά θα μπορούσε να είναι οτιδήποτε bool toggle = ToggleOptionSelected (); if (εναλλαγή) {menuNeedsPrint = true; } else {Serial.print ("Κάτι πήγε στραβά. Δοκιμάστε ξανά"); }} // Εναλλαγή κατάστασης για εναλλαγή μόνο εάν απελευθερωθεί και πατηθεί ξανά menuSelectPreviousState = menuSelectPressed; } if ((menuSavePressed == HIGH) && (menuSavePreviousState == LOW)) {// Έξοδος από το μενού // Εδώ μπορείτε να κάνετε οποιαδήποτε τακτοποίηση // ή να αποθηκεύσετε στο μενού EEPROMMode = false; Serial.println ("Έξοδος από το μενού"); // Εναλλαγή κατάστασης ώστε το μενού να εξέρχεται μόνο μία φορά από το menuSavePreviousState = menuSavePressed; }} // Εκτυπώστε την τρέχουσα επιλογή μενού ενεργή, αλλά εκτυπώστε την μόνο μία φορά εάν (menuMode && menuNeedsPrint) {// Έχουμε εκτυπώσει το μενού, επομένως, εκτός εάν συμβεί κάτι //, δεν χρειάζεται να το εκτυπώσετε ξανά menuNeedsPrint = false; char *optionActive = ReturnOptionSelected (); char *optionStatus = ReturnOptionStatus (); Serial.print ("Επιλεγμένα:"); Serial.print (optionActive); Serial.print (":"); Serial.print (optionStatus); Serial.println (); }}}

Το κύκλωμα είναι διαθέσιμο στην τοποθεσία Tinkercad. Έχω ενσωματώσει το κύκλωμα παρακάτω για να το δείτε κι εσείς!

Όπως πάντα, εάν έχετε ερωτήσεις ή προβλήματα, ενημερώστε με!

Συνιστάται: