Spisu treści:

Menu w Arduino i jak używać przycisków: 10 kroków (ze zdjęciami)
Menu w Arduino i jak używać przycisków: 10 kroków (ze zdjęciami)

Wideo: Menu w Arduino i jak używać przycisków: 10 kroków (ze zdjęciami)

Wideo: Menu w Arduino i jak używać przycisków: 10 kroków (ze zdjęciami)
Wideo: 2. Kurs Arduino - Przyciski [Tinkercad] 2024, Listopad
Anonim
Menu w Arduino i jak używać przycisków
Menu w Arduino i jak używać przycisków

W moim samouczku Arduino 101 dowiesz się, jak skonfigurować środowisko w Tinkercad. Używam Tinkercad, ponieważ jest to dość potężna platforma internetowa, która pozwala mi zademonstrować studentom szereg umiejętności budowania obwodów. Zapraszam do budowania wszystkich moich tutoriali przy użyciu Arduino IDE i prawdziwego Arduino!

W tym samouczku dowiemy się o przyciskach! Musimy wiedzieć:

  • Jak je podłączyć?
  • Czytanie ich wartości
  • Odbicie i dlaczego to ważne
  • Praktyczna aplikacja (tworzenie menu)

Większość ludzi uważa, że najpraktyczniejszą rzeczą, jaką można zrobić za pomocą przycisku, jest włączanie i wyłączanie światła. Nie tutaj! Użyjemy naszego do stworzenia menu i ustawienia niektórych opcji w Arduino.

Gotowy? Zacznijmy!

Krok 1: Skonfiguruj tablicę

Skonfiguruj tablicę
Skonfiguruj tablicę
Skonfiguruj tablicę
Skonfiguruj tablicę

Pierwszym krokiem jest umieszczenie Arduino i Breadboard Small w obszarze prototypowania. Sprawdź powyższe obrazy, aby zobaczyć, jak podłączyć szyny zasilające.

Breadboard Mini ma dwie szyny zasilające na górze i na dole. Podłączamy je do Arduino, dzięki czemu możemy zapewnić zasilanie większej liczbie komponentów. W dalszej części tego samouczka użyjemy 3 przycisków, więc będziemy potrzebować więcej mocy. Należy zauważyć, że na małej płytce stykowej szyny zasilające biegną poziomo po płytce. Różni się to od kolumn w głównym obszarze prototypowania pośrodku; te biegną pionowo. Możesz użyć dowolnego z pinów zasilania, aby zasilić dowolną kolumnę w głównym obszarze pośrodku.

Kiedy dodajesz zasilanie, użyj czarnych i czerwonych przewodów odpowiednio do ujemnego i dodatniego. Dodaj przewody na końcu, które prowadzą zasilanie na drugą stronę planszy. Nie będziemy korzystać z tej strony, ale to dobra praktyka.

Krok 2: Dodaj przycisk i rezystor

Dodaj przycisk i rezystor
Dodaj przycisk i rezystor
Dodaj przycisk i rezystor
Dodaj przycisk i rezystor
Dodaj przycisk i rezystor
Dodaj przycisk i rezystor

Dodaj mały przycisk z zasobnika komponentów. Powinien wyglądać jak ten na obrazku. Upewnij się, że to nie jest przełącznik! Dodaj też rezystor. Kliknij go i ustaw jego wartość na 10kΩ. Wystarczy wyciągnąć pin w dół, gdy nie jest podłączony, co jest bardzo ważne w dalszej części kodu.

Umieść element na środku płytki stykowej. Sposób działania przycisku to:

  • Od rogu do rogu przycisk nie jest podłączony. Naciśnięcie przycisku zamyka styki i łączy rogi.
  • Boki przycisku są połączone. Jeśli podłączysz przewód w lewym górnym i lewym dolnym rogu, obwód zostanie zamknięty.

Dlatego umieszczamy komponent w poprzek przestrzeni pośrodku. Zapewnia to, że rogi nie są połączone pod kołkami w płytce.

Następny krok zawiera kilka obrazów ilustrujących te punkty.

Umieść rezystor od prawego dolnego pinu w poprzek kolumn, tak aby był ustawiony poziomo.

Krok 3: Połączenia przycisków

