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