Programowanie mikrokontrolerow 8051 w jezyku C.pdf

(328 KB) Pobierz
Programowanie mikrokontrolerów 8051 w jezyku C - część 1
Programowanie mikrokontrolerów 8051 w jezyku C - część 1
Gdy już skompletujemy nasz warsztat programistyczny i sprzętowy, pora na napisanie pierwszego programu w
języku C. Najbardziej efektowne są programy, których działanie mozna odrazu zobaczyc na własne oczy. Ja
zwykle, gdy zaczynam pracę z nowym mikrokontrolerm, piszę program, który zapala diode LED. W ten sposób
można najszybciej przekonać się o poprawnym działaniu programu. Do mikrokontrolera należy podłączyc 8
diod LED w sposób pokazany na rysunku :
Wartości rezystorów należy dobrać odpwiednio do posiadanych diod LED. Jesli są to diody standardowe, to
rezystancja rezystorów powinna mieć wartość ok. 330 Ohm. Natomiast gdy dysponujemy diodami
niskopądowymi, to rezystancja rezystorów może mieć wartośc ponad 1 kOhm (należy zwrócić także uwagę na
wydajność prądową portów mikrokontrolera).
Operator przypisania .
W tym podtemacie zapozamy się z najczęściej używanym operatorem - operatorem przypisania. Służy on, jak
jego nazwa wskazuje, do przypisania do danej zmiennej wartości innej zmiennej, badź stałej.
// dołączenie pliku nagłówkowego
// zawierajacego definicje rejestrow
// wewnetrznych procesora
#include <8051.h>
// główna funkcja programu
void main(void)
{
// zapisanie do portu P0 liczby 0x55
P0 = 0x55;
// pusta pętla nieskonczona - zatrzymanie porgramu
while(1);
}
Na początku musimy dołączyć plik nagłówkowy z definicjami rejestrów procesora. Gdybyśmy tego nie zrobili,
to nie moglibyśmy odwoływac się do rejestrów procesora za pomocą nazw symbolicznych, tylko przez
podawanie adresu danego rejestru. Takie rozwiązanie byłoby bardzo niewygodne. Ja w naszym przykładzie
dołączyłem plik 8051.h - "bezpieczny" dla większości mikrokontrolerów z rodziny 8051. W przypadku,
gdybyśmy korzystali z rejestrów specyficznych dla danego mikrokontrolera, nie występujących w standartowym
8051, to musimy dołaczyć odpowiedni dla danego mikrokontrolera plik nagłówkowy. W sytuacji, gdy używamy
tylko typowych rejestrów można spokojnie zastosowac plik 8051.h.
Każdy program pisany w języku C musi się składać z głównej funkcji main. Funkcja ta nie zwraca żadnej
wartości ani do funkcji nie jest przekazywana żadna wartość, więc funkcję tą deklarujemy jako void main(void).
Słowo void przed nazwą fukcji mówi kompilatorowi, że funkcja nie zwraca wartości, albo inaczej mówiąc, że
655225430.001.png
zwracana wartośc jest typu void (pusty, brak typu). Słowo void w nawiasach okrągłych po nazwie fukcji mówi
kompilatorowi, że do funkcji nie jest przekazywana żadna wartość. W zależności od tego, jaką funkcę chcemy
napisac i jakie parametry ma ona przyjmować oraz jaką wartość może zwracać, deklaracja funkcji może
przyjmować najróżniejsze postaci :
void funkcja(char x) - funkcja przyjmująca jeden parametr typu char (znak), niezwracająca wartości
void funkcja(char x, char y) - funkca przyjmująca dwa parametry typu char, niezwracająca wartości
char funkcja(void) - funkcja nieprzyjmująca żadnych parametrów, zwracająca wartość typu char
Oczywiście mozliwych kombinacji jest bardzo dużo i zależą one od tego, jakie zadania ma spełniać dana
funkcja.
Gdy już mamy szkielet programu, to nalezy wpisac właściwy kod programu. W naszym pierwszym programie w
zasadzie decydujące dznaczenia ma jeden wiersz programu : P0 = 0x55;. Jest to instrukcja przypisująca do portu
P0 wartość 55h. Objawi się to zapaleniem co drugiej diody LED podłączonej do portu P0. Liczby w systemie
szesnastowym w języku C zapisujemy właśnie w podany sposób : liczbę szesnastkową (bez znaku 'h' na końcu)
nalezy poprzedzic ciągiem znaków '0x'.
Po zapisaniu do portu właściwej wartości należy zatrzymać wykonywanie programu. Najłatwiej dokonać tego
wykorzystując pętlę while. Pętla ta jest wykonywana tak długo, aż jej warunek jest prawdziwy. Poniewaz w
naszym programie warunek pętli jest wartością stałą, reprezentującą prawdę logiczną, to nasza pętla będzie się
wykonywała bez końca.
Funkcje logiczne.
Wyzerowanie odpowiednich linii portu możemy zrealizować także w inny sposób, przez wykonanie iloczynu
logicznego portu ze stałą. Przedstawia to tabela prawdy funkcji AND :
Jeśli potraktujemy zmienną A jako nasz port, a zmienną B jako maskę określającą które bity należy wyzerować,
to będą nas interesować dwa ostatnie wiersze tej tabeli. Jak wynika z tabeli odpowieni bit rejestru zostanie
wyzerowany, gdy odpowiadający mu bit maski będzie miał wartość 0. W przeciwnym przypadku stan bitu
rejestru sie nie zmieni. Rzeczą ważną jest aby pamietać, że odpowiednie bity rejestru, na których chcemy
przerowadzić iloczyn musza być w stanie 1. Kod programu realizującego zerowanie linii portu P0 za pomocą
iloczynu logicznego jest przedstawiony poniżej :
// dołączenie pliku nagłówkowego
// zawierajacego definicje rejestrow
// wewnetrznych procesora
#include <8051.h>
// główna funkcja programu
void main(void)
{
// iloczyn logiczny portu P0 ze stałą 55h
P0 &= 0x55;
// pusta pętla nieskonczona - zatrzymanie porgramu
while(1);
}
Wiekszość kodu jest taka sama jak w programie poprzednim. Wyjaśnienia wymaga jeden wiersz kodu :
655225430.002.png
P0 &= 0x55;
Jest to skrócony zapis nastepującego wyrażenia :
P0 = P0 & 0x55 ;
Język C umozliwia stosowanie skróconych wyrażeń, będących połączeniem operatora przypisania z operatorami
arytmetycznymi, badź logicznymi. Możliwe są następujące skrócone formy zapisu wyrażeń :
Funkcja
Zapis skrócony
Zapis
normalny
dodawanie
a += b
a = a + b
odejmowanie
a -= b
a = a - b
mnożenie
a *= b
a = a * b
dzielenie
a /= b
a = a / b
iloczyn logiczny
a &= b
a = a & b
suma lgiczna
a |= b
a = a | b
przesunięcie w lewo
a <<= b
a = a << b
przesunięcie w
prawo
a >>= b
a = a >> b
alternatywa logiczna
a ^= b
a = a ^ b
Po zerowaniu linii portu nadszedł czas na ich ustawianie. Służy do tego funkcja logiczna OR. Tabela prawdy
funkcji OR jest przedstawiona poniżej :
Tym razem interesują nasz dwa pierwsze wiersze tabeli. Wynika z nich, że aby ustawić odpowniedni bit rejestru,
to odpowiadający mu bit maski musi mieć wartość 1 no i oczywiście bity do ustawienia muszą mieć wartość 0.
Program przedstawiony jest poniżej :
// dołączenie pliku nagłówkowego
// zawierajacego definicje rejestrow
// wewnetrznych procesora
#include <8051.h>
// główna funkcja programu
void main(void)
{
// ustawienie wszystkoch linii portu P0 w stan niski
P0 = 0;
// suma logiczna portu P0 ze stałą F0h
P0 |= 0xF0;
// pusta pętla nieskończona - zatrzymanie porgramu
while(1);
}
W naszym programie pojawił się dodatkowy wiersz kodu :
P0 = 0;
655225430.003.png
Ustawia on wszystkie linie portu P0 w stan niski. Ponieważ chcemy linie portu P0 ustawić więc muszą być w
stanie niskim. Jednak zaraz po zresetowaniu procesora wszystkie pory są ustawiane w stan niski. Musimy
więczaraz przed ich ustawieniem je wyzerować. Samo ustawnienie wybranuch linii w stan wysoki realizuje
poniższy kod :
P0 |= 0xF0;
Ponownie zastosowałem skrócony zapis łaczący operator przypisania z operatorem sumy logicznej.
Programowanie mikrokontrolerów 8051 w języku C - część 2
W drugiej części kursu programowania zapoznamy się z obsługą klawiatury.W tym celu musimy podłączyć do
układu z poprzedniej części kursu, do portu P3, 8 przycisków w sposób pokazany na ponizszym rysunku :
Klawiatura ta działa w następujący sposób : po naciśnięciu przycisku wyprowadzenie portu, do którego jest
podłączony przycisk, jest zwierane do masy, co wymysza na wyprowadzeniu portu stan niski. Port musi
zawierać wewnętrzne rezystory podciągajęce linie portu do szyny zasilającej. W przeciwnym razie będziumy
musieli dołączyć zewnętrzne rezystory podciągające. W typowych mikrokontrolerach rodziny 8051 rezystory te
są wbudowane w każdy port, za wyjątkiem portu P0 a także w bardzo popularnym AT89C2051 za wyjątkiem
linii P1.0 i P1.1. Tak wiec przed podłączeniem klawiatury nalezy się upewnić, że port do którego chcemy
podłaczyc klawiaturę posada rezystory podciągające.
Pierwszy program wykorzystujący klawiaturę jest bardzo prosty i zamieszczony poniżej :
// dołączenie pliku nagłówkowego
// zawierajacego definicje rejestrow
// wewnetrznych procesora
#include <8051.h>
// główna funkcja programu
void main(void)
{
// pętla nieskończona
while(1)
// przepisanie do portu P0 stanu linii portu P3
P0 = P3;
}
Cały program opiera się w zasadzie na nieustannym przepisywaniu stanu linii portu P3 do portu P0. Efektem
tego jest zapalanie odpowiedniej diody LED po naciśnięciu dowolnego przycisku. Zauważmy, że naciśniecie
przycisku wywołuje wymuszenie na odpowiednim wyprowadzeniu portu P3 stanu niskiego, a zapalenie diody
LED jest spowodowane ustawieniem na odpowiednim wyprowadzeniu portu P0 również stanu niskiego. Dzięki
temu możemy po prostu przepisać stan linii portu P3 do portu P0, bez zadnych dodatkowych zabiegów. Jest to
zrealizowane przez instrukcję :
655225430.004.png
P0 = P3 ;
Nie są wymagane żadne dodatkowe zmienne pośredniczące w przesyłaniu danych z portu P3 do portu P0.
Instrukcja warunkowa if
Teraz poznamy bardzo ważną instrukcję warunkową if. Służy ona do warunkowego wykonania fragmentu
programu. Najprostsza wersja instrukcji if wygląda następująco :
if(warunek)
instrukcja;
Jesli warunek ma wartość true (prawda) to wykonywana jest instrukcja, w przeciwnym razie instrukcja nie
będzie wykonana.
Przykład zastosowania instrukcji warunkowe if jest pokazany poniżej :
// dołączenie pliku nagłówkowego
// zawierajacego definicje rejestrow
// wewnetrznych procesora
#include <8051.h>
// główna funkcja programu
void main(void)
{
// Pętla nieskończona
while(1)
{
// jeśli P3.0 jest w stanie niskim
if(P3_0 == 0)
// to ustaw na P0.0 stan niski
P0_0 = 0;
// jesli P3.1 jest w stanie niskim
if(P3_1 == 0)
// to ustaw na P0.0 stan wysoki
P0_0 = 1;
}
}
Zapis P3_0 odpowiada zapisowi P3.0, czyli określa pin 0 portu P3. Przyjrzyjmy sie teraz dokładniej instrukcji
if : if(P3_0 == 0)
W nawiasach okrągłych po słowie if umieszczono warunek . Warunkiem musi być wyrażenie zwracające
wartość logiczną, czyli prawda lub fałsz . W naszym przykładzie dokonujemy sprawdzenia, czy wyprowadzenie
P3.0 jest w stanie niskim. Jeśli tak, to oznacza to, że naciśnięty został przycisk podłączony do tego
wyprowadzenia. Należy podjąć wtedy odpowiednie działanie, czyli ustawić wyprowadzenie P0.0 w stan niski.
Początkujących adeptów programowania w jezyku C może zadziwić znak "==", czyli operator porównania. Jest
on inny niż w językach Basic lub Pascal i z początku bardzo łatwo się myli z operatorem przypisania "=".
Instrukcja if może także wyglądać następująco:
if(warunek)
instrukcja1;
else
instrukcja2;
Słowo else (w przeciwnym przypadku) umieszczone przed instrukcja2 mówi, że instrukcja2 zostanie wykonana
tylko wtedy, gdy warunek instrukcji if będzie niespełniony, czyli będzie wartości false . W sytuacji, gdy w
przypadku spełnienia danego warunku wykonanych ma być kilka instrukcji, to należy blok tych instrukcji ująć w
nawiasy klamrowe {}:
Zgłoś jeśli naruszono regulamin