Połączenia przycisków
Połączenia przycisków
Połączenia przycisków
Połączenia przycisków

Powyższe obrazy dość wyraźnie pokazują, w jaki sposób łączą się przyciski. To zawsze był punkt zamieszania, gdy myślisz, że coś jest dobre i nie działa!

Teraz dodajmy przewody.

  • Umieść czerwony przewód z dodatniego styku zasilania do tej samej kolumny, co prawy dolny styk na przycisku
  • Umieść czarny przewód z ujemnego pinu zasilania do tej samej kolumny co rezystor.
  • Umieść kolorowy przewód (nie czerwony/czarny) od lewego górnego styku do styku cyfrowego 2 na Arduino

Sprawdź powyższe obrazy, aby upewnić się, że okablowanie jest prawidłowe.

Krok 4: Kodeks…

Kod…
Kod…
Kod…
Kod…

Przyjrzyjmy się kodowi podstawowego przycisku.

Otwórz edytor kodu i zmień bloki na tekst. Usuń pojawiające się ostrzeżenie. Jesteśmy zadowoleni z tekstu!

Znasz podstawową konfigurację, więc zdefiniujmy przycisk i wykonajmy podstawowy odczyt. Wydrukujemy dane wyjściowe do Serial.

W poniższym kodzie umieściłem kilka dodatkowych komentarzy, aby był łatwiejszy do odczytania niż obraz.

// Zdefiniuj stałe

#define button 2 void setup() { pinMode(przycisk, INPUT); Serial.początek(9600); } void loop() { // Odczytaj cyfrowy pin, aby sprawdzić stan przycisku int wciśnięty = digitalRead(button); // Przycisk zwraca WYSOKIE, jeśli wciśnięty, NISKI, jeśli nie, jeśli (naciśnięty == WYSOKI){ Serial.println("Wciśnięty!"); } }

Dobrze, to działa!

Zasadniczo wszystko, co robimy, to sprawdzanie stanu pinu cyfrowego za każdym razem, gdy kod się zapętla. Jeśli klikniesz Uruchom symulację i naciśniesz przycisk, zobaczysz na monitorze szeregowym (kliknij przycisk pod kodem) komunikat „Wciśnięty!” wielokrotnie.

Jedną z funkcji, którą zobaczysz w powyższym kodzie, jest przeprowadzanie oceny warunku if(). Wszystko, co robi kod, to zadawanie pytań i ocena, czy w tym przypadku jest to prawda. Używamy is equal (podwójne znaki równości, np.: ==), aby sprawdzić, czy wartość zmiennej jest równa określonej wartości. DigitalRead() zwraca WYSOKI lub NISKI.

Używając if() else if / else możemy sprawdzić wiele warunków lub wszystkie warunki, a jeśli wrócisz do Arduino Basics, zobaczysz niektóre porównania, które możesz wykonać.

Teraz… Nasz kod może wyglądać na kompletny… Ale mamy problem.

Widzisz, to działa naprawdę dobrze w symulatorze. Ale prawdziwa elektryczność ma szum, zwłaszcza elektronika prądu stałego. Więc nasz przycisk może czasami zwracać błędny odczyt. I to jest problem, ponieważ Twój projekt może nie odpowiadać we właściwy sposób dla użytkownika.

Naprawmy to!

Krok 5: Małe odbicie

Trochę odbicia
Trochę odbicia

Używamy procedury zwanej debounce, aby przezwyciężyć nasz problem z przyciskami. Zasadniczo czeka to określoną ilość czasu między naciśnięciem przycisku a faktyczną reakcją na naciśnięcie. To nadal jest naturalne dla użytkownika (chyba że czas ten będzie zbyt długi). Możesz go również użyć do sprawdzania długości prasy, dzięki czemu za każdym razem możesz reagować inaczej. Nie musisz zmieniać żadnego okablowania!

Spójrzmy na kod:

#define przycisk 2#define debounceTimeout 100

Pierwsza zmiana dotyczy zasięgu globalnego. Pamiętasz, że w tym miejscu definiujemy zmienne, których może używać wiele naszych funkcji lub takie, których nie można zresetować za każdym razem, gdy pętla się uruchamia. Dodaliśmy więc debounceTimeout do zdefiniowanych stałych. Zrobiliśmy to 100 (które później przełoży się na 100 ms), ale może być krótsze. Jeszcze dłużej i poczujesz się nienaturalnie.

