Skocz do zawartości

Kurs Arduino - #7 - Wyświetlacz tekstowy, LCD 2x16


Pomocna odpowiedź

(edytowany)

@leh1992Wszystko fajnie. Pytanie: czy za pół roku jak spojrzysz w ten kod, będziesz pamiętał co znaczy stan numer dwa?

A tak przy okazji: jeśli zmienna czas jest typu int, co ma niby oznaczać

czas+0.01;

Jak myślisz - jeśli zmienna czas ma wartość x to jaką będzie miała po dodaniu 0.01?

 

Edytowano przez ethanak

@ethanak

3 godziny temu, ethanak napisał:

Pytanie: czy za pół roku jak spojrzysz w ten kod, będziesz pamiętał co znaczy stan numer dwa?

Myślę że wywnioskuję to z ogólnej budowy kodu. A jest możliwość nazywania przypadków w funkcji switch słownie?

 

3 godziny temu, ethanak napisał:

A tak przy okazji: jeśli zmienna czas jest typu int, co ma niby oznaczać


czas+0.01;

Zmienna czas jest typu float

float czas = 0.0;

 

(edytowany)
6 godzin temu, leh1992 napisał:

A jest możliwość nazywania przypadków w funkcji switch słownie?

Oczywiście. Możesz użyć np. dyrektywy #define, coś w rodzaju:
 

#define STAN_CZEKAM 1
#define STAN_COS_ROBIE 2
#define STAN_COS_INNEGO 3

i dalej w kodzie coś w stylu:
 

stan = STAN_CZEKAM;
...
switch(stan) {
   case STAN_CZEKAM:

W ten sposób zarówno Ty za pięć lat, jak i ktoś kto widzi kod po raz pierwszy będzie od razu wiedział o co chodzi w kodzie i że dana gałąż switch będzie wykonana w stanie oczekiwania.

Wygodniejszym sposobem jest użycie enum, czyli:
 

enum {
  STAN_CZEKAM = 1,
  STAN_COS_ROBIE,
  STAN_COS_INNEGO
};

W ten sposób w ogóle nie zajmujesz się drobiazgami typu "który stan odpowiada jakiej liczbie" bo w rzeczywistości nikogo to nie interesuje, a enum automatycznie przydzieli kolejne wartości kolejnym stanom. Oczywiście to najprostszy sposób zastosowania enum, można stworzyć np. nowy typ i zmienne tego typu, np.:

typedef enum {
  STAN_CZEKAM = 1,
  STAN_COS_ROBIE,
  STAN_COS_INNEGO
} stany; // tworzymy nowy typ "stany" do przechowywania stanów maszyny

stany stan; // i zmienną "stan" przed chwilą utworzonego typu

Temat dość obszerny - wpisz w google "typ wyliczeniowy" i poczytaj na ten temat trochę więcej jeśli chcesz.
 

6 godzin temu, leh1992 napisał:

Zmienna czas jest typu float

A, to zwracam honor, cóż - starość nie radość i oczy już nie te... chyba mi się dwie linijki ze sobą połączyły 😞

Edytowano przez ethanak
  • Lubię! 1

@leh1992 fajnie, że wrzuciłeś swoje rozwiązanie i przyznam, że to wygląda ładnie. To o czym pisze @ethanak to dobry zwyczaj w programowaniu, który poprawia czytelność kodu. Ja ze swojej strony polecam autoformat z Arduino bo trochę się nawiasy rozjechały pod koniec (Ctrl-T), a tak to dobra robota 🙂 

(edytowany)

@ethanak Dzięki za podpowiedź! Na pewno pogrzebie w tym temacie!

@Gieneq O autoformacie też pierwsze słyszę, rzeczywiście ułatwia życie 😉

 

Tutaj już kod z zastosowanymi waszymi poradami

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

float czas = 0.0;
int stanLicznika = 0;

enum stanLicznika {oczekiwanie, pomiar, wynik};

unsigned long aktualnyCzas = 0;
unsigned long zmianaCzasu = 0;
unsigned long zmiana = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);

  lcd.begin(16, 2);
}

