AVR GCC cz8


K U R S
AVR GCC: kompilator C
mikrokontrolerów AVR, część 8
Obsługa przerwań
Po uruchomieniu sesji AvrStudio
Kontunujemy omówienie obsługi przerwań za pomocą programów
dla naszego projektu (rys. 20) mo-
napisanych w AVR GCC. Jak się okazuje, jest to bardzo
żemy ustawić breakpoint i obejrzeć
skuteczne narzędzie do ich obsługi.
pracę programu. Na tym możliwości
wizualne AvrStudio się kończą. Jeśli
zechcemy zaprezentować symulację kolory dowolne)  jak na rys. 21.
w bardziej naturalny sposób musimy Konfigurację tę wpiszemy polece-
sięgnąć po dodatkowe wyposażenie. niem Save do pliku \Projects\Kurs\
Jest nim bezpłatne rozszerzenie Avr- Przyklad 04\test04.xml potwierdzając
Studio o nazwie Hapsim (Helmi s jego nadpisanie.
AVR Periphery Simulator) autorstwa Teraz po uruchomieniu (F5) sesji
Helmuta Wallnera (http://www.helmix. AvrStudio (i ewentualnym przywo-
at/hapsim.htm#hapsimdownload). Po- łaniu Hapsima na ekran) ujrzymy
zwala ono  podczas pracy symu-  rzeczywistą pracę portu Atmegi
latora AvrStudio  na wizualizację z podłączonymi diodami  rys. 22.
pracy peryferiów mikrokontrolera Hapsim potrafi czasem znacznie
(np. diod led, wyświetlacza graficz- spowolnić pracę AvrStudio. Wtedy
nego, terminala tekstowego). możemy wykorzystać kompilację wa-
Środowisko AvrSide zostało przy- runkową, np. do innego ustawienia Rys. 21. Konfiguracja sesji Hapsima
stosowane do współpracy z Hapsim. timerów dla prób z Hapsim i dla wer- dla naszego przykładu
Każdorazowo podczas zapisu nowe- sji docelowej. AvrSide wspiera taką
INTERRUPT (SIG_INTERRUPT0)
go projektu w subfolderze projek- operację definiując w wywołaniu kom- {
62: 78 94 sei
tu jest samoczynnie tworzony plik pilatora symbol HAPSIM po zaznacze- 64: 1f 92 push r1
66: 0f 92 push r0
konfiguracyjny sesji Hapsim: nazwa_ niu odpowiedniego checkboxa w oknie
68: 0f b6 in r0, 0x3f ; 63
6a: 0f 92 push r0
projektu.xml (na bazie ustawień za- opcji projektu (zakładka Kompilator).
6c: 11 24 eor r1, r1
6e: 8f 93 push r24
wartych w szablonie \AvrSide\bin\ Oczywiście opisywany przykład
PORTB=0x20;
70: 80 e2 ldi r24, 0x20 ; 32
haptemplate.xml). Natomiast pobrane ma znikomą wartość praktyczną
72: 88 bb out 0x18, r24 ; 24
74: 8f 91 pop r24
ze strony pliki wykonawcze Hapsim i służy głównie zaprezentowaniu
76: 0f 90 pop r0
należy umieścić w folderze \AvrSi- narzędzia. Symulacja terminala lub 78: 0f be out 0x3f, r0 ; 63
7a: 0f 90 pop r0
de\Hapsim. Teraz z poziomu menu wyświetlacza lcd może być spo- 7c: 1f 90 pop r1
7e: 18 95 reti
AvrSide możemy uruchomić symu- ro bardziej przydatna (chociaż nie
lator od razu z konfiguracją przy- zawsze będzie równoznaczna z pra- A teraz zadeklarujmy (extern void
pisaną projektowi (warunkiem jest widłowym działaniem rzeczywistego Little(void); w projdat.h) i zdefiniuj-
obecność pracującego AvrStudio, je- docelowego układu). Po tej przykła- my w main.c:
void Little(void)
śli nie jest on spełniony komenda dowej prezentacji zastosowania ogól-
{
PORTB=0x20;
menu, zamiast uruchamiać Hapsima nych zasad wróćmy jeszcze raz do
}
z występującym w takim przypadku mniej typowych problemów związa-
ostrzeżeniem, rozpoczyna zapobie- nych z przerwaniami. niewielką funkcję, która robi do-
gawczo od startu AvrStudio). Tworząc automatycznie szablon kładnie to samo używając tego sa-
W naszym przykładzie uruchomi- handlera makrem SIGNAL lub IN- mego rejestru:
void Little(void)
my Hapsima, zmienimy jego konfi- TERRUPT avr gcc chroni używane
{
PORTB=0x20;
gurację z szablonowej (wyświetlacz przez siebie rejestry (przepisując
5c: 80 e2 ldi r24, 0x20 ; 32
LCD) na zespół 8 diod led (przy- je na stos w prologu i odtwarzając 5e: 88 bb out 0x18, r24 ; 24
60: 08 95 ret
pisanych do portu B, bez inwersji, w epilogu). Dopiszmy do wcześniej-
szego testowego prze- Spróbujmy wykonać nową funk-
rwania SIG_INTERRUP- cję wewnątrz obsługi przerwania:
INTERRUPT (SIG_INTERRUPT0)
T0 jakąś najprostszą
{
Little();
operację, np.
}
INTERRUPT (SIG_INTERRUP-
T0)
{
i zobaczmy jak zmienił się kod
PORTB=0x20;
} wynikowy  spotyka nas niemiła
i sp r a w d zm y, ż e niespodzianka gdyż uległ on znacz-
chroniony jest tylko nemu (i w naszym przypadku zbęd-
Rys. 20. Kontrola pracy testowego programu w sy- użyty w kodzie rejestr nemu) wydłużeniu:
INTERRUPT (SIG_INTERRUPT0)
mulatorze AvrStudio r24:
{
Elektronika Praktyczna 10/2005
100
K U R S
62: 78 94 sei
64: 1f 92 push r1
wprowadzenie do Little zmian po-
66: 0f 92 push r0
68: 0f b6 in r0, 0x3f ; 63 wodujących użycie następnych re-
6a: 0f 92 push r0
jestrów wymagać będzie również
6c: 11 24 eor r1, r1
6e: 2f 93 push r18
równoległej ręcznej korekty powyż-
70: 3f 93 push r19
72: 4f 93 push r20
szego prologu i epilogu.
74: 5f 93 push r21
76: 6f 93 push r22
Aatwo zauważyć, że w podobny
78: 7f 93 push r23
7a: 8f 93 push r24
sposób możemy też zminimalizować
7c: 9f 93 push r25
7e: af 93 push r26 i maksymalnie przyśpieszyć obsłu-
80: bf 93 push r27
gę przerwania, która nie potrzebu-
82: ef 93 push r30
84: ff 93 push r31
je nawet niewielkiej podstawowej
Little();
86: ea df rcall . 44 ; 0x5c
ochrony  jak nasz pierwotny przy-
88: ff 91 pop r31
8a: ef 91 pop r30
kładowy handler ustawiający tylko
8c: bf 91 pop r27
8e: af 91 pop r26
port B , gdzie r0 i r1 nie są w ogó- Rys. 22. Ekran symulatora Hapsim
90: 9f 91 pop r25
92: 8f 91 pop r24 le użyte, zaś instrukcje ldi oraz out
94: 7f 91 pop r23
nie zmieniają flag w rejestrze stanu. przyjąłem w AvrSide wyłącznie
96: 6f 91 pop r22
98: 5f 91 pop r21
Wystarczy nam wtedy z powodze- rozszerzenia małe.s, natomiast
9a: 4f 91 pop r20
9c: 3f 91 pop r19
niem zapis (oczywiście sei także akcja preprocesora jest jawnie
9e: 2f 91 pop r18
a0: 0f 90 pop r0
według potrzeb): wymuszana odpowiednią opcją
a2: 0f be out 0x3f, r0 ; 63
void SIG_INTERRUPT0(void)
a4: 0f 90 pop r0
linii komendy kompilatora ( x
{
a6: 1f 90 pop r1
asm volatile ( sei  \n\t
a8: 18 95 reti assembler with cpp , możemy ją
 push r24  \n\t
 ldi r24,0x20  \n\t
Analiza użycia rejestrów nie odnalezć w pliku logu).
 out 0x18,r24  \n\t
sięga w głąb zagnieżdżonych funk-  pop r24  \n\t  Dołączenie umożli-
 reti );
cji  kompilator chroni na wszelki wia również używanie wszel-
}
wypadek wszystkie, które mogą być Innym przypadkiem ręcznej in- kich symbolicznych nazw re-
potencjalnie zagrożone. Chociaż ten gerencji programisty mogą być pro- jestrów (jak PORTB). Jednak
efekt na ogół nie powoduje jakichś cedury obsługi przerwań napisane sposób zdefiniowania rejestrów
problemów z działaniem programu to całkowicie w asemblerze chociaż I/O w avr libc nie jest zgod-
jednak może stwarzać kłopot w przy- niekoniecznie najkrótsze. Dłuższa ny z wymaganym w asemblerze
padkach krytycznych czasowo. porcja kodu jest dosyć uciążliwa do adresowaniem przestrzeni I/O
W takiej sytuacji możemy w ra- wpisywania w formie wstawki inline (z przesunięciem 0x20). Definicja
zie potrzeby przejąć całkowitą kon- (to oczywiście subiektywna opinia) __SFR_OFFSET 0 służy właśnie
trolę nad kodem handlera. Zamiast  dużo wygodniej jest wtedy prze- do skorygowania tej rozbieżności
stosować omawiane powyżej makra nieść cały kod do asemblerowego (możemy sprawdzić, że bez niej
zadeklarujmy po prostu funkcję modułu *.s. Dla przykładu dodajmy w wynikowym kodzie ładowany
o nazwie zgodnej z nazwą potrzeb- do projektu stronę z plikiem asem- jest nie rejestr portu B  0x18
nego wektora i nadajmy jej atrybut blerowym ints.s o treści: ale rejestr 0x38). Taki sam efekt
#define __SFR_OFFSET 0
naked. W ten sposób kompilator uzyskamy konwertując SFR na
#include
przypisze wektorowi skok do pro- adres liczbowy przy pomocy _
.global SIG_INTERRUPT1
cedury całkowicie pozbawionej pro- .section .text, ax ,@progbits SFR_IO_ADDR (PORTB) , co jest
logu i epilogu (nawet instrukcji po- SIG_INTERRUPT1:
częściej zalecane w wielu pora-
push r24
wrotu ret  zgodnie ze znaczeniem dach ale przy dłuższym kodzie
ldi r24,0x40
out PORTB,r24
atrybutu:  goła ,  ogołocona ). Po- wymaga większej ilości pisania.
pop r24
reti
trzebny prolog i epilog  ograniczo- Dla zapoznania się z tymi niu-
ne tylko do naszych rzeczywistych Po skompilowaniu znajdziemy ansami warto przejrzeć plik na-
potrzeb  wpiszemy samodzielnie w kodzie obsługę przerwania pod główkowy \avr\include\avr\sfr_defs.
jako wstawkę asemblerową inline nazwą __vector_2 wraz z odpowied- h w folderze kompilatora.
(możemy oczywiście jako podpo- nim adresem skoku w tablicy wek-  Opisy dodatkowych klasyfikato-
wiedz wykorzystać automatyczny torów. Jednak kilka spraw wymaga rów sekcji znajdziemy przegląda-
kod tworzony przez makra). Może dodatkowego wyjaśnienia: jąc dokumentację avr libc oraz
to wyglądać np. tak:  Nazwa procedury jest zgodna avr as (ax oznacza alokowalny
void SIG_INTERRUPT0(void) NAKED; //
z nazwą wektora z pliku nagłów- + wykonywalny; @progbits in-
NAKED to własna skrócona definicja z my-
names.h
kowego danego układu, który formuje, że sekcja zawiera dane);
void SIG_INTERRUPT0(void)
dołączamy dyrektywą #include klasyfikatory te nie są niezbęd-
{
asm volatile ( sei  \n\t
tak jak dla pliku C. ne do skompilowania (wystarcza
 push r1  \n\t
 push r0  \n\t  Aby uwzględnić tę nazwę plik samo podanie nazwy sekcji.sec-
 in r0,0x3f  \n\t
musi być poddany obróbce tion .text)
 push r0  \n\t
 eor r1,r1  \n\t
w preprocesorze. Avr gcc uru- Modułów i funkcji asemblerowych
 push r24 );
Little();
chamia samoczynnie preproce- nie będziemy niestety mogli obejrzeć
asm volatile ( pop r24  \n\t
 pop r0  \n\t
sor po napotkaniu rozszerzenia w postaci zródłowej w debugerze Avr-
 push r0  \n\t
 out 0x3f,r0  \n\t
*.S (natomiast pomija go przy Studio. Brak w nich wymaganej do
 pop r0  \n\t
 pop r1  \n\t rozszerzeniu *.s małe). Jednak tego odpowiednio sformatowanej in-
 reti );
 ponieważ Windows general- formacji. Ręczne dopisywanie jest ra-
}
Takie rozwiązanie oczywiście nie nie rozróżnia wielkości liter czej mało realne gdyż zapis jest zbyt
wymaga zwiększonej uwagi  np.  dla uniknięcia nieporozumień złożony (możemy go podpatrzeć w do-
Elektronika Praktyczna 10/2005
101
K U R S
wolnym tymczasowym pliku.s wyge- przez avr gcc stwierdziliśmy, że
nerowanym z modułu *.c poleceniem przerwania nie obsługiwane w pro-
menu Sprawdz poprawność kodu), nie gramie mają przypisany domyślny
zanosi się również na opracowanie skok do etykiety __bad_interrupt.
do tego automatycznego narzędzia. Takie określenie (złe, błędne prze-
W takich przypadkach pozostaje jedy- rwanie) oczywiście nie oznacza,
nie debugowanie na poziomie kodu że jakieś przerwania są  lepsze
asemblera (przykład z przerwaniami a inne  gorsze . Chodzi natomiast
INT0 oraz INT1 szybko sprawdzimy o podkreślenie, że w prawidłowo
w pracy krokowej ręcznie przestawia- skonstruowanym i oprogramowanym
jąc w AvrStudio potrzebne bity w re- urządzeniu brak obsługi przerwa-
jestrze GICR oraz PIND). nia oznacza, iż w żadnych oko-
Opisane powyżej użycie wła- licznościach z cała pewnością ono
snych handlerów asemblerowych lub nie wystąpi. Wyzwolenie takiego
naked może się też przydać gdy przerwania (np. poprzez omyłkowe
zechcemy przypisać kilku różnym odblokowanie, pozostawienie  pły-
wektorom przerwań wspólną proce- wającego , narażonego na zakłóce-
durę obsługi. Można to oczywiście nia pinu itp.) świadczy po prostu
zrealizować tradycyjnie, wywołując o błędzie wykonawczym. Dlatego
z kilku automatycznych handlerów domyślna akcja w takim przypadku
tę samą funkcję, ale przed chwilą nie jest zbyt rozbudowana  powo-
zobaczyliśmy, że może się to nie- duje skok pod adres 0 (nawet bez
korzystnie odbić na szybkości kodu. powrotu z przerwania reti). Czasem
Użyjmy więc makra SIGNAL (lub w trakcie uruchamiania chcieliby-
INTERRUPT) z nazwą wektora inną śmy tę akcję rozszerzyć  np. o zli-
niż istniejące w kostce  makro czanie nieprzewidzianych przerwań.
wygeneruje kod handlera ale nie Avr libc daje taką możliwość: wy-
przypisze mu żadnego adresu skoku starczy zdefiniować obsługę wektora
w obszarze wektorów przerwań (jest domyślnego __vector_default i tam
to właśnie wspomniany wcześniej wpisać potrzebny kod:
SIGNAL(__vector_default)
przypadek celowego wykorzystania
{
// obsługa nieprzewidzianych przerwań
zapisu, który przy zwykłym użyciu
}
zazwyczaj powoduje błąd). W tym
hadlerze wpisujemy kod wspólnej W kodzie wynikowym sprawdzi-
obsługi dla kilku różnych przerwań. my, że teraz etykieta __bad_inter-
Natomiast wybrane do tej obsługi rupt nie zawiera już skoku pod ad-
przerwania opisujemy procedurami res 0 ale skok do naszego nowego
naked zawierającymi tylko i wyłącz- domyślnego handlera.
nie skok pod jego adres. Przykłado- Z powyższych rozważań widać,
wo dla dwóch przerwań nadajnika że avr gcc daje nam praktycznie
uart moglibyśmy zapisać: pełną kontrolę nad mechanizmem
void SIG_UART_DATA (void) NAKED;
przerwań mikrokontrolera. Jak często
void SIG_UART_TRANS (void) NAKED;
te możliwości wykorzystamy  bę-
SIGNAL (SIG_COMMONINT)
{ dzie zależeć od naszych preferencji
// wykonanie wspólnej obsługi dla
i przyzwyczajeń. Moim subiektyw-
sig_uart_data
// oraz sig_uart_trans
nym zdaniem warto stosować prze-
}
rwania jak najczęściej, eliminując
void SIG_UART_DATA(void)
{
wszelkie pollingi (czyli cykliczne
asm volatile( rjmp SIG_COMMONINT );
}
sprawdzanie flag w rejestrach) i pętle
void SIG_UART_TRANS(void) oczekujące na wykonanie operacji
{
asm volatile( rjmp SIG_COMMONINT );  chociaż są one bardzo popularne
}
w rozmaitych przykładach i kursach
To samo możemy wykonać w pli- programowania. Dodatkowy nakład
ku asemblerowym  należy jedynie pracy szybko zwróci się z nawiązką
dołączyć do kodu asm dyrektywę w postaci bardziej logicznej i przej-
.extern SIG_COMMONINT. W kodzie rzystej struktury programu oraz jego
wynikowym sprawdzimy, że rzeczy- szybszego i płynniejszego działania.
wiście otrzymaliśmy skoki w potrzeb- Jerzy Szczesiul, EP
ne miejsca: z tablicy wektorów do jerzy.szczesiul@ep.com.pl
krótkich procedur pośrednich a na-
stępnie do wspólnego handlera za- UWAGA!
Środowisko IDE dla AVR GCC opracowane
kończonego instrukcją powrotu reti.
przez autora artykułu można pobrać ze
Przy wstępnym omawianiu au-
strony http://avrside.ep.com.pl.
tomatycznego kodu generowanego
Elektronika Praktyczna 10/2005
102


Wyszukiwarka

Podobne podstrony:
Using the EEPROM memory in AVR GCC
AVR GCC w Linuksie przykład instalacji ze źródeł
Kurs AVR GCC cz 5
Kurs AVR GCC, cz 3
Kurs AVR GCC Wyświetlacz LCD od Nokii310
AVR GCC kompilator C dla mikrokontrolerów AVR, część 12
AVR GCC kompilator C dla mikrokontrolerów AVR, część 11
Kurs AVR GCC cz 2
AVR GCC cz7
AVR GCC cz5

więcej podobnych podstron