PMiK Programowanie Mikrokontrolera 8051 Wykład 3 Mikrokontroler 8051 PMiK Programowanie mikrokontrolera 8051 - wykład S. Szostak (2006)
Zmienna typu bit #define YES 1 // definicja stałych #define NO 0 static bit RS_ready = NO; // zmienna typu bit bit check_lcd_busy // funkcja zwracająca zmienną typu bit ( bit zm1, // argumenty funkcji typu bit bit zm2) { bit zm_lokalna; // zmienna lokalna typu bit // ciało funkcji } return (1); // funkcja zwracająca zmienną typu bit PMiK Programowanie mikrokontrolera 8051 S. Szostak 2
Ograniczenia używania zmiennych typu bit Nie dopuszczalne jest deklarowanie wskaźnika definiowanie tablic zmiennych bitowych bit * PT_bit; bit bit_array[5]; Funkcje, które blokują system przerwań (poprzez deklarację #pragma disable) oraz te, które używają z góry zadanego zestawu rejestrów (deklaracja using n) nie mogą zwracać wartości w postaci zmiennej typu bit PMiK Programowanie mikrokontrolera 8051 S. Szostak 3
Obiekty adresowane bitowo (1) Obiekty takie (np. zmienne typu char, int, long, struktury, unie) muszą znajdować się w obszarze adresowanym bitowo czyli w obszarze pamięci wewnętrznej zaczynającym się od adresu 0x20H i mającym długość 16 bajtów. Obszar ten oznaczany jest jako bdata. Obiekty te musza być zadeklarowane jako zmienne globalne Przykład int bdata RS_Status; char bdata var_tab[4]; W tak zdefiniowanych zmiennych mamy dostęp do pojedynczych bitów tych zmiennych. sbit dev_ready = RS_Status^0; sbit dev_busy = RS_Status^15; sbit tab_1_5 = var_tab[1]^5; // dev_ready jest 0 bitem zmiennej RS_Status // dev_busy jest 15 bitem zmiennej RS_Status // tab_1_5 jest 5 bitem 1 elementu tablicy var_tab Uwaga! Pozycja bitu musi być określana poprzez stałą. Odwoływanie się do zmiennych bitowych zadeklarowanych w innych modułach extern bit dev_ready PMiK Programowanie mikrokontrolera 8051 S. Szostak 4
Obiekty adresowane bitowo (2) union lft { float data_fl; long data_long; }; bdata struct alarm { char index; union lft u; union lft u; } my_data; sbit index_6 = my_data.index ^ 6; // poniższa deklaracja jest błędna ponieważ nie można wskazywać zmienną bitową na pozycję w zmiennej typu float sbit my_data_f_30 = my_data.u.data_fl ^ 30; // 30 bit zmiennej float // ale można to zrobić tak sbit my_data_f_30 = my_data.u.data_long ^ 30; // i to już wskazuje na 30 bit zmiennej float Uwaga należy pamiętać, że w przypadku zmiennej typu int pierwszy jest przechowywany najstarszy bajt PMiK Programowanie mikrokontrolera 8051 S. Szostak 5
Adresowanie bitowe rejestrów specjalnych (SFR) sfr P0 = 0x80; sfr LCD_data = 0x80; LCD_data = 0x55; // port P0 // jeśli do portu P0 dołączona jest szyna danych wyświetlacza LCD to można // zdefiniować taką zmienną sfr16 T2 = 0xCC; // deklaracja 16 bitowego rejestru SFR Timer 2 T2L 0xCCH T2H 0xCDH // adres musi być mładszym bajtem rejestru sbit EA = 0xAF; // bit aktywujący system przerwań Tylko te rejestry mogą być adresowane bitowo których adres kończy się 0 lub 8 Wyznaczanie adresu bitu Adres bitu = adres rejestru SFR + numer bitu w rejestrze. Przykład - EA jest ostatnim (7) bitem rejestru IE (adres 0xA8) zatem adres EA = 0xA8+7=0xAF Można go zadeklarować na trzy sposoby (1) sbit EA = IE ^ 7; (1) sbit EA = 0xA8 ^ 7; (1) sbit EA = 0xAF; PMiK Programowanie mikrokontrolera 8051 S. Szostak 6
Deklaracja funkcji Rozszerzenia w porównaniu ze standardem ANSII funkcję deklarowane jako procedury obsługi przerwań możliwość wyboru zestawu rejestrów używanego przez funkcję możliwość określenia modelu pamięci dla deklarowanej funkcji funkcje typu reentrant funkcje typu alien (PL/M-51) Źródło : C51 Compilator Keil Software c51.pdf PMiK Programowanie mikrokontrolera 8051 S. Szostak 7
Przesyłanie parametrów funkcji Stos w 51 jest lokowany w adresowanej pośrednio pamięci wewnętrznej czyli max. 256 bajtów. Dlatego kompilator zamiast stosu wykorzystuję ściśle zdefiniowany obszar w pamięci do przekazywania parametrów do funkcji. Można wtedy wykorzystać także pamięć zewnętrzną (xdata). Podczas wywołania funkcji przed przekazaniem jej kontroli do pamięci kopiowane są argumenty a na stos odkładany jest jedynie adres powrotu. Funkcja jeśli potrzebuje argument to pobiera go z pamięci. Funkcje obsługi przerwań odkłada na stos rejestr stanu i dodatkowo wartości kilku używanych rejestrów. Najefektywniejszym sposobem jest przekazywanie parametrów do funkcji poprzez rejestry (R1-R7). Niestety kompilator może przesłać funkcji max. trzy parametry poprzez rejestry. PMiK Programowanie mikrokontrolera 8051 S. Szostak 8
Przesyłanie parametrów poprzez rejestry Max. trzy argumenty Źródło : C51 Compilator Keil Software c51.pdf Ponieważ nie ma potrzeby zapisywania i odczytywania parametrów z pamięci jest to znacznie efektywniejszy sposób przekazywania parametrów Można wymusić bądź zablokować przekazywanie parametrów poprzez rejestry używając odpowiednio dyrektyw REGPARMS i NOREGPARMS Jeśli rejestry są niedostępne, bądź jest ich zbyt mało to parametry są przekazywane poprzez określony obszar pamięci UWAGA! Jeśli pierwszym parametrem funkcji jest zmienna typu bit to następne parametry są przekazywane poprzez pamięć. Dlatego taki typ argumentu powinien być deklarowany na końcu listy parametrów. PMiK Programowanie mikrokontrolera 8051 S. Szostak 9
Wartości zwracane przez funkcje Funkcja zwraca wartość zawsze poprzez rejestry Źródło : C51 Compilator Keil Software c51.pdf PMiK Programowanie mikrokontrolera 8051 S. Szostak 10
Określanie zestawu rejestrów dla funkcji Deklaracja banku poprzez słowo kluczowe using n (n=0 3). Zastosowanie: Funkcje obsługi przerwań, systemy czasu rzeczywistego Nie można używać przy deklaracji prototypu funkcji. Wywołanie tak zdefiniowanej funkcji powoduje odłożenie na stosie aktualnego zestawu rejestrów i ustawienie określonego poprzez parametr using. Bezpośrednio przed wyjściem z funkcji przywracany jest poprzedni zestaw rejestrów. UWAGA używanie deklaracji using dla funkcji zwracających wartość może być niebezpieczne (ponieważ funkcja zwraca wartość poprzez rejestry). Dodatkowo - nawet jeśli funkcja wywołująca używała tego samego zestawu rejestrów to nie można zwracać wartości typu bit. Funkcja, która zwraca wartość musi używać tego samego zestawu rejestrów co funkcja wywołująca. Możliwość przełączania zestawu rejestrów jest szczególnie przydatna w przypadku funkcji obsługujących przerwania. Optymalne rozwiązanie to : Wszystkie funkcje nie obsługujące przerwań używają tego samego zestawu rejestrów. Funkcje obsługujące przerwania o różnym priorytecie używają różnych zestawów rejestrów. Funkcje obsługujące przerwania o tym samym priorytecie używają tego samego zestawu rejestrów PMiK Programowanie mikrokontrolera 8051 S. Szostak 11
Przykład użycia deklaracji using Źródło : C51 Compilator Keil Software c51.pdf PMiK Programowanie mikrokontrolera 8051 S. Szostak 12
Używanie zestawu rejestrów Po resecie PSW ma wartość 0 zatem wszystkie funkcje używają pierwszego zestawu rejestrów. Dyrektywa REGISTERBANK pozwala zmienić defaultowy zestaw rejestrów dla wszystkich funkcji w danym module. Dyrektywę tą można używać w pliku wielokrotnie. Standardowo kompilator generuje kod w którym rejestry R0.. R7 adresowane są w sposób bezpośredni - poprzez symbol AR0.. AR7 dla aktualnego zestawu rejestrów (w kodzie rozkazu jest podawany adres konkretnego rejestru) jest to najefektywniejszy sposób. ALE jest to rozwiązanie, w którym obie funkcje wywołująca i wywoływana muszą używać tych tego samego zestawu rejestrów. W przypadku gdy dana funkcja może być wywołana np. z funkcji main() i z funkcji obsługi przerwania to w momencie jej kompilacji nie znamy aktualnego zestawu rejestrów (w main () i w obsłudze przerwania powinny być one różne) i dlatego wynik takiego wywołania jest nie przewidywalny. Rozwiązanie! Zastosowanie dyrektywy NOAREGS Wtedy funkcja nie używa adresów (AR0.. AR7) rejestrów R0-R7 tylko ich nazwy przez co jest nie wrażliwa na aktualny zestaw rejestrów (ale jest to sposób mniej efektywny) PMiK Programowanie mikrokontrolera 8051 S. Szostak 13
Funkcje zdefiniowane ale nie używane Takich funkcji może być w naszym programie dość dużo, szczególnie na początkowym etapie pisania oprogramowania. Co z nimi robi linker (jeśli oczywiście kompilator kompiluje je bez żadnych błędów)? Jedynymi funkcjami, które nie są przez program nigdy wywoływane to funkcje obsługi przerwań. (Te wywołuje sprzęt). Niestety linker tak też musi traktować funkcje zdefiniowane ale nie wywoływane (chociaż generuje ostrzeżenie). Skutek jest taki, że choć funkcja nie jest wywoływana to jest traktowana jako potencjalna funkcja obsługi przerwania. A w tym przypadku linker musi zarezerwować miejsce w pamięci dla jej zmiennych lokalnych. (nie możliwe jest wykorzystanie mechanizmu nakładkowania zmiennych lokalnych różnych funkcji). W efekcie może dojść do zajęcia całej pamięci wewnętrznej (to tylko 256 bajtów). PMiK Programowanie mikrokontrolera 8051 S. Szostak 14
Funkcje obsługi przerwań Przykładowa deklaracja Kompilator generuje kod 1) Odkłada zawartość SFR ów ACC, B, DPH, DPL, PSW jeśli jest taka potrzeba na stosie 2) Jeśli nie jest użyta opcja using to wszystkie rejestry używane w funkcji obsługi przerwania są odkładane na stos 3) Generowany jest właściwy kod wykonujący obsługę przerwania 4) Przed wyjściem z funkcji ze stosu są zdejmowane odłożone wcześniej rejestry 5) Funkcja jest kończona instrukcją reti Źródło : C51 Compilator Keil Software c51.pdf PMiK Programowanie mikrokontrolera 8051 S. Szostak 15
Przykładowy listing funkcji obsługi przerwania Zauważmy brak przełączenia zestawu rejestrów pomimo użycia dyrektywy using 3. działanie optymalizacji kompilatora Keil Źródło : C51 Compilator Keil Software c51.pdf PMiK Programowanie mikrokontrolera 8051 S. Szostak 16
Właściwości funkcji obsługi przerwań Brak argumentów przekazywanych funkcji Funkcja nie może zwracać żadnych wartości musi być to void Nie należy wywoływać funkcji obsługi przerwania z poziomu programu (funkcja kończy się instrukcją reti a nie ret jak zwykła funkcja) Inne funkcje wywoływane z funkcji obsługi przerwań muszą używać tego samego zestawu rejestrów. W przypadku takich funkcji zalecane jest użycie dyrektywy NOAREGS co uniemożliwi kompilatorowi używanie adresowania bezpośredniego rejestrów R0.. R7. W przeciwnym razie może zostać wygenerowany kod dla innego niż zamierzamy zestawu rejestrów co zwykle skutkuje - wiadomo czym choć często bardzo trudno to wykryć. PMiK Programowanie mikrokontrolera 8051 S. Szostak 17
Dyrektywy preprocesora Źródło : C51 Compilator Keil Software c51.pdf PMiK Programowanie mikrokontrolera 8051 S. Szostak 18
Predefiniowane makra Przykładowe zastosowanie #if ( C51 < 700) ( C51 > 799) #error wymagana wersja kompilatora V7.00 #endif Źródło : C51 Compilator Keil Software c51.pdf char code compil_data[]= DATE ; char code compil_time[]= TIME ; PMiK Programowanie mikrokontrolera 8051 S. Szostak 19
Dyrektywa preprocesora defined #define identyfikator defined (identyfikator) #if defined (identyfikator) #else #endif PMiK Programowanie mikrokontrolera 8051 S. Szostak 20