kursC czesc013

background image

41

Programowanie

Elektronika dla Wszystkich

Dziś chcę zaproponować Ci pracę z wyświet-
laczem z telefonu NOKIA3310. Ponieważ
wyświetlacz ten wyposażony jest w interfejs
SPI, dowiemy się także, jak go obsługiwać.

Telefon Nokia3310, a także jego prosty,

monochromatyczny wyświetlacz graficzny
zapewne są znane wielu Czytelnikom.

Aktualna cena nowego wyświetlacza waha

się w granicach 7 zł za najprostszy model. Jest
to cena naprawdę rewelacyjna, biorąc pod
uwagę, co otrzymujemy w zamian. Wybrane
właściwości wyświetlacza zebrałem w tabeli

12. Na szczególną uwagę zasługuje szeroki
zakres temperatur pracy oraz niewielki pobór
prądu. Porównanie możliwości sprawia, że
typowe wyświetlacze alfanumeryczne pozo-
stają daleko w tyle.

Sterownik PCD8544

– podstawy

Na zewnątrz modułu wyświetlacza wyprowa-
dzono złącze umożliwiające programowanie
sterownika z wykorzystaniem interfejsu sze-
regowego. Interfejs ten jest w dużej mierze

zgodny z SPI. Możliwy jest
jedynie zapis danych i
instrukcji do sterownika. Ste-
rownik nie posiada możliwoś-
ci wysłania jakiejkolwiek
informacji zwrotnej. Interfejs
tworzą wyprowadzenia ozna-
czone jako SCLK – zegar
danych – dane są próbkowane
na narastającym zboczu,
SDIN – dane wejściowe, SCE
– stan niski powoduje wybra-

nie urządzenia, D/C – aktualnie przesyłany
bajt jest daną (1) lub instrukcją (0), RES –
zerowanie sterownika. Układ wyprowadzeń
modułu przedstawia rysunek 55.

Po włączeniu zasilania wyświetlacza jego

stan jest nieokreślony. W czasie maksymalnie
30ms należy przeprowadzić jego zerowanie po-
przez podanie krótkiego, niskiego impulsu na
wejście RES. W tym momencie wyświetlacz
zostanie wyłączony, a sterownik będzie gotowy
do przyjmowania komend. Dostępny zestaw
komend sterujących przedstawia tabela 13.

Komendami rozszerzonymi zajmiemy się

za chwilę. Teraz warto poznać samą ideę dzia-
łania sterownika. Pewną niedogodnością
naszego wyświetlacza jest to, że nie posiada
on wbudowanego generatora znaków. Ozna-
cza to, że jeśli będziemy chcieli napisać coś
na wyświetlaczu, to na procesor spada zada-
nie pamiętania wzorców znaków oraz ich
malowanie. Pamięć wyświetlacza jest zorga-
nizowana tak, aby wypisywanie tekstu, stan-
dardową czcionką o wysokości 8 pikseli, było
możliwie proste – spójrz na rysunek 56.

W podstawo-

wym zestawie
komend możemy
wybrać aktualny
adres zapisu w
postaci numeru
kolumny oraz
bajtu odpowiada-
jącego ośmiu
pikselom w ko-
lumnie. Po doko-
naniu zapisu każ-
dej danej, aktual-

ny adres zapisu
jest przesuwany.
Istnieją dwie
możliwości, które

PP

PP

rr

rr

oo

oo

gg

gg

rr

rr

aa

aa

m

m

m

m

oo

oo

w

w

w

w

aa

aa

nn

nn

ii

ii

ee

ee

pp

pp

rr

rr

oo

oo

cc

cc

ee

ee

ss

ss

oo

oo

rr

rr

óó

óó

w

w

w

w

w

w

w

w

jj

jj

ęę

ęę

zz

zz

yy

yy

kk

kk

uu

uu

CC

CC

część 13

Właściwości wyświetlacza z telefonu NOKIA3310
Sterownik:

PCD8544 (Philps)

Rozdzielczość:

48x84 (6x14)*

Zalecane napięcie zasilania:

2,7 – 3,3V (max. 5V)

Pobór prądu w trybie aktywnym

300

µA

Zakres temperatur pracy:

od -25 do +70°C

Interfejs:

Szeregowy, zgodny z SPI, 3 linie + 2 sterujące

Maksymalna częstotliwość SCLK:

4MHz

* liczba znaków 5x8

Rys. 55 Wyprowadze-

nia wyświetla-

cza

Rys. 56 Organizacja

pamięci

Komendy sterujące

Instrukcja

Bajt komendy

Opis

D7 D6 D5 D4 D3 D2 D1 D0

Każdy zestaw komend
NOP
Function Set

0

0

1

0

0 PD V

H

PD – tryb power down
V – adresowanie w trybie pionowym
H – rozszerzony zestaw komend

Zestaw komend podstawowych
Zarezerwowana

0

