Laboratorium Systemów wbudowanych Ćwiczenie nr l Podstawy

Transkrypt

Laboratorium Systemów wbudowanych Ćwiczenie nr l Podstawy
Laboratorium Systemów wbudowanych
Wyższa Szkoła Zarządzania i Bankowości, Informatyka studia inżynierskie
Ćwiczenie nr l
Podstawy programowania mikrokontrolerów rodziny AVR8
opracował dr inż. Wojciech Zaborowski
Plan ćwiczenia:
Ćwiczenie wykonywane jest z wykorzystaniem zestawu uruchomieniowego ZL15AVR
firmy Kamami. Zestaw uruchomieniowy zbudowany jest w oparciu o mikrokontroler
ATMEL Atmega32. Szczegółowe informacje na temat budowy zestawu można uzyskać
z jego dokumentacji (http://www.kamami.pl/dl/zl15avr.pdf). Do programowania
mikrokontrolera wykorzystany zostanie pakiet oprogramowania AVR Studio 4 wraz
z pakietem WinAVR. Połączenie tych dwóch pakietów pozwala w prosty sposób
programować mikrokontrolery rodziny AVR z poziomu języka C z wykorzystaniem
graficznego interfejsu użytkownika.
Zestaw jest zasilany z portu USB komputera. Dodatkowo do programowania
mikrokontrolera wykorzystuje się dedykowany programator z interfejsem JTAG
(ZL15PRG) podłączony do drugiego portu USB.
1 Zadanie 1
Uruchomić środowisko AVR Studio 4. Skopiować i rozpakować na lokalny dysk projekt o
nazwie LED. Przy pomocy polecenia Project→Open Project wczytać projekt (wczytać plik
o nazwie led.aps).
W pliku źródłowym led.c w sekcji komentarza opatrzonej słowem DESCRIPTIONS
znajduje się opis połączeń, jakie należy wykonać przy pomocy dostępnych przewodów.
Wykonanie wymienionych połączeń jest niezbędne do poprawnego uruchomienia
przykładu i zaobserwowania efektów jego działania.
UWAGA !!! – Wszelkie połączenia pomiędzy urządzeniami peryferyjnymi
a mikrokontrolerem mogą być dokonywane wyłącznie przy odłączonym zasilaniu.
Po wykonaniu połączeń opisanych w sekcji DESCRIPTION należy poprosić osobę
prowadzącą zajęcia o sprawdzenie poprawności ich wykonania. Dopiero po uzyskaniu
zgody można włączyć zasilanie zestawu.
Aby stworzyć pliki niezbędne do zaprogramowania mikrokontrolera, należy
przeprowadzić kompilację projektu. Wykonuje się to poleceniem Build→Build lub z
wykorzystaniem klawisza skrótu F7. Po poprawnej kompilacji projektu można
przystąpić do programowania wewnętrznej pamięci FLASH mikrokontrolera.
Jeśli jest to pierwsza próba programowania, należy wcześniej przeprowadzić
konfigurację programatora/debugera. Dokonuje się tego przy pomocy polecenia
Laboratorium Systemów Wbudowanych – Wyższa Szkoła Zarządzania i Bankowości w Krakowie
Tools→Program AVR→Connect… Wybranie tego polecenia powoduje pojawienie się okna
wyboru przedstawionego na Rys. 1. (Uwaga – w niektórych sytuacjach poprawne
skonfigurowanie programatora może wymagać uprawnień administratora na danym
komputerze – w takiej sytuacji należy się zwrócić o pomoc do prowadzącego zajęcia )
Rys. 1 Okno konfiguracji programatora
Z listy programatorów znajdujących się w oknie po lewej stronie należy wybrać
JTAG ICE. Port komunikacyjny pozostawiamy na Auto, lub jeśli było wybrane inne
ustawienie wybieramy Auto. Następnie wciskamy przycisk Connect… .
Jeśli
połączenia
między
komputerem,
programatorem
oraz
zestawem
uruchomieniowym funkcjonują poprawnie i konfiguracja przebiegła prawidłowo na
ekranie pojawi się następujące okno:
Rys. 2 Okno programatora w trybie JTAG
Najważniejsze opcje i polecenia znajdują się na zakładce Program. Przycisk Erase Device
powoduje wykasowanie wewnętrznej pamięci FLASH mikrokontrolera (co jest
równoznaczne z usunięciem zapisanego w niej programu).
2
Laboratorium Systemów Wbudowanych – Wyższa Szkoła Zarządzania i Bankowości w Krakowie
Do zaprogramowania tej pamięci wykorzystywać będziemy sekcję Flash. Powinna w niej
być zaznaczona opcja Input HEX File (jak na Rys. 2). W polu obok należy wskazać plik,
którym ma zostać zaprogramowana pamięć FLASH. Zwykle taki plik wynikowy posiada
nazwę taką jak nazwa projektu, rozszerzenie .hex . Kompilator tworzy ten plik
w podkatalogu ./default znajdującym się w katalogu z plikami projektu. Przed
programowaniem należy zwrócić uwagę czy wskazany jest właściwy plik
stanowiący rezultat kompilacji projektu nad którym aktualnie pracujemy, a nie
przypadkowy plik mogący być pozostałością po pracy innych grup. Po wciśnięciu
przycisku Program pamięć FLASH jest zapisywana zawartością pliku .hex i następuje
automatyczne uruchomienie wczytanego programu, co w przypadku projektu led
powinno być widoczne w postaci zapalających się i gasnących diod świecących D0-D7.
Po prawidłowym wykonaniu wszystkich etapów związanych z uruchomieniem przy
kładowego projektu o nazwie led dokonać modyfikacje w programie tak aby uzyskać
efekt wędrującego światła (zapalamy diodę D0, w kolejnym kroku zapalamy diodę D1 i
gasimy D0, w kolejnym zapalamy D2 i gasimy D1 itd. gdy zapalimy diodę D7 w kolejnym
kroku zapalamy D6 i gasimy D7 itd. aż dojdziemy do diody D0.
2 Zadanie 2 – obsługa wejść i wyjść binarnych
Punktem wyjścia będzie projekt o nazwie buzzer. W pierwszej kolejności należy
rozpakować pliki umieszczone w archiwum buzzer.zip. Następnie wykonać niezbędne
połączenia i zaprogramować mikrokontroler.
Wykonać zestaw eksperymentów pozwalający określić w jaki sposób kontroluje się
wysokość i czas trwania generowanych dźwięków.
Odłączyć zasilanie. Wykonać dodatkowe połączenia
Podłączyć wyjścia
czteroprzyciskowej klawiatury SW0÷SW3 znajdujące się na złączu Con19 do
wyprowadzeń portu PB0÷PB3 mikrokontrolera (Con16) w następujący sposób:
SW0→PB0, SW1→PB1, SW2→PB2, SW3→PB3.
Rozbudować projekt buzzer aby w zależności od wciśniętego przycisku generowany był
dźwięk o różnych parametrach.
Z punktu widzenia mikrokontrolera działanie przycisków SW0-SW3 jest następujące:
• gdy przycisk nie jest wciśnięty, na linię portu, do której przycisk jest podłączony
podawany jest stan wysoki (mikrokontroler „widzi” tą linie jako 1).
• gdy przycisk jest wciśnięty, na linię portu do której jest podłączony podawany
jest stan niski (mikrokontroler „widzi” tą linie jako 0).
Zestaw przydatnych wiadomości na temat programowania mikrokontrolerów rodziny
AVR8 z użyciem kompilatora AVR-GCC (wykorzystywanego w pakiecie AVR Studio 4)
można znaleźć pod adresem http://hobby.abxyz.bplaced.net/index.php?pid=4&aid=2.
Linie we/wy mikrokontrolera ATmega32 pogrupowane są w cztery ośmiobitowe porty
A, B, C, D. Do obsługi tych portów wykorzystywane są trzy rejestry specjalne, oddzielne
dla każdego portu:
• rejestr kontroli kierunku portu DDRx,
3
Laboratorium Systemów Wbudowanych – Wyższa Szkoła Zarządzania i Bankowości w Krakowie
• wykorzystywany już wcześniej rejestr wyjściowy PORTx
• rejestr wejściowy PINx
(za x należy wstawić odpowiednią nazwę portu. I tak dla Portu A mamy dedykowane
rejestry PORTA, PINA, DDRA itp.). Pozwala to praktycznie dowolnie konfigurować
poszczególne linie.
Odczytywanie stanu poszczególnych linii portów wiąże się z manipulacjami na
pojedynczych bitach. W związku z tym warto przypomnieć sobie w jaki sposób i
z użyciem jakich operatorów języka C takie manipulacje można wykonywać.
W języku C jest sześć operatorów bitowych:|,&,^,<<,>>,~. Zasadę ich działania
najprościej jest objaśnić na przykładach. Liczby używane w przykładach przedstawione
są w postaci dwójkowej.
operator "|" - bitowa alternatywa lub inaczej suma logiczna (OR)
01010101
|
00110011
=
01110111
operator "&" - bitowa koniunkcja lub inaczej iloczyn logiczny (AND)
01010101
&
00110011
=
00010001
operator "^" - bitowa alternatywa wykluczająca (XOR)
01010101
^
00110011
=
01100110
operator "<<" - przesunięcie w lewo
1 0 0 1 1 0 0 1 << 3 = 1 1 0 0 1 0 0 0
(argument po "<<" określa o ile bitów należy przesunąć. Przy przesuwaniu o każdy bit,
na najmniej znaczącej pozycji wpisywana jest wartość 0)
operator ">>" - przesunięcie w prawo
1 0 0 1 1 0 0 1 >> 5 = 0 0 0 0 0 1 0 0
(argument po ">>" określa o ile bitów należy przesunąć. Przy przesuwaniu o każdy bit,
na najbardziej znaczącej pozycji wpisywana jest wartość 0)
operator "~" - dopełnienie jedynkowe lub inaczej negacja każdego bitu
~
10011001
=
01100110
Aby móc odczytać stan przycisków SW0-3 podłączonych do linii PB0-PB3
mikrokontrolera musimy zacząć od odpowiedniego skonfigurowania portu PB.
Wykonuje się to poprzez wpisanie do rejestru DDRB odpowiedniej wartości. Zasady
konfiguracji linii portów są identyczne dla każdego z nich. Wpisanie do rejestru DDRx,
na odpowiadającej danemu wyprowadzeniu pozycji bitowej wartości 1, konfiguruje tą
linię jako wyjście, natomiast umieszczenie tam wartości 0 ustawia linię jako wejście.
4
Laboratorium Systemów Wbudowanych – Wyższa Szkoła Zarządzania i Bankowości w Krakowie
(polecenie DDRB = 0x0F; konfiguruje cztery starsze linie – PB4-PB7 jako wejścia, a
cztery młodsze linie – PB0-PB3 jako wyjścia).
Odczyt stanu linii wejściowych portu wykonuje się poleceniem PINx :
DDRB = 0x00; // konfiguracja wszystkich linii PB jako wejscia
przyciski = PINB; // przypisanie zmiennej wynik aktualnego
// linii portu PB stanu
Jak wspomniano wcześniej, wciśnięcie przycisku powoduje, że na odpowiednim bicie w
rejestrze PINx jest ustawiana wartość 0. Aby zatem stwierdzić fakt wciśnięcia
któregokolwiek przycisku należy sprawdzić, które bity w momencie odczytu stanu portu
B miały wartość 0 (powiedzmy, ze będziemy rozważać wciśnięcie przycisku S2
podłączonego do linii PB2).
Pierwszym krokiem jest odrzucenie zbędnych informacji o stanie pozostałych linii
portu. Najczęściej stosowanym rozwiązaniem jest tu wyzerowanie wszystkich bitów
z wyjątkiem tego, który nas interesuje (w rozważanym przykładzie interesuje nas stan
linii PB2 odwzorowywany na drugim bicie wartości odczytanej z portu B – dla
przypomnienia bity w bajcie numerujemy od 0).
Wyzerowania bitów dokonuje się poprzez operację iloczynu logicznego (operator &) na
odczytanej poleceniem PINB wartości z tzw. maską. W rozważanym przypadku maska
posiada wyłącznie jeden bit o wartości 1 na pozycji, która ma pozostać nie zmieniona.
Na pozostałych pozycjach bitowych umieszczone są zera. Zatem dla sprawdzenia stanu
linii PB2 maska będzie miała wartość 0b00000100 lub 0x04 w zapisie szesnastkowym.
Stan przycisku S2 podłączonego do portu PB2 można zatem ustalić, jako wynik
następującej operacji:
przycisk_s2 = przyciski & 0b00000100; //w zm. przyciski
// przechowywany jest stan portu B odczytany wcześniej
// poleceniem PINB
jeśli zmienna przycisk_s2 przyjmie wartość 0 oznaczać to będzie, że bit 2 w rejestrze
PINB miał wartość 0 co prowadzi do wniosku, że przycisk S2 był wciśnięty. Jeśli
natomiast wynik tej operacji będzie różny od zera oznacza to, że przycisk wciśnięty nie
był.
Aby nie marnować pamięci mikrokontrolera na deklaracje niepotrzebnych zmiennych,
sprawdzenia zwykle dokonuje się za pomocą pojedynczej instrukcji if:
if ( (przycisk_s2 & 0b00000100) == 0 )
{
// tu będzie procedura obsługi naciśnięcia przycisku S2
}
lub jeszcze prościej
if (!((przyciski &0b00000100)))
{
// tu będzie procedura obsługi naciśnięcia przycisku S2
}
5
Laboratorium Systemów Wbudowanych – Wyższa Szkoła Zarządzania i Bankowości w Krakowie
3 Zadanie 3 – Ciekłokrystaliczny wyświetlacz znakowy
Znakowy wyświetlacz LCD jest często stosowanym i stosunkowo prostym w obsłudze
urządzeniem wyjściowym stosowanym w układach zbudowanych z wykorzystaniem
różnych mikrokontrolerów jednoukładowych. Jedną z najbardziej popularnych
konstrukcji są wyświetlacze oparte o kontroler zgodny HD44780. Kontrolery te
posiadają możliwość sterowania wyświetlaczem ciekłokrystalicznym wyposażonym w
pole odczytowe od 1x8 do 4x40 znaków. W minimalnej konfiguracji podłączenie
wyświetlacza z mikrokontrolerem sterującym wykonywane jest przy użyciu 6 lub 7 linii
we/wy.
Przeanalizować i uruchomić przykładowy projekt umieszczony archiwum char_lcd.zip.
Zapoznać się ze sposobem wyświetlania różnych informacji tekstowych.
3.1
Definiowanie własnych znaków.
LCD ma miejsce dla ośmiu znaków zdefiniowanych przez użytkownika. Znaki te
posiadają kody o wartościach od 00H do 07H. Dane te są przechowywane w pamięci
wyświetlacza, która nazywa się CGRAM. Przed użyciem wzorce znaków muszą być
wysłane do wyświetlacza. Zwykle wykonywane jest to zaraz po jego
inicjalizacji
(wzorce znaków są tracone bezpowrotnie po wyłączeniu zasilania lub inicjalizacji
wyświetlacza).
Każdy zdefiniowany znak wymaga 8 bajtów danych. Ósmym bajtem jest zazwyczaj $00,
ponieważ jest to miejsce przeznaczone dla linii kursora. Standardowa czcionka
wyświetlacza ma 5 pikseli szerokości i 7 pikseli wysokości. Jeden rząd pikseli na samym
dole jest zarezerwowany na podkreślający znak kursora.
Kształt znaku jest taki jaki jest układ zer i jedynek w bicie danych. Jedynka zaświeca
piksel, zero pozostawia piksel zgaszonym. Oto przykład znaku zdefiniowanego przez
użytkownika:
6
Poniżej zamieszczono fragment programu prezentujący w jaki sposób definiuje się
i wykorzystuje własne znaki. (wystarczy go umieścić w przykładowym projekcie
wykorzystywanym w tej części ćwiczenia, zamieniając odpowiedni fragment kodu
źródłowego).
//------------------------------------// main program
//------------------------------------uint8_t znak[] = {0, 10, 10, 0, 17, 14, 6, 0}; //wlasny znak - buzka
int main(void)
{
char temp, i;
LCD_Initialize();
LCD_ProgrammChar(0, znak);
LCD_GoTo(0,0);
LCD_WriteText("- Wlasne znaki -");
// wyswietlenie zdefiniowanego znaku
LCD_GoTo(0,1);
LCD_WriteData(0);
while(1){}
return 0;
}
Na podstawie analizy przykładu przedstawionego powyżej zaprojektować zestaw
polskich znaków diakrytycznych, aby możliwe było poprawne wyświetlenie tekstu
„żółwik”.
Wersja z dnia 2011-10-27 09:57
7