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 + LCD 2x16... problem z inicjalizacją LCD (AVR-GCC)

06 Maj 2007 13:51 8065 15
  • Poziom 10  
    Witam
    Podpiąłem do ATMegi16 wyświetlacz LCD HD44780 2x16 w następujący sposób:
    DB0 - PortA.0
    DB1 - PortA.1
    ...
    DB7 - PortA.7
    (tryb 8-bitowy)

    E - PortC.7
    R/W - PortC.6
    RS - PortC.5

    Program piszę w AVR Studio (GCC).

    Próbowałem różnych rozwiązań, takich jak:
    http://mikrokontrolery.net/avr_c_08.htm
    http://radzio.dxp.pl/hd44780/hd44780_avr_8-bit_rw_c.htm
    gdzie zmieniałem odpowiednio porty i piny,
    jednak za każdym razem w 1. rzędzie LCD wyświetlają się "kwadraty" a w 2. nic.

    Wiem że ten temat pojawiał się już wiele razy, ale żadne z opisanych wcześniej rozwiązań nie sprawdziło się w moim przypadku.
    Język C znam dość dobrze, ale jest to mój pierwszy program na mikrokontroler.

    Z góry dziękuję za wszelką pomoc.
    Pozdrawiam
  • Poziom 17  
    a aby dobrze ustawiłeś kontrast tego wyświetlacza??
  • Poziom 11  
    Moim zdaniem czas opozniej nie jest dostosowany do twojego oscylatora.
  • Poziom 32  
    A JTAG wyłączyłeś w procku ?
  • Poziom 10  
    slomek83 napisał:
    Moim zdaniem czas opozniej nie jest dostosowany do twojego oscylatora.


    A jaki mam dać czas opóźnień?
    (Nie mam zewnętrznego kwarcu)

    Dodano po 1 [minuty]:

    GienekS napisał:
    A JTAG wyłączyłeś w procku ?


    Nic nie wyłączałem.
    A jak mam to zrobić? (przyznam że pierwszy raz programuje AVR-a)
  • Poziom 20  
    Hehe, tez sporo walczylem z tym samym problemem :) Ponizej masz moj kod, ktory jest sprawdzony i dziala, rozpiske podlaczenia sterujacych masz w #define a DB4-7 odpowiadaja PORTA4-7.
    Code:

    #include <avr/io.h>
    #include <util/delay.h>
    // Definicje dotyczace LCD
    #define LCD PORTA             //port z LCD
    #define RS 0                     // wybor rejestru
    #define RW 2                     // 1 - odczyt; 0 - zapis
    #define E 3                      // sygnal zezwalajacy (enable)
    #define SET_E LCD |= _BV(E)
    #define CLR_E LCD &= ~_BV(E)
    #define SET_RS LCD |= _BV(RS)
    #define CLR_RS LCD &= ~_BV(RS)
    #define SET_RW LCD |= _BV(RW)
    #define CLR_RW LCD &= ~_BV(RW)
    #define DDRLCD DDRA             // port z podlaczanym LCD
    #define PINLCD PINA             // port z podlaczanym LCD
    // Wykorzystujemy tylko cztery linie przesylowe D4-D7 portu PORTLCD
    // pcodedura zapisu bajtu do wyświetlacza LCD
    // bez rozróżnienia instrukcja/dana
    void write_to_lcd(char x)
    {
    SET_E; // ustaw na E stan wysoki
    LCD = ((LCD & 0x0F) | (x & 0xF0)); // zapis pierwszej połówki bajtu
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    asm("nop");
    SET_E; // ustaw na E stan wysoki
    LCD = ((LCD & 0x0F) | ((x & 0x0F) << 4)); // zapis drugiej połowki bajtu
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    _delay_ms(1); // czekaj 1ms
    }

    //***************** procedura zapisu instrukcji do wyświetlacza LCD
    void write_command(char x)
    {
    CLR_RS; // niski stan na RS -> zapis instrukcji
    write_to_lcd(x); // zapis do LCD
    }
    //***************** procedura zapisu danej do wyświetlacza LCD
    void write_char(char x)
    {
       SET_RS; // wysoki stan na RS -> zapis danej
       write_to_lcd(x); // zapis do LCD
    }
    //***************** procedura zapisu tekstu do wyświetlacza LCD
    void write_text(char * s)
    {
    while(*s) // do napotkania 0
      {
      write_char(*s); // zapisz znak wskazywany przez s na LCD
      s++; // zwiększ s (przygotuj nastepny znak)
      }
    }
    //***************** procedura inicjalizacji wyświetlacza LCD
    void lcd_init(void)
    {
    _delay_ms(15); // czekaj 15ms na ustabilizowanie się napięcia zasilającego
    CLR_E; // E = 0
    CLR_RS; // RS = 0
    char i; // zmienna licznikowa
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
      {
      SET_E; // E = 1
      LCD &= 0x30; //
      CLR_E; // E = 0
      _delay_ms(5); // czekaj 5ms
      }
    SET_E; // E = 1
    LCD &= 0x2E; //
    CLR_E; // E = 0
    _delay_ms(1); // czekaj 1ms
    write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7
    write_command(0x08); // wyłącz LCD, kursor i miganie
    write_command(0x01); // czyść LCD
    write_command(0x06); // bez przesuwania w prawo
    write_command(0x0C); // włącz LCD, bez kursora i mrugania
    }

    //***************** procedura ustawiania pozycji kursora
    void lcd_xy(unsigned char w, unsigned char k)
    {
       write_command((w*0x40+k) | 0x80);
    }
    int main(void)      // program główny
    {
       DDRA = 0xFF;
       lcd_init();         //inicjalizacja LCD
       lcd_xy(0,0);
       write_text("Zaczynamy");
       for(;;)                  //petla nieskończona
       {}
       return 0;
    }

    Ja mam kwarc 12MHz, nic nie kombinowalem z wylaczaniem JTAG'a w procku, tyle ze musialem ustawic bity CKSEL0...3 na taktowanie zegarem zewnetrznym. Powodzenia.
  • Poziom 11  
    Jak nic nie zmieniales w fuse bitach to masz oscylator wewnetrzny 1MHz, wiec wszystkie opoznienia musisz przystosowac do niego
  • Poziom 10  
    Pozmieniałem ten kod od TopGun-a w następujący sposób:

    Code:
    #define LCD PORTA             //port z LCD
    
    #define RS 5                     // wybor rejestru
    #define RW 6                     // 1 - odczyt; 0 - zapis
    #define E 7                      // sygnal zezwalajacy (enable)
    #define SET_E PORTC |= _BV(E)
    #define CLR_E PORTC &= ~_BV(E)
    #define SET_RS PORTC |= _BV(RS)
    #define CLR_RS PORTC &= ~_BV(RS)
    #define SET_RW PORTC |= _BV(RW)
    #define CLR_RW PORTC &= ~_BV(RW)
    #define DDRLCD DDRA             // port z podlaczanym LCD
    #define PINLCD PINA   


    później ustawiłem jeszcze:
    Code:
    #define F_CPU 1000000UL //  1 MHz
    
    #include <util/delay.h>


    Jednak dalej nic się nie zmieniło;/
    Czy znaczy to że muszę jakoś inaczej dobrać te czasy opóźnień albo ustawić inną wartość F_CPU ?
  • Poziom 11  
    tylko ze Top Gun ma magistrale danych 4 bitowa a ty jak napisales w pierwszym poscie wykorzystujesz 8 bitow danych wyswietlacza LCD, a to wiaze sie z innymi procedurami do zapisu instrukcji
  • Poziom 20  
    Campnou - wez odlutuj te 4 nozki z portu A i w ich miejsce wlutuj te 3 nozki sterujace wg mojego programu - malo roboty a gotowiec juz jest :)
  • Poziom 10  
    Top Gun napisał:
    Campnou - wez odlutuj te 4 nozki z portu A i w ich miejsce wlutuj te 3 nozki sterujace wg mojego programu - malo roboty a gotowiec juz jest :)


    Niby tak, ale ja już to mam na wytrawionej płytce i musiałbym teraz zdrapywać ścieżki i dorabiać kabelki :) a właśnie po to robiłem tą płytkę żeby nie było żadnych "pajączków" :)

    Dodano po 3 [minuty]:

    slomek83 napisał:
    tylko ze Top Gun ma magistrale danych 4 bitowa a ty jak napisales w pierwszym poscie wykorzystujesz 8 bitow danych wyswietlacza LCD, a to wiaze sie z innymi procedurami do zapisu instrukcji


    Ale mimo iż mam podpięte 8 pinów (cały port A) do LCD to nie znaczy że nie mogę używać tylko 4 najstarszych i prowadzić transmisji w trybie 4-bitowym. A w definicjach pozmieniałem piny E, R/W i RS.
    Więc wszystko powinno być OK.
  • Poziom 20  
    To chociaz odlutuj z plytki te 4 bity bo podejrzewam, ze jednak ma to wplyw, ze one sa podlaczone i na nie ida stany rozne.
  • Poziom 11  
    zmien funkcje void write_to_lcd na

    void write_to_lcd(char x)
    {
    SET_E; // ustaw na E stan wysoki
    asm("nop");
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    _delay_ms(1); // czekaj 1ms
    }


    i komendy w programie glownym na:

    write_command(0x38); // interfejs 8-bity, 2-linie, znak 5x7
    write_command(0x08); // wyłącz LCD, kursor i miganie
    write_command(0x01); // czyść LCD
    write_command(0x06); // bez przesuwania w prawo
    write_command(0x0F); // włącz LCD, z kursorem i mruganiem


    i juz masz obsluge na 8 bitach
  • Poziom 10  
    slomek83 napisał:
    zmien funkcje void write_to_lcd na

    void write_to_lcd(char x)
    {
    SET_E; // ustaw na E stan wysoki
    asm("nop");
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    _delay_ms(1); // czekaj 1ms
    }

    i komendy w programie glownym na:

    write_command(0x38); // interfejs 8-bity, 2-linie, znak 5x7
    write_command(0x08); // wyłącz LCD, kursor i miganie
    write_command(0x01); // czyść LCD
    write_command(0x06); // bez przesuwania w prawo
    write_command(0x0F); // włącz LCD, z kursorem i mruganiem


    i juz masz obsluge na 8 bitach


    Funkcję write_to_lcd powinienem chyba zmienić w taki sposób:
    Code:
    void write_to_lcd(char x)
    
    {
    SET_E; // ustaw na E stan wysoki
    LCD=x;
    asm("nop");
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    _delay_ms(1); // czekaj 1ms
    }

    bo tam zupełnie nie przypisałeś zmiennej x do portu.

    Jednak w takiej wersji też to nie działa;/
    Już nie mam pomysłu co może być nie tak.
    Zastanawiam się czy nie rozlutować tego wszystkiego i poskładać od nowa w innej konfiguracji pinów.
  • Poziom 12  
    To nie prościej już wstawić poprostu ten oscylator 12MHz zamiast kombinować z kodem?
  • Poziom 10  
    Okazało się że musiałem wyłączyć JTAG-a.
    Teraz już wszystko działa:)

    Standardowo ATMega ma go załączonego i przez to nie można używać pinów:
    PORTC.2
    PORTC.3
    PORTC.4
    PORTC.5
    jako wyjść.

    Jakby ktoś miał ten sam problem to JTAG-a wyłącza się zmieniając programatorem ustawienie bitu JTAGEN w bitach konfiguracyjnych procesora.