Skocz do zawartości

Dodatkowe ćwiczenia z wyświetlaczem 2x16 znaków


Gość

Pomocna odpowiedź

Witam wszystkich.

Na początku chciałbym zaznaczyć, że gdyby nie forum forbot, to nie wiem czy bym w ogóle od czegoś zaczął zważywszy na mój wiek. 

Postanowiłem dla zabawy rozwiązać kilka zadań z wyświetlaczem 2x16 znaków;

7.1  zrealizowane w ustawieniach void setup;

 1.thumb.jpg.b0d0e2a8a56c84c39f319f91e63196e2.jpg

Co prawda wyświetlacz podłączony poprzez githuba, ale to na chwilę obecną nie ma większego znaczenia.

7.2 oraz 7.3 Tutaj kłania się zasada działania wyświetlaczy ciekłokrystalicznych. Oczywiście jakość odświeżania zależy też od dobrze ustawionego kontrastu. Najefektywniej jest wtedy, kiedy piksele są delikatnie nasycone tj. na zdjęciu.  Jeżeli zależy nam na większej dynamice, to zawsze można zastosować wyświetlacz OLED.

7.4 No tu muszę przyznać, że straciłem trochę nerwów,

2.thumb.jpg.da7af1065a46ec3baaaac0d0ad4cd99f.jpg

a i tak  efekt wyszedł kiepski w porównaniu ze sterownikami PLC. Prawdopodobnie błąd leży gdzieś w kodzie który napisałem

#include <LCD-I2C.h> // https://github.com/hasenradball/LCD-I2C

LCD_I2C lcd(0x27, 16, 2);

volatile byte sw1 = 0; volatile byte sw2 = 0;

unsigned long TT = 0; unsigned long t0 = 0; unsigned long t1 = 0; unsigned long t2 = 999; unsigned long t_cms = 0;

unsigned int t3 = 0; unsigned int t4 = 0; unsigned int t5 = 0; unsigned int t6 = 0;

unsigned int a0 = 0; unsigned int a1 = 0; unsigned int a2 = 0;
unsigned int a3 = 0; unsigned int a4 = 0; unsigned int a5 = 0;
unsigned int a6 = 0; unsigned int a7 = 0; unsigned int a8 = 0;

uint8_t sym1[8] = {0b01100, 0b00100, 0b00110, 0b01100, 0b00100, 0b00100, 0b01110, 0b00000,}; // 'ł'
uint8_t sym2[8] = {0b00100, 0b00010, 0b01001, 0b00001, 0b01001, 0b00010, 0b00100, 0b00000,}; // ':)'
uint8_t sym3[8] = {0b11011, 0b01001, 0b10010, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000,}; // '"'

void setup() {
 
lcd.begin();
lcd.display();
lcd.backlight();

pinMode(2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), Start, FALLING);
pinMode(3, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(3), Stop, FALLING);
pinMode(4, INPUT_PULLUP);

lcd.createChar(0, sym1); lcd.setCursor(8, 0); lcd.write(0);
lcd.createChar(1, sym2); lcd.setCursor(10, 0); lcd.write(1);
lcd.createChar(1, sym2); lcd.setCursor(12, 0); lcd.write(1);

lcd.setCursor(4, 0);
lcd.print("Rafa");
lcd.setCursor(4, 2); lcd.print("forbot.pl");

delay(4000);

lcd.clear();

lcd.setCursor(6, 0); lcd.print("CZAS");
lcd.createChar(2, sym3); lcd.setCursor(10, 1); lcd.write(2);

}

void loop() {
  
byte sw3 = digitalRead(4);

TT = millis();

if (sw1 == 1) {t1 = TT - t0;}     
else {t0 = TT - t1; sw2 = 0;}   // Stoper start

if (sw2 == 1) {sw1 = 0;}  // Stoper stop

else if (sw3 == 0) {sw1 = 0; sw2 = 0; t2 = t1 + 999; // stoper reset
t3 = 0; t4 = 0; t5 = 0; t6 = 0;}    

t_cms = t1 - t2; // kompensacja czasu pętli
if (t1 > t2) {t2 = t1 + 999 - t_cms; t4++;} // zmienne wyjściowe czasu

t3 = t1 - (t2 - 999);
a1 = t3 / 100; a2 = t3 % 10; // setne

if (t4 > 59) {t4 = 0; t5++;} // sekundy
a3 = t4 / 10; a4 = t4 % 10;

if (t5 > 59) {t5 = 0; t6++;} // minuty
a5 = t5 / 10; a6 = t5 % 10;

if (t6 > 99) {t6 = 0;}
a7 = t6 / 10; a8 = t6 % 10; // godziny

lcd.setCursor(11, 1); lcd.print(a1); // setne
lcd.setCursor(12, 1); lcd.print(a2); 

lcd.setCursor(8, 1); lcd.print(a3); // sekundy
lcd.setCursor(9, 1); lcd.print(a4);

lcd.setCursor(7, 1); lcd.print("'");

lcd.setCursor(5, 1); lcd.print(a5); // minuty
lcd.setCursor(6, 1); lcd.print(a6);

lcd.setCursor(4, 1); lcd.print(':');

lcd.setCursor(2, 1); lcd.print(a7); // godziny
lcd.setCursor(3, 1); lcd.print(a8);

}

void Start() { 
sw1 = 1;
}
void Stop() { 
sw2 = 1;
}

ponieważ już po 5 min. zegar późni się o 1s względem stopera na smartfonie. Dla porównania w sterownikach PLC nawet po tygodniu zaprogramowany stoper chodzi co do sekundy.

Przerwania też działają tak jak by ich nie było. Pomiędzy wciśnięciem przycisku stop/ start upływa niecałe 0,1s.

Sumując; zrobienie profesjonalnego kodu pod zwykły stoper po kilku kursach Arduino wcale nie jest takie proste jakby się wydawało. To świadczy o tym, że mam dużo do nadrobienia, aby przy pomocy Arduino zbliżyć się do profesjonalnych sterowników PLC.

Edytowano przez rafal220
Link do komentarza
Share on other sites

Po pierwsze: kwarc w Arduino to nie kwarc zegarkowy i moze mieć odchylenia. Do precyzyjnego odmierzania czasu nie służy.

Po drugie jak wyświetlacz cały czas zasuwa to nic dziwnego, że w pętli mija nieco czasu zanim uprzejmie pozwolisz przyswoić sobie sw1 i sw2. 

Link do komentarza
Share on other sites

W tym programie mamy dwa czasy: czas mierzony, wynikający z millis() oraz czas odświeżania wyświetlacza. Na dokładność stopera wpływa tylko ten pierwszy, a samo wyświetlanie wcale nie musi być dokładne - różnicy ułamka sekundy nikt nie zauważy.

Dlatego wszelkie kompensacje czasu wykonania pętli nie mają sensu.

Link do komentarza
Share on other sites

(edytowany)

Kolejna rzecz która ma wpływ na czas wykonania to wczytywanie znak po znaku zamiast od razu cały bufor, myślę że autor w późniejszym czasie opanuje tą metodę obsługi wyświetlacza 

Edytowano przez _LM_
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

Gość
7 godzin temu, ethanak napisał:

Po pierwsze: kwarc w Arduino to nie kwarc zegarkowy i moze mieć odchylenia. Do precyzyjnego odmierzania czasu nie służy.

Po drugie jak wyświetlacz cały czas zasuwa to nic dziwnego, że w pętli mija nieco czasu zanim uprzejmie pozwolisz przyswoić sobie sw1 i sw2.

Ale tego nie musisz tłumaczyć, bo ja o tym dobrze wiem, tylko ta odchyłka jest zbyt duża jak na niedokładność kwarcu 16MHz. Z doświadczenia wiem, że te rezonatory są niejednokrotnie bardziej dokładniejsze, niż te standardowe stosowane w zegarach RTC 32.768kHz. Dlaczego taka wartość to każdy wie, ale nie każdy zdaje sobie sprawę, że te rezonatory potrafią być niezbyt precyzyjne. Osobiście wolę odmierzać czas standardowymi rezonatorami 16MHz. Po drugie (o ile spojrzałeś na kod) to masz tam zmienną kompensacyjną t_cms. Bez tej zmiennej stoper się rozjeżdża już po 30s. Co do przerwań, to jak widzisz są ogólne informacje w poradnikach jak je zastosować, ale nie jest wyjaśnione jak one dokładnie działają. Widomo, że przerwanie umożliwia zarejestrowanie przycisku. Osobiście myślałem, że jeżeli w przerwaniu znajduje się zmienna volatile, to program wychodząc z pętli przerwania od razu powędruje do punktu zmiennej volatile w petli loop. A tak nie jest, bo program kontynuuje loop w miejscu w którym ją przerwał. I teraz i tak wszystko zależy jak trafisz z momentem naciśnięcia przycisku start/ stop. Taki stoper wcale nie jest profesjonalny.

5 godzin temu, jand napisał:

Dlatego wszelkie kompensacje czasu wykonania pętli nie mają sensu.

W tym przypadku kompensacja wniosła to, że sekunda ucieka po 5min a nie 30s pracy stopera.

 

1 godzinę temu, _LM_ napisał:

Kolejna rzecz która ma wpływ na czas wykonania to wczytywanie znak po znaku zamiast od razu cały bufor, myślę że autor w późniejszym czasie opanuje tą metodę obsługi wyświetlacza 

No właśnie żeby ktoś to wyjaśnił jak to zrobić w jednej linijce. To samo z deklarowaniem zmiennych. Masz np. 20 albo i lepiej zmiennych x o wartości początkowej np. 0, i musisz za każdym razem dopisywać np. unsignet int. Ja to robię metodą kopiuj wklej, ale jak tych zmiennych będzie więcej to się uzbiera cała strona a nie 2 - 3 linijki. w poradniku Arduino są opisane zmienne, ale nie wiadomo jak je grupowo implementować. Tzn. Można dodać [], ale to nie deklaruje wszystkich zmiennych na raz, tylko trzeba wywołać jedną z całego zadeklarowanego ciągu.  Powinien powstać jakiś poradniach o tzw. sztuczkach i trikach ułatwiających pisanie kodu, oraz przyśpieszających pętlę programu. 

Link do komentarza
Share on other sites

1 godzinę temu, rafal220 napisał:

 Powinien powstać jakiś poradniach o tzw. sztuczkach i trikach ułatwiających pisanie kodu, oraz przyśpieszających pętlę programu. 

Przydał by się.

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

Ja myślę że warto nauczyć się przynajmniej podstaw języka w którym coś się pisze... ale z tego co widzę to chyba odosobnione zdanie.

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

A tak przy okazji co do stopera:

W funkcji przerwania od klawisza START coś w stylu:

if (!running) {
  running = 1;
  Tstart = millis();
}

W funkcji przerwania od klawisza STOP coś w stylu:

if (running) {
  running = 0;
  Tend = millis();
}

A w loop możesz użyć:

Tcurrent=millis() - Tstart.
Ttotal = Tend - Tstart;

Reszta to wyświetlanie.

 

Link do komentarza
Share on other sites

(edytowany)
1 godzinę temu, rafal220 napisał:

To samo z deklarowaniem zmiennych. Masz np. 20 albo i lepiej zmiennych x o wartości początkowej np. 0, i musisz za każdym razem dopisywać np. unsignet int. Ja to robię metodą kopiuj wklej, ale jak tych zmiennych będzie więcej to się uzbiera cała strona a nie 2 - 3 linijki. w poradniku Arduino są opisane zmienne, ale nie wiadomo jak je grupowo implementować.

Od tego są tablice i struktury, C daje takie możliwości i nie jest to żadna sztuczka, musisz po kolei przerobić kurs niema innej drogi. 

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

Gość
3 minuty temu, ethanak napisał:

Ja myślę że warto nauczyć się przynajmniej podstaw języka w którym coś się pisze... ale z tego co widzę to chyba odosobnione zdanie.

 

1 minutę temu, _LM_ napisał:

Od tego są tablice i struktury, C daje takie możliwości i nie jest to żadna sztuczka, musisz po kolei przerobić kurs niema innej drogi. 

Gdyby był jakiś kurs z przykładami, to by było prościej.

 

2 minuty temu, ethanak napisał:

A tak przy okazji co do stopera:

W funkcji przerwania od klawisza START coś w stylu:

Najpierw musze przeanalizować co oznaczają te pojęcia w Twoim kodzie (Tend, Ttotal itp.) , bo w opisie Arduino jak do tond nie rzuciły mi się w oczy.  

 

A teraz odnośnie co do dokładności stopera.

Otóż obkroiłem kod do możliwie najkrótszej pętli i jest to samo.

#include <LCD-I2C.h> // https://github.com/hasenradball/LCD-I2C

LCD_I2C lcd(0x27, 16, 2);


unsigned long TT = 0; unsigned long t0 = 0; unsigned long t1 = 0; 

unsigned int t2 = 0; 


void setup() {
 
lcd.begin();
lcd.display();
lcd.backlight();

}

void loop() {
 
TT = millis();

t0 = TT - t1;
if (t0 > 999) {t1 = TT; t2++;}

lcd.setCursor(11, 1); lcd.print(t2); 

}

 Po ok. 5min ucieka trochę więcej niż 1 sekunda bez kompensacji czasu pętli. Czyli więcej w porównaniu z poprzednim dłuższym kodem który takową posiadał. Sam już nie wiem. Może trzeba by zrobić całość w odniesieniu do funkcji micros oraz oprócz kompensacji czasu pętli wprowadzić kompensację czasu zegara? Albo opracować jakiś inny warunek odnoszący się do wewnętrznego zegara. No bo przecież w tych sterownikach PLC timery w postaci bloczków muszą być jakoś rozwiązane? W PLC można zająć całą pamięć, a timery bez względu na wszystko sztywno taktują liczniki. Prawdopodobnie kod tych bloczków jest lepiej zrobiony. W przypadku mojego stopera, to jest dosłownie jedna linijka która odnosi się do zegara wewnętrznego. Reszta kodu jak widać nie ma aż tak dużego znaczenia bo czas odnoszę do wartości 999ms.

Link do komentarza
Share on other sites

Te tajemnicze Tcośtam to nazwy zmiennych... tak jak Twoje TT czy t0.

Po jakiego grzyba robisz jakieś kombinacje z odejmowaniami różnych dziwnych zmiennych, kiedy czas masz po prostu w millis()?

Link do komentarza
Share on other sites

Gość
1 minutę temu, ethanak napisał:

o jakiego grzyba robisz jakieś kombinacje z odejmowaniami różnych dziwnych zmiennych, kiedy czas masz po prostu w millis()?

W powyższym przykładzie jest zrobione działanie zamiany millis na sekundy, oraz wyprowadzone na wyświetlacz tak aby zaobserwować odchyłkę. Przeniosę jeszcze  wyświetlacz do if, tak aby był odświeżany co sekundę. Zobaczę jaka będzie odchyłka.

Link do komentarza
Share on other sites

Jak nie będziesz wprowadzał jakichś dodatkowych działań to nie bedzie odchyłki i nie będzie co kompensować. PLC odwołuje się do jakiegoś bloczka "timer", tak? No to tu się to nazywa millis i liczy milisekundy od startu programu. I w rzeczywistości jest tylko wygodnym opakowaniem do sprzętowych timerów (które obsługuje się różnie w zależności od plaftormy - np. RPi Pico ma 64-bitowy licznik mikrosekund)

Link do komentarza
Share on other sites

Gość
2 minuty temu, ethanak napisał:

PLC odwołuje się do jakiegoś bloczka "timer", tak? No to tu się to nazywa millis i liczy milisekundy od startu programu.

To ja o tym wiem, tylko myślę jak oni napisali te timery, że bez względu na to czy użyjesz timera 10ms, czy też 1s, to nie patrząc na długość i czas pętli nie powstają jakieś odchyłki, a jeżeli nawet się z czasem pojawiają, to są one jedynie zależne od dokładności rezonatora.  Do mojego stopera brakuje właśnie timera, a raczej kawałka kodu który prawidłowo będzie się wciskać w odczyt z millis. 

Link do komentarza
Share on other sites

Przecież pisałem - to są sprzętowe timery a nie kawałki programu. I timer raz uruchomiony będzie liczył niezależnie od tego co procesor wyprawia.

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

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

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.