void loop() {
  aktualnyCzas = millis();

  switch (stanLicznika) {
    case oczekiwanie:
      lcd.setCursor(0, 0);
      lcd.print("Wcisnij");
      lcd.setCursor(0, 1);
      lcd.print("przycisk");
      if (digitalRead(8) == LOW) {
        lcd.clear();
        zmianaCzasu = aktualnyCzas;
        stanLicznika = pomiar;
      }
      break;
    case pomiar:
      lcd.setCursor(0, 0);
      lcd.print("Pomiar czasu");

      zmiana = aktualnyCzas - zmianaCzasu;
      if (zmiana >= 10) {
        zmianaCzasu = aktualnyCzas;
        czas = czas + 0.01;
      }
      lcd.setCursor(0, 1);
      lcd.print(czas);
      if (digitalRead(9) == LOW) {
        lcd.clear();
        stanLicznika = wynik;
      }
      break;

    case wynik:
      lcd.setCursor(0, 0);
      lcd.print("Koniec pomiaru");
      lcd.setCursor(0, 1);
      lcd.print(czas);
      if (digitalRead(10) == LOW) {
        lcd.clear();
        czas = 0;
        stanLicznika = oczekiwanie;
      } else if (digitalRead(8) == LOW) {
        lcd.clear();
        stanLicznika = pomiar;
      }
      break;
  }
}

 

Edytowano przez leh1992
Dodany kod
  • Lubię! 2

@leh1992 teraz wygląda bardzo ładnie, choć jeszcze jakbyś zastąpił wszystkie tzw. "magiczne liczby" w pinach jakimiś definami bo jednak nie jest to takie oczywiste:

else if (digitalRead(8) == LOW)

Widzę, że udało Ci się dać tylko jeden odczyt Seriala i dodać enuma jak sugerował @ethanak więc jest dużo lepiej 🙂 tak trzymaj!

  • Lubię! 1
  • 1 miesiąc później...
(edytowany)

Widziałem już podobne pytanie ale nie znalazłem odpowiedzi. Mój wyświetlacz czasem zamiast wyswietlać prawidłową treść pokazuje dziwne symbole.

Wrzucam krótki filmik i dwa zdj układu.

Wszystkie elementy poza potencjometrem należą do zestawu forbota. W układzie zmniejszyłem podświetlenie wyświetlacza (podpięte przez  rezystor) żeby było coś widać na filmie. Przewody odpowiadające za przesył danych skleiłem taśmą aby łatwiej odczytać schemat.

Do tego mój kod:

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void setup() {
  lcd.begin(16, 2); //deklaracja typu
  lcd.setCursor(0, 0); //ustawienie kursora
  lcd.print("Lukasz");
  lcd.setCursor(0, 1);
  lcd.print("forbot.pl");
  pinMode(10, OUTPUT);
  analogWrite(10, 50);
}

void loop() {
  lcd.noDisplay();
  delay(500);
  lcd.display();
  delay(500);
}

20200901_021622.jpg20200901_021447.jpg

Edytowano przez Gieneq

@hojda może jest jakiś błąd przy przesyle do Arduino. Zrób kilka testów:

  1. daj na początku setup opóźnienie np 2 sekundy, może przy starcie coś się dzieje,
  2. zamiast display/nodisplay daj kod, który masz w setup do części w loop - najlepiej zrób z tego funkcje i używaj w pętli loop - chodzi o to, żeby do Arduino był wysyłan napis, a nie sama komenda wygaszania,
  3. wymień kabelki i przełóż coś na płytce stykowej, bo może coś nie styka.
  • 2 tygodnie później...

Zadanie 7.1 

#include <LiquidCrystal.h> //biblioteka ekranu
LiquidCrystal lcd(2,3,4,5,6,7); //podłączenie wyświetlacza