0

0

0

0

1

-

-

Nie wywoływać

Display Control

0

0

0

0

1

D

0

E

DE = 00 wyświetlacz wygaszony
DE = 01 test (wszystkie piksele włączone)
DE = 10 tryb standardowy
DE = 11 tryb negatywowy

Zarezerwowana

0

0

0

1

-

-

-

-

Nie wywoływać

Set Y address

0

1

0

0

0 Y2 Y1 Y0

0

≤ Y < 6

Set X address

1 X6 X5 X4 X3 X2 X1 X0

0

≤ X < 84

Zestaw komend rozszerzonych
Zarezerwowana

0

0

0

0

0

0

0

1

Nie wywoływać

Zarezerwowana

0

0

0

0

0

0

1

-

Nie wywoływać

Temperature Control

0

0

0

0

0

1

T1 T0

T – krzywa kompensacji temperaturowej
Standardowo T=2

Zarezerwowana

0

0

0

0

1

-

-

-

Nie wywoływać

Bias System

0

0

0

1

0 B2 B1 B0

Sposób sterowania elektrodami
Dla 48 linii B = 3

Zarezerwowana

0

1

-

-

-

-

-

-

Nie wywoływać

Set VOP

1 V6 V5 V4 V3 V2 V1 V0

Napięcie zasilania matrycy (kontrast)
Bezpieczny zakres: 32-88
Standardowo: 72

Tabela 12 Wybrane właściwości wyświetlacza
Tabela 13 Zestaw komend sterujących wyświetla-

czem

background image

przedstawiają rysunki 57 i 58. Adresowanie
w trybie poziomym jest bardzo wygodne do
pisania tekstu. Adresowanie w trybie piono-
wym może okazać się przydatne w niektórych
przypadkach rysowania, my jednak teraz nie
będziemy z niego korzystać.

Sterownik PCD8544

– konfiguracja

Aby przejść do konfiguracji wyświetlacza,
należy przełączyć się na zbiór instrukcji roz-
szerzonych. Robimy to poprzez wydanie
komendy Function Set z ustawionym bitem
H. Od tej chwili aż do ponownego wywołania
Function Set z wyzerowanym bitem H lub do
chwili zerowania sterownika, aktywny jest
rozszerzony zestaw instrukcji. Do pełnej kon-
figuracji służą trzy, znajdujące się tutaj
komendy.

Pierwsza to Temperature Control. Umożli-

wia ona wybranie jedej z czterech krzywych
korekcji napięcia zasilania matrycy w zależ-
ności od temperatury. W założeniu ma to
zapewnić stały kontrast niezależnie od warun-
ków, w jakich wyświetlacz pracuje. Nasz
wyświetlacz najlepiej współpracuje z krzywą,
której dano numer 2 i taką wartość też wybie-
rzemy.

Przy kolejnej komendzie – Bias System,

nie mamy praktycznie żadnego wyboru.
Zgodnie z dokumentacją, dla 48 rzędowych
wyświetlaczy najlepszym ustawieniem jest 3.

Ostatnia komenda – Set V

OP

, będzie nam

już znacznie bliższa. Za jej pomocą ustawia-
my kontrast wyświetlacza. Mimo tego, że
fizycznie istnieje możliwość wybrania war-
tości 0-127, nie należy przekraczać zakresu
32-88. Przy zmniajszaniu się temperatury
napięcie matrycy rośnie. Jeśli wybierzemy
zbyt dużą wartość dla temperatury pokojowej,
może ono przekroczyć wartość dopuszczalną
po wyniesieniu urządzenia na mróz. W poda-
nych „bezpiecznych” granicach można usta-
wianą wartość zmieniać wedle uznania.

Jak się okazuje, mimo tego, że mamy moż-

liwość ustawiania bardzo niskopoziomowych

parametrów pracy wyświetlacza, nastaw
nie ma przerażająco dużo i wyświetlacz
można szybko doprowadzić do działania.

Przygotowanie sprzętu

Najpopularniejsza wersja wyświetlacza
do NOKII3310 jest dostępna w postaci
całego modułu, zawierającego sam wy-
świetlacz, ramkę oraz głośnik. Jest to
dość spory element i pewnie kusi Cię,
aby wydobyć wyświetlacz z ramki. Jed-
nak, przynajmniej na początku, tego nie
rób. Ramka zapewnia prawidłowy kon-
takt metalowych blaszek ze ścieżkami
znajdującymi się na szkle wyświetlacza.
Do czasu, aż przekonasz się, że część
sprzętowa działa bez zarzutu, nie pozby-
waj się tego ułatwienia. Fotografia 3
pokazuje wygląd omawianego modułu.
Fotografia 4 natomiast przedstawia złą-
cze, do którego będziemy lutować prze-
wody.

Wyświetlacz będzie przyłączony do złącza

LV-OUT. Zanim to zrobimy, ustaw przy po-
mocy potencjometru PR1 napięcie zasilające
wyświetlacz na wartość około 3V. Napięcie to
możesz mierzyć między 1 a 2 wyprowadze-
niem złącza LV-OUT.

Przygotuj przewód taśmowy zakończony

z jednej strony gniazdem do złącza LV-OUT.

Schemat połączeń pokazuje rysunek 59.
Połączenie zostało wykonane w taki sposób,
aby możliwe było wykorzystanie sprzętowe-
go interfejsu SPI do komunikacji z wyświetla-
czem.

Wykonywanie połączenia rozpocznij od

wlutowania kondensatora między pinami 6 a
7. Następnie pocynuj styki oraz końcówki
przewodów (fotografia 5). Połączenie tych
elementów wymaga trochę zręczności. Jeśli
pechowo jakieś punkty lutownicze się zleją,
proponuję od razu łapać za odsysacz. Blaszki
mają taki kształt, że inaczej dość trudno usu-
nąć z nich tak wykonane zwarcie.

Gdy uda Ci się szczęśliwie przebrnąć

przez etap montażu układu, pozostaje tylko
formalne podpięcie wyświetlacza oraz usta-
wienie zworki PullUP w pozycji ON.

42

Programowanie

Elektronika dla Wszystkich

Rys. 57 Adresowanie w trybie pozio-

mym

Rys. 58 Adresowanie w trybie piono-

wym

Rys. 59 Połączenie wyświetlacza

z AVT3505

Fot. 5 Wyświetlacz i przewód gotowe

do lutowania

Fot. 3 Wyświetlacz wraz z ramką oraz

przygotowanym przewodem

Fot. 4 Złącze wyświetlacza

background image

43

Elektronika dla Wszystkich

Uruchomienie wyświetlacza

Proponuję teraz napisanie szybko programu,
który umożliwi przekonanie się, że „to żyje”.
Projekt jednak będziemy od początku pisać
tak, aby móc go stopniowo rozwijać, aż do
pełnej aplikacji.

Utwórz nowy projekt. W moim przypadku

nazwałem go lcd3310test. Od razu skopiuj
z poprzedniej części plik makra.h. Utwórz
plik definicji sprzętu: harddef.h, części głów-
nej programu: main.c oraz pliki zawierające
funkcje obsługi wyświetlacza: lcd3310.c oraz
lcd3310.h. Pamiętaj o dodaniu obu plików
źródłowych w pliku makefile.

Od razu wypełnij plik harddef.h zgodnie

z listingiem 160.

Do pliku lcd3310.c dodajemy potrzebne

pliki nagłówkowe, zgodnie z listingiem 161.
Dla własnej wygody, w pliku nagłówkowym
dodajemy definicje nazw komend, zgodnie
z listingiem 162. Listing 163 pokazuje pro-
pozycję procedur niskiego poziomu. Założe-
nie jest takie, że linia D/C jest w spoczynku
utrzymywana w stanie wysokim. Jeśli w do-
wolnym momencie wywołamy funkcję
lcd_Send, zostanie to potraktowane jako
wysłanie danych. Jeśli wyślemy komendę,
zaraz po zakończeniu wysyłania linia D/C
powraca w stan wysoki. To założenie uprasz-
cza trochę pisanie programu, jednocześnie
oszczędzając wykonywania dodatkowej
instrukcji przy wysyłaniu danych. Trzeba
wziąć pod uwagę, że statystycznie do

wyświetlacza będziemy wysyłać znacznie
więcej danych niż komend.

Wróć teraz do pliku nagłówkowego.

Zadeklarujemy tutaj obie funkcje: lcd_Send
oraz lcd_Command. Ta druga pojawia się w
pliku nagłówka po to, aby możliwe było
umieszczenie niżej statycznej funkcji
widocznej na listingu 164. Zawartość listingu
powinna pojawić się w pliku lcd3310.h. Sta-
tyczność tej funkcji lcd_GoTo ma spore zna-
czenie dla optymalizacji. Najczęściej będzie
ona wywoływana ze stałymi wartościami x
i y. W takim przypadku wszystkie obliczenia

wykona kompilator, a funkcja zostanie rozwi-
nięta tylko do dwóch wywołań funkcji
lcd_Command.

Teraz jesteśmy gotowi, aby w prosty i czy-

telny sposób przeprowadzić inicjację wy-
świetlacza zgodnie z listingiem 165. Pamiętaj
o umieszczeniu deklaracji funkcji inicjującej
wyświetlacz w pliku nagłówkowym.

Przerwijmy na chwilę pisanie biblioteki

LCD i przejdźmy do pliku głównego. Prosty
kod z listingu 166 umożliwi włączenie
wyświetlacza. Jeśli nie zerujemy pamięci wy-
świetlacza, po włączeniu jej zawartość jest
przypadkowa. Oznacza to w praktyce, że po
wykonaniu aktualnego programu na wyświet-

