Skocz do zawartości

Przesuwanie znaków na wyświetlaczu LCD


adi1525

Pomocna odpowiedź

Witam, otóż na moim wyświetlaczu są 2 linie po 8 znaków.

Pierwsza linia ma adresy od 00 do 07, pamięć DDRAM dla pierwszej lini to 40 znaków

Gdy przesuwam tekst na ekranie, to znaki przesuwają się po pamięci DDRAM aż do 40 znaku. Jak w takim wypadku zaprogramować wyświetlacz aby np przy przesuwie w prawo znak z siódmej pozycji przenosił się na pierwszą??

Link do komentarza
Share on other sites

Typowy kontroler wyświetlacza znakowego nie wie jakie "szkło" zostało do niego podłączone. Z tego powodu funkcja wpisywania nowego znaku ze sprzętowym przesuwaniem będzie działała zawsze tak samo. Jeżeli chcesz zrobić fajne przesuwanie zawartości "zawijające się" tylko w obrębie widocznego ekranu to musisz:

- odwzorować to widoczne pole w jakiejś tablicy w RAMie, np. screen[32] lub ekran[2][16],
- funkcje robiące coś na LCD "przekierować" na tę tablicę tak, by wszelkie operacje były robione na zawartości tej tablicy,
- po zakończeniu manipulacji na tym wirtualnym obrazie całą zawartość tablicy przepisać do LCD.

Przy małym wyświetlaczu np. 2x8 czy 2x16 operacja przepisywania całej tablicy do pamięci LCD jest szybka i uaktualnianie można wołać zawsze gdy trzeba. Niestety trzeba o tym pamiętać lub dopisać na końcu każdej funkcji zmieniającej zawartość tablicy.

Drugą opcją jest przesuwanie poprzez odczytywanie i zapisy wprost z/do pamięci LCD, ale rzadko kiedy tak podłączamy te wyświetlacze by można je było odczytywać.

Ja zrobiłem kiedyś tak, że w przerwaniu zgłaszanym cyklicznie przez timer (np. 500Hz które i tak było podstawą czasu całego systemu) umieściłem wysyłanie jednego znaku z tablicy do LCD. W każdym przerwaniu wysyłałem jeden znak a po wysłaniu każdej pełnej linii (16 znaków) wysyłałem komendę zmiany adresu pamięci DDRAM. Tak więc łącznie po 32+2 przerwaniach miałem uaktualniony cały LCD i proces zaczynał się od nowa. Program robił tylko operacje na tablicy i w ogóle nie przejmował się odświeżaniem wyświetlacza, bo to robiło się samo w tle. W tej sytuacji zrobienie np. wpisywania z przesuwaniem chyba jest już trywialne 🙂

Link do komentarza
Share on other sites

Marek ale co jeśli np przesunął bym wyświetlenie pierwszego znaku gdzieś do środka pierwszej lini, to wysłanie całej lini będzie w innym miejscu, jeśli dobrze rozumiem co zrobiłeś. Ale wpadłem na pomysł, można by na przykład, przez odczytanie przerwania, odczytać adres znaku i jeżeli ten adres byłby ostatni w lini to po prostu przestawić go na początek. Można by tak zrobić ??

Funkcja przesuwu działa przez instrukcję "Cursor & display shift"

void przesun(int ile,int k_n,int kierunek)//kierunek = 1-prawo 0-lewo(3-bit)//napis-1 kursor-0(4-bit)
{
while(ile!=0)
{
	wyslij((0b00010000|(kierunek*0b00011000)|(k_n*0b00010100)),0);
	ile=ile-1;
	_delay_ms(100);
}
}
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

Nie do końca w czym jest problem z tym LCD, ale na pewno bufor w RAM pozwoli na dowolne cuda.

Natomiast, żeby uzyskać efekt wykorzystując samą pamięć kontrolera możesz spróbować zrobić tak:

1) w pierwszej linijce umieść cały komunikat np. "Ala ma kota123456789"

