logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

ATMEGA8 i HD44780 - szukam schematu i programu w C do LCD

Duch__ 24 Lut 2007 09:23 10291 18
REKLAMA
  • #1 3610465
    Duch__
    Poziom 31  
    Posty: 2338
    Pomógł: 33
    Ocena: 1598
    Witam. Szukam schematu i jakiegos gotowego programu w C do nauki wykorzystania za pośrednictwem mega8 wyświetlacza LCD opartego na sterowniku HD44780. Przeszukiwałem google w tej materii ale wyskakiwało dużo stron gdzie były albo gotowe programy ale bez schematów albo niesprawne programy. Ma ktoś jakieś gotowe sprawdzone rozwiązanie??

    Prosze mi nie mówić że za słabo szukałem, ale jestem dosyć mocno chory (38st C) i ledwo co widze monitor a się bardzo starałem. Pozdrawiam Duch__
  • REKLAMA
  • Pomocny post
    #2 3610580
    M. S.
    Poziom 34  
    Posty: 2107
    Pomógł: 259
    Ocena: 680
    Tu jest program:
    http://mikrokontrolery.net/avr_c_08.htm
    schemat połączenia możesz odczytać tu:
    #define LCD  PORTB

    Wyświetlacz jest sterowany 4bitami więc podłączamy DB7(końc. 14 LCD) do Portb.7 µC, DB6(końc. 13 LCD) do Portb.6 µC, DB5(końc. 12 LCD) do Portb.5 µC, DB4(końc. 11 LCD) do Portb.4 µC,
    #define E  3

    Linia sterująca E(końc. 6 LCD) do Portb.3
    #define RS  2

    Linia sterująca RS(końc. 4 LCD) do Portb.2
    Końc. 1 i 5 LCD - masa
    Końc. 2 LCD - +5V
    Końc. 3 LCD - kontrast zwyczajowo podłączyć przez rezystor 10kΩ do +5V i 470Ω do masy. W razie złego kontrastu nieco zmienić wartości.
    Reszta końcówek LCD do masy lub zostawić nie podłączone.
  • #3 3610890
    Duch__
    Poziom 31  
    Posty: 2338
    Pomógł: 33
    Ocena: 1598
    Oki działa :) masz odemnie pomógł, a wiesz jak wyświetlić teks w drugiej lini bo jest tylko wyświetlany w pierwszej.
  • REKLAMA
  • #5 3610942
    Duch__
    Poziom 31  
    Posty: 2338
    Pomógł: 33
    Ocena: 1598
    wojtkow napisał:
    Musisz wysłać komendę nowej linii która w tym przypadku wygląda (prawdopodobnie) tak:
    write_command(0xC0);



    Chyba się nie zrozumieliśmy. Chodzi mi o to by w dwóch liniach wyświetlić jakiś tekst naraz...
  • Pomocny post
    #6 3610955
    wojtkow
    Poziom 14  
    Posty: 80
    Pomógł: 9
    Jeżeli dobrze rozumiem chcesz wyświetlić tekst na raz w pierwszej i drugiej linii - ja to robię tak (wyświetlacz 8x2).

    	write_text("Ala ma k");
    	write_command(0xC0);
    	write_text("ota :D");
    
  • #7 3611335
    Duch__
    Poziom 31  
    Posty: 2338
    Pomógł: 33
    Ocena: 1598
    wojtkow napisał:
    Jeżeli dobrze rozumiem chcesz wyświetlić tekst na raz w pierwszej i drugiej linii - ja to robię tak (wyświetlacz 8x2).

    	write_text("Ala ma k");
    	write_command(0xC0);
    	write_text("ota :D");
    


    Również działa. A mógłbyś mi wysłać kilka swoich programów do obsługi LCD o ile oczywiśće takie posiadasz tak bym mógł się z tego pouczyć... Z góry dzięki.
  • #8 3611913
    wojtkow
    Poziom 14  
    Posty: 80
    Pomógł: 9
    Niestety nie mam własnych programów do obsługi LCD.
    W zasadzie bazuję na podanym przykładzie z mikrokontrolery.net, jedynie doczytałem w datasheet'cie jak wysłać znak nowej linii który potrzebowałem żeby cokolwiek zmieścić na takim małym wyświetlaczu
  • REKLAMA
  • #9 3611994
    Duch__
    Poziom 31  
    Posty: 2338
    Pomógł: 33
    Ocena: 1598
    Aha dzięki za szybką odpowiedź.
  • #10 3612861
    M. S.
    Poziom 34  
    Posty: 2107
    Pomógł: 259
    Ocena: 680
    void locate(char y, char x)
    {
    	
    	switch (y) // obliczenie o ile nalezy zwiekszyc x w zaleznosci od wartosci y
    	{
    		case 1:
    		x += 0x7F; // x = x + 0x80 - 1
    		break;
    		case 2:
    		x += 0xBF; // x = x + 0xA8 - 1
    		break;
    	}
    write_command(x);
    }


    Gdzie y to numer wiersza (1,2); x to numer kolumny.

    locate(2,2) ustawi kursor w 2 lini na 2 znaku. Od tego miejsca zostanie wyświetlony tekst.
  • #11 3615772
    Duch__
    Poziom 31  
    Posty: 2338
    Pomógł: 33
    Ocena: 1598
    Witam ponownie:

    Mam taki oto kod programu napisanego w C:

    #include <avr/io.h>
    #define F_CPU        1000000                                       
    #define CYCLES_PER_US ((F_CPU+500000)/1000000)
     
    //definiujemy stany portu sterującego diodą LED
    #define LED_ON sbi(DDRD,PD1);sbi(PORTD,PD1)
    #define LED_OFF sbi(DDRD,PD1);cbi(PORTD,PD1)
    //deklaruje LCD-ka
    #define LCD  PORTB
    #define E  3
    #define RS  2
    //Ustawiam E
    #define SET_E   LCD |= _BV(E)
    #define CLR_E   LCD &= ~_BV(E)
    //Ustawiam RS
    #define SET_RS  LCD |= _BV(RS)
    #define CLR_RS  LCD &= ~_BV(RS)
    
    // Piszemy procedury opóźnienia czasowego
    void delay(unsigned int us) 
    { 
        unsigned int delay_loops;
        register unsigned int  i;
        delay_loops = (us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty) 
        for (i=0; i < delay_loops; i++) {};
    } 
    void delayms(unsigned int ms)
    {
                unsigned int i;
                for (i=0;i<ms;i++)
                            {
                            delay(999);
                            asm volatile (
                            "WDR"::);
                                                   }
    }; 
    int main (void) 
    {
           for (;;)  
                      {
                            LED_ON;
                            delayms(1000);
                            LED_OFF;
                            delayms(1000);
                      }    
    }
    
    void waitms(char x)
    {
    unsigned char a, b; // zmnienne licznikowe
    for( ; x > 0; --x) // ta pętla zostanie wykonana x-razy
      for(b = 10; b > 0; --b) // a ta 10 razy
    	for(a = 100; a > 0; --a) // natomiast ta 100 razy
    	__asm("nop"); // dodatkowa instrukcja opóźniająca o 1 cykl
    	// razem to da opóźnienie ok. x * 1ms
    	// x od 0 do 255
    }
    
    // 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
    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
    waitms(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)
    {
    waitms(15); // czekaj 15ms na ustabilizowanie się napięcia zasilającego
    CLR_E; // E = 0
    CLR_RS; // RS = 0
    char i; // zmianna licznikowa
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
      {
      SET_E; // E = 1
      LCD &= 0x3F; //
      CLR_E; // E = 0
      waitms(5); // czekaj 5ms
      }
    SET_E; // E = 1
    LCD &= 0x2E; //
    CLR_E; // E = 0
    waitms(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
    };
    
    int main(void)
    {
    // konfiguracja portów we/wy
    DDRB = 0xFF;
    DDRD = 0xFC;
    PORTB = 0xFF;
    PORTD = 0xF7;
    // inicjalizacja LCD
    lcd_init();
    // zapisz na LCD przykładowy tekst
    write_text("Co jest ****??");
    write_command(0xC0); 
    write_text("Lato jest!!!");
    // petla nieskończona
    while(1);
    return 0;
    }


    Chce połączyć w celu nauki dwa różne programy ze sobą jeden do obsługi LCD a drugi od migania diody LED i podczas kompilacji wywala mi następujący błąd

    > "make.exe" all
    avr-gcc -g -Wall -O2 -mmcu=atmega8 -c -o lcd.o lcd.c
    lcd.c:122: error: redefinition of 'main'
    lcd.c:38: error: previous definition of 'main' was here
    make.exe: *** [lcd.o] Error 1

    > Process Exit Code: 2

    co jest nie tak z funkcją main??
  • #12 3615802
    wojtkow
    Poziom 14  
    Posty: 80
    Pomógł: 9
    W zasadzie main powinien występować raz, a Ty masz go dwa razy, w tym tkwi problem.
    Jak chcesz je połączyć to połącz ciała funkcji.
  • REKLAMA
  • #13 3616097
    Duch__
    Poziom 31  
    Posty: 2338
    Pomógł: 33
    Ocena: 1598
    wojtkow napisał:
    W zasadzie main powinien występować raz, a Ty masz go dwa razy, w tym tkwi problem.
    Jak chcesz je połączyć to połącz ciała funkcji.


    Czyli jak to ma wyglądać??
  • #14 3617325
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    Tak to powinno działać... :


    #include <avr/io.h> 
    #define F_CPU        1000000                                        
    #define CYCLES_PER_US ((F_CPU+500000)/1000000) 
      
    //definiujemy stany portu sterującego diodą LED 
    #define LED_ON sbi(DDRD,PD1);sbi(PORTD,PD1) 
    #define LED_OFF sbi(DDRD,PD1);cbi(PORTD,PD1) 
    //deklaruje LCD-ka 
    #define LCD  PORTB 
    #define E  3 
    #define RS  2 
    //Ustawiam E 
    #define SET_E   LCD |= _BV(E) 
    #define CLR_E   LCD &= ~_BV(E) 
    //Ustawiam RS 
    #define SET_RS  LCD |= _BV(RS) 
    #define CLR_RS  LCD &= ~_BV(RS) 
    
    // Piszemy procedury opóźnienia czasowego 
    void delay(unsigned int us) 
    { 
        unsigned int delay_loops; 
        register unsigned int  i; 
        delay_loops = (us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty) 
        for (i=0; i < delay_loops; i++) {}; 
    } 
    void delayms(unsigned int ms) 
    { 
                unsigned int i; 
                for (i=0;i<ms;i++) 
                            { 
                            delay(999); 
                            asm volatile ( 
                            "WDR"::); 
                                                   } 
    }; 
    
                                           
    } 
    
    //void waitms(char x) 
    //{ 
    //unsigned char a, b; // zmnienne licznikowe 
    //for( ; x > 0; --x) // ta pętla zostanie wykonana x-razy 
     // for(b = 10; b > 0; --b) // a ta 10 razy 
     //  for(a = 100; a > 0; --a) // natomiast ta 100 razy 
     //  __asm("nop"); // dodatkowa instrukcja opóźniająca o 1 cykl 
       // razem to da opóźnienie ok. x * 1ms 
       // x od 0 do 255 
    //} 
    
    // 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 
    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 
    waitms(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) 
    { 
    waitms(15); // czekaj 15ms na ustabilizowanie się napięcia zasilającego 
    CLR_E; // E = 0 
    CLR_RS; // RS = 0 
    char i; // zmianna licznikowa 
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji 
      { 
      SET_E; // E = 1 
      LCD &= 0x3F; // 
      CLR_E; // E = 0 
      waitms(5); // czekaj 5ms 
      } 
    SET_E; // E = 1 
    LCD &= 0x2E; // 
    CLR_E; // E = 0 
    waitms(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 
    }; 
    
    int main(void) 
    { 
    // konfiguracja portów we/wy 
    DDRB = 0xFF; 
    //DDRD = 0xFC; 
    PORTB = 0xFF; 
    //PORTD = 0xF7; 
    // inicjalizacja LCD 
    lcd_init(); 
    // zapisz na LCD przykładowy tekst 
    write_text("Co jest kaczusia??"); 
    write_command(0xC0); 
    write_text("Lato jest!!!"); 
    // petla nieskończona 
    while(1)
    {
                            LED_ON; 
                            delayms(1000); 
                            LED_OFF; 
                            delayms(1000); 
    } 
    return 0; 
    }


    A teraz proponuje looknąć do książek o c/c++ i bedzies wiedział dlaczego niedziałało. Miałeś 2 ciała main w jednym programie co jest nie zgodne z standardem c. A teraz zobacz żę masz 2 funkcje odp za opuznienia czasowe waitms i drugą tak samo nazywającą się którą skomentowałem.
    Poprostu pocytaj trochę o c /c++ i bedziesz kumał dlaczego tak jest a bie inaczej
  • #15 12588553
    sebcioetx
    Poziom 10  
    Posty: 40
    Ocena: 1
    Witam Kolegów.
    Walczę właśnie z powyższym wyświetlaczem i Atmega8-A.
    Program ze stronki mikrokontrolery.net skompilowałem i wgrałem do procka bez żadnych problemów. Schemat podłaczułęm tak jak kolega poniżej napisał:


    M. S. napisał:
    Tu jest program:
    http://mikrokontrolery.net/avr_c_08.htm
    schemat połączenia możesz odczytać tu:
    #define LCD  PORTB

    Wyświetlacz jest sterowany 4bitami więc podłączamy DB7(końc. 14 LCD) do Portb.7 C, DB6(końc. 13 LCD) do Portb.6 C, DB5(końc. 12 LCD) do Portb.5 C, DB4(końc. 11 LCD) do Portb.4 C,
    #define E  3

    Linia sterująca E(końc. 6 LCD) do Portb.3
    #define RS  2

    Linia sterująca RS(końc. 4 LCD) do Portb.2
    Końc. 1 i 5 LCD - masa
    Końc. 2 LCD - +5V
    Końc. 3 LCD - kontrast zwyczajowo podłączyć przez rezystor 10k do +5V i 470 do masy. W razie złego kontrastu nieco zmienić wartości.
    Reszta końcówek LCD do masy lub zostawić nie podłączone.


    Niestety, tylko świecą mi się kwadraciki a nie ma żadnego napisu...
    Wydaje mi się, że piny są również dobrze połączone, więc gdzie może być problem ??
    Proszę o jakąś podpowiedź gdzie szukać błędu.
  • #17 12594868
    sebcioetx
    Poziom 10  
    Posty: 40
    Ocena: 1
    Dziękuję za zainteresowanie.
    Powiem wam, że przerzuciłem procesor z płytki na której sie programuje na białą płytkę prototypową i zacząłem wszystko łączyć od nowa i ładnie... aby wyszły czytelne zdjęcia do pomocy. I odziwo z płytki prototypowej ruszyło od razu... czyli albo coś żle wyprowadziłęm z płytki do programowania, albo do niej nie wszystko było podłączone.

    Jednak mam do was kilka pytań o sam kod. Powyższy kod jest dość łopatologiczny i na piechotę. Na forum znalazłem bibliotekę HD44780.h oraz HD44780.c
    Dzięki niej mogę bardzo uprośćić sobie powyższy kod... jednak nie wiem jak ją podłączyć do projektu i zrobić jakąś prostą animacje z wyświetlaniem tekstu :(:( Pamiętam, że kiedyś walczyłem z podłączaniem w c++ i choroba ciężka też mi coś nie wychodziło :(...

    Podpowie mi ktoś jak podłączyć takie zewnętrzne pliki do mojeko pliku lcd.c ??

    PS: jak radzicie, do takich bardziej zaawansowanych aplikacji typu wyświetlanie obrazu w czasie rzeczywistym np. z ADC to lepiej na piechote obsługiwać wyświetlacz LCD jak z postów powyżej czy bazować na gotowej bibliotece ??
  • #18 15348008
    TiMon909
    Poziom 1  
    Posty: 1
    Witam,

    mi niestety wyświetlają się jedynie prostokąty i nic więcej.
    W kodzie w miejscu x wstawiam np. void waitms(char x1) czy inną liczbę od 0 do 255 ale nic się nie dzieje. Jestem jeszcze zielony w tej zabawie więc nie wiem czy to jest prawidłowo. Proszę o instrukcję krok po kroku jak prawidłowo mam zaprogramować ten wyświetlacz w eclipse.

    Pozdro.
  • #19 15348087
    dondu
    VIP Zasłużony dla elektroda
    Posty: 13906
    Pomógł: 1292
    Ocena: 809
    TiMon909 napisał:
    Witam,

    mi niestety wyświetlają się jedynie prostokąty i nic więcej.
    W kodzie w miejscu x wstawiam np. void waitms(char x1) czy inną liczbę od 0 do 255 ale nic się nie dzieje. Jestem jeszcze zielony w tej zabawie więc nie wiem czy to jest prawidłowo. Proszę o instrukcję krok po kroku jak prawidłowo mam zaprogramować ten wyświetlacz w eclipse.

    Pozdro.

    Eclipse to jedynie edytor tekstu i nie ma nic wspólnego z programowaniem. Używaj oryginalnego środowiska programistycznego Atmel Studio, gdyż ma symulator, a to znacząco ułatwia początkującym poznanie programowania mikrokontrolerów.

    Tutaj znajdziesz wszystko czego Ci trzeba w tym gotowce w dziale "Kurs AVR": http://mikrokontrolery.blogspot.com/p/spis-tresci.html

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy wykorzystania mikrokontrolera ATmega8 do sterowania wyświetlaczem LCD opartym na kontrolerze HD44780. Użytkownik poszukiwał sprawdzonego schematu połączeń oraz gotowego programu w języku C do nauki obsługi wyświetlacza. Podano schemat podłączenia w trybie 4-bitowym, gdzie linie danych DB4-DB7 są podłączone do portu B (PB4-PB7), a linie sterujące E i RS do PB3 i PB2. Omówiono sposób wyświetlania tekstu na dwóch liniach LCD, wykorzystując komendę ustawienia kursora (np. write_command(0xC0)) oraz funkcję locate(y,x) do precyzyjnego pozycjonowania kursora. Przedstawiono fragmenty kodu w C z definicjami portów, makrami do sterowania liniami E i RS oraz funkcjami opóźnień. Poruszono problem podwójnego występowania funkcji main w kodzie i konieczność ich połączenia. Wskazano na problemy z wyświetlaniem jedynie kwadracików, które mogą wynikać z błędów w połączeniach lub konfiguracji sprzętowej. Zaproponowano użycie środowiska Atmel Studio zamiast Eclipse dla łatwiejszej pracy z mikrokontrolerami AVR. Wspomniano o bibliotece HD44780.h i HD44780.c, która upraszcza obsługę LCD, jednak pojawiły się pytania o integrację tych plików z projektem i tworzenie prostych animacji tekstowych. Podsumowując, dyskusja zawiera praktyczne wskazówki dotyczące podłączenia, programowania i debugowania wyświetlacza LCD HD44780 z ATmega8 oraz sugestie dotyczące narzędzi programistycznych i bibliotek.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA