Uwaga! Ta strona wysyła Ci "ciasteczko".
Użytkowników online:
2
Artykuły>Mikrokontrolery i PLD>Kurs AVR-GCC Wyświetlacz LCD od nokii 3310
printer_icon

Kurs AVR-GCC Wyświetlacz LCD od nokii 3310

26.04.11 ABXYZ

Jak mówią, jeden obraz wart jest tysiąca słów, dlatego warto zainteresować się wyświetlaczami graficznymi. W tym artykule zajmiemy się wykorzystaniem wyświetlaczy LCD od popularnych niegdyś telefonów komórkowych Nokia 3310/3410, na allegro można taki kupić w cenie 5..7zł.

Wyświetlacz LCD od telefonu Nokia 3310 posiada monochromatyczny ekran o rozdzielczość 84x48 (wymiary czynnego pola ekranu 30x20mm). Wyposażony jest w sterownik PCD8544(lub podobny) z szeregowym interfejsem SPI. Dostępny jest wyłącznie tryb graficzny, ale można łatwo programowo zaaranżować tryb tekstowy; przykładowo można pokazać sześć linii tekstu, każda po 14 znaków wielkości 6x8 pikseli.

obrazek
Wyświetlacz od telefonu nokia 3310 wraz z oryginalną ramką. Identycznie wygląda wyświetlacz od noki 3410.
obrazek
Wyświetlacz od telefonu nokia 3310 wydobyty z ramki.

Wyświetlacz od Nokii3410 wygląda identycznie jak wyświetlacz od Nokii3310, ten sam układ wyprowadzeń złącza, ale ma nieco większą rozdzielczość: 96x65 (można pokazać 8 linii tekstu, każda po 16 znaków 6x8). Wyświetlacz od Nokii3410 wyposażony jest w kontroler "Philips OM6206", który programuje się prawie w ten sam sposób jak kontroler PCD8544 z Nokii3310. Do obsługi obu typów wyświetlaczy będziemy wykorzystywać te same funkcje napisane w języku C.

LCD Nokia 3310 LCD Nokia 3410
Rozdzielczość 84x48 96x65
kontroler PCD8544 OM6206
Wyświetlacze LCD od telefonów Nokia 3310/3410

Podłączenie wyświetlacza do mikrokontrolera AVR

Wyświetlacz jest delikatnym elementem, dlatego lepiej jest pozostawić go w jego oryginalnej ramce. Ramkę można odpowiednio przyciąć i wraz z wyświetlaczem przykręcić wkrętami do jakieś płytki, albo przykleić.

Na tylnej stronie ramki wyświetlacza dostępne jest złącze; w telefonie miedziane styki złącza przylegają do ścieżek na płytce drukowanej.

obrazek
Złącze na tylnej stronie wyświetlacza.
Nr styku Sygnał kierunek Opis
1 VDD zasilanie Zasilanie 2.7 .. 3.3 V
2 SCLK wejście Serial clock. Sygnał zegarowy taktujący dane na linii SDIN
3SDINwejścieWejście danych synchronizowane sygnałem SCLK
4 D/C wejście Wejście wyboru rodzaju danych wprowadzanych do sterownika (wyświetlane-1,sterujące -0)
5 SCE wejście Wejście aktywujące interfejs szeregowy(aktywny stan niski)
6 GND zasilanie Masa zasilania
7 VOUT zasilanie Ouptut voltage. Kondensator elektrolityczny 1-10 uF między VOUT i GND.
8 /RES input Reset LCD (aktywny stan niski)
Opis wyprowadzeń w złączu wyświetlacza od noki 3310/3410

Najprostszym sposobem przyłączenia wyświetlacza jest przylutować przewody bezpośrednio do miedzianych styków złącza, bez rozbierania ramki. Ale trzeba lutować szybko i zdecydowanie, inaczej plastykowa listwa, na której osadzone są miedziane styki złącza może się pod wpływem ciepła roztopić i odkształcić.

obrazek
Najprostszym sposobem przyłączenia wyświetlacza jest przylutować przewody do miedzianych styków złącza, bez wyciągania wyświetlacza z oryginalnej ramki.
obrazek
Wyświetlacz z przewodami przystosowanymi do podłączenia do płytki stykowej.

Wyświetlacz wymaga napięcia zasilania 2.7-3.3 VDC, zatem najprościej jest zasilać całość: mikrokontroler i wyświetlacz napięciem 3.3V. W takim przypadku wejścia sygnałowe wyświetlacza można podłączyć bezpośrednio do wyprowadzeń portów we/wy mikrokontrolera. Na schematach wejścia sygnałowe wyświetlacza połączone są do wyprowadzeń mikrokontrolera skojarzonych ze sprzętowym interfejsem SPI AVRa atmega. W przykładowych programach, które będziemy dalej uruchamiać, można wybrać sprzętowe lub programowe SPI; w przypadku wyboru programowego SPI, sygnały sterujące wyświetlaczem można przyłączyć do dowolnych porów we/wy AVRa.

obrazek
Schemat 1 Sposób przyłączenia wyświetlacza od nokii3310/3410 do interfejsu SPI mikrokontrolera atmega8(88) zasilanego napięciem 3.3V. Kliknij w obrazek, żeby powiększyć.

Nie wszystkie wersje AVR mogą być zasilane napięciem 3.3V, schemat nr 2 pokazuje, jak można podłączyć wyświetlacz zasilany napięciem 3.3V do mikrokontrolera zasilanego napięciem 5V. Wyświetlacz od Nokii 3310 zużywa minimalne ilości prądu, napięcie 3.3V do jego zasilania można uzyskać stosując dzielnik napięcia: rezystor i dioda zenera 3.3V. Na schemacie wejścia sterujące wyświetlacza połączono z portami we/wy AVRa poprzez bufor 74ls07. Scalony układ 74LS07 zawiera sześć cyfrowych buforów z wyjściami typu otwarty kolektor, wyjścia te zostały podciągnięte rezystorami 4k7 do napięcia 3.3V.

obrazek
Schemat 2 Sposób przyłączenia wyświetlacza od nokii3310/3410 zasilanego napięciem 3.3V do mikrokontrolera zasilanego napięciem 5V. Kliknij w obrazek, żeby powiększyć.

Komunikacja z wyświetlaczem

Wyświetlacz od Nokii 3310 wyposażony jest kontroler PCD8544 z szeregowym interfejsem SPI(Serial Peripheral Interface). Interfejs posiada cztery wejścia:

  • SDIN - szeregowe wejście danych,
  • SCLK - sygnał zegarowy taktujący dane na linii, SDIN
  • /SCE - wejście aktywujące interfejs szeregowy,
  • D/C - wejście wyboru rodzaju danych (wyświetlane lub sterujące).

Komunikacja przebiega tylko w jednym kierunku, od mikrokontrolera do wyświetlacza. Zależnie od stanu linii D/C, bajty danych wysyłane do wyświetlacza, mogą być interpretowane przez kontroler jako komendy do wykonania albo dane zapisywane do pamięci RAM obrazu; stan wysoki na linii D/C sygnalizuje daną, stan niski komendę.

Rys.1 pokazuje przebieg transmisji jednego bajtu danych od mikrokntrolera do wyświetlacza Komunikację rozpoczyna się od ustawienia linii /SCE w stan niski, co aktywuje interfejs SPI. Jeśli wysyłany bajt jest komendą, linię D/C ustawia się w stan niski, a jeśli zwykłą daną - w stan wysoki Następnie, linią SDIN, szeregowo(bit po bicie) przesyła się 8 bitów danej, zaczynając od bitu najbardziej znaczącego. Transmisja szeregowa jednego bitu przebiega w następujący sposób: Wpierw na linii danych SDIN ustawia się stan niski lub wysoki, zależnie od wartości przesyłanego bitu; następnie na linii SCLK podaje się impuls: 0-1-0. Zmiana na linii /SCE stanu niskiego na wysoki sygnalizuje zakończenie transmisji.

obrazek
Rys.1 Przesłanie jednego bajtu do wyświetlacza przez SPI.

A oto funkcja "lcd_write_byte" realizująca w sposób programowy przesłanie jednego bajtu z mikrokontrolera do wyświetlacza:

void lcd_write_byte(unsigned char c_d, unsigned char data )
{
    unsigned char m; 

    LCD_CE_CLR

    if(c_d)  
       LCD_DC_SET
    else 
       LCD_DC_CLR

    for(m=0x80; m; m>>=1)
    {        
       if(data & m)
          LCD_DATA_SET 
       else 
          LCD_DATA_CLR 
        
       LCD_CLK_SET
       LCD_NOP
       LCD_CLK_CLR
    }

    LCD_CE_SET
}
Listing nr 1. Funkcja przesyłająca szeregowo jeden bajt danych z mikrokontrolera do wyświetlacza LCD poprzez interfejs SPI zrealizowany programowo.

Pierwszy argument funkcji "lcd_write_byte" wskazuje czy wysyłana jest komenda, czy bajt danych (0-komenda, 1-bajt danych); drugi argument to kod komendy lub bajt danych. Użyte w funkcji makrodefinicje: LCD_x_SET, LCD_x_CLR ustawiają na liniach sygnałowych stan wysoki lub niski, a makro LCD_NOP to krótkie opóźnienie w programie.

