K U R S
Mikrokontrolery z rdzeniem ARM,
część 13
Porty GPIO
W poprzednich odcinkach zajmowaliśmy się układami peryferyjnymi tlacza LCD. Została ona zadeklarowana
następująco:
mającymi bezpośredni wpływ na pracę rdzenia mikrokontrolera.
void PortSend(unsigned char data,bo-
Omówiliśmy także przykładowy plik startowy konfigurujący powyższe
ol cmd=false);
układy oraz inicjalizujący pamięć mikrokontrolera zgodnie ze
Jako parametr data przekazujemy in-
standardem ANSI C/C++.
strukcję lub daną, którą chcemy wysłać
Tematem bieżącego odcinka będą porty wejścia wyjścia (GPIO)
do wyświetlacza LCD. Gdy parametr
mikrokontrolerów LPC213x, które umożliwiają bezpośrednie
cmd przyjmie wartość false, oznacza to,
sterowanie układami podłączonymi do wyprowadzeń mikrokontrolera.
że liczba przekazana jako data będzie
zinterpretowana jako znak do wyświe-
//Pin E P0.30
Program drugi wyświetlacz tlenia, w przeciwnym przypadku przesła-
static const unsigned int E =
0x40000000;
LCD na dana będzie stanowić rozkaz. W ję-
//Pin RW P0.31
Kolejnym programem jaki napisze- zyku C++ możemy deklarować metody
static const unsigned int RS =
0x80000000;
my w ramach ćwiczeń z portami GPIO i funkcje z parametrami domyślnymi.
//Maska danych
będą procedury obsługi znakowego wy- W przypadku, gdy wywołamy funkcję
static const unsigned int DMASK =
0x00FF0000;
świetlacza LCD (HD44180). Procedury bez drugiego argumentu parametr cmd
//Domyslne sprzetowe
te będziemy intensywnie wykorzystywać przyjmie wartość false, natomiast gdy
static const unsigned int DELAY_HW
= 15;
w dalszej części kursu. W różnych cza- drugi parametr będzie określony pod-
//Opoznienie komend
sopismach o tematyce elektronicznej ob- static const unsigned int DELAY_CMD czas wywołania, argument domyślny
= 3000;
sługa znakowego wyświetlacza LCD była będzie ignorowany. Mechanizm ten zo-
//Opoznienie dla CLS
static const unsigned int DELAY_CLS
poruszana wielokrotnie, dlatego aby nie stał stworzony w celu zastąpienia funk-
= 30000;
powielać tych samych schematów tym cji ze zmienną listą argumentów (& )
//Komendy wyswietlacza
enum {CLS_CMD=0x01,HOME_
razem biblioteka ta zostanie napisana znaną z języka C. Pozwala on zapewnić
CMD=0x02,MODE_CMD=0x04,ON_CMD=0x08,
w nieco odmienny sposób za pomocą większą kontrolę nad przekazywany-
SHIFT_CMD=0x10,FUNC_CMD=0x20,CGA_
CMD=0x40,DDA_CMD=0x80};
programowania obiektowego C++. W ze- mi argumentami. Działanie tej metody
//Komenda MODE
stawie ZL6ARM linie D0.D7 LCD pod- enum {MODE_R=0x02,MODE_L=0,MODE_
jest następujące. Najpierw sygnał E jest
MOVE=0x01};
łączone są do portu P1.16& P1.23. Linia ustawiany w stan 0, w efekcie czego
//Komenda SHIFT
E jest podłączona do portu P0.30, na- enum {SHIFT_DISP=0x08,SHIFT_ wyświetlacz ignoruje wszystkie stany
R=0x04,SHIFT_L=0};
tomiast RS do portu P0.31. W zestawie pojawiające się na liniach danych wy-
//Komenda FUNC
enum {FUNC_8b=0x10,FUNC_4b=0,FUNC_
niestety nie przewidziano możliwości świetlacza. Linie D0..D7 wyświetlacza
2L=0x08,
sterowania linią R/W przez co niemoż- LCD są zerowane poprzez ustawienie
FUNC1L=0,FUNC_5x10=0x4,FUNCx7=0};
};
liwe jest odczytywanie stanu wyświetla- bitów 16:23 w rejestrze IO1CLR. Do
cza, dlatego po wysłaniu każdego znaku Umieszczono tu także dwie me- portu IO1SET przesyłana jest zawartość
i rozkazu musimy odczekać pewien czas tody: Delay, odpowiedzialną za ge- zmiennej data przesuniętej o 16 bitów
tak aby wybrana operacja została wyko- nerowanie opóznień oraz PortSend w lewo. W wyniku tych dwóch opera-
nana. Prawie wszystkie komendy wy- wysyłającą bajt danych do wyświe- cji linie P1.16..P1.23 przyjmują wartość
konywane są w czasie do 120 ms poza tlacza Lcd. Pętla opózniająca zosta- zgodną z zawartością zmiennej data bez
rozkazem czyszczenia wyświetlacza, któ- ła napisana w asemblerze, aby było zmiany pozostałych bitów portu.
//E=0
ry może zająć maksymalnie 4,8 ms. Za możliwe dokładne określenie czasu
LCDCCLR = E;
obsługę LCD odpowiedzialna jest klasa jej wykonania. Jako argument meto-
//Data = 0;
LCDDCLR = DMASK;
CLcdDisp, której deklaracja znajduje się dy podajemy liczbę, która następnie
//Wyslij dane
w pliku CLcdDisp.h, natomiast definicja jest ładowana do któregoś z rejestrów
LCDDSET = ((unsigned int)data) <<
16;
została umieszczona w pliku CLcdDisp. ogólnego przeznaczenia w którym na-
c. Metody (funkcje) i obiekty (zmienne) stępuje cykliczne odejmowanie liczby Po przesłaniu danych na linie D0...
zadeklarowane z modyfikatorem private jeden, aż do momentu, gdy rejestr D7 następuje ustawienie linii RS w od-
mogą być używane tylko wewnątrz kla- ten osiągnie wartość 0. powiedni stan w zależności od tego, czy
void CLcdDisp::Delay(unsigned int
sy, co zapewnia ukrycie ich przed użyt- dane przesłane na magistrale zinterpre-
del)
kownikiem końcowym. W sekcji tej za- towane zostaną jako rozkaz (stan wy-
{
asm volatile
pisano stałe związane z wyświetlaczem soki), albo znak do wyświetlenia (stan
(
LCD, takie jak przypisanie bitów odpo- niski)
dloop%=:
subs %[del],%[del],#1\t\n
//Skasuj lub ustaw RS
wiedzialnych za linie E i RW wyświe-
bne dloop%=\t\n
if(cmd) LCDCCLR = RS;
tlacza oraz stałe związane z komendami : :[del] r (del)
else LCDCSET = RS;
);
kontrolera LCD. Następnie na linii E generowany
}
//Funkcja opozniajaca
jest dodatni impuls, w wyniku którego
void Delay(unsigned int del);
//Wysyla do portu
Metoda PortSend służy do wysyłania następuje zapisanie danych lub instruk-
void PortSend(unsigned char
pojedynczego bajtu danych do wyświe- cji do wyświetlacza LCD.
data,bool cmd=false);
Elektronika Praktyczna 12/2006
109
K U R S
//Ustaw Enable
wywołana metoda Write, której argument umożliwia tworzenie operacji łań-
LCDCSET = E;
Delay(DELAY_HW);
jest typu int. Poszczególne metody są cuchowych. W programie stworzono
//Skasuje enable
LCDCCLR = E; bardzo podobne, przedstawię tutaj me- także dodatkową klasę pos, której
Wszystkie metody zadeklarowane todę Write wypisująca łańcuch tekstowy. przesłanie do klasy wyświetlacza
jako public dostępne są dla użytkowni- void CLcdDisp::Write(const char
LCD spowoduje ustawienie kursora
*str)
ka i stanowią zewnętrzny interfejs kla- na wybranej pozycji. Definicja tej
{
while(*str)
sy. Klasa CLcdDisp zawiera następujące klasy jest następująca:
{
class pos
składowe publiczne:
PortSend(*str++);
{
Delay(DELAY_CMD);
public:
public:
}
CLcdDisp();
pos(unsigned char x,unsigned char
}
~CLcdDisp();
y):mx(x),my(y) {}
void Write(const char *str);
Działanie tej metody polega na
unsigned char mx,my;
void Write(char zn);
};
odczytaniu pojedynczego znaku, prze-
void Write(unsigned int licz);
//Wyczysc wyswietlacz
pisaniu jego zawartości do wyświe- Klasa ta zawiera tylko dwa pola
void Clear(void);
//Zalacz wylacz kursor tlacza LCD za pomocą metody Port- określające pozycję kursora na wy-
void SetCursor(unsigned char cmd);
Send oraz odczekaniu około 40 ms na świetlaczu oraz konstruktor, który
void GotoXY(unsigned char
x,unsigned char y); przesłanie znaku. Następnie wskaz- przyjmuje jako argumenty pozycję
template
CLcdDisp& opera-
nik jest zwiększany o jeden i wysy- kursora oraz przepisuje je do mx
tor <<(T obj)
{
łany jest kolejny znak. Dzieje się oraz my.
Write(obj);
tak do czasu, gdy zostanie wykry- Dla obiektu klasy pos stworzony
return *this;
}
ty znak 0 będący symbolem końca jest osobny operator <<, który wy-
CLcdDisp& operator <<(pos obj)
łańcucha. Metoda Clear() umożliwia wołuje metodę GotoXY() przesuwając
{
GotoXY(obj.mx,obj.my);
wyczyszczenie zawartości wyświe- kursor wyświetlacza LCD do odpo-
return *this;
} tlacza, natomiast metoda GotoXY() wiedniej pozycji zawartej w zmien-
CLcdDisp jest domyślnym konstruk- umożliwia przejście do wybranej po- nych mx, my.
CLcdDisp& operator <<(const pos
torem klasy i jest on wywoływany pod- zycji kursora. W języku C++ możemy
&obj)
czas tworzenia nowego obiektu danej zmieniać znaczenie operatorów, co
{
GotoXY(obj.mx,obj.my);
klasy. W konstruktorze napisano proce- nosi nazwę przeciążania operatorów.
return *this;
durę inicjalizacji wyświetlacza LCD. Ini- Korzystając z tej techniki napiszemy }
cjalizacja rozpoczyna się od ustawienia własne wersje operatora << umoż- W pliku testlcd.cpp znajduje się
linii RS, E i D0...D7 oraz odczekania liwiające wypisywanie liczb i zmien- bardzo prosty programik korzystający
kilkudziesięciu milisekund na ustabilizo- nych na przykład tak: l c d < < z klasy CLcdDisp, wypisujący na wy-
wanie napięcia zasilającego: Zmienna= << zm; Napiszemy świetlaczu LCD stan wciśniętego kla-
//Konstruktor klasy obslugi wyswie- także bardzo prostą klasę pos, której wisza S1..S4.
tlacza LCD
CLcdDisp cout;
przekazanie do obiektu klasy wyświe-
CLcdDisp::CLcdDisp()
{
tlacza LCD spowoduje przesunięcie
//Funkcja glowna main
//Linie E i RS jako wyjsciowe
int main(void)
kursora na wybraną pozycję np. tak:
LCDCDIR |= E|RS;
{
LCDCCLR = E|RS;
lcd << pos(1,2) << 2 li- cout << Witaj ! ;
//Linia danych jako wyjsciowa
cout << pos(1,2) << IO0PIN= ;
LCDDDIR |= DMASK; nia ; Wszystkie operatory korzysta-
unsigned int sk;
Delay(100000);
ją z wcześniej zdefiniowanych metod while(1)
{
Następnie trzykrotnie wysyłana Write() oraz GotoXY() i są zdefinio-
sk = (~IO0PIN >> 4) & 0x0f;
cout << pos(8,2)<< sk << ;
jest komenda ustawiająca wyświetlacz wane w deklaracji klasy zapewniając
}
w tryb 8-bitowy: rozwinięcie ich w miejscu wywołania.
}
PortSend(FUNC_CMD|FUNC_8b,true);
Operator wysyłający dane do strumie- Działanie programu rozpoczyna się
Delay(DELAY_CLS);
nia zdefiniowano w sposób następują- od utworzenia obiektu klasy CLcdDisp
PortSend(FUNC_CMD|FUNC_8b,true);
Delay(DELAY_CMD);
cy: o nazwie cout. W funkcji main() wypisy-
PortSend(FUNC_CMD|FUNC_8b,true);
template CLcdDisp& operator
Delay(DELAY_CMD); wany jest napis powitalny, a następnie
<<(const T &obj)
po czym następuje ustawienie wy- {
program wchodzi w pętlę nieskończoną,
Write(obj);
świetlacza tak, aby pracował w rozdziel- która odczytuje stan klawiszy S1...S4
return *this;
}
czości 5x7, załączenie wyświetlacza, oraz przepisuje ich zawartość do zmien-
wyczyszczenie oraz ustawienie kursora Zastosowano tutaj kolejną ce- nej sk, maskując pozostałe nie istotne
w pozycji początkowej. Kolejnymi me- chę języka C++ mianowicie funkcję bity. Następnie na pozycji 8,2 wypisy-
todami publicznymi są metody Write wzorcową. Mechanizm ten umożliwia wany jest stan zmiennej sk. Pomimo,
służące do wypisania na wyświetlaczu zadeklarowanie tylko jednej funkcji że mechanizmy tworzące operatory są
pojedynczego znaku, łańcucha tekstowe- niezależnie od argumentów jakie ona trochę zawiłe, korzystanie z samej bi-
go, oraz liczby stałoprzecinkowej. Uważ- przyjmuje. Po prostu w momencie blioteki obsługi wyświetlacza LCD jest
nego Czytelnika może zdziwić fakt, że wywołania funkcji z danym parame- bardzo proste. Czytelnikom znającym
metody o takiej samej nazwie zadekla- trem, kompilator na etapie kompila- język C++ proponuję napisanie klasy
rowane są kilkukrotnie. Jest to kolejna cji tworzy daną funkcję zamieniając o nazwie clear, której przekazanie do
zaleta języka C++, w którym możemy T na konkretny typ danych na przy- klasy CLcdDisp za pomocą operatora
deklarować funkcję i metody o takich sa- kład int. W wyniku tej czynności nie >> spowoduje wyczyszczenie wyświe-
mych nazwach. Kompilator w zależności musimy pisać trzech osobnych wersji tlacza LCD.
od argumentu przekazanego do metody operatora dla każdego typu danych: Lucjan Bryndza, EP
wywoła odpowiednią funkcję Write. Np. char*, int, char. Operator zwraca lucjan.bryndza@ep.com.pl
jeżeli napiszemy lcd.Write(100), zostanie wskaznik do klasy obiektu LCD, co
Elektronika Praktyczna 12/2006
110
Wyszukiwarka
Podobne podstrony:
Mikrokontrolery ARM cz1
Mikrokontrolery ARM cz10
Mikrokontrolery ARM cz14
Mikrokontrolery ARM cz8
Mikrokontrolery ARM cz12
Mikrokontrolery ARM cz15
Mikrokontrolery ARM cz21
Mikrokontrolery ARM cz19
Mikrokontrolery ARM cz3
Mikrokontrolery ARM cz6
Mikrokontrolery ARM cz22
Mikrokontrolery ARM cz18
Mikrokontrolery ARM cz18
Mikrokontrolery ARM cz11
Mikrokontrolery ARM cz17
Mikrokontrolery ARM cz5
Mikrokontrolery ARM cz20
Mikrokontrolery ARM cz7
Mikrokontrolery ARM cz9
więcej podobnych podstron