Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

LCD HD44780 - Miganie ekranu podczas przesuwania

superduo 04 Lis 2014 11:31 2877 20
  • #1 04 Lis 2014 11:31
    superduo
    Poziom 13  

    Próbuje zrobić coś z miganiem ekranu podczas wyświetlania tekstu na LCD 2x16...

    Wymyśliłem że tekst do wyświetlenia będę wrzucał najpierw w niewidoczną część ekranu (za 20-ty znak) a potem przesunę cały ekran o 20 znaków w lewo.

    Problem w tym że funkcja przesuwająca przesuwa ekran tylko o 1. Czy mam tą funkcje wykonać 20 razy? Czy może ma ona jakiś parametr bo się nie mogę tego doczytać (więc raczego go nie ma).

    Czy potem przed wpisaniem nowego tekstu mam przesunąć ekran o 20 w prawo?

    Może jest jakiś lepszy sposób na zlikwidowanie migania?

    0 20
  • #2 04 Lis 2014 11:33
    BlueDraco
    Specjalista - Mikrokontrolery

    Najpierw poprawić ortografię, a potem napisać dobrze kod. Nie jest żadną sztuką odświeżenie całego wyświetlacza w 30 ms, a przy takim czasie żadne migotanie nie powinno być zauważalne.

    0
  • #3 04 Lis 2014 11:50
    tomson5
    Poziom 16  

    Pewnie zbyt często odświeżasz zawartość.
    Postaraj się odświeżanie zrobić za pomocą Timera i flagi. Ewentualnie przez porównanie. Jeżeli coś się zmieniło to odśwież w przeciwnym razie przejdź dalej.

    0
  • #4 04 Lis 2014 11:59
    superduo
    Poziom 13  

    @BlueDraco: Jaką ortografie?

    @tomson5: Na wyświetlaczu mam np napis "Pozostało: 0:59" i co sekunde licznik jest dekrementowany.

    Wyświetlacz właściwie nie miga ale moment przeładowywania treści jest widoczny. Wiem że można to jakoś zlikwidować za pomocą przesuwania ekranu. Jedyne co mnie interesuje to czy moge przesunąć 20 znaków na raz czy musze funkcje przesuwania wywołać 20 razy..?

    0
  • #5 04 Lis 2014 12:16
    tomson5
    Poziom 16  

    Ja bym to zrobił w ten sposób że, "pozostało" bym nie odświeżał tylko zmienną zawierającą czas. Ty pewnie czyścisz za każdym razem całą zawartość ekranu.

    0
  • #6 04 Lis 2014 12:32
    nsvinc
    Poziom 35  

    BlueDraco napisał:
    Nie jest żadną sztuką odświeżenie całego wyświetlacza w 30 ms, a przy takim czasie żadne migotanie nie powinno być zauważalne.

    Of course. Jeśli zrezygnujesz z rozkazow typu clear screen i home. Znacznie szybciej forem zapisać do wyświetlacza (przyjmijmy 2x16) 32 spacje, niz wydać mu rozkaz clear screen. Ale wydaje mi się że to nie jest popularna wiedza wśród początkujących...

    0
  • #7 04 Lis 2014 13:01
    superduo
    Poziom 13  

    To był tylko przykład :)
    W miejscu liczników przeładowuje tylko znaki które tego wymagają i unikam migania ale co innego w przypadku menu gdzie przełączając napisy musze przeładować wszystkie znaki. I o taką sytuacje mi chodzi.

    Póki co ładuje znaki na zmianę wg. algorytmu:

    printxy(16, 0, "napis 1"); // Napis zostanie napisany w niewidocznej części ekranu

    przesuń_16_znaków_w_lewo(); // po tej instrukcji napisy stają się widoczne

    printxy(0, 0, "napis 2"); // Napis zostanie napisany w niewidocznej części ekranu która tym razem znajduje się po lewej stronie

    przesuń_16_znaków_w_prawo(); // po tej instrukcji napisy stają się widoczny a "napis 1" przesuwa się w niewidoczną część ekranu


    Czy to jedyny sposób? Czy może ktoś zna lepsze rozwiązanie?

    0
  • #8 04 Lis 2014 13:25
    tomson5
    Poziom 16  

    @nsvinc podał sposób wysłania 32 spacji tuż przed wysłaniem zawartości. Może to jest ten inny sposób. Nie testowałem.

    0
  • #9 04 Lis 2014 14:06
    michalko12
    Specjalista - Mikrokontrolery

    superduo napisał:
    Jaką ortografie?

    W temacie słowo "przesówanie" nie razi po oczach?

    Sensowny sposób jest tylko jeden. Buforujesz w pamięci zawartość całego ekranu i wysyłasz nową zawartość bez żadnego wstępnego czyszczenia. Wszystkie zmiany wykonujesz na buforze.

    0
  • #10 04 Lis 2014 14:17
    EuroGenio
    Poziom 17  

    michalko12 napisał:
    Sensowny sposób jest tylko jeden. Buforujesz w pamięci zawartość całego ekranu i wysyłasz nową zawartość bez żadnego wstępnego czyszczenia. Wszystkie zmiany wykonujesz na buforze.

    Racja!
    A to dlatego, że wysłanie jakiejkolwiek komendy zajmuje tyle samo czasu co wysłanie znaku.
    Przesunięcie kursora w dowolne miejsce to wysłanie szeregu komend przesunięcia w prawo (nawet 55!)
    Wysyłanie bufora poprzedzamy poleceniem ustawienia na (0,0) i wysyłamy bufor .
    Oczywiście wysyłanie takie trwa, dlatego też można to robić znak po znaku lub porcjami w przerwaniu od timera (wysłanie 1 znaku z obsługą przerwania itp. może na 4 bitach trwać blisko 1 ms!).
    Rozmiar bufora to 56 znaków (16 + uzupełnienie do 40 + 16)

    0
  • #11 04 Lis 2014 14:36
    BlueDraco
    Specjalista - Mikrokontrolery

    Wysyłanie jednego znaku zajmuje kilka mikrosekund. Nie spiesząc się ani trochę można odświeżyć cały wyświetlacz w 30 ms, czego człowiek nawet nie zauważy.

    Efekty, które opisuje nasz dysortogtraf, są spowodowane ewidentnymi błędami algorytmu.

    0
  • #12 04 Lis 2014 15:12
    nsvinc
    Poziom 35  

    tomson5 napisał:
    @nsvinc podał sposób wysłania 32 spacji tuż przed wysłaniem zawartości

    Nie. Nic nie mowilem o wysylaniu spacji przed zawartością. Stwierdziłem tylko, że clear screen wykona się nieporównywalnie wolniej niz wyslanie 32 spacji do wyświetlacza.

    EuroGenio napisał:
    A to dlatego, że wysłanie jakiejkolwiek komendy zajmuje tyle samo czasu co wysłanie znaku.
    Przesunięcie kursora w dowolne miejsce to wysłanie szeregu komend przesunięcia w prawo (nawet 55!)
    Wysyłanie bufora poprzedzamy poleceniem ustawienia na (0,0) i wysyłamy bufor .
    Oczywiście wysyłanie takie trwa, dlatego też można to robić znak po znaku lub porcjami w przerwaniu od timera (wysłanie 1 znaku z obsługą przerwania itp. może na 4 bitach trwać blisko 1 ms!).

    Bzdury wszelkiej maści i gatunku.
    Kontroler obsługuje postawienie kursora w dowolnym miejscu w DDRAM. Kontroler bardzo powoli wykonuje rozkaz home, ale za to bardzo szybko potrafi wpisać znak do DDRAM z automatyczną inkrementacją adresu. Maksymalny zegar danych (a więc linia E) to 2MHz (500ns na cykl). Rozkaz clear screen spowoduje flicker, więc nie ma sensu go wysyłać.
    Ustawienie adresu DDRAM to 37us, zapis znaku to 41us. Adres ustawiamy raz, potem wysylamy tresc bufora, więc operacja odswiezenia wyswietlacza 2x16 to:
    2x 37us + 32x 41us = 1386us. Doliczając zapas czasu itp itd, ustalmy ze to jest 2ms. Więc wyświetlacz mozna przerysować 500 razy na sekundę...

    0
  • #13 04 Lis 2014 21:50
    EuroGenio
    Poziom 17  

    Sposoby i czas zapisu do wyświetlacza oparłem na bibliotece "LCD4Bit_mod" a tam nie widziałem funkcji blokowego dostępu do DDRAM i wszystko zapisywane jest znak po znaku.
    Zauważyłem, że przy zapisie ponad 1000 znaków/s (no, może trochę więcej) mikrokontroler 16Mhz (Arduino UNO) praktycznie przestał wykonywać pętlę główną.

    Chętnie poznam inną bibliotekę mającą takie możliwości, chociaż akurat moje potrzeby nie są zbyt wygórowane i ww. biblioteka wraz z buforem wystarczały.

    nsvinc napisał:
    (...) Rozkaz clear screen spowoduje flicker, więc nie ma sensu go wysyłać. (...)

    Nigdzie nie pisałem aby wysyłać CLS

    0
  • #14 05 Lis 2014 02:09
    nsvinc
    Poziom 35  

    EuroGenio napisał:
    Zauważyłem, że przy zapisie ponad 1000 znaków/s (no, może trochę więcej) mikrokontroler 16Mhz (Arduino UNO) praktycznie przestał wykonywać pętlę główną.

    Ciekawe - nawet jakby wysylac na zmiane set_ddram_address (37us) i znak bez autoinkrementa (37us) + 4 zegary (2us) wychodzi 79us. 1k znakow zajmie więc 79000us wiec 79 milisekund. Więc z obliczeń wynika, że procek pracujący z zegarem kilka MHz (to juz pomijam jaka architektura) zuzyje ~10% swojego czasu na zapis tego 1k znaków.
    A taki STM32 @72MHz z wykorzystaniem timera, DMA, i marnując trochę ramu, zrobi to zuzywając ułamek czasu procesora...

    0
  • #15 05 Lis 2014 08:18
    EuroGenio
    Poziom 17  

    I właśnie takich lub podobnych timingów jak podane przez kolegę nsvinc się spodziewałem przystępując do używania wyświetlacza.
    Ale wielkie było moje zdziwienie, kiedy zauważyłem, że zapis jakiejkolwiek treści zajmuje kilkanaście/kilkadziesiąt milisekund i dlatego kombinacje z buforem a potem z wyświetlaniem bufora w przerwaniach.

    Myślę, że dotyczy to tej konkretnej biblioteki gdzie procedura:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    - jest wywoływana przy każdym zapisie do LCD (i w niej te nieszczęsne delay(1) na końcu).

    Dlatego serio pisałem, że jeśli jest jakaś inna biblioteka (bardziej dopracowana) do obsługi LCD na szynie 4-ro bitowej to chętnie ją poznam.

    Dla porządku w załączniku cała biblioteka.

    0
  • #16 05 Lis 2014 09:40
    BlueDraco
    Specjalista - Mikrokontrolery

    I w ten sposób po dwóch dniach bicia piany dowiedzieliśmy się wreszcie, że chodzi o Arduino i bardzo przyjazne dla programisty funkcje typu digitalWrite, wykonujące się w setkach cykli niezbyt szybkiego procesora... Oczywiście zbędne zatrzymanie na 1 ms też robi swoje, a delayMicroseconds(1) opóźnia zapewne o kilka us.

    0
  • #17 05 Lis 2014 11:33
    nsvinc
    Poziom 35  

    EuroGenio napisał:
    Dlatego serio pisałem, że jeśli jest jakaś inna biblioteka

    Trudno powiedzieć. Nigdy nie szukałem, bo nigdy nie miałem zamiaru korzystać. Obsługa jest tak prosta, że wystarczy na podstawie datasheeta napisać kod sterujący portem poprzez zapis do rejestru, zamiast przez skomplikowaną funkcję...

    0
  • #18 05 Lis 2014 12:20
    tmf
    Moderator Mikrokontrolery Projektowanie

    EuroGenio napisał:
    Sposoby i czas zapisu do wyświetlacza oparłem na bibliotece "LCD4Bit_mod" a tam nie widziałem funkcji blokowego dostępu do DDRAM i wszystko zapisywane jest znak po znaku.
    Zauważyłem, że przy zapisie ponad 1000 znaków/s (no, może trochę więcej) mikrokontroler 16Mhz (Arduino UNO) praktycznie przestał wykonywać pętlę główną.


    Tak jak napisał kolega BlueDraco winę ponosi Arduino, którego wydajność jest na poziome Bascoma, a w pewnych operacjach nawet poniżej. Jeśli musisz korzystać z Arduino, to popraw bibliotekę, tak, aby bezpośrednio odwoływała się do portów IO procka, a nie przez metody typu digitalWire itd. Oczywiście ceną za to jest mniejsza przenośność kodu, ale coś za coś.

    0
  • #19 05 Lis 2014 13:01
    EuroGenio
    Poziom 17  

    Dzięki za wskazówki.
    Z ciekawości pomierzę (oscyloskopem) czasy dla digitalWrite i dla delayMicroseconds.

    0
  • #20 05 Lis 2014 13:36
    tmf
    Moderator Mikrokontrolery Projektowanie

    A po co sobie komplikować? Nie prościej odpalić symulator i zobaczyć ile taktów wykonują się poszczególne metody?

    0
  • #21 05 Lis 2014 21:56
    EuroGenio
    Poziom 17  

    Dobry pomysł.
    Ale jaki symulator Arduino, który?

    Zrobiłem jednak wcześniej pomiary i zamieszczam co mi wyszło.
    Poniżej cały kod który generował przebieg:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    Wszystkie pomiary zrobione za pomocą oscyloskopu, więc dokładność powiedzmy taka sobie.

    LCD HD44780 - Miganie ekranu podczas przesuwania

    Jak widać, tak kluczowa procedura w mikrokontrolerze jak digitalWrite() potrzebuje trochę mniej niż 4us na ustawienie stanu na wyjściu (jak dobrze liczę to ok. 62..64 cykle).
    Sprawdziłem też, że maksymalna f do wygenerowania na wyjściu (w sytuacji kiedy uC nie robi nic innego) to tylko ok. 128kHz, spodziewałem się jednak ok. 1MHz.

    Ta wartość jest tylko teoretyczna, bo proszę zauważyć że wyłączyłem przerwania.
    Inaczej Arduino, bo tak tu to nazwę, generuje sobie jakieś przerwanie od timera co ok. 2ms trwające (zajmujące) ok. 4-6 us.

    Trochę inaczej ma się sytuacja z delayMicroseconds().
    Co ciekawe, 10-cio krotne wywołanie z czasem 1us nie odbiega zbytnio od jednokrotnego wywołania z parametrem 10us (a nawet - dziwne - zdaje się generować krótsze opóźnienie).

    Dzięki za kubeł zimnej wody...
    Hmm, faktyczne warto napisać własne procedury IO...

    0