2) w drugiej, przesunięty o 8 znaków: "ota123456789Ala ma k"

Przesuwając okno, powinno się pojawić wrażenie zawijania z jednej linijki do drugiej.

Link do komentarza
Share on other sites

Nie rozumiem tego:

"wysłanie całej lini będzie w innym miejscu"

i tego:

"przez odczytanie przerwania".

Próbując robić jakieś nietypowe rzeczy ze znakowym LCD jesteś skazany na jego kilka prymitywnych komend. Jeżeli żadna z nich nie pasuje bezpośrednio do tego co chcesz zrobić to możesz albo korzystać z nich trochę "na siłę" wykonując jakieś ich sekwencje plus ew. zapisy/odczyty LCD albo w ogóle o nich zapomnieć i traktować wyświetlacz jak okienko przez które widać Twój wirtualny ekran stworzony w pamięci RAM procesora. To drugie rozwiązanie właśnie opisałem.

Nie jest ważne jak spowodujesz aby na LCD pokazywana była zawartość tablicy znaków umieszczonej w RAMie procesora. To może być wysyłanie po jednym znaku lub całej tablicy na raz. Może być samoczynne i okresowe, w przerwaniu (jak u mnie) a może to być wywoływanie explicite jakiejś funkcji odświeżającej kiedy uważasz to za konieczne. Ważne, by to się działo. Jak już zrobisz mechanizm przepisywania całej tablicy (np. 32-znakowej w przypadku LCD 2x16) z RAMu do pamięci wyświetlacza to dalej jest już prosto. Wszystkie operacje (wpisywanie nowego znaku, przesuwanie, kasowanie itd) robisz wyłącznie na tablicy - co jest dużo prostsze (bo z indeksami tablicy możesz robić cuda) i szybsze . Jeżeli dodatkowo przepisywanie zrobiłeś w przerwaniach od timera to już nie musisz się o nic martwić. To co namieszałeś w tablicy będzie automatycznie widoczne na LCD. Proste.

W uproszczeniu, dla LCD 2x16 funkcja wysyłająca może wyglądać jakoś tak:

1. Ustaw adres DDRAM na 0x00

2. Wyślij do LCD znaki z ekran[0] do ekran[15]

3. Ustaw adres DDRAM na 0x40

4. Wyślij do LCD znaki z ekran[16] do ekran[31]

W sumie 34 transfery i na LCD widać to co masz w tablicy ekran[]. A jak robić manipulacje na tablicy to już chyba nie muszę Ci tłumaczyć 🙂

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

Aha, już rozumiem o co ci chodzi, tylko masz może jakiś przykład jak ta funkcja mogła by działać ?. To ma działać tak, że zapisuje znaki do tablicy na niech robię operację i wysyłam to do LCD??

"wysłanie całej lini będzie w innym miejscu" chciałem zrobić tak, że od początku wyświetlacza wyświetlają się znaki i gdy licznik zliczy ostatni znak na końcu ekranu to pozycja ustawia się na pierwszym znaku. To działa tylko w przypadku gdy wypisywanie rozpocznę na pierwszym miejscu.

A w drugim chciałem zrobić przy odczycie flagi, ponieważ jak czytałem w dokumentacji to instrukcja Read busy flag odczytuje stan flagi zajętości „Busy Flag” oraz bieżący adres w pamięci DD RAM lub G RAM. Gdybym odczytywał każdy znak na której jest pozycji, to bym wiedział, kiedy jest na ostatnim miejscu.

Link do komentarza
Share on other sites

No ale własnie przykład dostałeś. Funkcja wysyłająca tak własnie ma działać. Zakładając, że masz już opanowane podstawowe operacje zapisu do LCD i zdefiniowaną globalną tablicę znaków screen[32], to przekładając na C mogłoby to wyglądać tak:

void lcd_refresh(void)
{
   uint8_t n;
   lcd_write_cmd(LCD_SET_DDRAM_ADDR + 0);
   for (n=0; n<16; n++)
       lcd_write_data(screen[n]);
   lcd_write_cmd(LCD_SET_DDRAM_ADDR + 0x40);
   for (n=17; n<32; n++)
       lcd_write_data(screen[n]);
}

Oczywiście można to napisać na wiele sposobów.

Mając taką funkcję pokazanie nowego znaku np. na 3 pozycji górnej linii sprowadza się do wykonania sekwencji:

screen[LCD_LINE_0 + 3] = 'A';
lcd_refresh();

Idąc dalej, możesz szybko stworzyć funkcję wpisującą otrzymany znak do tablicy screen[] w miejsce pamiętane jako pozycja kursora, kontrolującą tę pozycję oraz przechodzenie do następnej linii a nawet przesuwającą zawartość LCD o 1 linię w górę gdy dojdziesz do końca ostatniej linii.

Generalnie musisz sobie wymyślić taki sposób obsługi LCD i napisać takie funkcje podstawowe, by reszta programu mogła z nich korzystać w najwygodniejszy sposób. Najfajniej jest zrobić to tak, by jak najszybciej zapomnieć o siermiężnym interfejsie sprzętowym do LCD przez "przykrycie" go funkcjami robiącymi to co potrzebujesz. Łatwo jest sobie wyobrazić co trzeba zrobić (i jak to napisać w danym języku) by znaki w tablicy przesunęły się o 1 miejsce w prawo lub w lewo, tak samo jest z kasowaniem całej linii czy wypisywaniem liczb w polach po określonej długości. Dlatego właśnie zaproponowałem przepisywanie tablicy jako szybką metodę szybkiego przejścia z poziomu sprzętu na poziom abstrakcji troszkę wyższy. Czy to jest dla Ciebie zrozumiałe?

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

Już rozumiem o co tam chodziło. Zrobiłem taką tablicę:

void tekst(char tab[])
{
int n=0;
polozenie(0,0);
for (n=0; n<8; n++)
{
	wyslij(tab[n],1);
	_delay_ms(100);
}
polozenie(64,0);
for (n=8; n<16; n++)
{
	wyslij(tab[n],1);
	_delay_ms(100);
}
}

Tylko teraz mam problem z tą funkcją przesuwania, gdy zaczynam przesuwać znak komendą:

for (n=16;n<100;n++)
{
	wyslij(0b00011011,0);//Cursor & display shift
	_delay_ms(100);
}

to znaki przesuwają się już tylko w swojej lini, nie wiem jak zrobić tam jakby połączenie tych dwóch lini.

Link do komentarza
Share on other sites

No nie, to jednak nie rozumiesz. Mając napisaną funkcję pokazywania na LCD zawartości całej tablicy zapominasz o jakichkolwiek komendach do wyświetlacza. Koniec. Nie masz już interfejsu sprzętowego ani kontrolera z jego kilkoma komendami i dziwnymi adresami początków linii. Wszystko co robisz ze znakami, robisz na zawartości tablicy.

Chcesz wstawić znak i przesunąć resztę w prawo? Proszę bardzo:

void insert_and_shift (char new_code)
{
   uint8_t n;
   for (n=31; n>0; n--)
      tab[n] = tab[n-1];
   tab[0] = new_code;
   tekst(tab);
}

Rozumiesz jak to działa? Oddzieliłeś się od warstwy sprzętu za pomocą funkcji tekst(). Od teraz masz wyłącznie tablicę tab[] i to na niej robisz co chcesz z wyświetlaczem. Po wszelkich modyfikacjach robisz odświeżenie i gotowe.

Po co Ci te opóźnienia 100ms?? Funkcja tekst() musi być szybka bo będzie wołana często.

Acha i staraj się nazywać funkcje (i wszystko inne) tak, by jakoś opisywało to rolę jako dany obiekt pełni programie. Czy po roku będziesz pamiętał co robi funkcja tekst() albo do czego służy tab[]? A gdyby nazywały się odswiez_lcd(), lcd_refresh() i np. ekran[]?

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.