Skocz do zawartości

[c][atmega128]problem z przerwaniem


sobal44

Pomocna odpowiedź

Witam

w trakcie przenoszenia kodu z atmegi32 do atmega128 natrafiłem na problem z przerwaniem i nie mam pojecia w czym może być problem

void serwo(void)//Inicjacja serw
{

DDRD = 0xFF;//Włączenie serw
DDRC = 0xFF;
DDRA = 0xFF;
PORTD &= ~0XF0 ;//"resetowanie" serw
PORTC = 0x00;
PORTA = 0x00;

                TIMSK = (1<<OCIE1A)|(1<<OCIE1B);//Ustawienie timera sygnałów
OCR1A = 0x9C40;//Ograniczenie przepełnienia timera sygnałów//40000
OCR1B = 0x9C40;
	TCCR1B = (1<<WGM12)|(1<<CS11);//Włączenie timera z preskalerem

}

gdy ustawiam w rejestrze TIMSK : OCIE1A, OCIE1B program nie działa,

gdy usunę ten rejestr program działa prawidłowo tylko oczywiście bez przerwań których potrzebuje.

a oto przerwanie

SIGNAL(SIG_OUTPUT_COMPARE1A)//Przerwanie obsługi serw)
{

PORTC = 0xFF;
PORTD |= 0X30;
_delay_ms(0.6);//minimalne dlugość impulsu

for(impuls=0;impuls<180;impuls++)//Kończenie sygnałów sterujących dla odpowiedniego przemieszczenia ramienia
{



	if(C0==impuls){PORTC &= 0b11111110;}
	if(C1==impuls){PORTC &= 0b11111101;}
	if(C2==impuls){PORTC &= 0b11111011;}
	if(C3==impuls){PORTC &= 0b11110111;}
	if(C4==impuls){PORTC &= 0b11101111;}
	if(C5==impuls){PORTC &= 0b11011111;}
	if(C6==impuls){PORTC &= 0b10111111;}
	if(C7==impuls){PORTC &= 0b01111111;}



	if(D4==impuls){PORTD &= 0b11101111;}
	if(D5==impuls){PORTD &= 0b11011111;}


	_delay_us(10);//Odczekiwanie pomiędzy kolejnymi stopniami konta 

}

   PORTC = 0b00000000;
  PORTD &= 0b11001111;

}
Link do komentarza
Share on other sites

Trochę więcej szczegółów by się przydało. Nie działa, czyli nie kompiluje się, działa nie obsługując przerwań, w ogóle nie działa? Datasheet Atmegi128 jest dosyć długi i tak w ciemno nie wiadomo czego szukać.

Link do komentarza
Share on other sites

w petli głównej dla zobrazowania działania problemu wgrałem i podłączyłem do jednego z portów diode by mmrugała w odstępach 1 sek. i gdy ustawie rejestr timsk dioda tylko swieci(czyli program zawiesił sie w pewnym momencie, przerwania tez nie działaja) gdy nie ustawie tego rejestru dioda mruga, oczywiscie przerwania nie działaja. na atmedze 16 i 32 działało to wszystko bez problemu.

Link do komentarza
Share on other sites

Niby w datasheetach nie ma żadnych różnic co do Timera1, spróbuj napisać najprostszy porgram obsługujący przerwania od Timera1 na atmedze128, łatwiej znaleźć sposób rozwiązania problemu.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

błąd jest w kodzie, zrobilem przerwanie od przepełnienia timera 1 i w przerwaniu miganie diody, i jest OK.

pożniej wywaliłem wszystko ze starego przerwania, znów ustawiłem miganie diody, timeri1 ustawiony jak tu:

void serwo(void)//Inicjacja serw 
{ 

   DDRD = 0xFF;//Włączenie serw 
   DDRC = 0xFF; 
   DDRA = 0xFF; 
   PORTD &= ~0XF0 ;//"resetowanie" serw 
   PORTC = 0x00; 
   PORTA = 0x00; 

                TIMSK = (1<<OCIE1A)|(1<<OCIE1B);//Ustawienie timera sygnałów 
   OCR1A = 0x9C40;//Ograniczenie przepełnienia timera sygnałów//40000 
   OCR1B = 0x9C40; 
    TCCR1B = (1<<WGM12)|(1<<CS11);//Włączenie timera z preskalerem 

}

i dioda równierz miga, wychodzi na to że w przerwaniu poprzednim program sie zapetla i niechce z niego wyjść, tylko że ja tam nic nie widze żeby było coś nie tak.

[ Dodano: 09 Sie 10 04:42 ]

zrobiłem już zeby przerwanie działało ale tym razem program w petli głownej nie działa.

Link do komentarza
Share on other sites

To jak sa postępy, to pokombinuj i wyjdzie, ja Ci na podstawie fragmentów kodu niewiele powiem, ewentualnie jak wiesz jaki fragment nie działa, to skasuj go i pisz fragmentami od nowa, może inaczej trochę, czasem się zrobi jakiś idiotyzm 🙂

Link do komentarza
Share on other sites

Patrząc na kod przerwania z pierwszego posta przyczepiam się do:

1. zmiennej impuls zadeklarowanej poza handlerem przerwania.

Ta zmienna wykorzystywana jest tylko do iterowania po pętli więc powinna być zadeklarowana wewnątrz handlera przerwania, a najlepiej wewnątrz pętli w stylu C++ czyli for(int impuls=0; ...). W obecnej sytuacji istnieje ryzyko, że nadrzędne przerwania nadpisze zmienną impuls i rozkrzaczy pętlę.

