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

ATmega32 i LCD alfanumeryczny - niby proste, ale...

05 Sie 2006 23:45 1740 4
  • Poziom 10  
    Mam problem, który właśnie zaczyna mi spędzać sen z powiek.
    Założenie było proste wysyłać dane do wyświetlacza, gdy flaga BUSY = 0.
    Niestety nie wiem gdzie robię błąd, ale gdy próbuję coś wyświetlić na LCD, badając stan flagi BUSY, to wyświetlacz działa nieprawidłowo. Albo nic nie wyświetli, albo jakieś dziwne rzeczy.
    W programie, który widac poniżej, zastosowałem opóźnienia i wystarczy, że zrezygnuję z podprogramu LcdBusy i już jest wszystko ok. Proszę powiedzcie, gdzie robię błąd, co zmienić, żeby można było obsługiwać LCD, badając tylko flagę BUSY.
    Code:

    .INCLUDE   "m32def.inc"

    .EQU   SYS_FREQ = 8         ; częstotliwość pracy mikrokontrolera

    .EQU   PortLcd      = PORTc   ; rejestr we/wy wyświetlacza LCD
    .EQU   PinLcd      = PINc   ; rejestr odczytu stanu portu LCD
    .EQU   kPortLcd   = DDRc   ; kierunek portu wyświetlacza LCD
    .EQU   LCD_RS      = 0      ; sygnał RS podpięty do pinu 0
    .EQU   LCD_RW      = 1      ; sygnał wyboru do pinu 1
    .EQU   LCD_EN      = 2      ; nr linii dla sygnału EN
    .EQU   LCD_DB4      = 4      ; linia danych DB4
    .EQU   LCD_DB5      = 5      ; linia danych DB5
    .EQU   LCD_DB6      = 6      ; linia danych DB6
    .EQU   LCD_DB7      = 7      ; linia danych DB7
    .EQU   LCD_BUSY   = PINc7   ; linia służy też do odczytu stanu LCD
       
    .ORG   0x0000
       rjmp      Reset

    .ORG   0x0060

    Reset:
       ldi      R16, high (RAMEND)
       ldi      R17, low (RAMEND)
       out      SPH, R16
       out      SPL, R17      ; ustawienie granicy stosu

       rcall   LcdInic      ; skok do procedury przygotowującej LCD do pracy

       ldi      R18, 0b11110000
       rcall   LcdWriteData   ; wypisz znak p
        ldi      R18, 0b01101010
       rcall   LcdWriteData   ; wypisz znak j
     
    Petla:   
       rjmp   Petla

    .INCLUDE "wait_ms.inc"
    .INCLUDE "wait_us.inc"

    ;**************************************
    ; Procedura inicjalizacji LCD
    ;**************************************

    LcdInic:
       ldi      R16, 0xff      ; wszystkie linie jako wyjście
       out      kPortLcd, R16   ; ustawienie funkcji linii portu

       cbi      PortLcd, LCD_RS   ; RS = 0, czyli instrukcje
       cbi      PortLcd, LCD_RW   ; RW = 0, czyli zapis
       cbi      PortLcd, LCD_EN   ; EN = 0   
          
       ldi      R16, 50
       ldi      R17, 1
       rcall   wait_ms         ;*** oczekiwanie 50 ms ****
       
       sbi      PortLcd, LCD_EN   ; EN = 1
       cbi      PortLcd, LCD_DB7; DB7 = 0
       cbi      PortLcd, LCD_DB6; DB6 = 0
       sbi      PortLCD, LCD_DB5; DB5 = 1
       sbi      PortLCD, LCD_DB4; DB4 = 1

       ldi      R17, 1
       ldi      R16, 1
       rcall   wait_us
       ldi      R16, 5
       cbi      PortLcd, LCD_EN   ; EN = 0, potwierdzenie danych na liniach DB4...DB7
       rcall   wait_ms         ; *** oczekiwanie 5 ms ****

       ldi      R16, 1         ;
       sbi      PortLcd, LCD_EN   ; EN = 1
       rcall   wait_us         ; czekaj 10 us
       cbi      PortLcd, LCD_EN   ; EN = 0, potwierdzenie danych na liniach DB4...DB7
       
       ldi      R16, 20
       rcall   wait_us         ; *** oczekiwanie 200 us ****

       ldi      R16, 1         ;
       sbi      PortLcd, LCD_EN   ; EN = 1
       rcall   wait_us         ; czekaj 10 us
       cbi      PortLcd, LCD_EN   ; EN = 0, potwierdzenie danych na liniach DB4...DB7

       ldi      R16, 20
       rcall   wait_us         ; *** oczekiwanie 200 us ****
       
    ;**************************************
    ; ustawienie interfejsu 4-bitowego
    ;**************************************

    LcdInic_0:
       rcall LcdBusy

       ldi      R16, 1
       cbi      PortLCD, LCD_DB4      ; DB4 = 0, interfejs 4-bitowy,
       sbi      PortLcd, LCD_EN         ;
       rcall   wait_us
       cbi      PortLcd, LCD_EN         ; EN = 0, potwierdzenie danych na liniach DB4...DB7 opadającym zboczem
       
       ldi      R18, 0b00101000         ; tryb 4-bitowy, wyświetlacz 2-liniowy, 5x8 punktów
       rcall   LcdWriteInstr

       ldi      R18, 0b00000110
       rcall   LcdWriteInstr         ; nowy znak wstawiany na prawo

       ldi      R18, 0b00001111         ;
       rcall   LcdWriteInstr         ; wyświetlacz włączony, kursor niewidoczny
       rcall   LcdClr
       
       ret                        ; powrót z podprogramu

    ;**************************************
    ; Procedura zapisu bajtu danych do LCD
    ; w trybie 4-bitowym
    ;
    ; Parametry:
    ; R18 - dana do wysłania
    ;**************************************
    LcdWriteByte:

       sbi      PortLcd, LCD_EN         ;
       cbi      PortLCD, LCD_DB7      ; wyzerowanie linii danych
       cbi      PortLCD, LCD_DB6      ;
       cbi      PortLcd, LCD_DB5      ;
       cbi      PortLcd, LCD_DB4      ;
       
       sbrc   R18, 7               ; transmisja starszego półbajtu
       sbi      PortLcd, LCD_DB7
       sbrc   R18, 6
       sbi      PortLcd, LCD_DB6
       sbrc   R18, 5
       sbi      PortLcd, LCD_DB5
       sbrc   R18, 4
       sbi      PortLcd, LCD_DB4
       nop
          
       cbi      PortLcd, LCD_EN         ; EN = 0, potwierdzenie danych na liniach DB4...DB7 opadającym zboczem
       nop
                   
       sbi      PortLcd, LCD_EN         ;
       cbi      PortLCD, LCD_DB4      ; wyzerowanie linii danych
       cbi      PortLCD, LCD_DB5      ;
       cbi      PortLcd, LCD_DB6      ;
       cbi      PortLcd, LCD_DB7      ;

       sbrc   R18, 3
       sbi      PortLcd, LCD_DB7      ; tranmisja młodszego półbajtu
       sbrc   R18, 2
       sbi      PortLcd, LCD_DB6
       sbrc   R18, 1
       sbi      PortLcd, LCD_DB5
       sbrc   R18, 0
       sbi      PortLcd, LCD_DB4
       nop
       nop
       nop
       nop
       nop

       cbi      PortLcd, LCD_EN         ; EN = 0, potwierdzenie danych na liniach DB4...DB7 opadającym zboczem

       ldi      R16, 12               
       rcall   wait_us               ; czekaj 120 us

       ret

    ;**************************************
    ; Procedura zapisu instrukcji do LCD
    ; w trybie 4-bitowym
    ;
    ; Parametry:
    ; R18 - instrukcja do zapisu
    ;--------------------------------------

    LcdWriteInstr:
       rcall   LcdBusy
       cbi      PortLcd, LCD_RS
       rcall   LcdWriteByte
       ret

    ;**************************************
    LcdWriteData:
       rcall   LcdBusy
       sbi      PortLcd, LCD_RS         ; LCD przyjmuje dane
       rcall   LcdWriteByte         ; zapisz bajt
       ret

    ;**************************************
    LcdBusy:
       
       cbi      PortLcd, LCD_RS         ; przy odczycie flagi Busy, RS musi być 0
       sbi      PortLcd, LCD_RW         ; LCD ustawiony na odczyt
       cbi      kPortLcd, LCD_DB7      ; koncówka portu jako wejście
       cbi      PortLcd, LCD_DB7      ; wyłaczenie rezystora podciągającego
       nop

    LcdBusy_0:   

       sbic   PinLcd, LCD_BUSY      ; jeśli LCD zajęty, czyli flaga BUSY = 1
       rjmp   LcdBusy_0            ; to czekaj, aż będzie wolny, czyli BUSY = 0

       sbi      kPortLcd, LCD_DB7      ; koncówka portu jako wyjście
       cbi      PortLcd, LCD_RW         ; LCD ustawiony na zapis
       
       ret


    ;**************************************
    ; Procedura czyszcząca ekran
    ;**************************************

    LcdClr:
       ldi      R18, 0b00000001
       rcall   LcdWriteInstr
       ldi      R16, 5
       ldi      R17, 1
       rcall   wait_ms               ; czekaj 5 ms
       ret
  • Pomocny post
    Poziom 39  
    Jarus napisał:
    Mam problem, który właśnie zaczyna mi spędzać sen z powiek.
    Założenie było proste wysyłać dane do wyświetlacza, gdy flaga BUSY = 0.
    Niestety nie wiem gdzie robię błąd, ale gdy próbuję coś wyświetlić na LCD, badając stan flagi BUSY, to wyświetlacz działa nieprawidłowo. Albo nic nie wyświetli, albo jakieś dziwne rzeczy.

    Sprawa jest niezwykle prosta , jak się wgryziesz w dokumentację sterownika.
    Ale ... do rzeczy ;)
    Aby cokolwiek odczytać z wyświetlacza , należy:
    a)piny proca , podłączone do linii danych LCD , ustawić na wejście
    b)wyłączyć na tych pinach pull-up'y
    c)linię R/W ustawić na odczyt
    d)z linią EN postępować tak , jak przy zapisie

    To tyle :D

    Piotrek
  • Poziom 10  
    Dzięki, dzięki pomogło, ale musiałem ze 20 razy poprawiać program, żeby zadziałało, bo taki już jestem nieprzytomny :)

    Rzecz leżała w tym, że nie używałem sygnału EN. W opisach, które znalazłem prawie nic nie było wspomniane o tym. Jednakże cały czas z jakiegoś powodu chodziło mi po głowie, że tam trzeba z sygnałem EN popracować.

    Jutro podam tu poprawiony kod, może się komuś przyda.

    Jeszcze raz dzięki, teraz mogę iść spokojnie kolację sobie zrobić, choć już trochę późno :)
  • Poziom 10  
    Faktycznie miałem podać kod, ale go nie podałem, bo trochę czasu nie miałem. Nie jestem pewien, czy prawidłowo zrobiłem ten odczyt, ale mi działa.
    Wytłumaczenie wcześniej już podał zumek, ale ja to trochę rozwinę.
    Jeśli dobrze doczytałem w instrukcji HD44780, to z odczytem danych należy postępować podobnie jak z zapisem danych. Analogie trzeba stosować w trybie 4-bitowym i 8-bitowym.
    Pamiętać trzeba, że w czasie odczytu nie tylko możemy odczytać status flagi BUSY, ale i chyba np. adres kursora na ekranie, czyli kolejne końcówki wyświetlacza.
    Tak więc jeśli LCD pracuje w trybie 8 bitowym i chcemy odczytać flagę BUSY lub kolejne końcówki linii, to mniej więcej wygląda to tak:
    1. zerujemy RS
    2. ustawiamy E
    3. odczytujemy stan linii DB7-DB0 lub tylko BUSY
    4. zerujemy E

    W trybie 4-bitowym wygląda to chyba tak:
    1. zerujemy RS
    2. ustawiamy E
    3. odczytujemy stan linii DB7-DB4 lub tylko BUSY
    4. zerujemy E
    5. ustawiamy E
    6. odczytujemy linie DB3-DB0. Jeśli zależy nam na odczycie tylko flagi Busy to nie musimy nic tu robić, ewentualnie odczekać chwilę.
    7. zerujemy E

    Jeśli chcemy odczytywać tylko flagę Busy to być może w trybie 4-bitowym można zastosować schemat z 8-bitowego. Nie wiem nie próbowałem.

    Na 32 i 33 stronie dokumentacji sterownika Hitachi HD44780 są wykresy przedstawiające kiedy należy odczytywać flagę busy. Trochę to skomplikowanie wygląda, ale można się coś doczytać. Dokumentację można pobrać gdzieś z elektrody za kilka punktów.

    Jeśli coś źle napisałem, to niech mnie ktoś poprawi.
    (zerowanie = 0, ustawianie = 1)

    Przyznam jeszcze, że czasami LCD potrafi mi nie wyświetlać jakiejś literki, czy linii. Wydaje mi się jednak, że to ze względu na długi kabel połączeniowy (50 cm kabel do dysku twardego) oraz ze względu na to, że układ zamontowany jest na uniwersalnej płytce stykowej, stąd różne zakłócenia.

    A oto poprawiony kod:


    Code:

    LcdBusy:

       cbi      kPortLCD, LCD_DB7      ; końcówka portu jako wejście
       cbi      PortLCD, LCD_DB7      ; wyłączenie rezystora podciągającego

       cbi      PortLcd, LCD_RS         ; przy odczycie flagi Busy, RS musi być 0
       sbi      PortLcd, LCD_RW         ; LCD ustawiony na odczyt

       nop

    LcdBusy_0:                     ; dla trybu 4-bitowego
       sbi      PortLcd, LCD_EN         ; ustaw sygnał E
       nop
       nop
       sbis   PinLcd, LCD_BUSY      ; jeśli LCD zajęty, czyli flaga BUSY = 1
       rjmp   LcdBusy_1

       cbi      PortLcd, LCD_EN         ; wyzeruj sygnał E
       
       sbi      PortLcd, LCD_EN         ; jako, że interfejs 4-bitowy, to
       nop
       nop
       cbi      PortLcd, LCD_EN   
       rjmp   LcdBusy_0
    LcdBusy_1:
       cbi      PortLcd, LCD_EN   
       sbi      kPortLcd, LCD_DB7      ; koncówka portu jako wyjście
       cbi      PortLcd, LCD_RW         ; LCD ustawiony na zapis


       ret

    Dodano:
    Jak wspomniałem w pierwszym poście, to w programie zastosowane były dodatkowe pętle opóźniające. Teraz gdy działa mi już odczyt flagi BUSY, to praktycznie wszędzie można je usunąć, poza procedurą Inicjalizacyjną wyświetlacza.