Skocz do zawartości

LCD 2x16 ESP32 – problem w wyświetlaniu tekstu


jakub51996

Pomocna odpowiedź

Witam. Mam zamiar stworzenia wyświetlacza który ma wyświetlać dwie różne informacje z wykorzystaniem przycisku. Czyli naciśnięcie (i puszczenie) przycisku powoduje zmianę tekstu na drugi. Tylko mój program na zmianę wyświetla obie opcje(nie w równych ostępach czasu) . W czym może być problem? Wyświetlacz pracuje z esp32.

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  
int buttonpin = 26;

int buttonState = 0;

void setup() 
{
lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();
  pinMode(buttonpin, INPUT);
  
}

void loop() {
  buttonState = digitalRead(buttonpin);
  if (buttonState == LOW) {
   lcd.setCursor(0, 0);
  // print message
  lcd.print("Hello, World!");
  delay(1000);
  // clears the display to print new message
  lcd.clear();
  }
  
  else {
   
  lcd.setCursor(0, 1);
  // print message
  lcd.print("Home, come!");
  delay(1000);
  // clears the display to print new message
  lcd.clear();
  }
  
}

 

Link do komentarza
Share on other sites

Twój program sprawdza czy wciśnięty przycisk najwyżej raz na sekundę przez krótką chwileczkę, zrób żeby często sprawdzał a raz na sekundę wypisywał. Pobaw się funkcją millis() będzie łatwiej zrealizować.

Link do komentarza
Share on other sites

Witam na forum!

Problem tych przełączeń leży tu:

pinMode(buttonpin, INPUT);

zamien to na INPUT_PULLUP i będzie ok. Jest tam w tym momencie stan nieokreślony i dzieje się co się chce. Podciągnięcie do zasilania sprawi, że będzie ptzy puszczonym przycisku stan 1.

Ale jeżeli chcesz 1 przyciskiem na trwałe przełączać 2 stany to obecny program to za mało. potrzebujesz zmienną która będzie pamiętać ostatni stan i momencie zmiany stanu np. z wysokiego na niski czyli

void setup() {
  int last = digitalRead(x);
}

void loop() {
  if (last == HIGH && digitalRead(x) == LOW) {
    ...
  }
  if (last == LOW && digitalRead(x) == HIGH) {
    ...
  }
  last = digitalRead(x);
}

Albo zrób na przerwaniach, są opisane w kursie Arduino na blogu.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

33 minuty temu, Gieneq napisał:

zamien to na INPUT_PULLUP i będzie ok. Jest tam w tym momencie stan nieokreślony i dzieje się co się chce. Podciągnięcie do zasilania sprawi, że będzie ptzy puszczonym przycisku stan 1.

To z dużym prawdopodobieństwem racja chyba, że jest zewnętrzny pull-up rezystorem co mało prawdopodobne :). Drgania styków też mogą mieć w rezultacie wpływ bo trudno stwierdzić w jakim momencie przycisk będzie naciśnięty.

33 minuty temu, Gieneq napisał:

potrzebujesz zmienną która będzie pamiętać ostatni stan i momencie zmiany stanu np. z wysokiego na niski

ta zmienna już jest: buttonState = digitalRead(buttonpin);   wystarczy ją ustawiać po delayu na komunikat.

Żeby częściej sprawdzał i wypisywał po naciśnięciu przez sekundę tekst "Hello World!" możesz zrobić też np. tak:

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  
int buttonpin = 26;

int buttonState = 0;

void setup() 
{
lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();
  pinMode(buttonpin, INPUT_PULLUP);
  lcd.print("Home, come!");
}

void loop() {
  delay(50);
  buttonState = digitalRead(buttonpin);
  if (buttonState == LOW) {
    lcd.clear();
    lcd.setCursor(0, 0);
    // print message
    lcd.print("Hello, World!");
    delay(1000);
    // clears the display to print new message
    lcd.clear();
    lcd.setCursor(0, 1);
    // print message
    lcd.print("Home, come!");
    
  } 
}

Ale lepiej jest stosować millis() a najlepiej przerwanie od zmiany stanu na pinie.

Edytowano przez Anonim
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dzięki za pomocą. Macie chyba rację, że w moim przypadku najlepszą opcją będą przerwania bo program ma działać że wyświetla cały czas hello World aż do przycisku i  przełączania  na Home come i tak w kółko. Mam pytanie do przerwan co powinnem wpisać funkcji button aby działało to na przemianie?

void setup (){
  attachInterrupt(digitalPinToInterrupt(26), button, RISING);
  }
void loop(){
  }
void button (){
  
  }

 

  • Lubię! 1
Link do komentarza
Share on other sites

W funkcji button wpisujesz tylko sygnalizację, że klawisz został wciśnięty, czyli coś w stylu:
 

volatile bool pressed;

void button(void) {
	pressed = true;
}

Resztę obsługi robisz już w loop(), czyli (bardzo brzydko z delajami):

void loop(void)
{
  if (pressed) {
    pressed = false;
    wyswietl("Napis drugi");
    delay(1000);
    wyswietl("Napis pierwszy");
  }
}
    

gdzie "wyswietl(cośtam)" to cała sekwencja czyszczenia LCD, ustawiania kursora i wypisywania czegoś tam.

Przy okazji - FALLING a nie RISING jeśli ma to reagować na wciśnięcie klawisza.

  • Lubię! 1
Link do komentarza
Share on other sites

Stworzyłem program jak mi podpowiadałeś ale dalej są dwa problemy pierwszy to Hello world wyświetla tylko sekunde ( chciałem aby był do ponownego naciśnięcia przycisku) oraz Home come wyświetla się wtedy kiedy jeszcze jest hello world.

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  
int buttonpin = 26;
volatile bool pressed;
int buttonState = 0;
int last = digitalRead(26);
void setup() 
{ 
lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();
  pinMode(buttonpin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(26), button, FALLING);
}

void loop() {
  if (pressed) {
    pressed = false;
     lcd.setCursor(0, 0);
  // print message
  lcd.print("Hello, World!");
  delay(1000);
    
  }else{
  lcd.setCursor(0, 0);
  // print message
  lcd.print("Home, come!");
  delay(1000);
  // clears the display to print new message
  lcd.clear();
}}
void button(void) {
  pressed = true;
}

 

Link do komentarza
Share on other sites

No to teraz sobie spróbuj sam przerobić. Pierwsza podpowiedź: w instrukcji if (pressed) nie ma sensu klauzula else (bo program ma reagować na naciśnięcie klawisza, a nie na to że nie nacisnąłeś bo zaspałeś albo poszedłeś na piwo). Druga podpowiedź: stwórz sobie jakąś zmienną globalną, zmieniaj jej stan za każdym naciśnięciem klawisza i wyświetlaj w zależności od stanu, np. w takim fragmencie:
 

/* zmienna globalna */
bool napis;

/* a w loop */

napis = !napis;
if (napis) wyświetl("Hello, home");
else wyświetl("Come, world");

A co do wyświetlania jednego jak jest jeszcze drugie to pozwolę sobie zacytować sam siebie:

3 godziny temu, ethanak napisał:

gdzie "wyswietl(cośtam)" to cała sekwencja czyszczenia LCD, ustawiania kursora i wypisywania czegoś tam.

O czym zapomniałeś?

  • Pomogłeś! 1
Link do komentarza
Share on other sites

bool lastPressed = false;

void loop() {
  if (pressed && !lastPressed) {
  	lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Hello, World!");
    delay(1000);
    lastPressed = pressed;
  }
  
  if (!pressed && lastPressed) {
    lcd.setCursor(0, 0);
    lcd.print("Home, come!");
    delay(1000);
    lcd.clear();
    lastPressed = pressed;
  }
}

void button(void) {
  pressed = !pressed; // przeciwny stan
}

Może spróbuj coś takiego, tu jest przełącznik na 1 przycisku, z pamięcią. O coś takiego Ci chodziło?

W tym podejściu coś się będzie zmieniać tylko przy zmianie zmiennej, ale nie będzie to kod umieszczony w przerwaniu. Gdyby kod ten był w przerwaniu to sytuacja byłaby prostsza, ale taka metodyka.

Edytowano przez Gieneq
Link do komentarza
Share on other sites

Masz gotowca

  bool static prevSw, switch_user;
  bool sw = digitalRead( PB_USER );
  uint32_t static timSw;
  if ( prevSw != sw && millis() > timSw ) {
    prevSw = sw;
    timSw = millis() + 100;   // Blokada SW na 100 ms
    if ( ! sw ) switch_user = true; else switch_user = false;
  }
  bool static prevSwUser;
  if ( prevSwUser != switch_user ) {
    prevSwUser = switch_user;
    if ( switch_user ) {
      Serial.print(">>>>>>>> PB ON <<<<<<<<\n\r");


    }
  }

Nie jest najdoskonalszy (reaguje nawet na krótki impulsy) ale działa i nie korzysta z przerwań. Jak chcesz poprawić to zrób programowy filtr dolnoprzepustowy. Zmiń "timSw = millis() + 100;" na np "timSw = millis() + 10;", dodaj zmienną ze znakiem i gdy sw == 0 zwiększaj zmienną do np 5, gdy sw != 0 to zmniejszaj do -5. Gdy zmienna osiągnie 5 to switch_sert ustaw na true gdy -5 na false.

Link do komentarza
Share on other sites

9 godzin temu, RFM napisał:

działa i nie korzysta z przerwań

Biorąc pod uwagę to, że kolega pytał właśnie o przerwania jak zwykle "pomogłeś"[1] pisząc nie na temat.

Poza tym istnieje szansa (niewielka co prawda, ale istnieje) że program się powiesi. No cóż - arytmetyka liczb bez znaku o ograniczonym zakresie bywa zdradliwa... a chcąc komuś pokazywać "jak to się robi" warto najpierw samemu się nauczyć.

9 godzin temu, RFM napisał:

if ( ! sw ) switch_user = true; else switch_user = false;

 

Ja bym napisał:

switchUser = !sw;

ale mi nie płacą od znaku.

Pomijam już fakt, że program robi coś zupełnie innego niż to, co chciał kolega pytający... ale to przecież drobiazg, ważne że licznik postów sobie nabiłeś.

--
[1] w swoim mniemaniu

Link do komentarza
Share on other sites

Bez komentaża

13 minut temu, ethanak napisał:

biorąc pod uwagę to, że kolega pytał właśnie o przerwania jak zwykle "pomogłeś"[1] pisząc nie na temat.

 

10 godzin temu, Gieneq napisał:

nie będzie to kod umieszczony w przerwaniu.

 

Link do komentarza
Share on other sites

Również zachęcam kolegów do wnikliwego czytania. Funkcja której wskaźnik autor tematu przekazuje jako procedurę przerwania jest? Jest. Mój komentarz odnosi się do nie umieszczania zawiłych instrukcji wewnątrz przerwania.

10 godzin temu, ethanak napisał:

Poza tym wyjaśnij, po co tam ten delay i dlaczego nie czyścisz ekranu przed wypisaniem "Home, come!".

Rozwiązanie zaproponowane miało zapewnić to o co autor prosił w pierwszej kolejności:

11 godzin temu, jakub51996 napisał:

chciałem aby był do ponownego naciśnięcia przycisku

 

11 godzin temu, Gieneq napisał:

Może spróbuj coś takiego, tu jest przełącznik na 1 przycisku, z pamięcią. O coś takiego Ci chodziło?

Nie jest to gotowe rozwiązanie, lecz jedna z iteracji, autor będzie w stanie coś dodać od siebie. Proszę przy tym o większą kulturę wypowiadania się.

 

10 godzin temu, ethanak napisał:

@Gieneq słyszałeś może kiedyś o operatorze porównania?

Np. if (pressed!= lastPressed)...

Dziękuję przyda się 🙂 

Edytowano przez Gieneq
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.