EMPTY_INTERRUP?(Nazwajpzzerwania)
ABC... C
Przypominam jeszcze raz: standard ANSI C nic definiuje sposobu obsługi przerwań. To, o czym będziemy dalej mówić, dotyczy ściśle kompilatora zastosowanego w pakiecie WinAVR.
Tworzenie funkcji obsługi przerwania znakomicie upraszcza dołączenie do programu pliku <avr\signal.h>. Definiuje on 3 różne makra. Po jego dołączeniu funkcję obsługi przerwania tworzymy jak lo przedstawia listing:
SI GNAŁ (Nazwa_pi zt?i w cm id)
// Ciało funkcji
Czyż nie wygląda prosto? Takie właśnie w istocie jest.
Najczęściej będziemy korzystać z zalecanego makra SIGNAL. Powoduje ono utworzenie funkcji obsługi w typowy dla AVR-ów
sposób, gdzie w czasie obsługi jednego przerwania zerowana jest globalna flaga zezwolenia na przerwanie. Nie oznacza to, że procesor jest „ślepy i głuchy na inne wołania”. Jeśli w tym czasie będzie zgłoszone żądanie obsługi innego zdarzenia, ustawiona zostanie odpowiednia flaga i będzie ono obsłużone, gdy tylko przerwania zostaną odblokowane (następuje to automatycznie przy kończeniu obsługi aktualnego przerwania).
Czasami jednak chcemy, aby nowe zdarzenie mogło przerwać bieżące zadanie. Możemy w takim przypadku przy tworzeniu funkcji obsługi słowo SIGNAL zamienić na INTERRUPT. Kompilator doda wtedy automatyczne odblokowanie przerwań zaraz po wywołaniu jego obsługi. Makra tego należy używać bardzo ostrożnie. Każde przerwanie odkłada na stos pewne informacje. Nieprzemyślane używanie makra typu INTERRUPT rnuże doprowadzić do zapchania stosu i nieprzewidzianego działania programu.
Pozostało nam jeszcze trzecie, rzadziej stosowane makro Umożliwia ono utworze
nie tak zwanego pustego przerwania. Wywołane przerwanie natychmiast zwróci sterowania do programu głównego. Jest to o tyle ważne, że standardowo wystąpienie nieprzewidzianego przerwania spowoduje restart całego programu Puste przerwanie możemy utworzyć jak niżej:
Nie należy definiować ciału funkcji makro tworzy je automatycznie.
Plik <avr/intcrrupt.h> definiuje bardzo przydatne funkcje sei() i city. Obie tłumaczone są na jedną instrukcję asemblera o nazwie identycznej z nazwą funkcji. Powoduje odpowiednio: globalne włączenie i globalne wyłączenie przerwań.
Istnieje tutaj także funkcja aktywacji przerwań liczników. Jednak chociażby ze względu na kompatybilność z innymi kompilatorami oraz banalność „ręcznego” realizowania takiego działania nie warto z niej korzystać.
Obsługa wyświetlacza wymaga od nas wysterowania każdej cyfry tak. aby niedostrzegalne było migotanie całego pola odczytowego. Za granicę widocznego przez człowieka migotania uznaje się około 50Hz. Każde przerwanie powodować będzie wyłączenie bieżącego wyświetlacza i uruchomienie następnego. Biorąc pod uwagę, że wyświetlaczy mamy 4 dochodzimy do wniosku. że musimy odpowiednią procedurę wywołać co najmniej 200 razy w ciągu sekundy. Oczywiście nie jest tutaj ważna duża dokładność odmierzenia czasu. Jeśli procedura obsługi wyświetlacza będzie wywoływana nawet 500 razy na sekundę, spowoduje to tylko większe obciążenie procesora, a jednocześnie mniej zauważalne migotanie wyświetlacza. Ostatecznie pod koniec całego powyższego toku rozumowania możemy stwierdzić. że całkowicie wystarczy nam zastosowanie prostszego tiincra. Bardziej rozbudowany pozostawiamy w celu jego ewentualnego wykorzystania do bardziej ambitnych zadań. Ze względu natomiast na prostotę
wywoływane w momencie przepełnienia licznika.
Koniecznie zapoznaj się teraz z ramką mówiącą o tym, jak w naszym kompilatorze wygląda obsługa przerwań. Tabela 2 prezentuje nazwy przerwań procesora AT90S2313. Wszystkie nazwy, jakie udostępnia nasz kompilator, można odnaleźć w manuału (przypominam: C:\W\nAVR\doc\avr-libc). Z mojego doświadczenia wynika jednak, że znacznie wygodniej jest zajrzeć do odpowiedniego pliku definiującego wszelkie stałe symboliczne dla wykorzystanego procesora. W naszym przypadku będzie to C:\WinAVR\avr\inclu-dt\avr\ ia23I3.fi. Listing 10 pokazuje, jak wygląda definicja wektorów przerwań. W ten sposób często łatwiej znaleźć interesującą nas nazwę niż za pomocą przedzierania się przez dokumentację, w której brak podziału na poszczególne procesory.
Uzbrojeni w wiedzę o przerwaniach możemy podjąć się już zadania napisania naszego kodu z ich wykorzystaniem. Spójrz na listing II. Przedstawiłem na mm prawie kompletny
kod naszego programu. Program został napisany na bazie tego, do czego udało nam się dojść w poprzedniej części. Spójrz na linie oznaczone na szaro. Są to linie, które nie uleg ły zmianom. Może zdziwi Cię wy szarzenie wnętrza naszej funkcji obsługi przerwania? Zrobiłem to specjalnie. Zauważ, że zawarty tutaj kod to nic innego jak poprzednia zawartość naszej pętli głównej Dzięki temu, że wykorzystujemy sprawdzony już fragment kodu, unikamy pracy oraz zmniejszamy możliwość pomyłki.
Zanim więc zaczniesz pisać nowy program, warto oszczędzić sobie pracy i przyj rżeć się co tak naprawdę jest do zrobienia w stosunku do jego wersji z poprzedniego miesiąca. Jeśli chcesz zachować kopię poprzedniego programu, skopiuj go teraz. Następnie otwórz go w Programmers INotepa-dzle. Tak naprawdę konieczne jest jedynie dodanie dwóch plików nagłówkowych pomagających w obsłudze przerwań Konieczne jest dopisanie trzech linii inicjacji, utworzenie szkieletu funkcji obsługi przerwania oraz przeniesienia do jej ciała wnętrza naszej pętli głównej. Samą (pusta już) pętlę główną proponuję zostawić. Zmiany opisałem tutaj bardzo skrótowo, ale jeśli podeprzesz się jeszcze listingiem 11 wprowadzenie odpowiednich zmian me będzie trudne.
Po skompilowaniu programu i jego wysłaniu do naszego układu testowego powinniśmy ujrzeć znajomy nam widok — wyświetlane kolejne cyfry na wyświetlaczach. Niektórzy
38 Lipiec2005 Elektronika dla Wszystkich