background image

Artykuł pochodzi ze strony XYZ HOBBY ROBOT (

xyz.isgreat.org

)

Kurs AVR-GCC Wyświetlacz LCD od Nokii_3310

26.04.11 ABXYZ

Niniejszy tekst jest dodatkiem poszerzającym tematykę
publikowanego na tej stronie 

kursu AVR-GCC

.

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. Pewnie
niektórzy czytelnicy zastanawiają się, czemu nie wybrałem duŜego,
kolorowego wyświetlacza o rozdzielczości QVGA. Przede wszystkim
ze względu na cenę, szkoda montować w kaŜdym urządzeniu
modułu LCD kosztujący ponad 100zł, zaś wyświetlacze od starych
komórek praktycznie nic nie kosztują i  teŜ są fajne:)

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.

Wyświetlacz od telefonu nokia 3310 wraz z oryginalną ramką. Identycznie wygląda

wyświetlacz od noki 3410.

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

1 z 11

background image

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

cena

<10zł

<10zł

Monochromatyczne 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.

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

3

SDIN

wejście

Wejś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ć.

2 z 11

background image

Najprostszym sposobem przyłączenia wyświetlacza jest przylutować przewody do

miedzianych styków złącza, bez wyciągania wyświetlacza z oryginalnej ramki.

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.

Schemat 1 Sposób przyłączenia wyświetlacza od nokii3310/3410 do interfejsu SPI

mikrokontrolera atmega8(88) zasilanego napięciem 3.3V

3 z 11

background image

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 330 do napięcia 3.3V.

Schemat 2 Sposób przyłączenia wyświetlacza od nokii3310/3410 zasilanego napięciem

3.3V do mikrokontrolera zasilanego napięciem 5V

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 - kontroler
odczytuje kolejne bity danych przy rosnącym zboczu sygnału SCLK.
Zmiana na linii /SCE stanu niskiego na wysoki sygnalizuje
zakończenie transmisji.

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)

)

)

)  

4 z 11

background image

       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 zwykłych danych (1-komend, 0-zwykła
dana); 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

5 z 11

background image

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.

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

6 z 11

background image

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 pierwszy. Jak wyświetlić obrazek

W programie 

MicroLCD

 narysowałem przykładowy obrazek w dwóch

kolorach, który zostanie pokazany na ekranie naszego
wyświetlacza. Obrazek ma wymiary 84x48 - zajmie cały ekran
wyświetlacza.

Przykładowy obrazek do pokazania na wyświetlaczu narysowany w programie 

MicroLCD

.

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).

7 z 11

background image

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.

Przykładowy obrazek pokazany na ekranie LCD od Nokii_3310

Katalog z plikami przykładu pierwszego moŜna pobrać klikają w link
poniŜej, są dwie wersje: 

wersja a

 - z programowym SPI, 

wersja

b

 - wykorzystująca sprzętowy interfejs SPI AVRa atmega. Katalogi z

plikami źródłowymi przykładów zawierają takŜe plik Makefile, który
naleŜy dostosować: wybrać typ AVRa, częstotliwość pracy
mikrokontrolera, typ programatora -przykłady były testowane na
atmega8 16MHz.

Przykład drugi. 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

8 z 11

background image

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 ze wzorami znaków dla wyświetlacza.

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>

9 z 11

background image

#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.

Przykładowy tekst na ekranie wyświetlacza od Nokii 3310.

Katalog z plikami przykładu drugiego moŜna pobrać klikają w link
poniŜej: są dwie wersje: 

wersja a

 - z programowym SPI, 

wersja

b

 - wykorzystująca sprzętowy interfejs SPI AVRa atmega.

Przykład trzeci. Płynący tekst.

Przykład trzeci. 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[]

[]

[]

[] =

=

=

= {

{

{

{

'ą'

,

,

,

,

'ć'

,

,

,

,

'ę'

,

,

,

,

'ł'

,

,

,

,

'ń'

,

,

,

,

'ó'

,

,

,

,

'ś'

,

,

,

,

'ź'

,

,

,

,

'Ŝ'

,

,

,

,

'Ą'

,

,

,

,

'Ć'

,

,

,

,

'Ę'

,

,

,

,

'Ł'

,

,

,

,

'Ń'

,

,

,

,

'Ó'

,

,

,

,

'Ś'

,

,

,

,

'Ź'

,

,

,

,

'ś'

};

};

};

};

10 z 11

background image

   

// 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 drugiego.

Katalog z plikami przykładu trzeciego moŜna pobrać klikają w link
poniŜej: są dwie wersje: 

wersja a

 - z programowym SPI, 

wersja

b

 - wykorzystująca sprzętowy interfejs SPI AVRa atmega.

26.04.11 ABXYZ

Copyright © 2009-2011 ABXYZ - Wszelkie prawa zastrzeŜone

11 z 11