2. wywołanie delay_us wewnątrz przerwania (i to wielokrotne!).

Przerwania powinny być obsługiwane tak szybko jak to tylko możliwe. W twoim kodzie istnieje realne prawdopodobieństwo, że w czasie tych ponad 180 * 10us + 600us = 2400us które trwa przerwania przyjdzie inne przerwanie które:

a) ma większy priorytet, zostanie wywołane natychmiast i nadpisze dane z których korzysta to przerwanie (np. zmienną impuls)

b) ma mniejszy priorytet i nie zostanie wykonane natychmiast ale dopiero po zakończeniu obsługi twojego przerwania czyli nawet z 2.4ms opóźnieniem.

c) przyjdzie takie samo przerwania i... no właśnie nie wiem co się stanie. (i) albo zacznie się wykonywanie nowego i po jego wykonaniu zostanie wznowione stare, (ii) albo nowe zostanie wykonane zaraz po zakończeniu starego.

Obstawiam, że u Ciebie ma miejsce przypadek 2. c) (ii) i program zaraz po wyjściu z przerwania wchodzi w kolejne.

Reasumując: dwie zasady których należy się trzymać:

1. Zasięg zmiennych powinien być tak mały jak to możliwe, w szczególności unikając zmiennych globalnych

2. Obsługa przerwań powinna zajmować tak mało czasu jak to tylko możliwe

Link do komentarza
Share on other sites

usunołem zmienna globalna.

czasu trwania przerwania niestety nie moge zmienic bo ma wysyłać impulsy o długości 0,6 - 2,4 ms na wyjścia uC.

niestety nadal nic. potkreślam że kod działał dobrze na atmedze 32

Link do komentarza
Share on other sites

czasu trwania przerwania niestety nie moge zmienic bo ma wysyłać impulsy o długości 0,6 - 2,4 ms na wyjścia uC.

Możesz tak:

volatile int interrupted = 0;

SIGNAL(SIG_OUTPUT_COMPARE1A)//Przerwanie obsługi serw)
{
   interrupted = 1;
}

void handle_interrupt()
{
   // kod wykonywany w tej chwili wewnątrz przerwania
}

int main()
{

   // zrob co swoje przed glowna petla

   while (1) // glowna petla
   {
       // zrob w petli co chcesz

       if (interrupted)
       {
           interrupted = 0;
           handle_interrupt();
       }

       // zrob w petli co chcesz
   }
}

Tak się powinno uzywać przerwań - krótki kod przerwania przestawiający flagę, a następstwa wystąpienia przerwania realizowane są poza przerwaniem.

Link do komentarza
Share on other sites

Witam.

Zgadzam się z użytkownikiem wsowa, W przerwaniu powinny znajdować się tylko instrukcje krytyczne czasowo.

Błędem, wręcz niedopuszczalnym, jest używanie w przerwaniu opóźnień, wielokrotnych iteracji itp.

Takie rzeczy przenosi się do programu głównego.

W przypadku odliczania relatywnie długich odcinków czasu niepewność rzędu kilku us wynikająca z przeniesienia obsługi przerwania do funkcji main nie jest problemem.

Oczywiście w takim przypadku programu musi być odpowiednio napisany, z wykorzystaniem większej liczby flag i instrukcji warunkowych, aby instrukcje które nie muszą być wykonywane we wszystkich iteracjach były pomijane. Takie rozwiązanie pozwoli skrócić czas opóźnienia między przerwaniem a obsługującą go instrukcją warunkową.

Link do komentarza
Share on other sites

mog123, takie użycie przerwań jakie widnieje w kodzie w pierwszym poście uniemożliwia wręcz prace w czasie rzeczywistym.

Procesor jest zablokowany wewnątrz obsługi przerwania wiec nie może ani zareagować na inne zdarzenie natychmiast po jego wystąpieniu ani nie ma nawet żadnej metody na przewidzenie kiedy procesor będzie w stanie obsłużyć nowe zdarzenie.

Link do komentarza
Share on other sites

W ogóle kto używając timer'y stosuje delay_ms?😋

masz jakąś inną metode obsługi serw, to sie podziel.

[ Dodano: 10 Sie 10 01:26 ]

volatile int interrupted = 0; 

SIGNAL(SIG_OUTPUT_COMPARE1A)//Przerwanie obsługi serw) 
{ 
   interrupted = 1; 
} 

void handle_interrupt() 
{ 
   // kod wykonywany w tej chwili wewnątrz przerwania 
} 

int main() 
{ 

   // zrob co swoje przed glowna petla 

   while (1) // glowna petla 
   { 
       // zrob w petli co chcesz 

       if (interrupted) 
       { 
           interrupted = 0; 
           handle_interrupt(); 
       } 

       IF(COS TAM)
       {
        //ZRÓB COS
      _DELAY_MS(1000);
        }

   } 
} 

nie moge zrobić tak jak napisałeś wsowa jeśli będzie taka sytuacja jaka napisałem wyżej(kilka instrukcji warunkowych, a w niej też trzeba troche odczekać), program dopiero po skączeniu tych instrukcji mógł by wejść w moją najważniejszą, a chodzi o to żeby dokładnie co 50Hz uc opuszczał program główny i wykonał moje przerwanie.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.