Mikrokontrolery atmega wyposażone są w sprzętowy interfejs SPI, który możemy wykorzystać do sterowania naszym wyświetlaczem. Poniżej znajduje się listing drugiej wersja funkcji "lcd_write_byte", która wysyła do wyświetlacza jeden bajt z wykorzystaniem sprzętowego interfejsu SPI.

/**/
SPCR =(1<<SPE)|(1<<MSTR)|(1<<SPR0);


/**/
void lcd_write_byte(unsigned char c_d, unsigned char data )
{
    LCD_CE_CLR

    if(c_d)  
       LCD_DC_SET
    else 
       LCD_DC_CLR

    SPDR = data;
    while(!(SPSR & (1<<SPIF)));

    LCD_CE_SET

}
Listing nr 2. Funkcja przesyłająca szeregowo jeden bajt danych z mikrokontrolera do wyświetlacza poprzez sprzętowy interfejs SPI AVRa atmega.

Do kontroli sprzętowego interfejsu SPI AVRa atmeaga wykorzystuje się trzy rejestry IO :

  • SPDR -SPI Data Register,
  • SPCR -SPI Control Register,
  • SPSR -SPI Status Register.

Sprzętowy interfejs SPI mikrokontrolera atmega ma szerokie możliwości konfiguracji, ale do sterowanie naszym wyświetlaczem pasują ustawienia domyślne. Pozostaje tylko wybrać szybkość działania interfejsu SPI, tzn. częstotliwość sygnału taktującego na linii SCLK. Służą do tego celu bity SPR0, SPR1 rejestru SPCR(SPI Control Register) oraz bit SPI2X rejestru SPSR(SPI -Status Register), tabela poniżej:

SPI2X SPR1 SPR0 SCK Frequency
0 0 0 fosc/4
0 0 1 fosc/16
0 1 0 fosc/64
0 1 1 fosc/128
1 0 0 fosc/2
1 0 1 fosc/8
1 1 0 fosc/32
1 1 1 fosc/64
Wybór częstotliwości sygnału taktującego na linii SCLK interfejsu SPI mikrokontrolera atmega

W naszych przykładach transmisja przez sprzętowy interfejs SPI będzie przebiegać z częstotliwością fosc/16, czyli przy częstotliwości pracy mikrokontrolera 16MHz sygnał taktujący na wyjściu SCLK będzie mieć częstotliwość 1MHz.

Ustawienie bitów SPE i MSTR w rejestrze SPCR(SPI Control Register) włącza interfejs SPI AVRa w trybie MASTER. Wysłanie bajtu następuje po zapisaniu danej do rejestru SPDR(SPI Data register), a ustawiony bit SPIF w rejestrze SPSR(SPI Status Register) sygnalizuje zakończenie transmisji.

Inicjalizacja wyświetlacza

Poniżej znajduje się listing funkcji inicjującej wyświetlacz. Na początku funkcji program resetuje wyświetlacz ustawiając linie /RES w stan niski na ok 15ms, po resecie funkcja wysyła kilka instrukcji inicjujących wyświetlacz.


/* Inicjuje wyświetlacz */
void lcd_init(void)
{
    LCD_RST_CLR; 
       
    //   < 30ms
    _delay_ms(15);    
    
    LCD_RST_SET

    LCD_CE_SET

    lcd_write_byte(LCD_CMD, 0x21); // Function set - extended instruction set
    lcd_write_byte(LCD_CMD, 0x13); // Bias - 1:48
    lcd_write_byte(LCD_CMD, 0x06); // Temperature Control
    lcd_write_byte(LCD_CMD, 0xa5); // Set Vop
    lcd_write_byte(LCD_CMD, 0x20); // Function set - basic instruction set, horizontal addressing
    lcd_write_byte(LCD_CMD, 0x0C); // Display control - normal mode 
}
Listing nr 3. Funkcja inicjująca wyświetlacz.

Pamięć RAM obrazu wyświetlacza

Każdemu pikselowi na ekranie wyświetlacza odpowiada jeden bit w pamięci RAM obrazu. Ekran wyświetlacza od Nokii 3310 ma rozdzielczość 84x48, zatem, aby zapamiętać cały obraz, kontroler wyświetlacza potrzebuje mieć 4032 bity pamięci RAM obrazu. Bity w pamięci obrazu pogrupowane są w komórki po 8 bitów(bajty), zapisując dane do pamięci obrazu zmieniamy od razu cały bajt(osiem pikseli na ekranie wyświetlacza). Niestety nie ma możliwości odczytu danych z pamięci RAM obrazu :( Komórki pamięci RAM obrazu są ponumerowane, numer komórki w pamięci nazywany jest jej adresem. Kolejnym ośmiu bitom każdej komórki pamięci RAM obrazu, odpowiada osiem kolejnych pikseli na ekranie LCD, ALE w kierunku pionowym, LSB na górze, MSB na dole ,patrz rys. 2. Przykładowo, jeśli gdzieś w pamięci RAM obrazu zapisana zostanie bajt o wartości 0xff, to w odpowiednim miejscu na ekranie wyświetlacza pojawi się pionowa kreska | o wysokości 8 pikseli, patrz rys.2.

obrazek
Rys.2 Tak można wyobrazić sobie pamięć obrazu wyświetlacza od nokii 3310, widzimy tablicę: 6 wierszy i 84 kolumny - każda kratka w tabeli to jeden bajt w pamięci RAM obrazu.

Dodatkowo, obok pamięci RAM obrazu, kontroler wyświetlacza posiada rejestr: licznik_adresu. Liczniku_adresu zawiera adres wskazujący na komórkę w pamięci RAM obrazu, gdzie zostanie zapisany następny bajt danych wysyłany do wyświetlacza, gdy na linii D/C występuje stan wysoki. Każdorazowo po zapisaniu bajtu danych w pamięci obrazu, licznik adresu zwiększa się automatycznie o jeden i wskazuje na następną komórkę w pamięci RAM obrazu. Wysyłając do wyświetlacza komendy: Set_Y_address_of_RAM i  Set_X_address_of_RAM można ustawić zawartość licznika_adresu tak, aby skazywał na dowolną komórkę w pamięci RAM obrazu.

Komendy kontrolera

Jak pisałem wcześniej, bajty danych wysyłane do wyświetlacza mogą być interpretowane przez kontroler wyświetlacza jako komendy do wykonania albo jako dane kopiowane do pamięci RAM obrazu - zależnie od stanu linii sygnału D/C. Bajty danych i komendy będziemy wysyłać do LCD omawianą wcześniej funkcją:

void lcd_write_byte(unsigned char c_d, unsigned char byte )

Parametr "c_d" to stan linii D/C, parametr "byte" to wysyłany bajt danych albo kod komendy.

Zbiór wszystkich komend wyświetlacza można znaleźć w dokumentacji kontrolera PCD8544. W naszych przykładach będziemy najczęściej wysyłać do LCD komendy Set_Y_address_of_RAM i Set_X_address_of_RAM", żeby ustawić zawartość licznika_adresu.

Wszystkie komendy kontrolera mają rozmiar jednego bajta(osiem bitów). Na bitach 6..0 kodu komendy Set_X_address_of_RAM kodowana jest współrzędna X, która może przyjmować wartości od 0 do 83, patrz rys.2.

1 X X X X X X X

Na bitach 2..0 kodu komendy Set_Y_address_of_RAM kodowana jest współrzędna Y, która może przyjmować wartości od 0 do 5, patrz rys.2

0 1 0 0 0 Y Y Y

W przypadku wyświetlacza od Nokii3410 z kontrolerem OM6206 można ustawić współrzędną Y na wartości 0..7, a współrzędną X na wartości 0..96

I to jest wszystko, co potrzebujemy wiedzieć, aby wykorzystać wyświetlacz od Nokii_3310. W dalszej części artykułu uruchomimy kilka przykładowych programików. Wszystkie przykłady są maksymalnie uproszczone, bo jak wiadomo, dobry przykład, to prosty przykład:)

Przykład 1. Jak wyświetlić obrazek

W programie MicroLCD narysowałem przykładowy obrazek, który zostanie pokazany na ekranie naszego wyświetlacza. Obrazek ma wymiary 84x48 - zajmie cały ekran wyświetlacza.

obrazek
Przykładowy obrazek do pokazania na wyświetlaczu narysowany w programie MicroLCD. Kliknij w obrazek, żeby powiększyć.

Dane obrazka wyeksportowałem do pliku tekstowego "hello_img.c", wybierając w menu programu MicroLCD opcję:

File->Export (.C hex file)

Plik z danymi obrazka zostaje dołączony do programu instrukcją preprocesora #include "hello_img.c", dane obrazka trafią do tablicy typu char.

unsigned char hello_img[] PROGMEM = {
#include "hello_img.c"
};

Słówko PROGMEM w deklaracji tablicy decyduje, że tablica zostanie utworzona w pamięci programu (we FLASHu AVRa).

Teraz, aby pokazać obrazek na ekranie, wystarczy przekopiować dane z tablicy we FLASHu AVRa do pamięci RAM obrazu wyświetlacza, robi to funkcja "lcd_image".

/* */
void lcd_image(unsigned char img[],char x0,char y0,char w,char h)
{     
   unsigned int i,j,k;
    
   for(i=0,j=0,k=0; i<h; i++)       
   {  
      /* Komenda  LCD "Set Y address of RAM" */
      lcd_write_byte(LCD_CMD, 0x40|(i+y0));
      /* Komenda "Set X address of RAM"*/
      lcd_write_byte(LCD_CMD, 0x80|(x0));

      /* Kopiowanie z FLASH do pamięci obrazu LCD  */
      for(j=0; j<w ; j++,k++)
         lcd_write_byte(LCD_DATA, pgm_read_byte(&img[k]));
   } 
}
Listing nr 4. Funkcja wyświetlająca obrazek na ekranie LCD.

Pierwszy argument funkcji "lcd_image" to tablica we FLASHu z danymi obrazka; kolejne dwa argumenty (x0,y0), to położenie górnego lewego rogu obrazka na ekranie LCD; argument czwarty i piąty to szerokość i wysokość obrazka. Parametry: y0 i wysokość obrazka trzeba podać w bajtach (osiem pikseli pionowo, patrz rys.2); na przykład, jeśli obrazek ma wysokość 48 pikseli, to należy wstawić 6.

A oto główny pliku pierwszego przykładu. Najpierw funkcja "lcd_init" inicjuje wyświetlacz, następnie funkcja "lcd_image" kopiuje dane obrazka z tablicy we FLASHu do pamięci RAM obrazu wyświetlacza.

/*
          Plik "main.c"  
*/
#include <avr/io.h>
#include <avr/pgmspace.h>

#include "lcd.h"

/* Dołącza dane z obrazkiem, obrazek zostanie
umieszczony w pamięci programu, we FLASHu  */
unsigned char hello_img[] PROGMEM = {
#include "hello_img.c"
};


int main(void)
{
    /* Inicjuje wyświetlacz */    
    lcd_init();

    /* Wyswietla obrazek  */ 
    lcd_image(hello_img,0,0,84,6);

    /* Zatrzymanie programu */    
    while(1);

    return 0;
}
Listing nr 5. Główny plik przykładu pierwszego.
obrazek
Przykładowy obrazek pokazany na ekranie LCD od Nokii_3310

Katalog z plikami źródłowymi przykładu pierwszego można pobrać klikają w link: 001.zip; katalog zawiera także plik Makefile, który należy dostosować do "sprzętu", tzn. wybrać typ AVRa, częstotliwość pracy mikrokontrolera, programator -przykłady były testowane na atmega88 8MHz. Plik Makefile wygodnie jest edytować z pomocą programu MFile dostarczonego razem z pakietem WinAVR. Jeśli nie wiesz jak skompilować przykłady, to polecam artykuł "Szybki start z WinAVR"

Przykład 2. Tekst na ekranie LCD

Nasz wyświetlacz nie udostępnia trybu tekstowego, zatem aby napisać na ekranie tekst, trzeba samemu rysować litery. W programie MicroLCD przygotowałem obrazek ze wzorami liter, cyfr i innych znaków z tablicy kodów ASCII, każdy znak narysowany jest na polu o wymiarach 6x8 punktów. Dane obrazka ze wzorami znaków wyeksportowałem do pliku tekstowego i dołączyłem do programu komendą preprocesora #include "font6x8p.c". Wzory znaków trafią do tablicy o nazwie "font" umieszczonej w pamięci programu (we FLASHu)

obrazek
Obrazek ze wzorami znaków dla wyświetlacza. Kliknij w obrazek, żeby powiększyć.

Aby tekst pojawił się na ekranie wyświetlacza, program będzie kopiował wzory znaków z tablicy "font" do odpowiedniego miejsca w pamięci RAM obrazu wyświetlacza. Ekran wyświetlacza podzielony jest na linie tekstowe o wysokości ośmiu punktów, taka jest organizacja pamięci RAM obrazu naszego wyświetlacza, patrz rys.2. Żeby narysować jeden znak o wymiarach 6x8, trzeba skopiować sześć kolejnych bajtów; każdy bajt to osiem ułożonych pionowo punków na ekranie wyświetlacza. Wyświetlacz Noki_3310 ma rozdzielczość 84x48, zatem można na nim pokazać 6 linii teksu, po 14 znaków 6x8. A to jest funkcja pisząca na ekranie wyświetlacza tekst:

/* 
   Wyświetla tekst - znaki 6x8
   s  - ciąg znaków zakończony zerem
   x - pierwsza kolumna 0..84(96)
   y - wiersz 0..5(7)
*/
void lcd_text(char s[], unsigned char x, unsigned char y)
{
   unsigned int c,j;
   unsigned char i,k;

   /* Kody polskich literek z ogonkami */
   char pl[] = {'ą','ć','ę','ł','ń','ó','ś','ź','ż','Ą','Ć','Ę','Ł','Ń','Ó','Ś','Ź','Ż'};
   
 /* Ustawia położenia pierwszej litery tekstu na ekranie LCD */
   lcd_write_byte(LCD_CMD, LCD_SETY|(y));
   lcd_write_byte(LCD_CMD, LCD_SETX|(x));

   /* Rysuje znak po znaku  */
   for(k=0; (c = s[k]); k++)
   {
      /* Dopasowuje kody znaków z ogonkami */
      for(i=0; (i<18) && (pl[i]!=c); i++) ;
      if(i<18) c= 0x80+i; 

      /* Kopiuje jeden znak(6x8) z FLASH do pamięci obrazu LCD  */ 
      for(i=0, j=(c-32)*6; i<6; i++,j++)
           lcd_write_byte(LCD_DATA, pgm_read_byte(&font[j]));
   }
}
Listing nr 6. Funkcja wyświetlająca ekranie LCD tekst

Pierwszym argumentem funkcji lcd_text jest ciąg znaków zakończony zerem, tekst może zawierać polskie znaki z ogonkami. Drugi i trzeci argument to położenie tekstu na ekranie LCD; x może przyjmować wartości 0..84, y-wartości 0..5.

A to jest główny plik drugiego przykładu:

/*
    Plik "main.c"

    LCD od nokia3310 przykład 2
    KURS AVR-GCC www.abxyz.bplaced.net

    testowane na atmega8 (16MHz) 
*/

#include <avr/io.h>
#include <avr/pgmspace.h>
#include "lcd.h"


/* */
int main(void)
{
    /* Inicjuje wyświetlacz */    
    lcd_init();
    /* Czyści ekran */
    lcd_clear();

    /* Wyświetla tekst */
    lcd_text("Kurs AVR-GCC", 1*6, 0);
    lcd_text("ABXYZ :)", 4*6, 1);
    lcd_text("Wyświetlacz", 1*6, 3);
    lcd_text("LCD", 5*6, 4);
    lcd_text("od Nokii 3310", 0*6, 5);

    /* Zatrzymanie programu */    
    while(1);

    return 0;
}
Listing nr 7. Główny plik przykładu drugiego.
obrazek
Przykład 2. Tekst na ekranie wyświetlacza od Nokii 3310.

Katalog z plikami źródłowymi przykładu drugiego można pobrać klikają w link 002.zip; katalog zawiera także plik Makefile, który należy dostosować do "sprzętu", tzn. wybrać typ AVRa, częstotliwość pracy mikrokontrolera, programator -przykłady były testowane na atmega88 8MHz. Plik Makefile wygodnie jest edytować z pomocą programu MFile dostarczonego razem z pakietem WinAVR. Jeśli nie wiesz jak skompilować przykłady, to polecam artykuł "Szybki start z WinAVR"

Przykład 3. Płynący napis.

W tym przykładzie, na górze ekranu LCD, pokazany jest obrazek, z użyciem funkcji "lcd_image", podobnie jak w przykładzie 1. W dolnej części ekranu, w linii nr 5, wyświetlany jest tekst, ale, żeby było nieco ciekawiej, tekst "płynący", robi to funkcja "scroll".

obrazek
Przykład 3. Obrazek na górze ekranu, płynący tekst na dole.
/*
    Plik "main.c"

    LCD od Nokii_3310 przykład 3
    KURS AVR-GCC www.abxyz.bplaced.net

    testowane na atmega8 16(MHz)
*/

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdio.h>
#include "lcd.h"

// Dane obrazka "avr_gcc"
unsigned char screen[] PROGMEM = {
#include "avr_gcc.c"
};

// Wzory znaków 6x8 dla funkcji "scroll"
extern unsigned char font[] PROGMEM;

// Tekst płynącego napisu 
unsigned char tekst[] PROGMEM = "              Internetowy kurs programowania mikrokontrolerów AVR w języku C              ";

//  Funkcja tworzy na ekranie LCD płynący napis 
void scroll(unsigned char txt[], unsigned char line)
{
   unsigned int j,l,k,n;
   unsigned char c,i,m;

   // Kody polskich literek z ogonkami
   unsigned char pl[] = {'ą','ć','ę','ł','ń','ó','ś','ź','ż','Ą','Ć','Ę','Ł','Ń','Ó','Ś','Ź','Ż'};

   // liczenie znaków w tekście
   for(n=0;pgm_read_byte(&txt[n]);n++);

   for(j=0; j<(n-(LCD_X/6))*6 ;j++)
   {
      LCD_GOTO(0, line) 
  
      for(i=0,l=j; i<LCD_X ;i++,l++)
      {
      c = pgm_read_byte(&txt[ (l/6) ]);

          // Dopasowuje kody polskich znaków z ogonkami
          for(m=0; (m<18) && (pl[m]!=c); m++) ;
          if(m<18) c= 0x80+m;

      k = (c-32)*6+(l%6);
          
      lcd_write_byte(LCD_DATA, pgm_read_byte(&font[k]));
      }
      _delay_ms(70);
   }
}


/*  MAIN  */
int main(void)
{
   // Inicjuje LCD    
   lcd_init();
    
   // Obrazek w górnej części ekranu 
   lcd_image(screen,0,0,84,5);
  
   // Płynący napis w linii nr 5
   while(1)
       scroll(tekst,5);

   return 0;
}
Listing nr 8. Główny plik przykładu trzeciego.

Katalog z plikami źródłowymi przykładu trzeciego można pobrać klikają w link 003.zip; katalog zawiera także plik Makefile, który należy dostosować do "sprzętu", tzn. wybrać typ AVRa, częstotliwość pracy mikrokontrolera, programator -przykłady były testowane na atmega88 8MHz. Plik Makefile wygodnie jest edytować z pomocą programu MFile dostarczonego razem z pakietem WinAVR. Jeśli nie wiesz jak skompilować przykłady, to polecam artykuł "Szybki start z WinAVR"

Przykład 4. Termometr z układem ds18b20

A teraz bardziej użyteczny przykład, termometr z układem ds18b20. Na środku ekranu wyświetlacza pokazywany jest wskaźnik cyfrowy, a po prawej wskaźnik analogowy - słupek cieczy. Podobny kity(zestaw do samodzielnego montażu) z mikrokontrolerem PIC dostępny jest w handlu.

obrazek
Przykład 4. Termometr z czujnikiem ds18b20

Na schemacie czujnik ds18b20 przyłączony jest do wyprowadzenia PD7 mikrokontrolera atmega, ale można wykorzystać dowolny port AVRa, w tym celu należy zmodyfikować makrodefinicje w pliku ds18b20.h

obrazek
Schemat 3. Sposób przyłączenia czujnika ds18b20.

W programie MicroLCD, przygotowałem tło, które będzie ładowane na ekran wyświetlacza jednorazowo, na początku programu funkcją "lcd_image"- podobnie jak w przykładzie pierwszym.

obrazek
Obrazek z tłem do przykładu 4. Na początku programu tło zostanie jednorazowo załadowane na ekran wyświetlacza. Kliknij w obrazek, żeby powiększyć.

Przygotowałem również obrazek ze wzorami cyfr dla wskaźnika cyfrowego. Każdy znak został narysowany na polu o wymiarach 8x16, czyli znaki cyferek mają wysokość dwóch linii tekstowych w pamięci RAM obrazu wyświetlacza.

obrazek
Obrazek ze wzorami cyfr o rozmiarze 8x16 do przykładu 4. Wzory cyferek zostaną wykorzystane do pokazania na ekranie wyświetlacza wskaźnika cyfrowego. Kliknij w obrazek, żeby powiększyć.

A poniżej znajduje się główny plik przykładu. W skrócie program działa następująco: Najpierw inicjowany jest wyświetlacz i na ekran ładowany jest obrazek z tłem; następnie, w pętli, odczytywana jest wartość temp z czujnika ds18b20, po czym na ekranie LCD rysowane są cyferki i słupek cieczy.

/*
    Plik "lcd.c"

    LCD od nokia3310 przykład 4
    KURS AVR-GCC www.abxyz.bplaced.net

    testowane na atmega8 16(MHz) 
*/
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <util/crc16.h>
#include <stdio.h>

#include "lcd.h"
#include "ds18b20.h"



// Obrazek z cyferkami dla wskaźnika cyfrowego 
unsigned char digits8x16[] PROGMEM = {
#include "dig8x16.c"
};

// Obrazek z tłem
unsigned char screen[] PROGMEM = {
#include "screen.c"
};

//
unsigned char tab[8];

// 9 bajtów odczytanych z ds18b20
unsigned char ds18b20_pad[9];


// Funkcja tworzy z liczby ciąg cyfr w kodzie BCD
// jeden bajt - jedna cyfra  
void i2dig(int t, unsigned char tab[])
{
   // Część ułamkowa liczby
   unsigned char frac[] = { '0','1','1','2','2','3','4','4','5','6','6','7','8','8','9','9' };
   signed char i, s = 0;
    
   if(t < 0) { t = -t; s = 1; }
   
   for(i=0; i < 4 ; i++) tab[i] = '9'+5; // spacja

   tab[7] = 0;
   tab[6] = '9'+4;  // Znak 'C'
   tab[5] = '9'+3;  // Znak '°'
   tab[4] = frac[t & 0x0f];
   tab[3] = '9'+1;  // znak kropka
   tab[2] = '0'; 
   tab[1] = '9'+5;  // spacja
   tab[0] = '9'+5; 

   t >>= 4;
   for(i=2; t; i--, t/=10) tab[i] = t%10+'0';

   if(i == 2)  i-- ;
   
   if(s) tab[i] = '9'+2; // znak minus

}


// Funkcja wyświetla wskaźnik cyfrowy
void lcd_d_t(unsigned char *s, unsigned char x, unsigned char y)
{
   unsigned int i,j;
   unsigned char k;

   LCD_GOTO(x, y) 
   for(k=0; s[k]; k++)
   { 
     lcd_write_byte(LCD_DATA, 0);
     
     for(i=0, j=(s[k]-'0')*8; i<8; i++, j++)
          lcd_write_byte(LCD_DATA, pgm_read_byte(&digits8x16[j]));
   }

   LCD_GOTO(x, y+1) 
   for(k=0; s[k]; k++)
   {
      lcd_write_byte(LCD_DATA, 0);
      
      for(i=0, j=(s[k]-'0')*8; i<8; i++, j++)
          lcd_write_byte(LCD_DATA, pgm_read_byte(&digits8x16[j+15*8]));
   }
}

// Funkcja rysuje słupek cieczy 
void lcd_a_t(char v, unsigned char x)
{
   char y,t,b;
   
    
   v+=7; 
   for(y=5,t=0; y>=0; y--,t+=8)
   {
      if(v>=t+8)
         b = 0xff;
      else if(v>t)
         b= 0xff00>>(v%8);
      else
         b = 0;
 
      LCD_GOTO(x, y) 
      lcd_write_byte(LCD_DATA, b);
      lcd_write_byte(LCD_DATA, b);
      lcd_write_byte(LCD_DATA, b);
   }
}


// MAIN 
int main(void)
{    
   unsigned int  crc = 0;
   unsigned char i;

   int t; // wartość temperatury * 16

   // Inicjuje wyświetlacz
   lcd_init();
  // lcd_contrast(0x25);
  // lcd_clear();

   // Pokazuje obrazek z tłem     
   lcd_image(screen,0,0,84,6);
  
   while(1)
   {
       // Polecenie pomiaru 
       if(ds18b20_ConvertT())
       {
          // Zatrzymuje do czasu zakończenia pomiaru 
          while(!OneWireReadTimeSlot());       
          
          // Odczyt danych z ds18b20 
          ds18b20_Read(ds18b20_pad);       
          
         // Oblicza sumę kontrolną CRC danych z ds18b20
          for (i = 0, crc =0; i < 9; i++)
              crc = _crc_ibutton_update(crc, ds18b20_pad[i]);

          // Jeśli suma kontrolna się zgadza, 
          // pokazuje nowe wyniki pomiaru  
          if(!crc)
          {
             // Zmienna "t" zawiera wartość temperatury * 16
             t = (ds18b20_pad[1] << 8) | ds18b20_pad[0] ;
      
             i2dig(t,tab);      // tworzy z liczby ciąg cyfr  
             lcd_d_t(tab,0,2);  // rysuje wskaźnik cyfrowy
             lcd_a_t(t>>4, 68); // rysuje słupek cieczy 
          }
       }
   }

       return 0;
}
Listing nr 9. Główny plik przykładu 4.

Katalog z plikami źródłowymi przykładu czwartego można pobrać klikają w link 004.zip; katalog zawiera także plik Makefile, który należy dostosować do "sprzętu", tzn. wybrać typ AVRa, częstotliwość pracy mikrokontrolera, programator -przykłady były testowane na atmega88 8MHz. Najlepiej skompilować program otwierając projekt w edytorzy "Programers's Notepad" dostarczonym wraz z pakietem "WinAVR". Jeśli nie wiesz jak skompilować przykłady, to polecam artykuł "Szybki start z WinAVR"

26.04.11 ABXYZ
legenda

Komentarze (96)

Patryk
20.11.2018 (23:05)
gość
Witam! spędziłem sporo czasu nie wiedząc dlaczego atmega328p nie komunikuje sie z ds18b20, oscyloskop pokazywał mi sygnał prostokątny na szynie danych onewire. Treść tła wyświetlała się prawidłowo na LCD, jednak brakowało temperatury. Okazało się, że trzeba odznaczyć przy programowaniu low fuse bit CKDIV8=0, który to dzielił mi taktowanie przez 8 i skutecznie zabrał kilka ładnych godzin życia. Jest on fabrycznie ustawiony w atmega328.
Poza tym cały kurs oceniam jako 10/10.
Rysiek
18.04.2018 (20:35)
gość
Szkoda, że nie ma jeszcze przykładu z jakimś menu :(
Krzysiek
25.03.2015 (12:12)
gość
Trochę się nagłowiłem zanim doprowadziłem wyświetlacz do działania, a wystarczyło "Set Vop" ustawić na 0xC8 zamiast 0xa5. Dzięki neo_84!
Dla lepszego kontrastu ustawiłem także Temperature Control na 0x07, może nic się nie zjara (w sumie i tak kupiłem drugi myśląc, że dostałem uszkodzony :P). Ogólnie ciężko połapać się o co chodzi z tymi napięciami i jak to liczyć, a sama dokumentacja jest dla mnie niezrozumiała..
Dzięki za kurs i pozdrowienia! :)
Witek85
30.12.2014 (20:47)
gość
Witam, mam pytanie czy w tych wyświetlaczach do się zrealizować odwrócenie obrazu o 180 stopni?
rxxxp
21.08.2014 (23:33)
gość
Witam.

Nareszcie uruchomiłem projekt. Wszystko działa świetnie. Poprzez kombinacje uwaliłem jeden uC, ale było warto- bo nauka kosztuje :)

Pozdrawiam
rxxxp
19.08.2014 (20:19)
gość
Witam.

Udał mi się uruchomić wyświetlacz, ale znów coś jest nie tak.Wyświetla tylko treść, ale nie mierzy temperatury, oraz wyświetlacz wyświetla do momentu gdy odłączę programator.
Proszę o jakieś sugestie.
rxxxp
15.08.2014 (14:58)
gość
Witam.

Udało się skompilować i wgrać program do uC, ale nie działa wyświetlacz nic nie wyświetla. Wyświetlacz sprawdzałem na noki i działa kupiłem. Atmegę88PA (TQFP zrobiłem przejściówkę nie ma zwarć). Nie wiem co robię nie tak być może coś źle podłączyłem jeżeli chodzi o zasilanie? Na pinie VOUT mam 3,3V.
abxyz
07.08.2014 (11:28)
autor strony
Tak, bo masz nowszą wersję kompilatora, pozmieniali:), Teraz w deklaracji zmiennych PROGMEM trzeba dodać słówko "const'


// Obrazek z cyferkami dla wskaźnika cyfrowego
const unsigned char digits8x16[] PROGMEM = {
#include "dig8x16.h"
};

// Obrazek z tłem
const unsigned char screen[] PROGMEM = {
#include "screen.h"
};
rxxxp
06.08.2014 (23:59)
gość
Witam.
Nie wiem co źle robię, ale otrzymuję taki błąd:
Compiling C: main.c
avr-gcc -c -mmcu=atmega88p -I. -gdwarf-2 -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=./main.lst -std=gnu99 -MMD -MP -MF .dep/main.o.d main.c -o main.o
main.c:21:15: error: variable 'digits8x16' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
main.c:26:15: error: variable 'screen' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
make.exe: *** [main.o] Błąd 1

Proszę o podpowiedź bo jestem zielony w tym temacie a chciałbym uruchomić ten termometr.
abxyz
15.06.2014 (21:13)
autor strony
Patrz przykład z termometrem :)
marwis95
13.06.2014 (21:52)
gość
Witam.
Świetny poradnik :D
Mam pytanie jak zrobić własną czcionkę?
Robię właśnie licznik do roweru i potrzebuje wypisywać prędkość większymi cyframi :)
Zaprojektowałem cyfry w tym programie, ale nie wiem co dalej.
https://www.dropbox.com/s/ks0znmmt5d70tdd/Zrzut%20ekranu%202014-06-13%2021.51.12.png
peter_pl
20.03.2014 (23:07)
gość
Witam.
Ja także musiałem wprowadzić zmiany w kodzie inicjującym wyświetlac,te,które opisał kolega neo_84.
Teraz wszystko ładnie śmiga.
abxyz
27.02.2014 (23:12)
autor strony
Wyjaśniam j=(c-32)*6

Razy 6, bo jeden znak to 6 kolejnych bajtów w pamięci ekranu( patrz do artykułu jak zorganizowana jest pamięć ekranu tego wyświetlacza). Odejmujemy 32, gdyż pierwsze 32 znaki w tablicy kodów ASCII nie są wyświetlane w prost (kody kontrolne np. nowy wiersz czy tabulacja ).
Adam
27.02.2014 (21:35)
gość
Faktycznie :)
Jeszcze mam ostatnie pytanie związane z poniższym fragmentem:

/* Kopiuje jeden znak(6x8) z FLASH do pamięci obrazu LCD */
for(i=0, j=(c-32)*6; i<6; i++,j++)
lcd_write_byte(LCD_DATA, pgm_read_byte(&font[j]));

a mianowicie operacją j=(c-32)*6
Mógłbyś dokładnie wyjaśnić co obliczasz w ten sposób?
Robię proste OSD dlatego staram się dokładnie zrozumieć w jaki sposób kopiujesz poszczególne bajty do pamięci.

Z góry dzięki.
abxyz
26.02.2014 (13:43)
autor strony
Całe wyrażenie (c = s[k])
ma wartość logiczną PRAWDA, jeśli zmienna 'c' zawiera wartość różną od zera.
To są podstawy języka C :)


Adam
24.02.2014 (22:59)
gość
Witam, artykuł super jednak nie rozumiem czemu w drugim argumencie pętli for stosujesz operatora przypisywania?

tutaj:
for(i=0, j=(c-32)*6; i<6; i++,j++)...

i tu:
/* Rysuje znak po znaku */
for(k=0; (c = s[k]); k++)
{
.
.
.
}
Pozdrawiam :)
lukasz
13.11.2013 (22:00)
gość
Witam czy ma może kolega program ale na 2szt ds18b20. kombinuje i kombinuje a nie znam się jedyne co mi się udało to wyświetlenie 2* tą samą temperaturę, która z czytywana jest z jednego czujnika.
Tomek
23.10.2013 (18:10)
gość
linie tekstu w sensie 2 linie różnego tekstu w obrębie jednego bajtu.
Tomek
23.10.2013 (18:09)
gość
Jasne dzięki ;)
tak myślałem, i żeby zrobić to co miałem na myśli, trzeba było by najpierw w mikrokontrolerze naeysować to co ma się znajdować na ekranie a dopiero później przesłać to. Do procka. Chodzilo mi o to, by linie tekstu nachodziły na siebie.
abxyz
23.10.2013 (14:10)
autor strony
Rozważ, jak to mówią :), przykład z termometrem, gdzie cyferki mają
wymiar 8x16, wartość liczbowa temperatury rysowana jest na dwa razy, wpierw górne części cyfr, następnie dolne części cyfr.

W pamięci flash AVR umieszczamy obrazek ze wzorami wszystkich używanych znaków. Obrazek jest wcześniej konwertowany do formatu pamięci obrazu wyświetlacza, czyli jeden bajt, osiem punktów w pionie (patrz rys.2 w artykule).

Obrazek jest podzielony na prostokątne pola o jednakowej szerokości i wysokości, a na każdym polu narysowany jest jeden znak.

Zatem nietrudno jest obliczyć pozycję w tablicy gdzie znajduje się pierwszy
bajt dowolnego znaku.

Tomek
21.10.2013 (20:54)
gość
Nie do końca o to chodzi, bardziej miałem na myśli jak kontroler odnajduje odpowiedni znak w tablicy. Czy próbowałeś pisać znaki o innych rozmiarach? Albo żeby zaczynały się np w połowie Bajtu?
abxyz
21.10.2013 (15:48)
autor strony
To proste jak ...

Patrz na ilustrację, jaka jest organizacja pamięci obrazu w tych wyświetlaczach -
jeden bajt(8-bitów) to osiem kolejnych pikseli ale w pionie, nie poziomo.

Jeden znak o wymiarach 6x8 to sześć kolejnych bajtów, więc,
żeby pokazać jeden znak, kopiujemy 6 bajtów z flash AVR do pamięci obrazu wyświetlacza
Tomek
20.10.2013 (07:40)
gość
Witam, chciałbym się zapytać jak działa procedura wybierania jednego ze znaków z tablicy, siedze i próbuję to zrozumieć i chyba nie daje rady. W jaki sposób przy pisaniu, biblioteka dobiera te właściwe litery?
Pozdrawiam
abxyz
28.09.2013 (23:33)
autor strony

Zwyczajnie, na allegro w wyszukiwarce wpisujemy słówka: nokia 3310 lcd -
właśnie takie wyświetlacze mają sterownik PCD8544 lub podobny.
Łukasz
28.09.2013 (16:54)
gość
To zadam inaczej pytanie czy opisany tutaj sposób komunikacji mogę wykorzystać na innym wyświetlaczu graficznym? Przeszukałem allegro ale nie znalazłem wyświetlacza z podobnym sterownikiem.
abxyz
31.08.2013 (19:07)
autor strony
Ja niczego tutaj nie sprzedaję ani nie reklamuję.
Łukasz
28.08.2013 (23:06)
gość
Mam takie pytanie i proszę o pomoc. Nie dysponuję wyświetlaczem z Nokii 3310, zamierzam kupić na allegro wyswietlacz i prosił bym o pomoc. Jaki wyświetlacz wybrać aby opisany tutaj kontroler/sposób komunikacji był taki sam.
macko
28.07.2013 (08:46)
gość
W termometrze wyświetla mi tylko tło i nie mam temperatury. Co może być przyczyną? Czy mam użyć zewnętrzny oscylator? Pozdrawiam
dEn
09.06.2013 (19:08)
gość
Witam. Jak ma wyglądać program i schemat pod atmega8. Czy mega8 da radę wysterować taki wyświetlacz z przykładu 4 ?

Jeśli tak to jak to ma wyglądać
abxyz
11.05.2013 (18:47)
autor strony
Ustawić wyjścia ( do których przyłączono wyświetlacz) w stan wysoki i miernikiem pomierzyć napięcia :)
pholat
11.05.2013 (17:07)
gość
Z braku zenerów, czy jakiego kolwiek innego wygodnego stabilizowania sygnałów wziąłem po 3 diodki w szereg dla uzyskania ~3,2V na wyjściach (SCKL, VDD , RES , D/C , SCE , SDIN wszystkie przewodząc w kierunku wyświetlacza). Pytanie brzmi: może to powodować brak jakiegokolwiek odzewu od wyświetlacza?
Wszystko było sprawdzane 3 razy i tylko taki wniosek mi się nasuwa.
SzymiR
17.04.2013 (23:53)
gość
Witam właśnie męczę się z odpaleniem układu ze schematu na attiny2313 próbuję i próbuję... dopiero zaczynam zabawę z wyświetlaczem i nie mam pojęcia co jest nie tak. Schemat sprawdzałem kilka razy teraz próbuję parę rzeczy pozmieniać w programie a konkretnie w przykładzie1 chciałbym żeby chociaż cokolwiek się zaświeciło:P wyczytałem że attiny2313 nie ma sprzętowego spi czy to może być problemem?
abxyz
12.03.2013 (21:06)
autor strony
Powtarzam:
Spotykane w handlu wyświetlacze do nokii 3310 mogą mieć inny typ kontrolera niż PDC8544, te inne kontrolery mogą różnić się od PDC8544 wymiarami pamięci obrazu (PDC8544 ma pamięć obrazu o wymiarach 84x6 bajtów), mimo jednakowej rozdzielczości ekranu. Przykładowo jeśli wyślemy do wyświetlacza obrazek o wymiarach ekranu 84x48, to zobaczymy obrazek pocięty na pasy o wysokości 8 pikseli przemieszczone w poziomie. W takim przypadku można do wyświetlacza wysłać instrukcje przełączające kontroler w tryb pracy zgodny z PDC8544.

Ja, zamiast wysyłać do wyświetlacza jakieś tajemnicze kody, napisałem funkcje obsługi wyświetlacza w taki sposób, aby działały poprawnie bez względu na szerokość pamięci obrazu wyświetlacza. Przykłady były testowane na wielu egzemplarzach wyświetlaczy od nokii3310 i 3410 (z różnych źródeł), więc powinny działać bez żadnych przeróbek.

Oczywiście nie twierdzę, że mój artykuł całkowicie wyczerpuje temat i również polecam googlowanie w sieci.
Hotek
12.03.2013 (17:02)
gość
Potwierdzam post @życzliwego odnośnie wysyłanych wartości:
~neo_84 wspomniał, że do niektórych podróbek wyświetlacza należy wysłać nieco inne komendy inicjalizujące. Autor artykułu nieco go przygasił, a - niestety - nie ma w tej kwestii racji. W moim modelu należy na przykład zastąpić komendy "0x13" i "0x06" odpowiednio "0x15" i "0x05". Polecam poszukać w google, są tam bardzo ciekawe artykuły o tego typu problemach z tym wyświetlaczem.
Maciak
11.03.2013 (21:16)
gość
mam WinAVR-20100110 i poprostu w konsoli pisze make i buduje. Oczywiscie najpierw w makefile zmienam na atmege 8 i zegar 1mhz tak jak mam ustawione.
abxyz
11.03.2013 (21:11)
autor strony
A jak kompilujesz te przykłady ?
Maciak
11.03.2013 (20:36)
gość
Ok wadliwy wyswietlacz przepraszam ze meczylem z drugim dziala normalnie. Bawie sie czwartym przykladem i tu pytanie. Jak ni ema czujnika to wyswietli choiaz zera? bo nie wiem czy dobrze podlaczylem czujnik ale nic poza obrazkiem w tle mi nie wyswietla.
Maciak
11.03.2013 (19:51)
gość
W czwartym przykładzie jest coś takiego // lcd_contrast(0x25); ale nie ma fej funkcji nigdzie. Układ sprawdzałem i wydaje się by ok. Uzywam zasilania z usb i do tego LM1084 powinno byc ok nie?
abxyz
11.03.2013 (16:58)
autor strony
Dziwne , zwykle to jest zbyt mały kontrast, może wyświetlacz niewłaściwie działa, źle podłączony, zasilanie lub coś innego.

Przejrzyj wszystkie przykłady, chyba w którymś jest funkcja ustawienia kontrastu.
Maciak
11.03.2013 (15:33)
gość
Witam,
Wlasnie poskladalem sobie taki ukladzik na atmedze8 i pytanie czy da sie jakos kontrast regulowac. Po podlaczeniu do zasilania obraz jest caly czarny. Ale jak sie pod swiatlo zerknie to widac tez lekko wyswietlany obrazek. Prosze o pomoc.
jacek28
24.01.2013 (17:49)
użytkownik
Problem rozwiązany :)
jacek28
24.01.2013 (17:44)
użytkownik
Dzięki! :) Teraz już mi działa, ale mam kolejny problem. Jak mam prawidłowo skonfigurować "lcd_image(hello_img,0,0,84,6);
" (z przykładu pierwszego) jak mam wyświetlacz od 3410. W 3310 opisane jest, że trzeba z "84x48" 48:8 to wychodzi tam 6, które trzeba wpisać. Co muszę zrobić skoro mam 96x65? Wiem, że 96 przepisuję, a co z 65? 65:8 = 8,125? Co mam wpisać tam po przecinku, żeby mi wyświetlało obrazek na pełnym ekranie?
abxyz
21.01.2013 (13:55)
autor strony
Układ atmega8 może być zasilany napięciem 4.5 - 5.5V, jeśli mikrokontroler ma być zasilany napięcie 3.3V, to należy użyć atmega8L albo lepiej atmega8a. Przykłady uruchamiałem na atmega88 (przy napięciu zasilania 3.3V max 10MHz).
Tak czy inaczej, przy uruchamianiu przykładów z tego artykułu, częstotliwość taktowania mikroprocesora nie ma znaczenia .
jacek28
19.01.2013 (22:20)
użytkownik
Mam problem z tym projektem. Podłączyłem LCD wg pierwszego schematu, sprawdziłem styki, mam Atmege 8 i zasiliłem ją 3,3 v i rezonator kwarcowy 16 MHz. Wgrałem odpowiednio skonfigurowany pod 16 MHz program z wyświetlanym tekstem. Ale na wyświetlaczu nic się nie pokazuje! Proszę o pomoc z fuse bitami (jestem początkujący i już dwie Atmegi przez to zepsułem), jak je powinienem skonfigurować? Proszę o pomoc.
zaklopotany
06.12.2012 (22:59)
gość
Staram się uruchomić program 001 na ATmega32. Zmieniłam w lcd.h definicje CLK, DATA itd. na odpowiedajace porty ATmegi32. Ale nic nie wyświetla. Czy coś jeszcze należy zmienić? Dodam że pliki źródłowe skopiowałam do nowego projektu w AVRStudio.
Piotrek_P
07.11.2012 (18:24)
użytkownik
Po kilkunastu minutach od napisania poprzedniego komentarza, przerobiłem funkcję wyświetlającą tekst na LCD i pięknie działa w negatywie tak jak chciałem :).
Piotrek_P
07.11.2012 (17:51)
użytkownik
Wszystkie przykłady mi ładnie działają, ale teraz kombinuję jak wyświetlić tekst w negatywie. Chodzi mi o zanegowanie konkretnych znaków, a nie całego LCD w trakcie inicjalizacji. Jak można się domyślić idę w kierunku zrobienia menu na tym LCD. Może ktoś podpowie?

Z góry dziękuję i pozdrawiam
PP
taki
24.08.2012 (15:19)
gość
Jeśli projekt chciałbym uruchomić na M32 to wszystko mogę podłączyć tak jak na M8 tylko pin SCE wyświetlacza podłączam do PB4(SS)?
miszczo
11.08.2012 (21:17)
gość
Witam
Jest drobny błąd przy opisie. Jeżeli chcemy wysłać komendę to linia dc powinna być cbi, natomiast jeżeli wysyłamy dane do pamięci ram dc powinno być sbi.
abxyz
02.08.2012 (08:53)
autor strony
Bo cztery mniej znaczące bity liczby odczytanej z ds18b20 to część ułamkowa wartości temperatury.
Jagi
29.07.2012 (20:28)
gość
Mam pytanie dotyczące termometru a zwłaszcza tej linijki kodu w funkcji której tworzy z liczby ciąg cyfr w kodzie BCD.

t >>= 4;
for(i=2; t; i--, t/=10) tab[i] = t%10+'0';

Dlaczego przesuwamy temperature (t) w prawo o 4 bity?
czy mógłby ktoś wytłumaczyć działanie pętli for?!?! Skąd wiadomo że reszta z modulo odpowiednio przesunie na daną cyfrę? Cały kurs zrozumiałem i wiem jak każdy powyższy przykład działa ale tej jednej linijki nie rozumiem. Z góry dziękuję. (prosiłbym tłumaczenie łopatologiczne. Chciałbym to zrozumieć)
abxyz
05.05.2012 (19:52)
autor strony
Tak, albo cztery diody .
abc123
05.05.2012 (17:38)
gość
Zamiast konwentera napięć można użyć rezystorów. - sygnał idzie z atmegi do wyświetlacza. :)
abxyz
04.04.2012 (21:20)
autor strony
Pisałem że, najlepiej skompilować program otwierając projekt w edytorzy "Programers's Notepad" dostarczonym wraz z pakietem "WinAVR".

Aby skompilować przykład:

1. Pobierasz plik "001.zip" np. na pulpit
2. Rozpakowujesz archiwum i wchodzisz do katalogu 001
3. Klikasz w ikonę pliku "przyklad01.pnproj", otwiera się "Programers's Notepad".
4. Aby uruchomić kompilację wybierasz w menu edytora "Programers's Notepad" opcję Tools->[WinAVR]Make All
5. Aby zaprogramować Flash AVRa wybierasz opcję Tools->[WinAVR] Program

Katalog projektu zawiera także plik Makefile, który należy dostosować do "sprzętu", tzn. wybrać typ AVRa, częstotliwość pracy mikrokontrolera oraz nazwę programatora. Plik Makefile wygodnie jest edytować z pomocą programu MFile również dostarczonego razem z pakietem WinAVR. - jak to zrobić, opisałem to w pierwszej części "Kursu AVR-GCC" oraz w artykule "Szybki start z WinAVR"
Paczi
04.04.2012 (20:10)
gość
Cześć. Ostatatnio zacząłem zabawę z wyświetlaczem nokia 3310 . Po wielu problemach udało mi się go w końcu odpalić, ale teraz mam kolejny (a dokładniej to 2) pierwszy z nich jest taki że odrazu po zaprogramowaniu procka kontrast jest odpowiedni ale gdy zresetuje procesor kontrast wyraźnie słabnie. Drugi problem jest taki że eclipse wykrywa ten zwrot jako błąd:
unsigned char screen[] PROGMEM = {
#include "screen.h"
};
Z tym sobie jeszcze jakoś radzę i wgrywam kod bezpośrednio przez char screen[] = "tutaj kod HEX".
Mam także problem z wyświetlaniem otóż miś powstaje bardzo dobrze ale jest przesunięty do prawego dolnego rogu (więc widać tylko czubek głowy i lewe ucho).
Życzliwy
30.03.2012 (01:57)
gość
Mniejsza z przyczyną, ważne jest rozwiązanie problemu :) Warto więc o tym wspomnieć, jeśli nie w artykule, to w komentarzach.

W moim przypadku wysłanie komend inicjalizujących takich jak w artykule skutkowało niepoprawnym wyświetlaniem się trzech dolnych linii obrazu - pokazywały się tam jakieś losowe krzaczki. Z pewnością zależy to od egzemplarzu, autor pewnie testował na tych z Chin, a mi akurat trafił się ten z Tajwanu.

Artykuł to kawał naprawdę dobrej roboty. Czekamy na kolejne poradniki.
abxyz
29.03.2012 (22:43)
autor strony
Spotykane w handlu wyświetlacze do nokii 3310 mogą mieć inny typ kontrolera niż PDC8544, te inne kontrolery różnią się od PDC8544 wymiarami pamięci obrazu (PDC8544 ma pamięć obrazu o wymiarach 84x6 bajtów). Przykładowo jeśli wyślemy do wyświetlacza obrazek o wymiarach ekranu 84x48, to zobaczymy obrazek pocięty na pasy o wysokości 8 pikseli przemieszczone w poziomie. W takim przypadku można do wyświetlacza wysłać instrukcje przełączające kontroler w tryb pracy zgodny z PDC8544.

Ja, zamiast wysyłać do wyświetlacza dodatkowe instrukcje , napisałem kod funkcji w taki sposób , aby działał poprawnie bez względu na szerokość pamięci obrazu. Przykłady były testowane na wielu egzemplarzach wyświetlaczy od nokii3310 i 3410 (z różnych źródeł), więc powinny działać bez żadnych przeróbek
Życzliwy
29.03.2012 (13:10)
gość
Wspaniały artykuł, okazał się bardzo pomocny. Muszę się jednak podzielić kilkoma uwagami:

1) Przy połączeniu do ATMegi zasilanej napięciem 5V, układ obniżający napięcie na 3,3V spisywał się tylko i wyłącznie wtedy, kiedy na każde z pięciu używanych wyjść ATMegi był podawany stan logiczny 1. Kiedy na którymkolwiek wyjściu pojawiało się 0, napięcie na każdym pozostałym (a także na zasilaniu wyświetlacza), spadało do ok. 1,7V. Problem można rozwiązać tak, jak poradził ~damian - 5 rezystorów 330Ohm należy zastąpić rezystorami 4,7KOhm. Ten rezystor, który podchodzi pod zasilanie wyświetlacza zostawiłem w spokoju. Wyświetlacz zaświecił i śmiga.

2) ~neo_84 wspomniał, że do niektórych podróbek wyświetlacza należy wysłać nieco inne komendy inicjalizujące. Autor artykułu nieco go przygasił, a - niestety - nie ma w tej kwestii racji. W moim modelu należy na przykład zastąpić komendy "0x13" i "0x06" odpowiednio "0x15" i "0x05". Polecam poszukać w google, są tam bardzo ciekawe artykuły o tego typu problemach z tym wyświetlaczem.

3) W funkcji wysyłającej bajt danych, zamiast assemblerowych komend, pomiędzy zmianą stanu logicznego CLK wystarczy podać _delay_us(1) - działa ;)
abxyz
22.01.2012 (00:32)
autor strony
Z pomiaru: atmega8 (8MHz) 5mA ; wyświetlacz 0,12 mA
gk2011
21.01.2012 (16:01)
użytkownik
zasilam całość 3V. jaki prąd powinien pobierać taki układ? U mnie ok. 160mA, z czego 35mA to wyświetlacz. Spodziewałem się trochę mniej, jak u was?
gk2011
07.01.2012 (01:38)
użytkownik
@greg- kolega kiedyś podobnie męczył się z wyświetlaczem, okazało się że kupił chińską podróbę która miała zamienione ze sobą 2 wyprowadzenia. Dobrze by było jakbyś miał nokię do sprawdzenia tego wyświetlacza. Zanim to zrobisz, wyczyść nożykiem końcówki przewodów, żeby być pewnym że wszystko łączy.
@abxyz
zastanawia mnie sposób w jaki inicjalizuje się wyświetlacz, chodzi mi o wysyłanie bajtów w trybie instrukcji. Czytałem datasheet OM6206 bo akurat na nim testuję, ale nie wszystko jest proste do zrozumienia. O ile wiadomo o co chodzi z poziomym i pionowym adresowaniem, to np Bias system, Set Vop, Display control niewiele mi mówią, nie wspominając o tym dlaczego akurat takie a nie inne wartości powinny tam być ustawione.
abxyz
05.01.2012 (20:01)
autor strony
W programie nie musisz niczego zmieniać.
Oczywiście częstotliwość w pliku makefile musi być taka, z jaką faktycznie procesor pracuje.
greg
05.01.2012 (19:04)
gość
a czy powinienem coś zmienić w programie jeśli używam atmegi8a a nie atmegi88?
częstotliwość w makefile ustawić na 16Mhz?
i czy powinienem wyswietlacz wypinać w traksie programowania atmegi?
połączenia sprawdziłem, zasilanie na wyswietlaczu jest, atmege programowałem już na innych prostrzych programach i było wszystko ok.
abxyz
05.01.2012 (17:31)
autor strony
Cóż można doradzić. Dalej musisz walczyć sam :) Sprawdź po kolei wszystko jeszcze raz: połączenia ( podociskać - może coś nie łączy) , zasilanie wyświetlacza, porty we/wy AVRa -czy działają itd.
greg
05.01.2012 (01:59)
gość
usiłuje od paru godzin bez skutecznie uruchomić wyświetlacz z owej noki 3310 przy pomocy atmegi8a. podpiąłem wszystko wg schematu, zasilanie 3.5 V. programator robiony na wzór stk200.
pobralem pierwszy przykład, w makefile ustawiłem: atmega8, stk200, lpt1. program wgrałem przy pomocy WinAVR, nie wystąpiły błędy, lecz na wyświetlaczu nic się nie pojawiło.
co robie nie tak??
abxyz
30.12.2011 (14:02)
autor strony
Po prostu, dla ostatniej linii znaczenie mają tylko pierwsze bity wysyłanych bajtów
gk2011
30.12.2011 (03:02)
użytkownik
próbował ktoś z 3410? w karcie jest że OM6206 ma rozdzielczość 65x102.
Jak powinien wyglądać zapis pełnego ekranu skoro 65 nie jest podzielne przez 8?
abxyz
27.12.2011 (12:01)
autor strony
DS18B20 nie wymaga kalibracji
damian
25.12.2011 (21:40)
gość
Witam,
Wyświetlacz przeżył :) Rezystorki(330Ohm), które na schemacie łączące linie wyświetlacza z napięciem 3,3V zastąpiłem 4,7k i napięcie nie siada, wyświetlacz działa. Przykład z pomiarem temp. pokazuje -56'C. Jak podgrzewam czujnik to temperatura rośnie. To trzeba jakoś dokalibrować czy coś robię nie tak..?
abxyz
25.12.2011 (11:59)
autor strony
Nie, nie trzeba niczego zmieniać w kodzie inicjującym wyświetlacz. Zamieszczone tutaj funkcje napisane są w taki sposób, aby omijały problem niekontatybilności różnych kontrolerów stosowanych w wyświetlaczach nokii3310.

"Jezeli niewidac nic na ekranie", to raczej należy sprawdzić poprawność połączeń:)
neo_84
25.12.2011 (10:42)
gość
Witam nie wszystkie wyswietlacze 3310 sa do konca kompatybilne jezeli niewidac nic na ekranie nalezy zmienic troche procedure ini:
lcd_write_byte(LCD_CMD, 0x21);
lcd_write_byte(LCD_CMD, 0x05);
lcd_write_byte(LCD_CMD, 0x14);
lcd_write_byte(LCD_CMD, 0x06);
lcd_write_byte(LCD_CMD, 0xC8);
lcd_write_byte(LCD_CMD, 0x20);
lcd_write_byte(LCD_CMD, 0x0C);
i juz wszystko gra :D zamiast buforu użyłem rezystora 330 om i diody zenera 3,3 V działa swietnie ! pozdrawiam i milej zabawy z 3310 :D
ar2
23.12.2011 (22:39)
gość
dzięki. to ja spróbuję odpowiedzieć na pytanie Damiana:
Zasilam wszystko baterią 3V i raz zapomniałem odłączyć LCD przed programowaniem (5V z USB). Przez chwilę działał, potem przestał reagować. Po kilku godzinach znów zadziałał, ale na chwilę i od tego czasu nie daje znaków życia. Czyli raczej mu to zaszkodziło
abxyz
23.12.2011 (14:29)
autor strony
Tak, przykład 001 będzie działał na LCD od nokii 3410 bez żadnych poprawek, tyle że prezentowany obrazek (o wymiarach 84x48) nie wypełni całego ekranu, bo lcd od nokii 3410 ma większą rozdzielczość (96x65).


Natomiast w przykładach 2,3 i 4, wystarczy zmodyfikować na początku pliku "lcd.h" dwie linie kodu

zmieniamy
// 3310
#define LCD_X 84
#define LCD_Y 6

na

//3410
#define LCD_X 96
#define LCD_Y 8

===========================================================
Kolejne pytanie

Czy wyświetlacz mógł się uszkodzić po padaniu na jego wejścia napięcia 5V ?

Nie wiem, nie próbowałem tego :) Najlepiej zasilać wszystko mikrokontroler i lcd napięciem 3,3V.

damian
23.12.2011 (10:46)
gość
Mam problem, zasilanie LCDka mam przez diodę zenera 3,3V. Na pinie zasilania (1) wyświetlacza miernik pokazuje 3,2V ale gdy którykolwiek z pinów atmegi podłączonych do wyświetlacza ustawie na 1, to napięcie zasilania wyświetlacza spada na 0,9V. Napięcie główne 5V jest utrzymywane. (lcd jest odłączony) Użyłem układu SN7404N. Wcześniej ścieżka od masy przy diodzie zenera mi nie łączyła i wyświetlacz dostał całe 5V. Czy mógł się uszkodzić?
ar2
23.12.2011 (01:32)
gość
Czy program 001 powinien zadziałać na wyświetlaczu od 3410 bez najmniejszych zmian w kodzie?
pendrive
21.12.2011 (10:50)
gość
Odpaliłem na MC9S12NE64 i hula jak miło. Świetny artykuł :)
gk2011
11.12.2011 (23:05)
użytkownik
Po problemie. przeczyściłem nożykiem wszystkie styki, przelutowałem połączenia kabli z LCD i wszystko działa jak należy.
gk2011
11.12.2011 (17:40)
użytkownik
nie pomogło niestety. Próbowałem na 10, 4.7, 3.3, 1 uF, nie widać różnicy. Zastanawia mnie to, że efekt jest taki jakby wyświetlony był co drugi bit.
abxyz
11.12.2011 (16:23)
autor strony
Podobny efekt powstaje, gdy brak kondensatora na wyprowadzeniu numer 7 (VOUT) wyświetlacza
gk2011
11.12.2011 (14:38)
użytkownik
Bardzo fajny artykuł, nawet dla początkującego. Mam niestety pewien problem w pierwszym przykładzie. na wyświetlaczu, niezależnie od obrazka, co drugi wiersz jest całkowicie wyzerowany. Po wyświetleniu wygląda to tak: http://img72.imageshack.us/img72/8808/hello2.png . Trudno mi znaleźć powód, bo dopiero zaczynam zabawę z elektroniką. W obecnej chwili nie mam możliwości podłączenia innego wyświetlacza.
Paskud
21.10.2011 (13:13)
gość
Faktycznie. Proste i skuteczne. Dzięki! trzeba tylko zapamiętać który krzaczek z klawiatury co oznacza ;D
abxyz
19.10.2011 (23:04)
autor strony
W rozszerzonej tabeli kodów ASCII, np. z kodowaniem "Windows-1250", mamy 256 pozycji, spójrz tu:

http://pl.wikipedia.org/wiki/Windows-1250

Polskie znaki z ogonkami mają kody powyżej 128. Możesz zastąpić własnymi znakami dowolne znaki z rozszerzonej tablicy ASCII , których kody są większe od 128 i które można wbić łatwo z klawiatury, na przykład znaki: ð,đ,ħ

Paskud
19.10.2011 (15:44)
gość
W jaki sposób mogę dodać najłatwiej własne znaki. Dorysowałem je do mapy literek, tylko jak łatwo je wpisywać w funkcji lcd_text()

Dopisać je jako kolejne elementy do tablicy liter polskich (w postaci liczby, nie jako znak), A później jak je tylko wysyłać do lcd_text()?
abxyz
14.09.2011 (13:48)
autor strony
Można przyśpieszyć zmniejszając w funkcji scroll opóźnienie - instrukcja
_delay_ms(70);
Arti
13.09.2011 (20:50)
gość
Witam.
Czy da sie przyspieszyć "płynący" tekst ?
Mam procka ustawionego na 8MHz i więcej nie wyjdę bo to Atmega 8L
20rafalo
10.08.2011 (14:33)
użytkownik
* poprawa: z PB5 na PB7
20rafalo
10.08.2011 (14:32)
użytkownik
Przerobiłem program na atiny 2313 jednak wyświetlacz nie daje oznak życia.
Zamieniłem z PB5 na PB&, PB3 na PB 5, reszta bez zmian.
Używam jedynie AVR studio(mam również wgrany winavr)
Być może problemem jest częstotliwość. W programie użyłem #define F_CPU 10000000, gyż dla większej miałem ostrzeżenie.
Podczas wgrywania programu w menu AVRS trzeba wybrać częstotliwość(zakładka "advanced" ->"calibrate for frequency" ustawiam wartość maksymalną czyli 8Mhz; w zakładce "HW Settings" ->"clock generator" ustawiam wartość maksymalną czyli ok 3,6MHz.
Co jest nie tak, jak skonfigurować poprawnie, czy muszę konfigurować te częstotliwości w zakładkach? nie wystarczy programowo- czhyba nie, gdyż jak nie ustawię to coś krzyczy i chyba domyślnie ustawia minimalną...
abxyz
08.08.2011 (20:05)
autor strony
Można na atiny 2313, czemu nie ?

Nie, ten typ LCD wymaga programowego resetu.
20rafalo
08.08.2011 (09:40)
użytkownik
Moje Atmegi 8 i 16 działają pod napięciem min 4,5V. Nie działa program.
Posiada jeszcze atiny 2313, czy na niej możliwe jest odpalenie programu? Tak patrzę, ale coś brakuje mi wyprowadzeń.
Ps czy podpięcie LCD pod 5zeniu do zasilania LCD daje jakieś oznaki?
Z góry dzięki
abxyz
03.08.2011 (13:10)
autor strony
Jeśli jest zamontowane na komputerze JRE(Java Runtime Environment), to wystarczy kliknąć w ikonę pobranego pliku i program się powinien uruchomić.

Ewentualnie można uruchomić program wpisując w "wierszu poleceń"
java -jar microlcd.jar
20rafalo
02.08.2011 (20:46)
użytkownik
Mam problem z odpaleniem programu Micro LCD.
Początkowo otwierała mi plik aplikacja Nokia OVI, później otworzyłem za pomocą JRE i wyskakuje komunikat: "unable to launch the application."
Posiadam Windows 7 pro 32bit
abxyz
28.07.2011 (13:21)
autor strony
Nie zadziała, 3510i to zupełnie "inna para kaloszy"
20rafalo
27.07.2011 (23:05)
użytkownik
Witam
Czy program zadziała pod 3510i?
Czy ma ona identyczne wyprowadzenia?
kosta
24.05.2011 (19:00)
gość
Dzięki za odpowiedź. Już działa. Rzeczywiście problemem był kwarc. Zastosowałem u siebie 8MHz, ale po porawieniu w makefile i ponownym skompilowaniu działa teraz ok.
abxyz
23.05.2011 (19:55)
autor strony
Przed chwilą sprawdziłem ten przykład, działa poprawnie z zasilaniem 3.3V, mam w pokoju temp 25.2 stopni Celsjusza :)
A z jaką częstotliwością pracuje Twój AVR, z 16MHz ? Jeśli z inną, to należy w pliku Makefile odpowiednio zmodyfikować zmienną F_CPU i ponownie skompilować .
kosta
23.05.2011 (13:11)
gość
Super artykuł. Mam jednak pytanie.
Załadowałem program termometru w wersji b. Tło się wyswietla, ale temperatura już. Podłączyłem czujnik DS18B20 do pinu PORTD.7 poprzez rezystor 4k7 do napięcia 3V3. Z noty katalogowej wynika, że DS18B20 może być zasilany od 3V do 5,5V. Mógłbym prosić o pomoc w uruchomieniu pomiaru temperatury. Dzięki za odpowiedź.
Artykuły>Mikrokontrolery i PLD>Kurs AVR-GCC Wyświetlacz LCD od nokii 3310
Ostatnie artykuły