long int lastDebounceTime;

Ta zmienna jest zadeklarowana poniżej stałych. Jest to typ typu long int, który zasadniczo pozwala nam przechowywać w pamięci długie liczby. Nazwaliśmy to lastDebounceTime.

Nie musimy nic zmieniać w funkcji void setup(). Zostawmy to.

void loop() { // Odczytaj cyfrowy pin, aby sprawdzić stan przycisku int wciśnięty = digitalRead(button); long int aktualnyCzas = millis(); // Kod przycisku }

Pierwsza zmiana, jaką wprowadzamy w funkcji loop(), znajduje się pod wywołaniem odczytu przycisku. Musimy śledzić aktualny czas. Funkcja millis() zwraca aktualny czas zegara od momentu uruchomienia Arduino w milisekundach. Musimy to przechowywać w zmiennej typu long int.

Teraz musimy upewnić się, że znamy czas od naciśnięcia przycisku, więc resetujemy licznik, gdy nie jest wciśnięty. Spójrz:

void loop() { // Odczytaj cyfrowy pin, aby sprawdzić stan przycisku int wciśnięty = digitalRead(button); long int aktualnyCzas = millis(); if(wciśnięty == LOW){ // Zresetuj licznik czasu, gdy przycisk nie jest wciśnięty lastDebounceTime = currentTime; } // Kod przycisku }

Algorytm if(wciśnięty == LOW) sprawdza, czy przycisk nie jest wciśnięty. Jeśli tak nie jest, kod przechowuje aktualny czas od ostatniego odbicia. W ten sposób za każdym razem, gdy przycisk jest wciśnięty, mamy punkt w czasie, od którego możemy sprawdzić, kiedy przycisk został wciśnięty. Następnie możemy wykonać szybkie obliczenia matematyczne, aby zobaczyć, jak długo przycisk był wciśnięty i poprawnie zareagować. Spójrzmy na resztę kodu:

void loop() { // Odczytaj cyfrowy pin, aby sprawdzić stan przycisku int wciśnięty = digitalRead(button); long int aktualnyCzas = millis(); if(wciśnięty == LOW){ // Zresetuj licznik czasu, gdy przycisk nie jest wciśnięty lastDebounceTime = currentTime; } // Przycisk został naciśnięty przez określony czas if(((currentTime - lastDebounceTime) > debounceTimeout)){ // Jeśli upłynął limit czasu, przycisk został naciśnięty! Serial.println("Wciśnięty!"); } }

Ostatni blok kodu przyjmuje bieżący czas, odejmuje czas ostatniego odbicia i porównuje go z ustawionym przez nas limitem czasu. Jeśli jest większa, kod przyjmuje, że przycisk został naciśnięty przez ten czas i odpowiada. Schludny!

Uruchom swój kod i sprawdź, czy działa. Jeśli masz błędy, sprawdź swój kod!

Spójrzmy teraz na praktyczny przykład.

Krok 6: Tworzenie menu

Tworzenie menu
Tworzenie menu

Guziki są ciekawe, bo z nimi jest tyle możliwości! W tym przykładzie stworzymy menu. Załóżmy, że stworzyłeś to naprawdę świetne urządzenie i potrzebujesz, aby użytkownicy mogli zmieniać opcje, aby włączać lub wyłączać określone rzeczy lub ustawić konkretną wartość ustawienia. Ten projekt z trzema przyciskami może to zrobić!

Tak więc do tego projektu potrzebujemy:

  • Trzy przyciski
  • Trzy rezystory ustawione na 10kΩ

Jeden już mamy, potrzebujemy tylko dwóch pozostałych. Więc dodaj je do tablicy. Okablowanie jest trochę bardziej skomplikowane, ale tylko dlatego, że chciałem, aby było naprawdę kompaktowe. Możesz zastosować ten sam wzór dla pierwszego przycisku lub postępować zgodnie z powyższym obrazkiem.

Te trzy przyciski to opcja otwierania/następnego menu, opcja zmiany (jak w przypadku zmiany ustawienia) oraz przycisk zapisywania/zamykania menu.

Podłącz go, spójrzmy na kod!

Krok 7: Podział kodu - globalny

Ok, to będzie długi krok, ale przejdę przez każdą sekcję kodu.

Najpierw spójrzmy na potrzebne zmienne globalne.

// Zdefiniuj stałe#define menuButton 2 #define menuSelect 3#define menuSave 4 #define debounceTimeout 50 // Zdefiniuj zmienne int menuButtonPreviousState = LOW; int menuSelectPreviousState = NISKI; int menuSavePreviousState = NISKI; long int lastDebounceTime; // Opcje menu char * menuOptions = {"Sprawdź temp", "Sprawdź światło"}; bool featureSetting = {false, false}; bool menuMode = false; bool menuPotrzebyDrukuj = false; int opcjaWybrany = 0;

Te trzy bloki są dość podobne do tego, co widzieliśmy wcześniej. W pierwszym zdefiniowałem trzy przyciski i limit czasu. W tej części projektu ustawiłem go na 50 ms, więc wymaga to celowego naciśnięcia, aby zadziałało.

Drugi blok to wszystkie zmienne. Musimy śledzić przyciskPreviousState i musimy śledzić lastDebounceTime. To wszystko są zmienne typu int, ale ostatnia jest typu long, ponieważ zakładam, że potrzebujemy miejsca w pamięci.

Blok opcji menu ma kilka nowych funkcji. Po pierwsze, znak * (tak, to celowa gwiazdka), który jest zmienną literału znakowego/łańcuchowego. Jest to wskaźnik do statycznego przechowywania w pamięci. Nie możesz tego zmienić (jak na przykład w Pythonie). Ta linia char *menuOptions tworzy tablicę literałów łańcuchowych. Możesz dodać tyle pozycji menu, ile chcesz.

Zmienna bool featureSetting to po prostu tablica wartości reprezentująca każdy element menu. Tak, możesz przechowywać wszystko, co chcesz, po prostu zmień typ zmiennej (wszystkie muszą być tego samego typu). Teraz mogą istnieć lepsze sposoby zarządzania tym, takie jak słowniki lub krotki, ale jest to proste w przypadku tej aplikacji. Prawdopodobnie stworzyłbym jedną z tych ostatnich we wdrożonej aplikacji.

Śledziłem menuMode, więc gdybym chciał mieć inne rzeczy na moim wyświetlaczu, mógłbym to zrobić. Ponadto, gdybym miał logikę czujnika, mógłbym ją zatrzymać podczas obsługi menu, na wypadek konfliktu. Mam zmienną menuNeedsPrint, ponieważ chcę wydrukować menu o określonych porach, a nie tylko przez cały czas. Na koniec mam zmienną optionSelected, więc mogę śledzić wybraną opcję, gdy uzyskuję do niej dostęp w wielu miejscach.

Przyjrzyjmy się kolejnemu zestawowi funkcji.

Krok 8: Podział kodu - konfiguracja i funkcje niestandardowe

Funkcja setup() jest dość prosta, wystarczy trzy deklaracje wejściowe:

void setup() { pinMode(menuSelect, INPUT); pinMode(menuSave, INPUT); pinMode(menuSelect, INPUT); Serial.początek(9600); }

Dalej są trzy funkcje niestandardowe. Przyjrzyjmy się dwóm pierwszym, a następnie ostatniemu osobno.

Potrzebujemy dwóch funkcji, które zwracają pewne informacje. Powodem jest to, że chcemy się upewnić, że jest to czytelne dla człowieka. Pomoże to również w debugowaniu kodu, jeśli mamy problem. Kod:

// Funkcja zwracająca aktualnie wybraną opcjęchar *ReturnOptionSelected(){ char *menuOption = menuOptions[optionSelected]; // Powrót opcjaWybrany powrót menuOption; } // Funkcja zwracająca status aktualnie wybranej opcji char *ReturnOptionStatus(){ bool optionSetting = featureSetting[optionSelected]; char *optionSettingVal; if (optionSetting == false){ optionSettingVal = "False"; }else{ optionSettingVal = "True"; } // Return optionSetting return optionSettingVal; }

Funkcja char *ReturnOptionSelected() sprawdza wybraną opcję (jeśli widzisz powyżej, ustawiamy zmienną, aby to śledzić) i pobiera literał ciągu z tablicy, którą utworzyliśmy wcześniej. Następnie zwraca go jako typ znaku. Wiemy o tym, ponieważ funkcja wskazuje typ zwracany.

Druga funkcja, char *ReturnOptionStatus(), odczytuje status opcji zapisanej w tablicy i zwraca literał ciągu reprezentujący wartość. Na przykład, jeśli zapisane przez nas ustawienie to false, zwróciłbym „False”. Dzieje się tak, ponieważ pokazujemy użytkownikowi tę zmienną i lepiej trzymać całą tę logikę razem. Mógłbym to zrobić później, ale bardziej sensowne jest zrobienie tego tutaj.

// Funkcja przełączania bieżącej opcjibool ToggleOptionSelected(){ featureSetting[optionSelected] = !featureSetting[optionSelected]; zwróć prawdę; }

Funkcja bool ToggleOptionSelected() to wygodna funkcja do zmiany wartości ustawienia, które wybraliśmy w menu. To po prostu odwraca wartość. Jeśli masz bardziej złożony zestaw opcji, może to wyglądać zupełnie inaczej. Zwracam true w tej funkcji, ponieważ moje wywołanie zwrotne (wywołanie w dalszej części kodu, który uruchamia tę funkcję) oczekuje odpowiedzi prawda/fałsz. Jestem na 100% pewien, że to zadziała, więc nie brałem pod uwagę tego, że nie działa, ale zrobiłbym we wdrożonej aplikacji (na wszelki wypadek).

Krok 9: Pętla…

Funkcja loop() jest dość długa, więc zrobimy to w częściach. Możesz założyć, że wszystko poniżej gniazd w tej funkcji:

pusta pętla () {

// Pracuj tutaj <----- }

Ok, widzieliśmy to wcześniej:

// Odczytaj przyciski int menuButtonPressed = digitalRead(menuButton); int menuSelectPressed = digitalRead(menuSelect); int menuSavePressed = digitalRead(menuSave); // Pobierz aktualny czas long int currentTime = millis(); if(menuButtonPressed == NISKI && menuSelectPressed == NISKI && menuSavePressed == NISKI){ //Zresetuj odliczany czas, gdy przycisk nie jest naciśnięty ostatnioDebounceTime = currentTime; menuButtonPreviousState = NISKI; menuSelectPreviousState = LOW; menuSavePreviousState = NISKI; }

Wszystko, co musiałem tutaj zrobić, to dodać trzy wywołania digitalRead() i upewnić się, że wziąłem pod uwagę fakt, że jeśli wszystkie przyciski są w stanie niskim, powinniśmy zresetować licznik czasu (lastDebounceTime = currentTime) i ustawić wszystkie poprzednie stany na niski. Przechowuję również millis() w currentTime.

Następna sekcja zagnieżdża się wewnątrz linii

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

//Pracuj tutaj <---- }

Istnieją trzy sekcje. Tak, mogłem przenieść je do ich własnych funkcji, ale dla uproszczenia zachowałem tutaj trzy główne algorytmy przycisków.

if((menuButtonPressed == HIGH) && (menuButtonPreviousState == LOW)){ if(menuMode == false){ menuMode = true; // Poinformuj użytkownika Serial.println("Menu jest aktywne"); }else if (menuMode == true && optionSelected = 1){ // Resetuj opcję optionSelected = 0; } // Wydrukuj menu menuNeedsPrint = true; // Przełącz przycisk wstecz. stan, aby wyświetlić menu tylko // po zwolnieniu i ponownym naciśnięciu przycisku menuButtonPreviousState = menuButtonPressed; // byłoby WYSOKIE }

Ten pierwszy obsługuje, gdy menuButtonPressed ma wartość HIGH lub gdy przycisk menu jest naciśnięty. Sprawdza również, czy poprzedni stan był NISKI, aby przycisk musiał zostać zwolniony przed ponownym naciśnięciem, co uniemożliwia programowi ciągłe uruchamianie tego samego zdarzenia.

Następnie sprawdza, czy jeśli menu nie jest aktywne, aktywuje je. Wydrukuje pierwszą wybraną opcję (która jest domyślnie pierwszą pozycją w tablicy menuOptions. Jeśli naciśniesz przycisk drugi lub trzeci (itd.) raz, otrzymasz następną opcję na liście. Coś, co mógłbym naprawić, to że kiedy dochodzi do końca, wraca do początku. Może to odczytać długość tablicy i ułatwić powrót, jeśli zmienisz liczbę opcji, ale na razie było to proste.

Ostatnia mała sekcja (//Wydrukowanie menu) oczywiście wyświetla menu, ale ustawia również poprzedni stan na WYSOKI, więc ta sama funkcja nie będzie się zapętlać (patrz moja uwaga powyżej o sprawdzaniu, czy przycisk był wcześniej LOW).

// naciśnięto menuSelect, zapewnij logicif((menuSelectPressed == HIGH) && (menuSelectPreviousState == LOW)){ if(menuMode){ // Zmień wybraną opcję // W tej chwili to tylko prawda/fałsz // ale może być cokolwiek bool toggle = ToggleOptionSelected(); if(toggle){ menuNeedsPrint = true; }else{ Serial.println("Coś poszło nie tak. Spróbuj ponownie"); } } // Przełącz stan, aby przełączać tylko po zwolnieniu i ponownym naciśnięciu menuSelectPreviousState = menuSelectPressed; }

Ten fragment kodu obsługuje przycisk menuSelectPressed w ten sam sposób, z tą różnicą, że tym razem po prostu uruchamiamy funkcję ToggleOptionSelected(). Jak powiedziałem wcześniej, możesz zmienić tę funkcję, aby robiła więcej, ale to wszystko, czego potrzebuję.

Najważniejszą rzeczą do zapamiętania jest zmienna toggle, która śledzi sukces wywołania zwrotnego i wyświetla menu, jeśli jest prawdziwe. Jeśli nie zwróci nic lub fałsz, wyświetli komunikat o błędzie. Tutaj możesz użyć swojego wywołania zwrotnego do innych rzeczy.

if((menuSavePressed == HIGH) && (menuSavePreviousState == LOW)){ // Wyjdź z menu // Tutaj możesz posprzątać // lub zapisać do EEPROM menuMode = false; Serial.println("Zamknięto menu"); // Przełącz stan, aby menu wychodziło tylko raz menuSavePreviousState = menuSavePressed; } }

Ta funkcja obsługuje przycisk menuSave, który po prostu wychodzi z menu. To jest miejsce, w którym możesz mieć opcję anulowania lub zapisania, może posprzątać lub zapisać do EEPROM. Po prostu drukuję "Menu exited" i ustawiam stan przycisku na HIGH, aby się nie zapętlał.

if(menuMode && menuNeedsPrint){ // Wypisaliśmy menu, więc jeśli coś // się nie wydarzy, nie ma potrzeby drukowania go ponownie menuNeedsPrint = false; char *opcjaAktywna = ReturnOptionSelected(); char *StatusOpcji = StanZwrotuOpcji(); Serial.print("Wybrany: "); Serial.print(opcjaAktywna); Serial.print(": "); Serial.print(opcjaStatus); Serial.println(); }

Jest to algorytm menuPrint, który jest uruchamiany tylko wtedy, gdy menu jest aktywne i gdy zmienna menuNeedsPrint jest ustawiona na true.

Można to zdecydowanie przenieść do własnej funkcji, ale dla uproszczenia..!

Cóż, to wszystko! Zobacz następny krok dla całego bloku kodu.

Krok 10: Ostateczny blok kodu

// Zdefiniuj stałe

#define menuPrzycisk 2 #define menuWybierz 3 #define menuZapisz 4 #define debounceTimeout 50 int menuPrzyciskPreviousState = LOW; int menuSelectPreviousState = NISKI; int menuSavePreviousState = NISKI; // Zdefiniuj zmienne long int lastDebounceTime; bool lightSensor = prawda; bool czujnik temp = prawda; // Opcje menu char * menuOptions = {"Sprawdź temp", "Sprawdź światło"}; bool featureSetting = {false, false}; bool menuMode = false; bool menuPotrzebyDrukuj = false; int opcjaWybrany = 0; // Funkcja konfiguracji

void setup() { pinMode(menuSelect, INPUT); pinMode(menuSave, INPUT); pinMode(menuSelect, INPUT); Serial.początek(9600); }

// Funkcja zwracająca aktualnie wybraną opcję char *ReturnOptionSelected(){ char *menuOption = menuOptions[optionSelected]; // Powrót opcjaWybrany powrót menuOption; } // Funkcja zwracająca status aktualnie wybranej opcji char *ReturnOptionStatus(){ bool optionSetting = featureSetting[optionSelected]; char *optionSettingVal; if (optionSetting == false){ optionSettingVal = "False"; }else{ optionSettingVal = "True"; } // Return optionSetting return optionSettingVal; } // Funkcja przełączania bieżącej opcji bool ToggleOptionSelected(){ featureSetting[optionSelected] = !featureSetting[optionSelected]; zwróć prawdę; } // Główna pętla

void loop(){ // Odczytaj przyciski int menuButtonPressed = digitalRead(menuButton); int menuSelectPressed = digitalRead(menuSelect); int menuSavePressed = digitalRead(menuSave); // Pobierz aktualny czas long int currentTime = millis(); if(menuButtonPressed == NISKI && menuSelectPressed == NISKI && menuSavePressed == NISKI){ //Zresetuj odliczany czas, gdy przycisk nie jest naciśnięty ostatnioDebounceTime = currentTime; menuButtonPreviousState = NISKI; menuSelectPreviousState = LOW; menuSavePreviousState = NISKI; } if(((currentTime - lastDebounceTime) > debounceTimeout)){ // Jeśli upłynął limit czasu, przycisk wciśnięty!

// menuButton jest wciśnięty, podaj logikę

// Uruchamia się tylko wtedy, gdy przycisk został wcześniej zwolniony if((menuButtonPressed == HIGH) && (menuButtonPreviousState == LOW)){ if(menuMode == false){ menuMode = true; // Poinformuj użytkownika Serial.println("Menu jest aktywne"); }else if (menuMode == true && optionSelected = 1){ // Resetuj opcję optionSelected = 0; } // Wydrukuj menu menuNeedsPrint = true; // Przełącz przycisk wstecz. stan, aby wyświetlić menu tylko // po zwolnieniu i ponownym naciśnięciu przycisku menuButtonPreviousState = menuButtonPressed; // byłoby HIGH } // menuSelect zostało naciśnięte, podaj logikę if((menuSelectPressed == HIGH) && (menuSelectPreviousState == LOW)){ if(menuMode){ // Zmień wybraną opcję // W tej chwili jest to po prostu prawda/fałsz // ale może być cokolwiek bool toggle = ToggleOptionSelected(); if(toggle){ menuNeedsPrint = true; }else{ Serial.print("Coś poszło nie tak. Spróbuj ponownie"); } } // Przełącz stan, aby przełączać tylko po zwolnieniu i ponownym naciśnięciu menuSelectPreviousState = menuSelectPressed; } if((menuSavePressed == HIGH) && (menuSavePreviousState == LOW)){ // Wyjdź z menu // Tutaj możesz posprzątać // lub zapisać do EEPROM menuMode = false; Serial.println("Zamknięto menu"); // Przełącz stan, aby menu wychodziło tylko raz menuSavePreviousState = menuSavePressed; } } // Wydrukuj bieżącą opcję menu jako aktywną, ale wydrukuj ją tylko raz if(menuMode && menuNeedsPrint){ // Wydrukowaliśmy menu, więc jeśli coś // się nie wydarzy, nie ma potrzeby drukowania go ponownie menuNeedsPrint = false; char *opcjaAktywna = ReturnOptionSelected(); char *StatusOpcji = StanZwrotuOpcji(); Serial.print("Wybrany: "); Serial.print(opcjaAktywna); Serial.print(": "); Serial.print(opcjaStatus); Serial.println(); } } }

Tor jest dostępny na stronie Tinkercad. Umieściłem poniższy obwód, abyś mógł również zobaczyć!

Jak zawsze, jeśli masz pytania lub problemy, daj mi znać!

Zalecana: