LCD, assembler i 89s51

To forum jest dla wszystkich pasjonatów wiecznie młodych mikrokontrolerów '51. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
Raflles
-
Posty: 77
Rejestracja: 06 sie 2005, 17:15
Lokalizacja: Tychy
Kontakt:

LCD, assembler i 89s51

Post autor: Raflles » 03 sie 2006, 14:51

Witam !! Wiem, że temat ten był już niejednokrotnie wałkowany tu na forum, ale ja już mam dosyć, 3 dni siedzenia nad jednym i tym samym trochę męczy i zniechęca. Poniżej zamieściłem kod mojego programu obsługi LCD i prosiłbym, aby ktoś powiedział mi dlaczego on nie chce działać. Inicjalizację robiłem na podstawie algorytmu z książki "Mikrokontrolery 8051 w praktyce" dla 4 - bitowej magistrali.

Kod: Zaznacz cały


;Obsluga wyswietlacza

Data_LCD EQU P2
EN EQU P2.3
RW EQU P2.2
RS EQU P2.1
LED EQU P1.0

lcall LCD_INIT
lcall LCD_CLR

mov A,#'X'
lcall WYSW_ZNAK

Blink:

cpl LED
loop2:
djnz R5,$
djnz R6,loop2

ljmp blink

WYSW_ZNAK:

setb RS
clr RW
lcall LCD_ZAPIS
lcall Readbusy

ret

LCD_ZAPIS:

push ACC
orl Data_LCD,#0F0h
orl A,#0Fh
anl Data_LCD,A
setb En
mov R3,#5d
lcall Delay_ms
clr En

pop ACC
swap A
orl Data_LCD,#0F0h
orl A,#0Fh
anl Data_LCD,A
setb En
mov R3,#5d
lcall Delay_ms
clr En

ret

LCD_CLR:

clr RS
clr RW
setb En

orl Data_LCD,#0F0h
anl Data_LCD,#0Fh

clr En
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

ret

LCD_INIT:

clr RS
clr RW
setb En

mov R3,#50d             ;czeka 50 ms
lcall Delay_ms          ;

anl Data_LCD,#3Fh       ;wpisuje do portu 3Fh
clr En                  ;zapisuje wartosc 3 do wyswietlacza (8-bit)
mov R3,#5d              ;czeka 5 ms
lcall Delay_ms          ;
setb En                 
mov R3,#10d             ;czeka 10 ms
lcall Delay_ms
clr En                  ;zapisuje 3 do wyswietlacza (8-bit)
mov R3,#5d              ;czeka 5 ms
lcall Delay_ms         
setb En                 
mov R3,#1d              ;czeka 1 ms
lcall Delay_ms
clr En                  ;zapisuje 3 do wyswietlacza (8-bit)
mov R3,#5d
lcall Delay_ms

setb En
clr RS
clr RW

orl Data_LCD,#0F0h
anl Data_LCD,#2Fh

clr En                  ;wpisanie do LCD 2 (4-bit)
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

clr En                  ;Function set (4-bit)
mov R3,#5d              ;
lcall Delay_ms          ;
setb En                 ;
mov R3,#5d              ;
lcall Delay_ms          ;
orl Data_LCD,#0F0h      ;Function set N=1-dwie linie
anl Data_LCD,#8Fh       ;F=0-znaki 5x7 punktow

clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

orl Data_LCD,#0F0h      ;Display ON/OFF
anl Data_LCD,#0Fh       ;

clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

orl Data_LCD,#0F0h      ;Display ON/OFF
anl Data_LCD,#8Fh       ;

clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

orl Data_LCD,#0F0h      ;
anl Data_LCD,#0Fh       ;

clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

orl Data_LCD,#0F0h      ;
anl Data_LCD,#1Fh       ;

clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

orl Data_LCD,#0F0h      ;Entry mode set
anl Data_LCD,#0Fh       ;

clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

orl Data_LCD,#0F0h
anl Data_LCD,#6Fh

clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms
setb En

lcall Readbusy

ret

ReadBusy:

clr RS
setb RW
orl Data_LCD,#0F0h
Busy:
setb En
mov A,Data_LCD
clr En
JB ACC.7,Busy
clr RW

ret

Delay_ms:

mov R1,#45d
mov R2,#10d
Loop:
DJNZ R1,$;trwa 0,0001 sekundy przy zegarze 11,0592MHz
DJNZ R2,loop; calosc trwa w przyblizeniu 1 ms
DJNZ R3,loop; w zaleznosci od zawartosci rejestru R3

ret

end
[/code]

ZbeeGin

Post autor: ZbeeGin » 03 sie 2006, 19:26

Na początek wyciąłbym sprawdzanie czy LCD jest gotowy po przesłaniu danych, a tam gdzie należałoby odczekać przed przesłaniem kolejnych danych zastosować stałe opóźnienia, zgodnie z tablelą czasów realizacji poleceń przez LCD.

