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

Atmega32 i LCD 4 bity. Uruchomienie wyświetlacza.

Chivo 08 Lip 2011 09:33 3455 20
REKLAMA
  • #1 9695029
    Chivo
    Poziom 26  
    Witam

    Proszę o pomoc w uruchomieniu wyświetlacza LCD sterowanego przez mikrokontroler Atmega32. Przesyłam mój kod i schemat podłączenia. Problem polega na tym, że nic mi się nie wyświetla.

    Pozdrawiam, Rafał
    
    #include <avr/io.h>
    #include <util/delay.h> 
    
    #define F_CPU 1000000UL
    #define LCD  PORTB
    #define E    2
    #define RS   1
    
    #define SET_E   LCD |= _BV(E)
    #define CLR_E   LCD &= ~_BV(E)
    
    #define SET_RS  LCD |= _BV(RS)
    #define CLR_RS  LCD &= ~_BV(RS)
    
    // funkcja opóźniająca o x*1ms
    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
    }
    //program
    int main(void)
    {
       DDRB=0xFF;
       DDRD = 0xFC;
       PORTB = 0xFF;
       PORTD = 0xF7;
    // inicjalizacja LCD
    lcd_init();
    // zapisz na LCD przykładowy tekst
    write_text("Ala ma kota :D");
    // petla nieskończona
    while(1);
    return 0;
    }
    

    Atmega32 i LCD 4 bity. Uruchomienie wyświetlacza.
  • REKLAMA
  • #2 9695136
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Niepoprawne opóźnienia - Twoje założenie dotyczące funkcji waitms() nie mają żadnych podstaw.

    W funkcji tej zostaw tylko pętlę zależną od parametru i do niej wstaw oryginalne delay_ms(1).

    Potem można się zastanawiać nad resztą jeśli dalej nie będzie działać.

    4\/3!!
  • #3 9695163
    Chivo
    Poziom 26  
    Hej

    Zmieniłem to opóźnienie ale bez zmian.


    
    #include <avr/io.h>
    #include <util/delay.h> 
    
    #define F_CPU 1000000UL
    #define LCD  PORTB
    #define E    2
    #define RS   1
    
    #define SET_E   LCD |= _BV(E)
    #define CLR_E   LCD &= ~_BV(E)
    
    #define SET_RS  LCD |= _BV(RS)
    #define CLR_RS  LCD &= ~_BV(RS)
    
    // funkcja opóźniająca o x*1ms
    void waitms(char x)
    {
      _delay_ms(1);
    }
    // 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
    }
    //program
    int main(void)
    {
       DDRB=0xFF;
       DDRD = 0xFC;
       PORTB = 0xFF;
       PORTD = 0xF7;
    // inicjalizacja LCD
    lcd_init();
    // zapisz na LCD przykładowy tekst
    write_text("Ala ma kota :D");
    // petla nieskończona
    while(1);
    return 0;
    }
    
  • #4 9695187
    gaskoin
    Poziom 38  
    Zmień je tak, żeby dało się wprowadzić różne opóźnienia, a nie tylko stałe i równe 1ms. Albo nie rób swojej funkcji w ogóle.
  • #5 9695242
    drzasiek
    Specjalista CNC
    A zastanowiłeś się jaki to ma sens?
    
    // funkcja opóźniająca o x*1ms
    void waitms(char x)
    {
      _delay_ms(1);
    } 
    

    Po co wogóle ci argument x? Skoro on nic nie zmienia i co byś tam nie wpisał funkcja powoduje jedynie opóźnienie 1 ms.
    
    // funkcja opóźniająca o x*1ms
    void waitms(char x)
    {
    while(x>0)
    {
    _delay_ms(1);
    x--
    }
    } 
    
  • #6 9695259
    Chivo
    Poziom 26  
    Dzięki za funkcję opóźnienia, ale dalej nic na wyświetlaczu na górnej linii są tylko czarne kwadraty.
  • REKLAMA
  • #7 9695261
    gaskoin
    Poziom 38  
    takie opóźnienia dla dużych x bardzo się rozjadą :)
  • #8 9695272
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Chivo napisał:
    Dzięki za funkcję opóźnienia, ale dalej nic na wyświetlaczu na górnej linii są tylko czarne kwadraty.

    W takim razie problem jest z samą inicjalizacją - jeszcze przed komendą czyszczenia wyświetlacza i wysyłania do niego czegokolwiek.

    gaskoin napisał:
    takie opóźnienia dla dużych x bardzo się rozjadą :)

    No nie wiem - czas wykonania instrukcji dekrementacji, skoku i sprawdzenia warunku to w porównaniu do 1ms dużo mniej niż 1% (im wyższe F_CPU tym mniej), więc o jakim rozjeździe tu mowa i jakie to ma znaczenie? Czy jest urządzenie, które wymagałoby opóźnienia o 32142ms z dokładnością do 10us?

    4\/3!!
  • REKLAMA
  • #9 9695287
    drzasiek
    Specjalista CNC
    gaskoin napisał:
    takie opóźnienia dla dużych x bardzo się rozjadą :)

    Poza tym argument jest typu char więc specjalnie dużych opóźnień to tu nie będzie :)
  • REKLAMA
  • #10 9695325
    gaskoin
    Poziom 38  
    Freddie Chopin napisał:
    Czy jest urządzenie, które wymagałoby opóźnienia o 32142ms z dokładnością do 10us?

    4\/3!!


    Nie wiadomo, może za pomocą takich opóźnień autor będzie chciał co 4 lata w dokładnej µs wyświetlić informację o tym, że jest rok przestępny ?

    Chłopaku, zmień kod, tak, żeby był w syntaxie - trochę wygodniej się go czyta.

    Po każdym wysłaniu komendy powinieneś czekać czas podany w DS na jego przetworzenie, mogłeś w tych hexach się gdzieś pokopać - wpisywanie wartości tak na sztywno nie jest dobrym pomysłem, lepiej zrobić makra (wg DS).

    Czarne kwadraty oznczają, że wyświetlacz jest ok, ale inicjalizacja jest skopana, tak jak Freddie napisał. Po poprawnej inicjalizacji ekran powinien być czarny, więc skup się na tym kawałku kodu związanym z nią i nie pisz do mnie na priw bo nie napiszę nic za Ciebie, tym bardziej, że w necie jest gotowiec, którego bez skrupułów możesz ściągnąć i wykorzystać.
  • #12 9695361
    gaskoin
    Poziom 38  
    http://radzio.dxp.pl/hd44780/ tu radzio ma bardziej dopracowane te kody z tego co widzę.

    Na dole wybierasz Sterowanie w trybie 4-bitowym bez odczytu flagi zajętości z dowolnym przypisaniem linii sterujących, i tam gdzieś na dole jest zip do pobrania.
  • Pomocny post
    #13 9695381
    snnaap
    Poziom 25  
    Wg programu

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    linia E wyświetlacza powinna być podpięta pod PB2, a linia RS pod PB1

    Na schemacie natomiast linia E jest podpięta pod PB1 a linia RS pod PB0 tak więc w programie aby był zgodny ze schematem powinno to wyglądać tak

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Pozdrawiam
  • #14 9695417
    Chivo
    Poziom 26  
    Hej

    Wszystko już działa dzięki pomocy kolegi snnaap. Błąd był w numeracji - zamiast numeru bitu portu B wpisałem numer pinu na obudowie. Dziękuję wszystkim za pomoc.

    Pozdrawiam, Rafał
  • #15 9767251
    Chivo
    Poziom 26  
    Hej

    Mam jeszcze takie pytanie: co zrobić, żeby w drugiej linii też wyświetlić tekst bo mam go tylko w pierwszej??

    Pozdrawiam, Rafał
  • #16 9767281
    Piotrek-787
    Poziom 15  
    Witam

    Przesuń kursor wyświetlacza na początek drugiej linii.
  • #17 9767295
    Chivo
    Poziom 26  
    Oki już mam rozwiązanie:

    #define HD44780_DDRAM_SET	0x80
    // Funkcja ustawienia współrzędnych ekranowych
    void lcd_goto(unsigned char x, unsigned char y)
    {
      write_command(HD44780_DDRAM_SET | (x + (0x40 * y)));
    }
    lcd_goto(0,1); // 2 linia
  • #18 9891521
    Chivo
    Poziom 26  
    Hej

    Potrafię już wyświetlać teksty ale mam problem z wyświetlaniem liczb. Oto przykład: zmienna wynik ma wartość 2 i chce ją wyświetlić na LCD, żeby było też 2 bo są jakieś znaczki.Poniżej mój kod. Proszę o pomoc.
    
    // 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
    }

    
     char  wynik=2;
     write_char(wynik);
    
  • #19 9891625
    tronics
    Poziom 38  
    Cyfra 2 to kod ASCII 32 (hex) - i tyle musisz na wyświetlacz wysłać. Liczba 55 to dwa bajty o wartości 35h wysłane na wyświetlacz. Chcesz liczbę 2 cyfrową dziesiętną wysłać? Podziel przez 10 i dodaj 30h - wynik wrzuć na wyświetlacz, następnie do reszty z dzielenia przez 10 dodaj 30h i wrzuć na wyświetlacz. Można też użyć itoa jak ktoś ma ochotę.
  • #20 9891631
    Chivo
    Poziom 26  
    A możesz napisać to jako kod programu???Mam używać funkcji write_char do liczb???

    Dodano po 57 [minuty]:

    Hej

    Do wyświetlania liczb używam funkcji dtostrf. Oto przykład:
    
    
    double wynik1=2.5;
    char wynik2[4];
    
    dtostrf(wynik1,2,2,wynik2);
    write_text(wynik2);
    
  • #21 9891824
    tronics
    Poziom 38  
    Czy typ double nie jest ciut za duży jak na 8 bitowe MCU? Jeśli masz liczbę bez ułamka to po prostu rozdziel ją na 2-3 zmienne uint8_t reprezentujące poszczególne cyfry tej liczby (np. 000-255 to setki, dziesiatki, jednosci).
    Przykład (iirc)
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Sprawdzałem na atmedze 8 i eclipse z pluginem AVR, wygląda ok
REKLAMA