Skocz do zawartości

Użycie przycisku do przełączania się między pętlami


Pomocna odpowiedź

Napisano

Witam. Jestem w trakcie tworzenia projektu na bazie Arduino, lecz zatrzymał mnie problem, którego nie potrafię rozwiązać - mianowicie chciałbym za pomocą przycisku(dokładniej takiego z joystick'a) przełączać się między funkcjami, tak, żeby działały one w pętli. Mój problem polega na tym, że gdy nacisnę przycisk to pętla odpala się ale gdy wciskam kolejny raz chcąc przełączyć się na kolejną pętlę nic się nie dzieje. Kod przeznaczony do obsługi przycisku wygląda tak:

int buttonPin=2;
int buttonNew;
int buttonOld=1;
int buttonState = 0;
 
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
 
}
 
void loop() { 
buttonNew=digitalRead(buttonPin);
if(buttonOld==0 && buttonNew==1){
  if (buttonState==0){
    loop1();
    buttonState=1;
  }
  else{
    loop2();
    buttonState=0;
  }
}
buttonOld=buttonNew;
delay(100);
}

void loop1(){
  while(true){
    Serial.println("1");
  }
}

void loop2(){
  while(true){
    Serial.println("2");
  }
}

Gdy wciskam przycisk na monitorze dostaję serię jedynek ale po ponownym wciśnięciu nic się nie dzieje.

Prosiłbym o pomoc.

Powodem jest to, że po pierwszym przyciśnięciu przycisku wpadasz w pętlę while, która jest wykonywana dotąd aż wypełniony jest warunek podany w nawiasie. W Twoim przypadku jest to true. Stąd też program nie jest w stanie opuścić pętli. Proponuję, żebyś poczytał sobie o instrukcji switch lub zastosował proste if. Poniżej przykład z zastosowaniem switcha.

switch(buttonState)
{
	case 0:	// jeśli buttonState = 0
	{
		Serial.println(“1”);
		break; // bez tego, jeśli buttonState = 0, wykonałby się też kod przypisany do wartości 1				
	}
	case 1: // jeśli buttonState = 1
	{
		Serial.println(“0”);
		break;
	}
}

Wówczas pozbywasz się w ogóle loop1 i loop2, a switch wstawiasz przed buttonOld = buttonNew i o ile nie popełniłem prostego błędu, działa. 

 

Nic się nie dzieje ponieważ gdy już wejdziesz w jedną z pętli nie sprawdzasz stanu przycisku. W pętli 1 i 2 musisz mieć możliwość wyjścia z nich

Dnia 16.04.2021 o 16:36, _LM_ napisał:

Nic się nie dzieje ponieważ gdy już wejdziesz w jedną z pętli nie sprawdzasz stanu przycisku. W pętli 1 i 2 musisz mieć możliwość wyjścia z nich

Jak w prosty sposób sprawdzać stan przycisku w pętli żeby dało się z niej wyjść?

(edytowany)
25 minut temu, MrReus napisał:

Jak w prosty sposób sprawdzać stan przycisku w pętli żeby dało się z niej wyjść?

Jak chcesz uzywac while w taki sposob ze chcesz w niej zostac do czasu ponownego wcisniecia guzika to moze cos takiego..

uint8_t stan = 0;

if (digitalRead(guzik) == LOW) {
  stan = 0;
  loop1();
  }

void loop1() {
  
while (stan == 0) {
  //kod
  if (digitalRead(guzik) == LOW) {
    stan = 1;
    }
  }
  }

Pozatym musisz zdawac sobie sprawe z tego jak juz wspomnial kolega _LM_  ze musisz miec mozliwosc wyjscia z while...a zapis..

while(true)

nigdy Ci nie da takiej mozliwosci...to jest nieskonczona petla! gdy raz do niej "wpadniesz" to juz zostajesz...

Edytowano przez farmaceuta

Pytanie: po co while w loop1 i loop2? Przecież i tak wykonuje się pętla while w której siedzi loop()

Co się stanie, jeśli zrobisz po prostu:
 

void loop1()
{
  Serial.println("1");
}

void loop2()
{
  Serial.println("2");
}

 

2 godziny temu, MrReus napisał:

Jak w prosty sposób sprawdzać stan przycisku w pętli żeby dało się z niej wyjść?

Już Ci @opp34 podpowiedział musisz użyć instrukcji break; wcześniej sprawdzić stan przycisku i jeśli wciśnięty to wyjście 

Dnia 19.04.2021 o 13:09, ethanak napisał:

Pytanie: po co while w loop1 i loop2? Przecież i tak wykonuje się pętla while w której siedzi loop()

Co się stanie, jeśli zrobisz po prostu:
 


void loop1()
{
  Serial.println("1");
}

void loop2()
{
  Serial.println("2");
}

 

Mój główny program posiada funkcje, które mają zmieniać opcje sterowania silnikami gdy kliknę na przycisk. Jeśli nie dam tego w pętli to zmiana sterowania działa tylko gdy trzymam przycisk a gdy puszczę wraca do pierwotnego sterowania. Być może coś robię źle, ale nie udało mi się zrobić tego bez użycia pętli. 

9 minut temu, MrReus napisał:

Być może coś robię źle, ale nie udało mi się zrobić tego bez użycia pętli. 

Mozesz uzyc petli tylko trzeba uzywac jej prawidlowo, a zapis while(true) nie jest prawidlowy..(w twoim przypadku oczywiscie)..to co Ci wyzej napisalem rozwiazuje twoj problem

(edytowany)

A nie prościej zapamiętać stan przycisku?

Pętla w pętli, sprawdzanie stanu przycisku w kilku miejscach, najlepszy sposób na niepotrzebne komplikacje i dziwne błędy.

uint8_t stan=0;

void loop()
{
  if (digitalRead(Button1) == LOW) stan = 1;
  if (digitalRead(Button2) == LOW) stan = 2;
  switch(stan) {
    case 1:
      loop1();
      break;
     
    case 2:
      loop2();
      break;
  }
}

Coś w tę stronę (oczywiście w loop1 i loop2 nie ma żadnych while)

Edytowano przez ethanak
5 godzin temu, farmaceuta napisał:

Mozesz uzyc petli tylko trzeba uzywac jej prawidlowo, a zapis while(true) nie jest prawidlowy..(w twoim przypadku oczywiscie)..to co Ci wyzej napisalem rozwiazuje twoj problem

Przeanalizowałem twój kod, użyłem do obu funkcji i działa bardzo dobrze, ale natknąłem się na mały problem: mianowicie pętle zmieniają się tylko wtedy gdy naciśnięcie przycisku jest natychmiastowe. Gdy go przytrzymam, lub nie wcisnę wystarczająco szybko to nic się nie dzieje. Da się coś z tym zrobić? 

 

9 minut temu, MrReus napisał:

ale natknąłem się na mały problem: mianowicie pętle zmieniają się tylko wtedy gdy naciśnięcie przycisku jest natychmiastowe. Gdy go przytrzymam, lub nie wcisnę wystarczająco szybko to nic się nie dzieje. Da się coś z tym zrobić? 

Da sie...jak wiadomo kod wykonuje sie strasznie szybko..wiec zanim zdazysz puscic guzik to przeskoczysz juz dalej...dodaj zwykly delay() w kazde miejsce gdzie uzywasz przycisku np.

if (digitalRead(guzik) == LOW) {
  delay(1000); ///tutaj
  stan = 0;
  loop1();
  }

void loop1() {
  
while (stan == 0) {
  //kod
  if (digitalRead(guzik) == LOW) {
    delay(1000); /// tutaj
    stan = 1;
    }

na poczatek delay() wystarczy...ale w bardziej zaawansowanych kodach to by nas za te delay'e powiesili..😉 teraz masz 1 sekunde na to zeby zdazyc puscic guzik...przeanalizuj rowniez przyklad kolegi @ethanak z case'ami bo to tez dobre i proste rozwiazanie, z tym ze po zakonczeniu case wychodzisz z niego i lecisz caly kod odnowa do ponownego wejscia w case...

16 godzin temu, farmaceuta napisał:

na poczatek delay() wystarczy...ale w bardziej zaawansowanych kodach to by nas za te delay'e powiesili..😉 teraz masz 1 sekunde na to zeby zdazyc puscic guzik...przeanalizuj rowniez przyklad kolegi @ethanak z case'ami bo to tez dobre i proste rozwiazanie, z tym ze po zakonczeniu case wychodzisz z niego i lecisz caly kod odnowa do ponownego wejscia w case...

Rozumiem, że w tym przypadku mam zadeklarować Button1 i Button2 na ten sam pin? Po wstępnej próbuje opcja z case'ami wrzuca mnie do mojego "loop2" i nie wychodzi po ponownym kliknięciu. 

(edytowany)
27 minut temu, MrReus napisał:

Rozumiem, że w tym przypadku mam zadeklarować Button1 i Button2 na ten sam pin

Nie nie...z regoly tak sie nie robi...a robi sie tak ze jeden pin to jedna nazwa...

Reszty nie zgadne bo nie wiem co masz w tych loop1/2...ktore zreszta nie sa Ci do niczego potrzebne...umiesc dwie petle while w loop() i po krzyku...

uint8_t stan = 0;

void loop() {
  
  stan_guzik();

  while (stan == 1) {
  //kod pierwszy
  stan_guzik();
}
  while (stan == 2) {
  //kod drugi
  stan_guzik();
}

void stan_guzik() {
  if (digitalRead(guzik) == LOW) {
  delay(1000); ///tutaj
  stan++;
  if (stan > 2) {
    stan = 1;
  }
}
  }

Moze takie cos...tylko musisz pamietac ze nie ma tutaj zabezpieczenia przed zbyt dlugim wcisnieviem guzika...tak samo jesli nawalisz delay'ow do while to bedzie to kulawo chodzic...

A najlepiej poczytaj tu na forum...bo to chyba juz 3 temat w tym tygodniu ktory porusza ten sam problem...czyli przelaczanie sie miedzy podprogramami..

Edytowano przez farmaceuta
13 minut temu, farmaceuta napisał:

Nie nie...z regoly tak sie nie robi...a robi sie tak ze jeden pin to jedna nazwa...

Reszty nie zgadne bo nie wiem co masz w tych loop1/2...ktore zreszta nie sa Ci do niczego potrzebne...umiesc dwie petle while w loop() i po krzyku...

Chciałem zrozumieć kod @ethanak z tym case'ami i dlaczego są dwa Buttony. Ale zostanę chyba przy Twojej wersji bo działa bardzo dobrze i w sumie rozwiązało to mój problem.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...