Idea rozwiązania

Oszczędne sterowanie wyświetlaczem z

telefonu NOKIA3310

Bardzo prawdopodobne, że spotkałeś się już z wyświetla-
czem, który dziś przedstawiam. Ze względu na prostotę
sterowania oraz cenę jest to element dość chętnie stoso-
wany przez elektroników. Większość propozycji sterowa-
nia, jakie udało mi się do tej pory znaleźć, zakładało zało-
żenie w pamięci RAM bufora danych wyświetlacza oraz
ich przesyłanie dopiero po wcześniejszym przygotowaniu
obrazu. Jest to rozwiązanie bardzo wygodne, dające
ponadto możliwości rysowania dość złożonych figur.

Problemem w rysowaniu na naszym wyświetlaczu jest to,
że nie możemy odczytać wartości wcześniej wpisanej do
komórki pamięci. Chcąc narysować jakiś obiekt, zmienia-
my zawsze całe 8 pikseli.

Jeśli jednak będziemy chcieli pisać zawsze bezpośred-

nio na wyświetlacz, uzyskamy program zużywający mało
zasobów. Ponadto program ten często okaże się szybszy
od programu korzystającego z bufora. Chcę pokazać dziś,
że obsługa naszego wyświetlacza ma szanse zmieścić się
nawet do procesora ATtiny2313.

Bez bufora – bez czyszczenia

Gdy wszystkie dane są wysyłane na ekran bez wcześniej-

szego buforowania, trzeba zdać sobie sprawę z pewnego
nieoczywistego ograniczenia. Jeśli będziemy wypisywać
dane na wyświetlaczu w trybie ciągłym (na przykład war-
tości pomiarów), nie powinniśmy przed każdym wypisa-
niem czyścić wyświetlacza. Takie działanie sprawi, że
wypisywany tekst stanie się nieczytelny (efekt na
wyświetlaczu LCD jest gorszy niż migotanie – obraz staje
się zupełnie nieczytelny). Jeśli piszemy bezpośrednio na
ekran, należy unikać jego czyszczenia.

Zauważ, że gdybyśmy mieli bufor obrazu w pamięci

RAM, także nie czyścilibyśmy wyświetlacza. Czyszczony
byłby najwyżej bufor, a następnie przesyłany na zapełnio-
ny wyświetlacz.

Listing 160 Plik harddef.h

#ifndef HARDDEF_H_INCLUDED
#define HARDDEF_H_INCLUDED

// LCD

#define LCD_PORT B
#define LCD_RES 2
#define LCD_SCK 7
#define LCD_SD 5
#define LCD_DC 3
#define LCD_SCE 4

#endif /

/HARDDEF_H_INCLUDED

Listing 161 Pliki nagłówkowe w lcd3310.c

#include <avr/io.h>
#include <inttypes.h>

#include "harddef.h"
#include "makra.h"
#include "lcd3310.h"

Listing 162 Definicja komend

// H = X

#define LCDC_FS 0x20

#define LCDC_FS_BASIC 0
#define LCDC_FS_EXTENDED 0x01
#define LCDC_FS_HORADDR 0
#define LCDC_FS_VERTADDR 0x02
#define LCDC_FS_PD 0x04

// H = 0 (BASIC)

#define LCDC_DC 0x08

#define LCDC_DC_BLANK 0
#define LCDC_DC_NORMAL 0x04
#define LCDC_DC_ALLON 0x01
#define LCDC_DC_INVERT 0x05

#define LCDC_XADR 0x80
#define LCDC_YADR 0x40

// H = 1 (EXTENDED)

#define LCDC_TEMP 0x04
#define LCDC_BIAS 0x10
#define LCDC_VOP 0x40

Listing 163 Procedury niskiego poziomu

void

lcd_Send(uint8_t data)

{

uint8_t n;

// SCK w stan niski

PORT(LCD_PORT) &= ~(

1

<<

LCD_SCK);

// Aktywacja interfejsu

PORT(LCD_PORT) &= ~(

1

<<

LCD_SCE);

for

(

n=

8

;

n!=

0

; —

n)

{

// Wyprowadzenie bitu

if

(

data >=

128

)

PORT(LCD_PORT) |=

1

<<

LCD_SD;

else

PORT(LCD_PORT) &= ~(

1

<<

LCD_SD);

// Sygnał zegarowy i przesunięcie

PORT(LCD_PORT) |=

1

<<

LCD_SCK;

data <<=

1

;

PORT(LCD_PORT) &= ~(

1

<<

LCD_SCK);

}

// Wyłączenie interfejsu

PORT(LCD_PORT) |=

1

<<

LCD_SCE;

}

// Wysłanie komendy do wyświetlacza

void

lcd_Command(uint8_t command)

{

PORT(LCD_PORT) &= ~(

1

<<

LCD_DC);

lcd_Send(command);

// natychmiast do trybu danych

PORT(LCD_PORT) |=

1

<<

LCD_DC;

}

Listing 164 Funkcja lcd_GoTo w lcd3310.h

static inline void

lcd_GoTo(uint8_t x, uint8_t y)
{

lcd_Command(LCDC_XADR|x);
lcd_Command(LCDC_YADR|y);

}

Listing 165 Inicjacja wyświetlacza

void

lcd_Init(

void

)

{

// Zerowanie.

PORT(LCD_PORT) &= ~(

1

<<

LCD_RES);

asm volatile

(

„nop\n\t nop\n\t“

::);

PORT(LCD_PORT) |=

1

<<

LCD_RES;

// Wysyłanie sekwencji startowej

lcd_Command(LCDC_FS|LCDC_FS_EXTENDED);
lcd_Command(LCDC_VOP|

72

);

lcd_Command(LCDC_TEMP|

2

);

lcd_Command(LCDC_BIAS|

3

);

lcd_Command(LCDC_FS|LCDC_FS_BASIC|

LCDC_FS_HORADDR);

lcd_Command(LCDC_DC|LCDC_DC_NORMAL);
lcd_GoTo(

0

,

0

);

}

Listing 166 Pierwsze uruchomienie

#include <avr/io.h>
#include <inttypes.h>

#include „harddef.h“
#include „makra.h“
#include „lcd3310.h“

int

main(

void

)

{

// Inicjacja portów

DDR(LCD_PORT) =

1

<<

LCD_RES |

1

<<

LCD_SCK |

1

<<

LCD_SD |

1

<<

LCD_DC |

1

<<

LCD_SCE;

PORT(LCD_PORT) =

1

<<

LCD_SCK |

1

<<

LCD_SD |

1

<<

LCD_DC |

1

<<

LCD_SCE;

lcd_Init();

return

0

;

}

background image

44

Programowanie

Elektronika dla Wszystkich

laczu powinny pojawić się dość fantazyjne
wzory. Jeśli na ekranie nic się nie pojawiło –
skontroluj część sprzętową.

Uwaga: Jeśli w poprzedniej części pisa-

łeś program bootloadera, to aktualnie masz
dwie możliwości wpisania programu do
procesora:

1. Przez bootloader – w takim przypad-

ku, jeśli bootloader został prawidłowo
skonfigurowany, możesz pracować na nim
bez zmian.

2. Przez programator szeregowy

– w takim przypadku pamiętaj o wyzero-
waniu bitu konfiguracyjnego BOOTRST.

Rysowanie obrazka

Gdy tylko udało nam się uruchomić wyświet-
lacz, wszystkie jego możliwości stoją przed
nami otworem. Zacznijmy od prostego ryso-
wania obrazka z pamięci FLASH na ekranie.
Dane z obrazka będą odwzorowywać w bez-
pośredni sposób dane, które mają być prze-
słane do wyświetlacza. Naszym zadaniem
jest jedynie odpowiednie ustawianie adre-
sów oraz przesyłanie danych pobranych
z pamięci. Tak zdefiniowany obrazek w za-
sadzie nie nadaje się do ręcznej edycji. Aby
ułatwić sobie i czytelnikom zadanie, napisa-
łem specjalną aplikację realizującą zamianę
bitmapy na dane inicjujące odpowiednią tab-
licę dwuwymiarową. Program ten będzie
dostępny na stronie Elportalu razem z ko-
dem źródłowym.

Funkcję wyświetlającą tak spreparowane

obrazki przedstawia listing 167. Aby była ona
kompilowana prawidłowo, w pliku lcd3310.h
dołącz nagłówek <avr/pgmspace.h> Funkcja
ta została zbudowana w taki sposób, że umoż-
liwia wyświetlenie w dowolnym miejscu
ekranu obrazka o dowolnym rozmiarze. Nale-
ży zdawać sobie sprawę, że w tak prostym
rozwiązaniu „dowolność” w pionie jest ogra-
niczona przez sposób działania wyświetlacza.
Adres y jest podawany w bajtach, a nie bez-
pośrednio w liniach. Funkcja nie pilnuje tego,
czy obrazek nie wystaje poza obszar ekranu.
Jeśli tak się stanie, obrazek będzie „zawinię-
ty” na drugą stronę wyświetlacza.

Wywołanie funkcji lcd_Load może wyglą-

dać tak jak na listingu 168. W przykładzie
img to dwuwymiarowa tablica utworzona
przez wspomniany program realizujący kon-
wersję. Makro ELEMS nie powinno Ci być
już obce. W tym przypadku umożliwia ono
odzyskanie informacji o wymiarach kopiowa-
nego obrazka na podstawie wymiarów tablicy.

Pisanie tekstu

Rysowanie obrazków daje bardzo ciekawe
efekty. Zmieniając obrazki kilka, kilkanaście
razy na sekundę uzyskamy wrażenie animacji.
Można sobie nawet wyobrazić program, które-
mu taka możliwość wystarczy. Często jednak
cenna okazuje się możliwość napisania dowol-
nego tekstu. Jak już wspominałem, nasz
wyświetlacz nie posiada wbudowanego gene-
ratora znaków. Oznacza to, że każdą literkę
będziemy rysować w podobny sposób, jak
rysowaliśmy dowolny obrazek. Po szczegóły
odsyłam do odpowiedniej ramki. Listing 169
pokazuje funkcję realizującą wyświetlenie jed-
nego znaku. Stąd do wypisania całego tekstu
już prosta droga, co udowadnia listing 170.

Bardziej dociekliwi Czytelnicy zauważą,

że drukujemy napis z pamięci RAM. Zwykle

tworzyliśmy też bliźniaczą funkcję drukującą
napisy bezpośrednio z pamięci FLASH. Tym
razem utworzenie odpowiedniej funkcji pozo-
stawiam chętnym. Jest to bardzo proste zada-
nie.

Wspomniałem o tym, że do końca naszej

tablicy możemy dodać polskie znaki. Raczej
nie ma sensu umieszczać polskich znaków,
tak aby były dostępne bezpośrednio w łańcu-
chach. Lepiej będzie posłużyć się w łańcuchu
podaniem odpowiedniego kodu. Polskie znaki
co prawda znajdują się w tabeli ASCII, ale są
one rozsiane po końcowych kodach. Ostatnia
litera ,ó’ ma kod 0xF3. Oryginalnie nasza tab-
lica kończy się znakiem ,z’ o kodzie 0x7A.

Na pewno jednak w dobry nastrój powinno

wprowadzić nas to, że własnych znaków
możemy zdefiniować w zasadzie dowolną
ilość i nie będzie konieczności stosowania
sztuczek, rodzaju dynamicznego ich przydzie-
lania.

Spróbuj samodzielnie rozszerzyć tablice

o własne znaki. Propozycja rozwiązania,
pojawi się na stronie Elportalu. Aktualna tab-
lica znaków nie będzie rozwijana w ramach
kursu – następnym razem będziemy pisać
w nieco inny sposób.

Sprzętowy SPI

Do tej pory nie wykorzystaliśmy tego, że
procesor zestawu AVT3505 posiada sprzę-
towy interfejs SPI, który może być wyko-
rzystany do komunikacji z wyświetla-
czem. W celach eksperymentalnych pro-
ponuję napisać teraz program w taki spo-
sób, aby umożliwiał przełączanie się mię-
dzy opcją ze sprzętowym i programowym
interfejsem szeregowym. Umożliwi to
porównanie wydajności obu rozwiązań.
Zmiany w funkcji lcd_Send przedstawia
listing 171. Listing 172 przedstawia
natomiast część kodu odpowiedzialną za
inicjację sprzętowego interfejsu SPI.
W ustawionym trybie pracy, przy taktowa-
niu procesora zegarem 8MHz, dane będą
wysyłane interfejsem szeregowym z zega-
rem 4MHz. Jest to maksymalna szybkość,
jaką przyjmuje PCD8544.

Idea rozwiązania

Pisanie tekstu

Najprostszy chyba sposób pisania tekstu na wyświetlaczu
z telefonu NOKIA3310 opiera się na założeniu, że każdy
znak ma ściśle określony wymiar. W naszym przypadku
będzie to 8x5 pikseli. Wszystkie znaki zebrane są w tym
przypadku w sporą tablicę, składającą się z elementów w
postaci pięciu ośmiobitowych liczb.

Przyznam szczerze, że nie tworzyłem tablicy znaków

samodzielnie. W sieci jest wystarczająco dużo kodów
zawierających gotowe tablice. Zawsze istnieje możliwość
dopisania znaków, które będą nam potrzebne, a jest to
dużo łatwiejsze niż tworzenie tablicy znaków od podstaw.

Za każdym razem, gdy trzeba wypisać znak na ekra-

nie, przeprowadzana jest analiza drukowanego symbolu.
Definicja znaków w tablicy zaczyna się od spacji, która
ma kod 32. Brak definicji niższych znaków jest związany
z tym, że w standardzie ANSI są to znaki niedrukowalne.
Z drugiej strony, zakres możliwych do wypisania znaków
jest ograniczony rozmiarem tablicy. Jeśli znak który ma
być wydrukowany, wykracza poza którąkolwiek z tych
granic, jest zamieniany na symbol hash (‘#’).

Gdy do wyświetlacza zostaną przesłane już wszystkie

dane znaku, dodawany jest jeszcze jeden bajt pusty, reali-
zujący odstęp między znakami. Brzmi to prosto? Listingi
169 oraz 170
udowadniają, że to jest proste.

Listing 167 Wczytywanie obrazka z pamięci FLASH

void

lcd_Load(prog_uint8_t* pData, uint8_t x,

uint8_t y, uint8_t sx, uint8_t sy)

{

uint8_t xcnt;

for

(;

sy!=

0

;

sy—)

{

// Ustawienie adresu

lcd_GoTo(x, y);

// Od razu zwiększam y na przyszłość

++

y;

// Przesyłam linię

for

(

xcnt=sx; xcnt!=

0

;

xcnt—)

{

lcd_Send(pgm_read_byte(pData++));

}

}

}

Listing 169 Wypisanie jednego znaku

void

lcd_char(

char

znak)

{

// Sprawdzenie znaku

if

(

znak <

‘ ‘

||

znak > ((

char

)

’ ‘

+

ELEMS(lcd_Font)))

znak =

‘#’

;

// Wysłanie 5 kolejnych bajtów z tablicy

uint8_t n;
prog_uint8_t* pData = lcd_Font[znak -

‘ ‘

];

for

(

n=

0

;

n<

5

;

n++)

{

lcd_Send(pgm_read_byte(pData++));

}

}

Listing 168 Wywołanie funkcji lcd_Load

lcd_Load((prog_uint8_t*)img,

0

,

0

,

ELEMS(img[

0

]),

ELEMS(img));

Listing 170 Wypisanie łańcucha

void

lcd_str(

char

*

str)

{

while

(*

str !=

0

)

{

lcd_char(*str++);

// Wypisanie przerwy

lcd_Send(

0

);

}

}

background image

45

Elektronika dla Wszystkich

Teraz, aby aktywować wykorzystanie

sprzętowego interfejsu, w pliku harddef.h
dodaj wpis widoczny na listingu 173. Jeśli
zechcesz wrócić do opcji korzystającej z
interfejsu programowego, wystarczy wstawić
znak komentarza na początku dodanej linii.

Po napisaniu nowej wersji programu wyko-

nałem doświadczenie mające na celu spraw-
dzenie czasu wykonania instrukcji lcd_Send.
Zmierzony czas uwzględnia skok oraz powrót
z podprogramu. Wersja sprzętowa, niezależnie
od wysyłanej danej, wymaga 49 cykli na swoje
wykonanie. Czas wykonywania wersji progra-

mowej zależy od wysyłanej wartości.
Dla samych zer wynosi 119, a dla
samych jedynek 127 cykli. Widzimy,
że uzyskaliśmy ponaddwukrotne przy-
śpieszenie wysyłania danych.

Próby usunięcia

ramki z wyświetlacza

Jeśli posiadasz wyświetlacz z ramką,
możliwe, że zechcesz go z tej ramki
wydostać. Ja wpadłem właśnie na taki
pomysł. Chcę jednak w tym punkcie
Cię ostrzec. Ramka zawiera elementy
umożliwiające dobre przyleganie
metalowych kontaktów do wyświet-
lacza. Wystarczy przylutować przewody do
złącza i wszystko działa. Punkty przewodzące,
wykonane na szkle, z którymi należy zapewnić
kontakt, są duże i, pod światło, dość widoczne.
Daje to wrażenie, że łatwo będzie trafić blasz-
kami w odpowiednie miejsce. Ogólnie jest to
prawda. Problem jest na innym poziomie.
Blaszki nie tylko muszą trafić w odpowiednie
miejsca, ale muszą także być odpowiednio
dociśnięte. Osobiście nie udało mi się tego
zapewnić żadnym klejem. W ten sposób
uszkodziłem dwa wyświetlacze. Wydaje się
więc, że jedynym rozsądnym sposobem jest
obcięcie z ramki elementu trzymającego głoś-
nik i klawiaturę, natomiast nieruszanie samego
wyświetlacza. Z drugiej strony, wyświetlacz
wyjęty z ramki prezentuje się znacznie ładniej
(patrz fotografia 6)... same wyświetlacze są
tanie – może ktoś znajdzie sposób ;)

Podsumowanie

Na stronie www znajdzie się program z koda-
mi z dzisiejszego odcinka. Program ten po

starcie wyświetla logo razem z animowaną,
śmiejącą się buzią. Po pewnym czasie ekran
jest czyszczony i wypisywane są trzy linijki
tekstu. Cały program, w wersji z programo-
wym interfejsem SPI, zajął w pamięci 1782B.
Z tego 504B to pamięć zajmowana przez
obrazek startowy, tablica znaków to około
450B. Widać z tego, że prostą wersję obsługi
wyświetlacza telefonu komórkowego można
zmieścić nawet w mikrokontrolerze zawiera-
jącym 2KB pamięci programu.

Poznany dziś wyświetlacz będzie nam tro-

chę jeszcze towarzyszył. Zachęcam do za-
opatrzenia się w ten niezwykle ciekawy ele-
ment, tym bardziej że jego aktualna cena jest
na poziomie czteropaku... koncentratu pomi-
dorowego.

Radosław Koppel

radoslaw.koppel@elportal.pl

Szczegóły techniczne

Sprzętowy interfejs SPI

Nasz procesor wyposażono w sprzętowy interfejs SPI.
Jego wykorzystanie umożliwia znaczące przyspieszenie
transmisji. Poprzez interfejs sprzętowy procesor jest w sta-
nie przesłać jeden bit w ciągu dwóch taktów zegarowych.
Nasza programowa implementacja potrzebuje na to znacz-
nie więcej czasu.

Interfejs SPI posługuje się 4 wyprowadzeniami. Są to

MOSI (Master Output Slave Input – wyjście mastera, wej-
ście slave); MISO (Master Input Slave Output – analo-
gicznie); SCK (Serial ClocK – zegar); /SS (Slave Select –
aktywacja urządzenia typu slave).

Pełna praca magistrali SPI umożliwia działanie wielu

urządzeń na jednej szynie, w tym kilku urządzeń typu
master. Nie będziemy jednak omawiać SPI aż tak dokład-
nie. Aktualnie interesuje nas fakt, że od strony sprzętowej,
interfejs SPI to rejestr przesuwny o konfigurowalnych
możliwościach wyszeregowywania i wszeregowywania
danych. Zajmiemy się jedynie pracą interfejsu w trybie
master. W trybie tym to procesor generuje sygnał zegaro-
wy. Rejestr przesuwny, będący centrum interfejsu, służy
jednocześnie jako wejście oraz wyjście. Dane są wczyty-
wane jednocześnie z ich wysyłaniem. Jeśli więc chcesz
wczytać bajt danych, należy w tym celu wysłać jakąś
pustą wartość (zalecane 0xff lub 0);

Mnogość opcji konfiguracji umożliwia dopasowanie

działania interfejsu do praktycznie każdego urządzenia
wykonawczego. Większość nastaw odbywa się z poziomu

rejestru SPCR. Drugim rejestrem, którym powinniśmy się
zainteresować, jest SPSR. Znajduje się w nim bit umożli-
wiający podwojenie prędkości transmisji w trybie master.

Ostatnim elementem, na jaki

należy zwrócić uwagę, jest konfigu-
racja wyprowadzeń. Okazuje się, że
samo włączenie SPI nie nadpisuje
automatycznie ustawień wszystkich
portów. W trybie pracy jako master,
jedynie wyprowadzenie MISO jest
automatycznie konfigurowane jako
wejście. O konfiguracje pozostałych
wyprowadzeń powinniśmy zadbać
samodzielnie. Szczególna uwaga
należy się tutaj wyprowadzeniu /SS.

Uwaga: w trybie pracy jako

master, może nas spotkać pewna
zaskakująca niespodzianka dotyczą-
ca wyprowadzenia /SS. Jeśli chce-
my traktować wyprowadzenie /SS
jako wyjście do wybrania odbiorni-
ka, interfejs SPI nie ma jakiegokol-
wiek wpływu na to wyprowadzenie
– musimy sterować nim samodziel-
nie. Jednak gdy nierozważnie usta-
wimy je jako wejście, okaże się,
że z chwilą pojawienia się na nim
stanu niskiego, interfejs SPI zosta-
nie natychmiast przełączony w tryb

slave. Po takim przełączeniu ponowne wejście w tryb
master wymaga programowego ustawienia bitu MSTR
w rejestrze SPCR.

Listing 171 Wykorzystanie sprzętowego SPI

void

lcd_Send(uint8_t data)

{

#if defined LCD_HARDWARE_SPI

PORT(LCD_PORT) &= ~(

1

<<

LCD_SCE);

SPDR = data;

while

(!(

SPSR &

1

<<

SPIF)) {}

PORT(LCD_PORT) |=

1

<<

LCD_SCE;

#else

(...)

#endif

}

Listing 172 Konfiguracja sprzętowego SPI

int

main(

void

)

{

// Inicjacja portów

DDR(LCD_PORT) = (...)
PORT(LCD_PORT) = (...)

#if defined LCD_HARDWARE_SPI

// Aktywacja interfejstu SPI

SPCR =

1

<<

SPE |

0

<<

DORD |

1

<<

MSTR |

0

<<

CPOL |

0

<<

CPHA;

SPSR =

1

<<

SPI2X;

#endif

(...)

Listing 173 Wpis w pliku harddef.h włączający sprzęto-

wy SPI

#define LCD_HARDWARE_SPI

Fot. 6 wyświetlacz wyjęty z ramki


Wyszukiwarka

Podobne podstrony:
kursC czesc007
kursC czesc006
kursC czesc001
kursC czesc003
kursC czesc006a przeprowadzka
kursC czesc000 programowanie
kursC czesc018
kursC czesc008
kursC czesc002
kursC czesc011
kursC czesc010
kursC czesc007
kursC czesc018

więcej podobnych podstron