Awatar użytkownika
gaweł
Użytkownik
Posty: 651
Rejestracja: 05 kwie 2004, 8:38
Lokalizacja: Białystok
Kontakt:

Post autor: gaweł » 03 sie 2006, 22:27

No więc... zakładam, że program zaczyna się od lcall LCD_INIT. No idźmy tą drogą:

Kod: Zaznacz cały

lcall LCD_INIT 
.
.
.
LCD_INIT: 

clr RS 
clr RW
no to jest zrozumiałe


Kod: Zaznacz cały

setb En 
tu już mniej, dlaczego nie jest wysterowana szyna danych do LCD. W chwili wystawienie 1 na E do LCD, na szynia danych powinien być już ustalony stan na szynia danych


Kod: Zaznacz cały

mov R3,#50d             ;czeka 50 ms 
lcall Delay_ms          ; 
no, wiadomo ....


Kod: Zaznacz cały

anl Data_LCD,#3Fh       ;wpisuje do portu 3Fh 
ale tu Raflles, musisz wyjaśnić, dlaczego instrukcja anl (jak również nie wiadomo, do których pinów jest przypięta szyna danych do LCD, piszesz tylko, że 4 bity).


Kod: Zaznacz cały

clr En                  ;zapisuje wartosc 3 do wyswietlacza (8-bit) 
i rodzi się pytanie, jakie dane wysłałeś do LCD? W kolejnych wierszach programu jest podobnie. Robisz "manewry" na sygnale En, ale co jest z szyną danych do LCD.

Raflles
-
Posty: 77
Rejestracja: 06 sie 2005, 17:15
Lokalizacja: Tychy
Kontakt:

Post autor: Raflles » 04 sie 2006, 11:05

Witam !! Szyna danych jest przypięta do pinów:
D4 -> P2.4 ;
D5 -> P2.5 ;
D6 -> P2.6 ;
D7 -> P2.7

Data_LCD EQU P2
EN EQU P2.3
RW EQU P2.2
RS EQU P2.1

jeżeli chodzi o dane to nie bardzo wiem o co koledze chodzi. Chcę wysłać do wyświetlacza znak X, a jeżeli chodzi o rozkazy przesyłane do wyświetlacza, to postępuję zgodnie z książką podaną w pierwszym poście. Tam jest ten sam algorytm inicjalizacji co w nocie katalogowej HD44780. Pozdrawiam i proszę o dalszą pomoc.

Kod: Zaznacz cały


;Obsluga wyswietlacza

Data_LCD EQU P2
EN EQU P2.3
RW EQU P2.2
RS EQU P2.1
LED EQU P1.0

lcall LCD_INIT
lcall LCD_CLR

mov A,#'X'
lcall WYSW_ZNAK

Blink:

cpl LED
loop2:
djnz R5,$
djnz R6,loop2

ljmp blink

WYSW_ZNAK:

setb RS
clr RW
lcall LCD_ZAPIS
mov R3,#5d
lcall Delay_ms

ret

LCD_ZAPIS:

push ACC
orl Data_LCD,#0F0h
orl A,#0Fh
anl Data_LCD,A
setb En
mov R3,#5d
lcall Delay_ms
clr En

pop ACC
swap A 
orl Data_LCD,#0F0h
orl A,#0Fh
anl Data_LCD,A
setb En
mov R3,#5d
lcall Delay_ms
clr En

ret

LCD_CLR:

clr RS
clr RW

orl Data_LCD,#0F0h
anl Data_LCD,#0Fh

setb En
mov R3,#5d
lcall Delay_ms
clr En
mov R3,#5d
lcall Delay_ms

orl Data_LCD,#0F0h
anl Data_LCD,#0FFh

setb En
mov R3,#5d
lcall Delay_ms
clr En
mov R3,#5d
lcall Delay_ms

ret

LCD_INIT:

clr RS
clr RW

mov R3,#50d             ;czeka 50 ms
lcall Delay_ms          ;

anl Data_LCD,#3Fh       ;wpisuje do portu 3Fh
setb En
mov R3,#5d              ;czeka 5 ms
lcall Delay_ms
clr En                  ;zapisuje wartosc 3 do wyswietlacza (8-bit)
mov R3,#10d              ;czeka 5 ms
lcall Delay_ms          ;
setb En                 
mov R3,#5d             ;czeka 10 ms
lcall Delay_ms
clr En                  ;zapisuje 3 do wyswietlacza (8-bit)
mov R3,#5d              ;czeka 5 ms
lcall Delay_ms          
setb En                 
mov R3,#1d              ;czeka 1 ms
lcall Delay_ms
clr En                  ;zapisuje 3 do wyswietlacza (8-bit)
mov R3,#5d
lcall Delay_ms


clr RS
clr RW

orl Data_LCD,#0F0h
anl Data_LCD,#2Fh

setb En
mov R3,#5d
lcall Delay_ms
clr En                  ;wpisanie do LCD 2 (4-bit)
mov R3,#5d
lcall Delay_ms
setb En
mov R3,#5d
lcall Delay_ms
clr En                  ;Function set (4-bit) 
mov R3,#5d              ;
lcall Delay_ms          ;