void setup() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("    MIKOLAJ!");
  lcd.setCursor(0, 1);
  lcd.print("--> forbot.pl<--");
}

void loop() {
}

117950639_347470626255637_5217487722258711628_n.thumb.jpg.69238e8f22645b4bbbe80c320c7b79a9.jpg

Zadanie 7.2

W wyniku zastosowania funkcji clear() program czyści wszystko co zostało przez nas wyświetlone. Napis "Nap. Odczytane" znika na zawsze, natomiast sama wartość napięcia odczytana z fotorezystora pojawia się ponownie ponieważ jest odczytywana i wyświetlana w pętli loop przez cały czas działania programu. 

Zadanie 7.3

Poniżej 100ms wynik jest już ciężki do odczytania, ponieważ zmiany wartości następują bardzo szybko. Około 50ms ciężko już odczytać cokolwiek ponieważ wartość nie jest ani przez moment stała. 

Zadanie 7.4

 

Niedawno z bratem robiliśmy podobne zadanie bo ma zajęcia z Arduino w technikum 😄 

#include <LiquidCrystal.h>            //dołączenie biblioteki wyświetlacza
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);  //zadeklarowanie pinów wyświetlacza

float czas = 0.0;
int licznik = 0;

enum licznik {oczekiwanie, pomiar, wynik};   //wyliczeniowy typ danych; zmienna typu licznik może przyjąć 3 różne wartości zapisane w klamrach

unsigned long aktualnyCzas = 0;              //zadeklarowanie zmiennych umożliwiających sprawne posługiwanie się czasem
unsigned long zmianaCzasu = 0;
unsigned long zmiana = 0; 

void setup() {
  Serial.begin(9600);
  
  pinMode(8, INPUT_PULLUP);                  //przypisanie przycisków do odpowiednich pinów
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);

  lcd.begin(16, 2);                          //deklaracja typu wyświetlacza 
}

void loop() {
  aktualnyCzas = millis();   //millis zwraca czas w milisekundach, który minął od momentu uruchomienia programu
  
  switch (licznik) {                   //instrukcja warunkowa wielokrotnego wyboru
    case oczekiwanie:                  //przypadek pierwszy, gdy licznik jest w stanie oczekiwania
      lcd.setCursor(0, 0);             //ustawienie kursora w 1 linijce
      lcd.print("Wcisnij przycisk");   //piszemy w 1 linijce
      lcd.setCursor(0, 1);             //ustawienie kursora w 2 linijce
      lcd.print("...");                //piszemy w 2 linijce
      if (digitalRead(8) == LOW) {     //gdy przycisk nr 1 zostanie wcisniety
        lcd.clear();                   //czyscimy zawartosc wyswietlacza
        zmianaCzasu = aktualnyCzas;    //przypisanie do zmiennej "zmianaCzasu" ilości milisekund które upłynęły od momentu uruchomienia programu
        licznik = pomiar;              //przeniesienie stanu licznika w tryb pomiaru
      }
      break;

    case pomiar:                       //etap drugi, gdy licznik jest w stanie pomiaru
      lcd.setCursor(0, 0);             //ustawienie kursora w 1 linijce
      lcd.print("Pomiar czasu:");      //piszemy w 1 linijce
     
      //Serial.print("Aktualny czas: "); Serial.print(aktualnyCzas);
      //Serial.print("zmianaCzasu: "); Serial.print(zmianaCzasu); 
      
      zmiana = aktualnyCzas - zmianaCzasu;    //odjecie od aktualnej ilosci czasu, czasu ktory uplynal w momencie wcisniecia 1 przycisku
      if (zmiana >= 10) {                     //jesli zmiana jest wieksza niz 10ms 
        zmianaCzasu = aktualnyCzas;           //znowu przypisujemy do zmiennej "zmianaCzasu" czas który upłynął od początku uruchomienia programu;
        czas = czas + 0.01;                   //czas się zwiększa symulując stoper
      } 
      lcd.setCursor(0, 1);                    //piszemy w 2 linijce  
      lcd.print(czas);                        //wyswietlamy aktualna ilosc czasu, zmieniajaca sie o 0.01
      if (digitalRead(9) == LOW) {            //jesli wcisniemy przycisk nr 2 
        lcd.clear();                          //czyscimy aktualna zawartosc wyswietlacza
        licznik = wynik;                      //i aktualny status licznika ustawiamy na ostatni tryb czyli wynik
      }
      break;

    case wynik:                        //etap trzeci, gdy licznik jest w stanie wyniku
      lcd.setCursor(0, 0);             //kursor na 1 linijke
      lcd.print("Koniec pomiaru!");    //piszemy w 1 linijce
      lcd.setCursor(0, 1);             //kursor na 2 linijke
      lcd.print(czas);                 //wyswietlamy aktualny czas i pozostawiamy go bez zmian
      if (digitalRead(10) == LOW) {    //jesli wcisniemy 3 przycisk
        lcd.clear();                   //czyscimy zawartosc wyswietlacza
        czas = 0;                      //zerujemy czas
        licznik = oczekiwanie;         //licznik ustawiamy w tryb 1: oczekiwanie
      } else if (digitalRead(8) == LOW) {     //jesli wcisniemy ponownie przycisk nr 1
        lcd.clear();                          //czyscimy zawartosc wyswietlacza
        licznik = pomiar;                     //licznik jest w trybie 2, pomiaru i kontynuuje mierzenie czasu od momentu w ktorym zostal zatrzymany
      }
      break;
  }
}

 

  • Lubię! 1
  • 2 miesiące później...

