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

[Atmega16][asm]Graficzny wyświetlacz LCD.

06 Lis 2010 22:30 4055 27
  • Poziom 34  
    Usiłuję nawiązać jakąś komunikację z wyświetlaczem graficznym LGM2412. Ma on rozdzielczość 240x128 pikseli. Jednak ze strony wyświetlacza nie ma odzewu. Poniżej kod:
    Code:
    .nolist
    
    .include "m16def.inc"
    .list
    .cseg

    ;sterowanie LCD
    .EQU WR   = 7
    .EQU RD   = 6
    .EQU CE   = 5
    .EQU C_D  = 4
    .EQU RST  = 3
    .EQU FS   = 2
    .EQU STER_LCD     = PORTA
    .EQU STER_LCD_DDR = DDRA

    ;dane LCD
    .EQU DANE_LCD     = PORTB
    .EQU DANE_LCD_DDR = DDRB
    .EQU DANE_LCD_PIN = PINB

    .org 0 rjmp RESET
       reset_LCD:
          cbi STER_LCD,RST
          ldi R17,254
          delay:
             inc R17
          brne delay
          sbi STER_LCD,RST
       ret


       zajety_tryb_zwykly:
          ;szyna danych LCD - jako wejście
          clr R17
          out DANE_LCD_DDR, R17 ;DDRB
          ser R17
          out DANE_LCD, R17 ;PORTB

          sbi STER_LCD,WR
          sbi STER_LCD,C_D
          cbi STER_LCD,RD
          nop
          nop
          cbi STER_LCD,CE

          ldi R16,0x03
          oczekiwanie:
             in R17,DANE_LCD_PIN
             andi R17,0x03
             cpse R17,R16
          rjmp oczekiwanie
          sbi STER_LCD,CE
       ret

       zajety_tryb_auto:
          ;szyna danych LCD - jako wejście
          clr R17
          out DANE_LCD_DDR, R17 ;DDRB
          ser R17
          out DANE_LCD, R17 ;PORTB

          sbi STER_LCD,WR
          sbi STER_LCD,C_D
          cbi STER_LCD,RD
          nop
          nop
          cbi STER_LCD,CE

          ldi R16,0x0C
          oczekiwanie_:
             in R17,DANE_LCD_PIN
             andi R17,0x0C
             cpse R17,R16
          rjmp oczekiwanie_
          sbi STER_LCD,CE
       ret

       wyslij_polecenie:
             ;w R17 wysyłane polecenie
             sbi STER_LCD,RD
             cbi STER_LCD,WR
             sbi STER_LCD,C_D

             ;szyna danych LCD - jako wyjście
             ser R16
             out DANE_LCD_DDR,R16
             out DANE_LCD,R17

             nop
             nop
             cbi STER_LCD,CE
             nop
             nop
             sbi STER_LCD,CE
       ret

       wyslij_dane:
             ;w R17 wysyłane dane
             sbi STER_LCD,RD
             cbi STER_LCD,WR
             cbi STER_LCD,C_D

             ;szyna danych LCD - jako wyjście
             ser R16
             out DANE_LCD_DDR,R16
             out DANE_LCD,R17

             nop
             nop
             cbi STER_LCD,CE
             nop
             nop
             sbi STER_LCD,CE
       ret

    RESET:

    ldi R17, high(RAMEND) ;inicjalizacja wskaźnika stosu
    ldi R16, low(RAMEND)
    out SPH, R17
    out SPL, R16

    ;ldi R20,0xFF
    ;out DDRA,R20
    ;out PORTA,R20 ;dioda zgaszona i port ustawiony jako wyjście

    ldi R17, 0x00
    out DANE_LCD_DDR, R17 ;DDRB

    ldi R17, 0xFF
    out DANE_LCD, R17 ;PORTB

    ;konfiguracja linii sterujących LCD
    clr R17
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)|(1<<FS)
    out STER_LCD_DDR,R17
    out STER_LCD,R17


    rcall reset_LCD

    rcall zajety_tryb_zwykly
    ldi R17,0x93 ;cursor on, blink on
    rcall wyslij_polecenie

    rcall zajety_tryb_zwykly
    ldi R17,0x83 ;AND mode
    rcall wyslij_polecenie

    rcall zajety_tryb_zwykly
    ldi R17,0xA2 ;3-line cursor
    rcall wyslij_polecenie


    petla_glowna:
    rjmp petla_glowna

    Pracuję na wewnętrznym taktowaniu 4MHz. Datasheet od tego wyświetlacza jest tu. Sterownik na module LCD to T6963C. Teoretycznie przedstawiony program powinien zresetować LCD i wyświetlić migający kursor o wybranym rozmiarze.

    Osoba, która udzieli pomocnej odpowiedzi otrzyma 100 punktów.
  • Pomocny post
    Poziom 28  
    Proponuję lekturę Writing Software for T6963C based Graphic LCDs.

    Zgodnie z tym dokumentem napisałbym np. procedurę odczytu statusu mniej więcej tak:
    Code:

    status_check:
          ;szyna danych LCD - jako wejście
          clr R17
          out DANE_LCD_DDR, R17 ;DDRB

          sbi STER_LCD, C_D   ; C/D = 1
          sbi STER_LCD, WR    ; WR = 1
          cbi STER_LCD, RD    ; RD = 0
          ldi r16, 0x03       ; STA0 = 1 , STA1 = 1

    status_loop1:
          cbi STER_LCD, CE
          nop                  ; opóźnienie na ustawienie danych przez LCD
          in R17,DANE_LCD_PIN
          andi R17, 0x03
          sbi STER_LCD, CE
          cpse R17, R16       ; sprawdzenie czy STA0 = 1 i STA1 = 1
          rjmp status_loop1   ; jeżeli nie, ponów pętlę
          sbi STER_LCD, RD    ; jeżeli tak, zakończ działanie procedury
          ret



    Poza tym poczytaj dokładnie rozdział 5 - "Initialising the display", bo wygląda na to, że masz nieprawidłową/niepełną inicjalizację wyświetlacza. Brakuje np. ustawienia takich parametrów jak TEXT HOME ADDRESS, TEXT AREA SET czy ADDRESS POINTER.

    Tutaj np. używasz DISPLAY MODE:
    Code:

    ldi R17,0x93 ;cursor on, blink on

    ale bit 2, który jest odpowiedzialny za włączenie wyświetlacza tekstowego, masz ustawiony na 0.

    Aby kursor był widoczny, musisz też ustawić jego pozycję za pomocą CURSOR POINTER SET.

    Zwróć uwagę, że niektóre komendy wymagają wysłania dwóch lub trzech bajtów danych. Np. CURSOR POINTER SET wymaga wysłania po kolei:
    #1 bajt: współrzędna X
    #2 bajt: współrzędna Y
    #3 bajt: komenda 0x21
    Oczywiście przed wysłaniem każdego bajtu należy sprawdzać status.

    Życzę powodzenia.
  • Poziom 34  
    Aktualnie mam taki kod:
    Code:
    ;PORTB szyna danych LCD
    

    .nolist
    .include "m16def.inc"
    .list
    .cseg

    ;sterowanie LCD
    .EQU WR   = 7
    .EQU RD   = 6
    .EQU CE   = 5
    .EQU C_D  = 4
    .EQU RST  = 3
    .EQU FS   = 2
    .EQU STER_LCD     = PORTA
    .EQU STER_LCD_DDR = DDRA

    ;dane LCD
    .EQU DANE_LCD     = PORTB
    .EQU DANE_LCD_DDR = DDRB
    .EQU DANE_LCD_PIN = PINB

    ;instrukcje LCD
    .EQU TEXT_ATTRIBUTE_MODE = 0x8C
    .EQU SET_GRAPHIC_HOME_ADRESS = 0x42
    .EQU SET_GRAPHIC_AREA = 0x43
    .EQU SET_TEXT_HOME_ADRESS = 0x40
    .EQU SET_TEXT_AREA = 0x41
    ;.EQU MODE_SET = 0x82 ;internal CGROM, AND mode
    .EQU MODE_SET = 0x80 ;internal CGROM, OR mode
    .EQU DISPLAY_MODE = 0x9F
    .EQU SET_CURSOR_POINTER = 0x21
    .EQU SET_ADRESS_POINTER = 0x24
    .EQU DATA_WRITE_INC_ADP = 0xC0

    .org 0 rjmp RESET
       reset_LCD:
          cbi STER_LCD,RST
          ldi R17,200
          delay:
             inc R17
          brne delay
          sbi STER_LCD,RST
       ret


       zajety_tryb_zwykly:
             ;szyna danych LCD - jako wejście
             clr R17
             out DANE_LCD_DDR, R17 ;DDRB

             sbi STER_LCD, C_D   ; C/D = 1
             sbi STER_LCD, WR    ; WR = 1
             cbi STER_LCD, RD    ; RD = 0
             ldi r16, 0x03       ; STA0 = 1 , STA1 = 1

            status_loop1:
                cbi STER_LCD, CE
                nop                  ; opóźnienie na ustawienie danych przez LCD
                in R17,DANE_LCD_PIN
                andi R17, 0x03
               sbi STER_LCD, CE
                cpse R17, R16       ; sprawdzenie czy STA0 = 1 i STA1 = 1
            rjmp status_loop1   ; jeżeli nie, ponów pętlę
             sbi STER_LCD, RD    ; jeżeli tak, zakończ działanie procedury
        ret



       zajety_tryb_auto:
          ;szyna danych LCD - jako wejście
          clr R17
          out DANE_LCD_DDR, R17 ;DDRB
          ser R17
          out DANE_LCD, R17 ;PORTB

          sbi STER_LCD,WR
          sbi STER_LCD,C_D
          cbi STER_LCD,RD
          nop
          nop
          cbi STER_LCD,CE

          ldi R16,0x0C
          oczekiwanie_:
             in R17,DANE_LCD_PIN
             andi R17,0x0C
             cpse R17,R16
          rjmp oczekiwanie_
          sbi STER_LCD,CE
       ret

       wyslij_instrukcje:
             ;w R17 wysyłane polecenie
             sbi STER_LCD,RD
             cbi STER_LCD,WR
             sbi STER_LCD,C_D

             ;szyna danych LCD - jako wyjście
             ser R16
             out DANE_LCD_DDR,R16
             out DANE_LCD,R17

             nop
             nop
             cbi STER_LCD,CE
             nop
             nop
             sbi STER_LCD,CE
       ret

       wyslij_dane:
             ;w R17 wysyłane dane
             sbi STER_LCD,RD
             cbi STER_LCD,WR
             cbi STER_LCD,C_D

             ;szyna danych LCD - jako wyjście
             ser R16
             out DANE_LCD_DDR,R16
             out DANE_LCD,R17

             nop
             nop
             cbi STER_LCD,CE
             nop
             nop
             sbi STER_LCD,CE
       ret

    RESET:

    ldi R17, high(RAMEND) ;inicjalizacja wskaźnika stosu
    ldi R16, low(RAMEND)
    out SPH, R17
    out SPL, R16

    ldi R17, 0x00
    out DANE_LCD_DDR, R17 ;DDRB

    ldi R17, 0xFF
    out DANE_LCD, R17 ;PORTB

    ;konfiguracja linii sterujących LCD
    clr R17
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)|(1<<FS)
    out STER_LCD_DDR,R17
    out STER_LCD,R17


    rcall reset_LCD

    ;rcall zajety_tryb_zwykly
    ;ldi R17,TEXT_ATTRIBUTE_MODE
    ;rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,0xFF ;młodszy bajt adresu
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x3F ;starszy bajt adresu
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_GRAPHIC_HOME_ADRESS
    rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,0x20 ;32 bajtów na pole grafiki
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_GRAPHIC_AREA
    rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,0x00
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_TEXT_HOME_ADRESS
    rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,0x20 ;32 bajtów na pole tekstu
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_TEXT_AREA
    rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,MODE_SET
    rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,DISPLAY_MODE
    rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,0x01 ;X
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00 ;Y
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_CURSOR_POINTER
    rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,0x00 ;młodszy
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00 ;starszy
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_ADRESS_POINTER
    rcall wyslij_instrukcje

    rcall zajety_tryb_zwykly
    ldi R17,0x21 ;znak 'A'
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje


    petla_glowna:
    rjmp petla_glowna

    Na wyświetlaczu wyświetlają się same śmieci. Kursor miga na prawidłowej pozycji (ustawionej pozycji). Jednak litera 'A' nie pojawia się w wyznaczonym miejscu. Zamiast niej jest "krzak". Ponadto jak wyczyścić pamięć ? Wysłanie zerowego bajtu nie powoduje wyczyszczenia wybranego miejsca. Wskazany przez kolegę PDF okazał się być bardzo pomocny.
  • Poziom 28  
    Nie mam teraz czasu, żeby analizować dokładnie kod. Na pierwszy rzut oka nie widzę błędów.
    Spróbuj ustawić GRAPHIC HOME ADRESS na 0x0200, bo Ty masz dużo większy i być może to powoduje problemy.

    Nie wiem, czy znasz tę stronę. Napisane w C, nie w assemblerze, ale wiele może wyjaśnić, np. w pliku T6963C.h jest przedstawione, jak obliczać takie parametry jak właśnie GRAPHIC HOME ADDRESS czy też TEXT AREA lub GRAPHIC AREA.
  • Poziom 34  
    Przeanalizowałem kod kolegi radzio z podanej strony. Szczególnie plik nagłówkowy T6963C.h. Jednak nie do końca to rozumiem. Poniżej zaznaczyłem moją interpretację poszczególnych stałych.

    Code:

    //-------------------------------------------------------------------------------------------------
    // Graphic LCD with Toshiba T6963 controller
    // Copyright (c) Radosław Kwiecień, 2007r
    // http://en.radzio.dxp.pl/t6963/
    // Compiler : avr-gcc
    //-------------------------------------------------------------------------------------------------

    // display properties
    #define GLCD_NUMBER_OF_LINES            128 //prawdopodobnie ilość linii w pikselach/ilość pikseli w pionie
    #define GLCD_PIXELS_PER_LINE            240
    #define GLCD_FONT_WIDTH                  8 //zależne od linii FS -> dla FS=1 FONT_WIDTH=8
    //
    #define GLCD_GRAPHIC_AREA               (GLCD_PIXELS_PER_LINE / GLCD_FONT_WIDTH) //ilość znaków na linię 240/8=30
    #define GLCD_TEXT_AREA                  (GLCD_PIXELS_PER_LINE / GLCD_FONT_WIDTH) //ilość znaków na linię 240/8=30
    #define GLCD_GRAPHIC_SIZE               (GLCD_GRAPHIC_AREA * GLCD_NUMBER_OF_LINES) //??? 30*128=3840 znaki*piksele ???
    #define GLCD_TEXT_SIZE                  (GLCD_TEXT_AREA * (GLCD_NUMBER_OF_LINES/8))//jeżeli font jest 8x8, to jest to
                                                                                           //ilość znaków w całym LCD 30*128/8=30*16=480


    #define GLCD_TEXT_HOME                  0 //pewnie tekst ma się zaczynać od adresu 0x0000 w pamięci ???
    #define GLCD_GRAPHIC_HOME               (GLCD_TEXT_HOME + GLCD_TEXT_SIZE) //czyli grafika ma się znajdować zaraz za tekstem ???
    #define GLCD_OFFSET_REGISTER            2 //???
    #define GLCD_EXTERNAL_CG_HOME            (GLCD_OFFSET_REGISTER << 11) //jak rozumieć "offset register" 2 << 11=4096

    Dziękuję za zaangażowanie. Ustawienie GRAPHIC_HOME_ADRESS=0x2000 nic nie zmienia.
    [edit]
    Ustawiłem wszystkie parametry wg kodu kolegi radzio. Jednak w zasadzie dalej to samo.
  • Pomocny post
    Poziom 28  
    Nie wiem, czy tylko tu się pomyliłeś, czy w kodzie też. Napisałeś, że ustawiłeś GRAPHIC_HOME_ADRESS=0x2000, a ja miałem na myśli raczej 0x0200. Jeśli LCD ma przykładowo 8K RAM, to wartość 0x2000 jest już poza zakresem. Trudno przewidzieć, co w takim przypadku będzie wyświetlane.

    Code:

    #define GLCD_GRAPHIC_SIZE               (GLCD_GRAPHIC_AREA * GLCD_NUMBER_OF_LINES) //??? 30*128=3840 znaki*piksele ???

    No tak 30 bajtów 8bitowych (dla ustawienia FS=1) * 128 wierszy (linii) daje:
    30*8*128=240*128=30720 bitów (30*128=3840 bajtów)
    czyli tyle bitów ile pikseli. Inaczej mówiąc GLCD_GRAPHIC_SIZE to rozmiar (w bajtach) pamięci graficznej.

    Code:

    #define GLCD_OFFSET_REGISTER            2 //???
    #define GLCD_EXTERNAL_CG_HOME            (GLCD_OFFSET_REGISTER << 11) //jak rozumieć "offset register" 2 << 11=4096

    Masz to opisane na ostatniej stronie dokumentu, do którego link umieściłem w pierwszym swoim poście. GLCD_OFFSET_REGISTER to po prostu najstarsze 5 bitów adresu bazowego do przechowywania znaków "user defined". Stąd też to przesunięcie o 11 bitów w lewo (16-5). Można zdefiniować maks. 256 znaków. W trybie "Internal CG" dostępnych dla użytkownika jest "górne" 128, czyli znaki o kodach 0x80 do 0xFF. Znaki od 0x00 do 0x7F wyświetlane są wtedy z wewnętrznej pamięci ROM. W trybie "External CG" dostępnych jest wszystkie 256 znaków. Każdy znak to 8 bajtów, dlatego obszar pamięci potrzebny na zapamiętanie tych znaków zawiera się w granicach:
    od (GLCD_OFFSET_REGISTER << 11)
    do (GLCD_OFFSET_REGISTER << 11) + (256*8 - 1) = (GLCD_OFFSET_REGISTER << 11) + 0x07FF

    Jeśli nie będziesz definiował|używał własnych znaków, możesz nie ustawiać offsetu. Ewentualnie dla pewności możesz ustawić go tak, by obszar danych znaków definiowalnych nie pokrywał się z innymi danymi.

    Co do kodu, na razie nie dopatrzyłem się błędów (poza tym GRAPHIC_HOME_ADRESS). Proponuję spróbować nie włączać wyświetlania grafiki (DISPLAY_MODE=0x97). Jak nie pomoże, to jeszcze raz sprawdzić, czy na pewno wszystkie parametry są dobrze ustawione.
  • Poziom 34  
    Pomyliłem się z tym GRAPHIC_HOME_ADRESS (również w kodzie). Na module LCD znajduje się układ 62256, czyli mam pamięć RAM 32KB. Czy cała szyna adresowa pamięci jest dołączona do sterownika, tego nie wiem. Pokombinuję jeszcze z tym LCD jak wrócę w środę do domu. Spróbuję też pewnie odpalić kod w C, choć i tak muszę mieć swoje procedury obsługi.
  • Użytkownik usunął konto  
  • Poziom 34  
    Ustawiłem GRAPHIC_HOME_ADRESS na 0x0200 i jest pewna różnica. Otóż w wybranych pozycjach na wyświetlaczu pojawia się to co powinno. Jednak w polu każdego znaku znajdują się piksele, które nie powinny się palić.

    Wyłączyłem też prowizorycznie tryb graficzny. Wówczas wszystko wyświetla się tak jak powinno. Wysłanie bajtu 0x00 powoduje "wyczyszczenie" danego pola znaku. W związku z tym coś nie tak jest z ustawieniami grafiki...
  • Poziom 28  
    Spróbuj może jeszcze wyczyścić pamięć grafiki, czyli jeżeli GRAPHIC_HOME_ADRESS masz równy 0x0200, a GRAPHIC_AREA=3840, to wprowadź 0x00 do komórek pamięci od 0x0200 do 0x10FF.
    Zresztą pewnie nie zaszkodziłoby wyczyszczenie całej pamięci, albo przynajmniej używanego obszaru.
  • Poziom 28  
    Ten dokument też może okazać się przydatny.

    Proponowałbym też:

    #1 nie ustawiać pinu /RESET wstępnie w stan wysoki, czyli zamiast:
    Code:

    RESET:
    .....

    ;konfiguracja linii sterujących LCD
    clr R17
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)|(1<<FS)
    out STER_LCD_DDR,R17
    out STER_LCD,R17


    rcall reset_LCD

    zrobiłbym np. tak:
    Code:

    RESET:
    .....

    ;konfiguracja linii sterujących LCD
    clr R17
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)|(1<<FS)
    out STER_LCD_DDR,R17
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<FS)
    out STER_LCD,R17


    rcall reset_LCD


    #2 wydłużyć czas resetu, bo zgodnie z dokumentacją powinien mieć min. 1ms (patrz tabelka na stronie 25 podanego wyżej dokumentu, rozdział "Recommended Initialization"), a u Ciebie jest 0,04ms:
    Code:

       reset_LCD:
          cbi STER_LCD,RST
          ldi R17,200
          delay:
          inc R17    ; pętla wykona się 55 razy !!!
          brne delay ; a trwa 3 takty
                     ; więc całkowite opóźnienie wyniesie 55*3=165 taktów
                     ; +2 takty na wykonanie 'inc R17' i 'brne delay' w ostatniej (56-tej) pętli, czyli 167 taktów
                     ; +1 takt na wykonanie 'ldi R17,200', czyli 168 taktów
                     ; tak więc dla zegara 4MHz będzie to ok. 0,04ms
          sbi STER_LCD,RST
       ret
  • Poziom 34  
    Zwiększyłem czas resetu do ok. 2ms. Jednak w oryginalnym pdf Toshiby podano, że reset ma trwać przynajmniej 15 okresów zegara dla T6963C. Na moim module LCD występuje rezonator 6MHz. Wyczyściłem też całą pamięć RAM. Jest o wiele lepiej, chociaż nie ma niepotrzebnych pikseli w polach wyświetlanych znaków. Jednak teraz jeżeli mam załączony tryb tekstowy i graficzny, to wysłanie bajtu 0xFF pod GRAPHIC_HOME_ADRESS=0x0200 powinno spowodować zapalenie wszystkich pikseli tego bajtu pamięci. Tak, się dzieje, ale zapalają się piksele na samym początku ekranu, gdzie teoretycznie jest pole tekstu. Poniżej aktualny kod:
    Code:
    .nolist 
    
    .include "m16def.inc"
    .list
    .cseg

    ;parametry LCD
    .EQU MAX_RAM_LCD = 0x7FFF ;256Kb=32KB
    .EQU MAX_X = 240
    .EQU MAX_Y = 128
    .EQU FONT_WIDTH = 8 ;8x8 font

    .EQU TEXT_HOME_ADRESS    = 0x0000
    .EQU TEXT_AREA           = MAX_X / FONT_WIDTH
    .EQU GRAPHIC_HOME_ADRESS = 0x0200
    .EQU GRAPHIC_AREA        = MAX_X / FONT_WIDTH

    ;sterowanie LCD
    .EQU WR   = 7
    .EQU RD   = 6
    .EQU CE   = 5
    .EQU C_D  = 4
    .EQU RST  = 3
    .EQU STER_LCD     = PORTA
    .EQU STER_LCD_DDR = DDRA

    ;dane LCD
    .EQU DANE_LCD     = PORTB
    .EQU DANE_LCD_DDR = DDRB
    .EQU DANE_LCD_PIN = PINB

    ;instrukcje LCD
    .EQU TEXT_ATTRIBUTE_MODE     = 0x8C
    .EQU SET_GRAPHIC_HOME_ADRESS = 0x42
    .EQU SET_GRAPHIC_AREA        = 0x43
    .EQU SET_TEXT_HOME_ADRESS    = 0x40
    .EQU SET_TEXT_AREA           = 0x41

    ;Mode Set
    .EQU MD = 0
    ;MD=0 -> OR  MODE
    ;MD=1 -> XOR MODE
    ;MD=2 -> AND MODE
    ;MD=4 -> TEXT ATTRIBUTE MODE
    ;CG=0 -> Internal CG ROM; 1 -> RAM CG
    .EQU CG = 0
    .EQU MODE_SET = MD + 8*CG + 0x80

    ;Display Mode
    .EQU GRAPH  = 1
    .EQU TEXT   = 1
    .EQU CURSOR = 1
    .EQU BLINK  = 1
    .EQU DISPLAY_MODE = BLINK + 2*CURSOR + 4*TEXT + 8*GRAPH + 0x90

    .EQU SET_CURSOR_POINTER  = 0x21
    .EQU SET_ADRESS_POINTER  = 0x24
    .EQU DATA_WRITE_INC_ADP  = 0xC0
    .EQU DATA_WRITE_NONV_ADP = 0xC4

    ;Cursor Pattern Select
    .EQU LINE = 7
    ;LINE = 0 -> 1-line cursor
    ;LINE = 1 -> 2-line cursor
    ;LINE = 2 -> 3-line cursor
    ;LINE = 3 -> 4-line cursor
    ;LINE = 4 -> 5-line cursor
    ;LINE = 5 -> 6-line cursor
    ;LINE = 6 -> 7-line cursor
    ;LINE = 7 -> 8-line cursor
    .EQU CURSOR_PATTERN_SELECT = LINE + 0xA0

    .org 0 rjmp RESET
       reset_LCD:
          cbi STER_LCD,RST

    ;      ldi R17,200 ;1
          ldi R17,155 ;1
          delay:
            ldi R16,230 ;1
          delay2:
             inc R16 ;1
          brne delay2 ;2/1, 1+25*3+1+1=78

            inc R17 ;1 cykl
          brne delay ;2 cykle / 1 gdy nie ma skoku
                  ;pętla wykona się 155 razy, czyli 1+100*81 cykli
                ;w 256 skoku mamy 1+100*81+1+1=8103*(4MHz)^-1=2,02575ms
          sbi STER_LCD,RST
       ret

       wyczysc_RAM_LCD:
          ldi R18,0x00 ;młodszy
          rcall wyslij_dane
          ldi R18,0x00 ;starszy
          rcall wyslij_dane
          ldi R18,SET_ADRESS_POINTER
          rcall wyslij_instrukcje

          clr R25
          clr R24

          wysylaj:
             ldi R18, 0x00
             rcall wyslij_dane
             ldi R18, DATA_WRITE_INC_ADP
             rcall wyslij_instrukcje

             cpi R24, MAX_RAM_LCD & 0xFF
             brne przeskocz
                cpi R25, (MAX_RAM_LCD & 0xFF00) >> 8
                brne przeskocz
                   ret
             przeskocz:
             adiw R24, 1
          rjmp wysylaj
       ret

       zajety:
             ;szyna danych LCD - jako wejście
             clr R17
             out DANE_LCD_DDR, R17 ;DDRB

             sbi STER_LCD, C_D   ; C/D = 1
             sbi STER_LCD, WR    ; WR = 1
             cbi STER_LCD, RD    ; RD = 0
             ldi r16, 0x03       ; STA0 = 1 , STA1 = 1

            status_loop1:
                cbi STER_LCD, CE
                nop                  ; opóźnienie na ustawienie danych przez LCD
                in R17,DANE_LCD_PIN
                andi R17, 0x03
                sbi STER_LCD, CE
                cpse R17, R16       ; sprawdzenie czy STA0 = 1 i STA1 = 1
            rjmp status_loop1   ; jeżeli nie, ponów pętlę
             sbi STER_LCD, RD    ; jeżeli tak, zakończ działanie procedury
        ret

       wyslij_instrukcje:
             ;w R18 wysyłane polecenie
           rcall zajety
             sbi STER_LCD,RD
             cbi STER_LCD,WR
             sbi STER_LCD,C_D

             ;szyna danych LCD - jako wyjście
             ser R16
             out DANE_LCD_DDR,R16
             out DANE_LCD,R18

             nop
             nop
             cbi STER_LCD,CE
             nop
             nop
             sbi STER_LCD,CE
       ret

       wyslij_dane:
             ;w R18 wysyłane dane
           rcall zajety
             sbi STER_LCD,RD
             cbi STER_LCD,WR
             cbi STER_LCD,C_D

             ;szyna danych LCD - jako wyjście
             ser R16
             out DANE_LCD_DDR,R16
             out DANE_LCD,R18

             nop
             nop
             cbi STER_LCD,CE
             nop
             nop
             sbi STER_LCD,CE
       ret

       dzielenie:
             ;R17 dzielna
             ;R16 dzielnik
          ;w R17 wynik ; w R16 reszta
          tst R17
          brne zero
             clr R16
             ret
          zero:

          clr R18
          petla:
             inc R18
             mul R18,R16 ;sprawdzenie czy R18 jest wynikiem
             push R17
             sub R17,R0 ;obliczenie reszty
             cp R17,R16 ;jeżeli R17=<R16 to R18 jest wynikiem
             brsh koniec
                mov R16,R17
                mov R17,R18
                pop R18 ;kasowanie wierzchołka stosu, by dało się wrócić
                ret
             koniec:
             pop R17
          rjmp petla
       ret

       zapal_piksel:
             ;X=R18 ; Y=R19
          ldi R25,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8
          ldi R24,GRAPHIC_HOME_ADRESS & 0xFF

          mov R17,R18
          ldi R16,FONT_WIDTH
          rcall dzielenie
          push R16
          add R24,R17
          clr R18
          adc R25,R18

          ldi R18,GRAPHIC_AREA
          mul R18,R19

          add R24,R0
          adc R25,R1

          mov R18,R24
          rcall wyslij_dane
          mov R18,R25
          rcall wyslij_dane
          ldi R18,SET_ADRESS_POINTER
          rcall wyslij_instrukcje

          pop R16
          ldi R18,0xF8 ;zapalenie piksela
          or R18,R16
          rcall wyslij_instrukcje
       ret

       init_LCD:
             ;configuracja szyny danych LCD
          ldi R17, 0x00
          out DANE_LCD_DDR, R17 ;DDRB
          
          ldi R17, 0xFF
          out DANE_LCD, R17 ;PORTB
          
          ;konfiguracja linii sterujących LCD
          clr R17
          ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)
          out STER_LCD_DDR,R17
          ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)
          out STER_LCD,R17
          
          rcall reset_LCD
          rcall wyczysc_RAM_LCD
          
          ldi R18,GRAPHIC_HOME_ADRESS & 0xFF ;młodszy bajt adresu
          rcall wyslij_dane
          ldi R18,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8 ;starszy bajt adresu
          rcall wyslij_dane
          ldi R18,SET_GRAPHIC_HOME_ADRESS ;!!!
          rcall wyslij_instrukcje
          
          ldi R18,GRAPHIC_AREA
          rcall wyslij_dane
          ldi R18,0x00
          rcall wyslij_dane
          ldi R18,SET_GRAPHIC_AREA
          rcall wyslij_instrukcje
          
          ldi R18,TEXT_HOME_ADRESS & 0xFF
          rcall wyslij_dane
          ldi R18,(TEXT_HOME_ADRESS & 0xFF00) >> 8
          rcall wyslij_dane
          ldi R18,SET_TEXT_HOME_ADRESS
          rcall wyslij_instrukcje
          
          ldi R18,TEXT_AREA
          rcall wyslij_dane
          ldi R18,0x00
          rcall wyslij_dane
          ldi R18,SET_TEXT_AREA
          rcall wyslij_instrukcje
          
          ldi R18,MODE_SET
          rcall wyslij_instrukcje
          
          ldi R18,DISPLAY_MODE
          rcall wyslij_instrukcje
          
          ldi R18,0x04 ;X
          rcall wyslij_dane
          ldi R18,0x01 ;Y
          rcall wyslij_dane
          ldi R18,SET_CURSOR_POINTER
          rcall wyslij_instrukcje
          
          ldi R18,CURSOR_PATTERN_SELECT
          rcall wyslij_instrukcje
        ret
    RESET:

    ldi R17, high(RAMEND) ;inicjalizacja wskaźnika stosu
    ldi R16, low(RAMEND)
    out SPH, R17
    out SPL, R16

    rcall init_LCD

    ldi R18,0x29 ;młodszy
    rcall wyslij_dane
    ldi R18,0x00 ;starszy
    rcall wyslij_dane
    ldi R18,SET_ADRESS_POINTER
    rcall wyslij_instrukcje

    ldi R18,0x48 ;znak 'h'
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,0x22 ;znak 'B'
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,0x23 ;znak 'C'
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,0x21 ;znak 'A'
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,0x00 ;nic
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje



    ldi R18,0x00 ;młodszy
    rcall wyslij_dane
    ldi R18,0x02 ;starszy
    rcall wyslij_dane
    ldi R18,SET_ADRESS_POINTER
    rcall wyslij_instrukcje

    ldi R18,0xFF
    rcall wyslij_dane
    ldi R18,DATA_WRITE_NONV_ADP
    rcall wyslij_instrukcje


    petla_glowna:
    rjmp petla_glowna
  • Pomocny post
    Poziom 28  
    Cytat:

    Jednak teraz jeżeli mam załączony tryb tekstowy i graficzny, to wysłanie bajtu 0xFF pod GRAPHIC_HOME_ADRESS=0x0200 powinno spowodować zapalenie wszystkich pikseli tego bajtu pamięci. Tak, się dzieje, ale zapalają się piksele na samym początku ekranu, gdzie teoretycznie jest pole tekstu.

    Tak właśnie powinno być. Zarówno tryb graficzny jak i tekstowy mają do dyspozycji cały ekran. Wpisywanie danych pod adresy TEXT_HOME_ADRESS lub GRAPHIC_HOME_ADRESS powoduje wyświetlanie tych danych w lewym górnym rogu. Relacja między danymi tekstowymi i graficznymi jest określona poprzez MODE_SET:
    OR - dany piksel "zapala się", jeżeli w trybie tekstowym LUB w trybie graficznym jego wartość jest równa 1
    AND - dany piksel "zapala się", jeżeli w trybie tekstowym ORAZ w trybie graficznym jego wartość jest równa 1
    EXOR - dany piksel "zapala się", jeżeli w trybie tekstowym ma wartość 1 a w trybie geaficznym ma wartość 0, ORAZ, jeżeli w trybie tekstowym ma wartość 0 a a trybie geaficznym ma wartość 1; jeżeli w obydwu trybach piksel ma wartość 0 LUB w obydwu trybach ma wartość 1 piksel jest "zgaszony"

    Masz to przedstawione graficznie np. w dokumencie - podanym przez Ciebie w pierwszym poście - na stronie 20.
  • Pomocny post
    Użytkownik usunął konto  
  • Poziom 34  
    Myślę, że rozwiązałem już większość problemów z tym LCD. Mam już działającą funkcję zapal_piksel. Poniżej dość ostateczny kod (może ktoś skorzysta):
    Code:
    .nolist 
    
    .include "m16def.inc"
    .list
    .cseg

    ;parametry LCD
    .EQU MAX_RAM_LCD = 0x7FFF ;256Kb=32KB
    .EQU MAX_X = 240
    .EQU MAX_Y = 128
    .EQU FONT_WIDTH = 6 ;6x8 font

    .EQU TEXT_AREA           = MAX_X / FONT_WIDTH
    .EQU GRAPHIC_AREA        = MAX_X / FONT_WIDTH
    .EQU GRAPHIC_SIZE        = (GRAPHIC_AREA * MAX_Y)
    .EQU TEXT_SIZE           = (TEXT_AREA * (MAX_Y/8))

    .EQU TEXT_HOME_ADRESS    = 0x0000
    .EQU GRAPHIC_HOME_ADRESS = TEXT_HOME_ADRESS + TEXT_SIZE

    .EQU OFFSET_REGISTER     = 2
    .EQU EXTERNAL_CG_HOME    = OFFSET_REGISTER << 11

    ;sterowanie LCD
    .EQU WR   = 7
    .EQU RD   = 6
    .EQU CE   = 5
    .EQU C_D  = 4
    .EQU RST  = 3
    .EQU STER_LCD     = PORTA
    .EQU STER_LCD_DDR = DDRA

    ;dane LCD
    .EQU DANE_LCD     = PORTB
    .EQU DANE_LCD_DDR = DDRB
    .EQU DANE_LCD_PIN = PINB

    ;instrukcje LCD
    .EQU TEXT_ATTRIBUTE_MODE     = 0x8C
    .EQU SET_GRAPHIC_HOME_ADRESS = 0x42
    .EQU SET_GRAPHIC_AREA        = 0x43
    .EQU SET_TEXT_HOME_ADRESS    = 0x40
    .EQU SET_TEXT_AREA           = 0x41

    ;Mode Set
    .EQU MD = 0
    ;MD=0 -> OR  MODE
    ;MD=1 -> XOR MODE
    ;MD=2 -> AND MODE
    ;MD=4 -> TEXT ATTRIBUTE MODE
    ;CG=0 -> Internal CG ROM; 1 -> RAM CG
    .EQU CG = 0
    .EQU MODE_SET = MD + 8*CG + 0x80

    ;Display Mode
    .EQU GRAPH  = 1
    .EQU TEXT   = 1
    .EQU CURSOR = 1
    .EQU BLINK  = 1
    .EQU DISPLAY_MODE = BLINK + 2*CURSOR + 4*TEXT + 8*GRAPH + 0x90

    .EQU SET_CURSOR_POINTER  = 0x21
    .EQU SET_ADRESS_POINTER  = 0x24
    .EQU SET_OFFSET_REGISTER = 0x22
    .EQU DATA_WRITE_INC_ADP  = 0xC0
    .EQU DATA_WRITE_NONV_ADP = 0xC4

    ;Cursor Pattern Select
    .EQU LINE = 7
    ;LINE = 0 -> 1-line cursor
    ;LINE = 1 -> 2-line cursor
    ;LINE = 2 -> 3-line cursor
    ;LINE = 3 -> 4-line cursor
    ;LINE = 4 -> 5-line cursor
    ;LINE = 5 -> 6-line cursor
    ;LINE = 6 -> 7-line cursor
    ;LINE = 7 -> 8-line cursor
    .EQU CURSOR_PATTERN_SELECT = LINE + 0xA0

    .org 0 rjmp RESET
       reset_LCD:
          cbi STER_LCD,RST

    ;      ldi R17,200 ;1
          ldi R17,155 ;1
          delay:
            ldi R16,230 ;1
          delay2:
             inc R16 ;1
          brne delay2 ;2/1, 1+25*3+1+1=78

            inc R17 ;1 cykl
          brne delay ;2 cykle / 1 gdy nie ma skoku
                  ;pętla wykona się 155 razy, czyli 1+100*81 cykli
                ;w 256 skoku mamy 1+100*81+1+1=8103*(4MHz)^-1=2,02575ms
          sbi STER_LCD,RST
       ret

       wyczysc_RAM_LCD:
          ldi R18,0x00 ;młodszy
          rcall wyslij_dane
          ldi R18,0x00 ;starszy
          rcall wyslij_dane
          ldi R18,SET_ADRESS_POINTER
          rcall wyslij_instrukcje

          clr R25
          clr R24

          wysylaj:
             ldi R18, 0x00
             rcall wyslij_dane
             ldi R18, DATA_WRITE_INC_ADP
             rcall wyslij_instrukcje

             cpi R24, MAX_RAM_LCD & 0xFF
             brne przeskocz
                cpi R25, (MAX_RAM_LCD & 0xFF00) >> 8
                brne przeskocz
                   ret
             przeskocz:
             adiw R24, 1
          rjmp wysylaj
       ret

       zajety:
             ;szyna danych LCD - jako wejście
             clr R17
             out DANE_LCD_DDR, R17 ;DDRB

             sbi STER_LCD, C_D   ; C/D = 1
             sbi STER_LCD, WR    ; WR = 1
             cbi STER_LCD, RD    ; RD = 0
             ldi r16, 0x03       ; STA0 = 1 , STA1 = 1

            status_loop1:
                cbi STER_LCD, CE
                nop                  ; opóźnienie na ustawienie danych przez LCD
                in R17,DANE_LCD_PIN
                andi R17, 0x03
                sbi STER_LCD, CE
                cpse R17, R16       ; sprawdzenie czy STA0 = 1 i STA1 = 1
            rjmp status_loop1   ; jeżeli nie, ponów pętlę
             sbi STER_LCD, RD    ; jeżeli tak, zakończ działanie procedury
        ret

       wyslij_instrukcje:
             ;w R18 wysyłane polecenie
           rcall zajety
             sbi STER_LCD,RD
             cbi STER_LCD,WR
             sbi STER_LCD,C_D

             ;szyna danych LCD - jako wyjście
             ser R16
             out DANE_LCD_DDR,R16
             out DANE_LCD,R18

             nop
             nop
             cbi STER_LCD,CE
             nop
             nop
             sbi STER_LCD,CE
       ret

       wyslij_dane:
             ;w R18 wysyłane dane
           rcall zajety
             sbi STER_LCD,RD
             cbi STER_LCD,WR
             cbi STER_LCD,C_D

             ;szyna danych LCD - jako wyjście
             ser R16
             out DANE_LCD_DDR,R16
             out DANE_LCD,R18

             nop
             nop
             cbi STER_LCD,CE
             nop
             nop
             sbi STER_LCD,CE
       ret

       dzielenie:
             ;R17 dzielna
             ;R16 dzielnik
          ;w R17 wynik ; w R16 reszta
          cp R17,R16
          brsh mniejszy
             mov R16,R17
             clr R17
             ret
          mniejszy:

          tst R17
          brne zero
             clr R16
             ret
          zero:

          clr R18
          petla:
             inc R18
             mul R18,R16 ;sprawdzenie czy R18 jest wynikiem
             push R17
             sub R17,R0 ;obliczenie reszty
             cp R17,R16 ;jeżeli R17=<R16 to R18 jest wynikiem
             brsh koniec
                mov R16,R17
                mov R17,R18
                pop R18 ;kasowanie wierzchołka stosu, by dało się wrócić
                ret
             koniec:
             pop R17
          rjmp petla
       ret

       zapal_piksel:
             ;X=R18 ; Y=R19
          ldi R25,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8
          ldi R24,GRAPHIC_HOME_ADRESS & 0xFF

          mov R17,R18
          ldi R16,FONT_WIDTH
          rcall dzielenie
          push R16
          add R24,R17
          clr R18
          adc R25,R18

          ldi R18,GRAPHIC_AREA
          mul R18,R19

          add R24,R0
          adc R25,R1

          mov R18,R24
          rcall wyslij_dane
          mov R18,R25
          rcall wyslij_dane
          ldi R18,SET_ADRESS_POINTER
          rcall wyslij_instrukcje

          pop R16
          ldi R18,FONT_WIDTH-1
          sub R18,R16
          mov R16,R18

          ldi R18,0xF8 ;zapalenie piksela
          or R18,R16
          rcall wyslij_instrukcje
       ret

       init_LCD:
             ;configuracja szyny danych LCD
          ldi R17, 0x00
          out DANE_LCD_DDR, R17 ;DDRB
          
          ldi R17, 0xFF
          out DANE_LCD, R17 ;PORTB
          
          ;konfiguracja linii sterujących LCD
          clr R17
          ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)
          out STER_LCD_DDR,R17
          ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)
          out STER_LCD,R17
          
          rcall reset_LCD
          rcall wyczysc_RAM_LCD
          
          ldi R18,GRAPHIC_HOME_ADRESS & 0xFF ;młodszy bajt adresu
          rcall wyslij_dane
          ldi R18,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8 ;starszy bajt adresu
          rcall wyslij_dane
          ldi R18,SET_GRAPHIC_HOME_ADRESS ;!!!
          rcall wyslij_instrukcje
          
          ldi R18,GRAPHIC_AREA
          rcall wyslij_dane
          ldi R18,0x00
          rcall wyslij_dane
          ldi R18,SET_GRAPHIC_AREA
          rcall wyslij_instrukcje
          
          ldi R18,TEXT_HOME_ADRESS & 0xFF
          rcall wyslij_dane
          ldi R18,(TEXT_HOME_ADRESS & 0xFF00) >> 8
          rcall wyslij_dane
          ldi R18,SET_TEXT_HOME_ADRESS
          rcall wyslij_instrukcje
          
          ldi R18,TEXT_AREA
          rcall wyslij_dane
          ldi R18,0x00
          rcall wyslij_dane
          ldi R18,SET_TEXT_AREA
          rcall wyslij_instrukcje
          
          ldi R18,MODE_SET
          rcall wyslij_instrukcje
          
          ldi R18,DISPLAY_MODE
          rcall wyslij_instrukcje
          
          ldi R18,0x04 ;X
          rcall wyslij_dane
          ldi R18,0x01 ;Y
          rcall wyslij_dane
          ldi R18,SET_CURSOR_POINTER
          rcall wyslij_instrukcje
          
          ldi R18,OFFSET_REGISTER
          rcall wyslij_dane
          ldi R18,0x00
          rcall wyslij_dane
          ldi R18,SET_OFFSET_REGISTER
          rcall wyslij_instrukcje

          ldi R18,CURSOR_PATTERN_SELECT
          rcall wyslij_instrukcje
        ret
    RESET:

    ldi R17, high(RAMEND) ;inicjalizacja wskaźnika stosu
    ldi R16, low(RAMEND)
    out SPH, R17
    out SPL, R16

    rcall init_LCD

    ldi R18,0x29 ;młodszy
    rcall wyslij_dane
    ldi R18,0x00 ;starszy
    rcall wyslij_dane
    ldi R18,SET_ADRESS_POINTER
    rcall wyslij_instrukcje

    ldi R18,0x48 ;znak 'h'
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,0x22 ;znak 'B'
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,0x23 ;znak 'C'
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,0x21 ;znak 'A'
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,0x00 ;nic
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje



    ldi R18,GRAPHIC_HOME_ADRESS & 0xFF ;młodszy
    rcall wyslij_dane
    ldi R18,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8;starszy
    rcall wyslij_dane
    ldi R18,SET_ADRESS_POINTER
    rcall wyslij_instrukcje

    ldi R18,0xFF
    rcall wyslij_dane
    ldi R18,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje

    ldi R18,180 ;X
    ldi R19,100 ;Y
    rcall zapal_piksel

    petla_glowna:
    rjmp petla_glowna

    Bardzo dziękuję kolegom za okazaną pomoc, bez tego nie udałoby mi się napisać procedur obsługi dla tego wyświetlacza. Teraz zabiorę się za funkcje graficzne i definiowanie własnych znaków. W razie problemów odezwę się w tym temacie. Dlatego też proszę o nie zamykanie tego tematu.
  • Poziom 34  
    Próbuję wyświetlić znak zdefiniowany samodzielnie.
    OFFSET_REGISTER=2
    EXTERNAL_CG_HOME=OFFSET_REGISTER << 11

    Kod funkcji wysyłającej wzorzec znaku. Znajduje się on w tablicy "znak" (8 bajtów).
    Code:
           definiuj_znak:
    
          ;R20=kod definiowanego znaku
          ldi R31, high(znak*2+1)
          ldi R30, low(znak*2)

          ldi R24,EXTERNAL_CG_HOME & 0xFF
          ldi R25,(EXTERNAL_CG_HOME & 0xFF00) >> 8

          ldi R18,8
          mul R20,R18

          add R24,R0
          adc R25,R1


          mov R18,R24
          rcall wyslij_dane
          mov R18,R25
          rcall wyslij_dane
          ldi R18,SET_ADRESS_POINTER
          rcall wyslij_instrukcje

          ldi R19,8
          wysylanie_znaku:
             lpm R18,Z+
             rcall wyslij_dane
             ldi R18,DATA_WRITE_INC_ADP
             rcall wyslij_instrukcje

             dec R19
          brne wysylanie_znaku
       ret

    W obszarze grafiki widać wysłane bajty, definiujące znak. Jako kod znaku przyjąłem 0x80. Załączony mam tryb internal CG ROM. Jeżeli próbuję wyświetlić znak o kodzie 0x80, to wyświetla mi zupełnie co innego niż zdefiniowałem (zamiast tego co ma być jest znak o kodzie 0x60).
  • Użytkownik usunął konto  
  • Poziom 34  
    _marek napisał:
    W internal_cg_ROM nie definiuje się znaków .

    Zobacz to:
    Cytat:
    In internal CG ROM mode, character codes 00H to 7FH represent the predefined“internal CG ROM characters, and codes 80H to FFH represent the user's own external characters. In external CG RAM mode, all 256 codes from 00H to FFH can be used to represent the user' s own characters. The three least significant bits indicate one of the eight rows of eight dots that define the character's shape.

    No chyba, że ja to źle rozumiem.
  • Pomocny post
    Poziom 28  
    maciej_333 napisał:

    W obszarze grafiki widać wysłane bajty

    ...bo obszary pamięci dla grafiki i CG_RAM nachodzą na siebie. Jak dobrze policzysz to potrzebujesz na TEXT_SIZE + GRAPHIC_SIZE łącznie 5760 bajtów, czyli pierwszy wolny adres dla CG_RAM jest równy 0x1680. Ustawiając OFFSET_REGISTER na 2 otrzymujesz adres startowy EXTERNAL_CG_HOME równy 0x1000. Spróbuj ustawić na OFFSET_REGISTER na 3.

    Mała uwaga: zamiast pisać ldi R24,EXTERNAL_CG_HOME & 0xFF i ldi R25,(EXTERNAL_CG_HOME & 0xFF00) >> 8 prościej (i czytelniej) chyba użyć ldi R24, low(EXTERNAL_CG_HOME) i ldi R25, high(EXTERNAL_CG_HOME).
  • Poziom 28  
    Cytat:

    OFFSET_REGISTER ustawiłem na 3, ale dalej nie widzę zdefiniowanego znaku, który ma mieć kod 0x80.

    Na razie chodziło mi o to, żeby nie było widać danych CG_RAM na wyświetlaczu graficznym. Co do tego znaku, to w tej chwili nie mam czasu na dokładną analizę.
  • Poziom 34  
    Problem był trywialny. Mam już zrobioną funkcję do wysyłania łańcuchów, zapisanych w tablicach pamięci programu Atmegi. W tej funkcji musiałem zrobić odejmowanie od każdego odczytanego kodu znaku 32, bo w tym LCD znaki mają kody od zera. W związku z tym spacja ma kod 0, a nie jak w zwykłym ASCII 32. Teraz oczywiście widzę zdefiniowany znak. Zabiorę się za definicję wszystkich ogonków.

    Jednak mam nieco inne pytanie. Dlaczego przy obliczaniu adresu dla rejestru indeksowego Z muszę mieć coś takiego:
    Code:
    ldi R31, high(znak*2+1)
    
    ldi R30, low(znak*2)


    Coś takiego nie wystarczy:
    Code:
    ldi R31, high(znak)
    
    ldi R30, low(znak)

    Chodzi o to, że pamięć programu jest podzielona na 16-bitowe słowa ? W związku z tym za pomocą LPM adresuję nie bajty tylko 16-bitowe słowa ??? A co jeżeli w tablicy umieściłbym stałą 16-bitową ?
  • Użytkownik usunął konto  
  • Poziom 28  
    maciej_333 napisał:

    Code:

    ldi R31, high(znak*2+1)
    ldi R30, low(znak*2)


    W zasadzie powinno być ldi R31, high(znak*2) a nie ldi R31, high(znak*2+1). Jedynkę musisz dodać, jak chcesz odczytać wyższy bajt 16-bitowego słowa.
    maciej_333 napisał:

    A co jeżeli w tablicy umieściłbym stałą 16-bitową?

    Musiałbyś ją odczytać dwoma instrukcjami np.:
    Code:

    LPM R18, Z+ ;niższy bajt
    LPM R19, Z+ ;wyższy bajt


    Dodano po 9 [minuty]:

    maciej_333 napisał:

    Dlaczego przy obliczaniu adresu dla rejestru indeksowego Z muszę mieć coś takiego...
    .........
    Chodzi o to, że pamięć programu jest podzielona na 16-bitowe słowa ? W związku z tym za pomocą LPM adresuję nie bajty tylko 16-bitowe słowa ???

    W zasadzie sam sobie odpowiedziałeś. Instrukcja LPM odczytuje bajt a nie słowo 16-bitowe. Pomnożenie przez 2 daje przesunięcie o jeden bit w lewo, dzięki czemu najmniej znaczący bit adresu w rejestrze Z można wykorzystać do rozróżnienia, który bajt 16-bitowego słowa odczytujemy (0 - niższy, 1 - wyższy).
  • Poziom 34  
    Jestem zmuszony zadać kolegom kolejne pytania związane z tym wyświeltaczem.
    1. Jakie praktyczne znaczenie mają polecenia SCREEN PEEK i SCREEN COPY ?
    2. Czy można w jakiś prosty sposób skopiować TEXT AREA do GRAPHIC AREA ? Chodzi mi o odczytanie tekstu, jako grafikę. Wykonuję funkcję zrzutów ekranu wyświetlacza. W związku z tym wysyłam do PC całe GRAPHIC AREA poprzez RS232. Jednak w ten sposób nie jestem w stanie odczytać tekstu.
  • Użytkownik usunął konto  
  • Poziom 34  
    _marek napisał:
    Spróbuj wykonać screen_copy i wyczyścić text_area .

    Aby coś takiego zrobić musiałbym postępować wg. tego grafu:
    [Atmega16][asm]Graficzny wyświetlacz LCD.
    Jeżeli dobrze rozumiem, to najpierw ustawiam Adress Pointer na Text Home Adress. Następnie sprawdzam status i wysyłam polecenie Screen Copy. Potem odczytuję status z STA6. Jeżeli jest tam 1, to wracam do początku i inkrementuję wskaźnik rozkazów. Jeżeli nie ma 1 to dalej zgodnie z grafem.

    Jak rozumiem ten algorytm sam się zakończy po dojechaniu do Text Home Adress + Text Size ???
  • Użytkownik usunął konto