orl Data_LCD,#0F0h      ;Function set N=1-dwie linie
anl Data_LCD,#8Fh       ;F=0-znaki 5x7 punktow


setb En                 ;
mov R3,#5d              ;
lcall Delay_ms          
clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms

orl Data_LCD,#0F0h      ;Display ON/OFF
anl Data_LCD,#0Fh       ;
setb En
mov R3,#5d
lcall Delay_ms
clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms

orl Data_LCD,#0F0h      ;Display ON/OFF
anl Data_LCD,#8Fh       ;
setb En
mov R3,#5d
lcall Delay_ms
clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms

orl Data_LCD,#0F0h      ;
anl Data_LCD,#0Fh       ;

setb En
mov R3,#5d
lcall Delay_ms
clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms


orl Data_LCD,#0F0h      ;
anl Data_LCD,#1Fh       ;

setb En
mov R3,#5d
lcall Delay_ms
clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms


orl Data_LCD,#0F0h      ;Entry mode set
anl Data_LCD,#0Fh       ;
setb En
mov R3,#5d
lcall Delay_ms
clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms


orl Data_LCD,#0F0h
anl Data_LCD,#6Fh
setb En
mov R3,#5d
lcall Delay_ms
clr En                  ;wpisanie do LCD
mov R3,#5d
lcall Delay_ms


ret

;ReadBusy:

;clr RS
;setb RW
;orl Data_LCD,#0F0h
;Busy:
;setb En
;mov A,Data_LCD
;clr En
;JB ACC.7,Busy
;clr RW

;ret

Delay_ms:

mov R1,#45d
mov R2,#10d
Loop:
DJNZ R1,$;trwa 0,0001 sekundy przy zegarze 11,0592MHz
DJNZ R2,loop; calosc trwa w przyblizeniu 1 ms
DJNZ R3,loop; w zaleznosci od zawartosci rejestru R3

ret

end
NOOO !! Nareszcie ten program zadziałał, ale mam jeszcze jedno pytanie. Czy większość z tych opóźnień wnosi coś wogóle ?? Czy można je usunąć i czy podprogram Readbusy jest napisany prawidłowo ??

Pozdrawiam i czekam na odpowiedź

Awatar użytkownika
gaweł
Użytkownik
Posty: 651
Rejestracja: 05 kwie 2004, 8:38
Lokalizacja: Białystok
Kontakt:

Post autor: gaweł » 04 sie 2006, 12:41

Jak podałeś położenie szyny danych, to pewne czynności stały się jasne (dla mnie).

Kod: Zaznacz cały

LCD_INIT: 
clr RS 
clr RW 
mov R3,#50d             ;czeka 50 ms 
lcall Delay_ms          ; 
anl Data_LCD,#3Fh       ;wpisuje do portu 3Fh 
setb En 
mov R3,#5d              ;czeka 5 ms 
lcall Delay_ms 
clr En
Wiedząc gdzie szyna danych LCD jest przyłączona, wysyłasz do LCD polecenie o kodzie 0011xxxx (x-oznacza nieistotne), co znaczy, że będzie interfejs 4-bitowy z 8-bitowym interface. W moim mniemaniu powinieneś wykonać instrukcję anl Data_LCD,#2Fh
i określić, że interfejs będzie 4-btowy i od tej chwili używać jako 4-bitowy. Ty robisz to później.
W kwestii opóźnień :arrow: https://elportal.pl/n0003/lcd/hd44780.pdf strona 260, czas trwania impulsu E musi być nie mniejszy niż 230 ns, więc opóźnienie między setb En i clr En musi wystąpić. Wykonanie każdego rozkazu przez LCD wymaga jakiegoś czasu i tu są dwie szkoły: przed wysłaniem następnego należy odczekać określony czas lub posiłkować się wskaźnikiem zajętości (ja jestem zwolennikiem wskaźnika zajętości). W moim przekonaniu masz źle napisą procedurę jego odczytu. Skoro masz interface 4-bitowe, to również odczyt musisz robić przez "dwutakt", odczytać jedną połowę i następnie drugą połowę szyny danych i po odpowiednim złożeniu bajtu sprawdzić, czy masz ustawioną flagę zajętości.

Raflles
-
Posty: 77
Rejestracja: 06 sie 2005, 17:15
Lokalizacja: Tychy
Kontakt:

Post autor: Raflles » 04 sie 2006, 13:57

No właśnie jeżeli chodzi o przełączenie na interface 4 bitowy, to na 49 stronie noty aplikacyjnej w algorytmie jest pokazane, żeby 3 razy podać daną 0011xxxx a dopiero później przełączyć się na 4 bitową. Dla mnie też jest to trochę bez sensu, ale skoro tak piszą w nocie katalogowej ?? A jeżeli chodzi o sprawdzanie bitu busy to zaraz poprawię program. Pozdrawiam

ODPOWIEDZ