WinAVR, jak zmienić funkcję obsługi przerwania w t

Oct 04, 2012 9 Replies

Witam uprzejmie,



W programie pisanym na mikrokontroler ATmega128 w języku C (kompilator WinAVR) mam zdefiniowaną funkcję obsługi jednego z przerwań



SIGNAL (SIG_OVERFLOW1) { // jakiś kod }


Przy czym mam potrzebę, aby w trakcie działania programu móc przypisywać różne funkcje pod obsługę tego przerwania (przykładowo użytkownik wybiera pracę bipolarną albo unipolarną urządzenia, dla których to trybów powinny być inne funkcje podpinane pod obsługę przerwania). Mógłbym pewnie zrobić tak:



SIGNAL (SIG_OVERFLOW1) { if (pracaBipolarna) { // kod dla pracy bipolarnej } else { // kod dla pracy unipolarnej } }



Ale może da się podpinać pod obsługę przerwania różne funkcje w trakcie działania programu. Jeśli da się, to jak to zrobić?



Z góry dziękuję za pomoc.



Robbo PS. Wiem, że obecnie SIGNAL jest przestarzały.


Am 04.10.2012 16:31, schrieb Robbo:

Nie programuję w WinAVR, ale możliwe jest pewnie podmienienie adresu w tabeli przerwań. Atmele programuję w assemblerze, ale inne procki tak mogą. Tylko nie zapomnij o wyłączeniu przerwania przed podmianą i załączeniem po, bo może być burda.

Waldek

Ad maiorem Waldemar Krzok gloriam :

Tabela przerwań siedzi we flashu...

Sławek

W dniu 04.10.2012 16:31, Robbo pisze:

Witam Jeśli to tylko dwie procedury do wyboru, to zaproponowane rozwiązanie jest chyba najoptymalniejsze. Jeśli do wyboru ma być więcej procedur, to zamiast ewentualengo switch()..case (różny czas reakcji na przerwanie w zależności od położenia w łancuchu case) proponuję tablicę wektorów do poszczególnych procedur.

AVRki mają rozkaz skoku do adresu określonego w rejestrze indeksowym Z.

Pozdrawiam Grzegorz

W dniu 2012-10-04 17:13, Grzegorz Kurczyk pisze:

Sensowny kompilator powinien przerobić switch właśnie na tablicę wektorów, jeśli uzna to za bardziej optymalne. Nawet SDCC tak robi.

Pozdrowienia, MKi

Witam,

do zmiany "w locie" cu wykonuje sie w przerwaniu dobrze sie wykorzystuje wskaznik do funkcji. Zadeklaruj sobie zmienna typu wskaznik do funkcji w pliku, gdzie masz obsluge przerwania . Dodatkowo, w tym samym pliku stworz funkcje SetIrqHandler(), ktorej parameterm jest wskaznik na funkcje. W samym przerwaniu wywolujesz funkcje przez jej wskaznik.

na szybko cos podobnego do:

static void(*pIrqHandler)(void);

/** @file main.c */

// zmienna globalna dla tego pliku, niedostpena z innych modulow static void (*pIrqHandler)(void);

// funkcja do inicjalizacji wskaznika do funkcji, exportowana w irq.h void SetIrqHandler(void( *pNewHandler)(void)) { pIrqHandler = pNewHandler; }

/** to wlasciwa funkcja przerwania SIGNAL (SIG_OVERFLOW1) ale nie mam WinAvr zeby calosc kompilowac, testowalam poprawnosc skladni na Yagarto

*/ //SIGNAL (SIG_OVERFLOW1) void Doirq(void) { pIrqHandler(); }

/****************************/

int EnableIrq() { return 0; }

int DisableIrq() { return 0; }

void f1(void) { // zrob cos }

void f2(void) { // zrob co innego }

void main1 (void) { StandardowaInicjalizacja(); SetIrqHandler(f1);

EnableIrq();

while(1) {

// zrob co trzeba // a jak dojdziesz ze irq ma robic co innego to: // to tylko do testow, normalnie funkcja wywolana przez hardware irq Doirq(); DisableIrq(); SetIrqHandler(f1); EnableIrg(); // to tylko do testow, normalnie funkcja wywolana przez hardware irq Doirq(); // kontynuuj z main }

}

mankament jaki widze, to to ze obsluga przerwania wydluzy sie o wywolanie kolejnej funkcji oraz odlozy troche na stos. Ogowlnie, wskazniki do funkcji to bardzo uzyteczna rzecz, np. tablica takich wskaznikow zastepuje swietnie skomplikowane if czy switch no i mozna zmieniac je podczas dzialania programu

oczywiscie poza literowkami, mialo byc:

DisableIrq(); SetIrqHandler(f2); // zmiana funcji jaka wykona przerwanie EnableIrq();

no i podwojnie sie wkleilo static void(*pIrqHandler)(void);

Marcin

Tez myslalem o wywolywaniu funkcji. Elegancko to wyglada, alewiaze sie z narzutem zwiazanym z odlozeniem rejestrów na stos. Mysle, ze poprzestane na zwyklym if (mam tylko dwa warianty kodu do przelaczania).

R.

Lekko w bok od głównego tematu. Stosujesz stare funkcję obsługi przerwania. Zamiast SIGNAL stosuj ISR() z nowymi wektorami. Ich wykaz i zamianę starych na nowe znajdziesz tutaj:

formatting link

Mam małe doświadczenie z AVR-ami, ale może poczytaj o atrybutach OS_main, OS_task i przede wszystkim o naked.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required