Witam! Udało mi się zrobić zad.7.4 z dwoma przyciskami. Natomiast moje pytanie jest, czy da się to zrealizować za pomocą tylko jednego przycisku? Próbowałam to zrobić, ale niestety program nie chce do końca działać. Stoper się uruchamia i czas zaczyna się liczyć po pierwszym wciśnięciu przycisku, natomiast nie zatrzymuje się po kolejnym wciśnięciu (a taki był zamysł). Bardzo prosiłabym o wytłumaczenie problemu i wyrozumiałość, bo jestem dopiero początkująca 🙂 .

#include <LiquidCrystal.h> 
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

bool wcisniety = false;

void setup() {
  lcd.begin(16,2);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Stoper");
  lcd.setCursor(8,1);
  lcd.print("0  s");

  pinMode(12, INPUT_PULLUP);

}
int czas = 0;


void loop() {
  if(digitalRead(12) == LOW){//jesli przycisk wcisniety
     wcisniety = !wcisniety;
  }
  
  if(wcisniety == true){
    lcd.setCursor(0,1);
    lcd.print("Start: ");
    lcd.setCursor(8,1);
    delay(1000);
    czas = czas + 1;
    lcd.print(czas); 
    
  }else{
    lcd.setCursor(0,1);
    lcd.print("Stop: ");
     
  }

}

 

@AnnaC witam na forum 🙂

Pewnie, że da się na jednym przycisku, ale trzeba podejść do tego trochę inaczej. Spróbuj zrobić coś takiego - zrób zmienną, która oznacza co w danej chwili robi stoper (odlicza lub stoi). Po wciśnięciu przycisku sprawdzaj jaki jest aktualny stan stopera i zmieniaj go na przeciwny. To taka mała podpowiedź na początek - kombinuj, pokaż co uda Ci się zrobić. Powodzenia 😉

@Claumach witam na forum 🙂 Ciężko coś doradzić, jeśli nie widzimy Twojego układu. Możliwe, że coś nie styka lub popełniłeś jakiś błąd w montażu. Upewnij się, że nie pomyliłeś kolejności przewodów idących do wyświetlacza. Jeśli wszystko jest dobrze to pokaż dla pewności zdjęcie swojego układu oraz program.

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...