Pytanie:
Jaki jest maksymalny czas wykonywania procedury obsługi przerwań na ATmega328P?
thebear8
2019-07-11 17:44:36 UTC
view on stackexchange narkive permalink

Mam ATmega328P, który sprawdza, czy przycisk został naciśnięty przez przerwanie zmiany pinów.Teraz chcę włączyć diodę LED na 200 ms. Czy mogę po prostu włączyć diodę LED, odczekać 200 ms i wyłączyć ją w ISR, jak w poniższym kodzie?

  ISR (PCINT1_vect)
{
    jeśli (PINB & 0b1)
    {
         PORT = 0b10;
         _delay_ms (200);
         PORT = 0;
    }
}
 

W kilku postach na forum na AVR Freaks przeczytałem, że nie powinieneś spędzać dużo czasu w ISR, ale nigdy nie widziałem żadnych dokładnych liczb.Niestety nie mogę już znaleźć tych postów, więc nie mogę ich połączyć.O ile pamiętam, wszyscy mówili, że jeśli spędzisz zbyt dużo czasu w ISR, mikrokontroler może się zawiesić. Czy to prawda?A jeśli tak, to czy istnieje dokładny termin, po którym to może się wydarzyć?

Pięć odpowiedzi:
Neil_UK
2019-07-11 17:52:02 UTC
view on stackexchange narkive permalink

Jeśli nic innego nie działa w MCU, możesz zająć się tak długo, jak chcesz, w ISR. Ale to zły nawyk, a to oznacza, że jeśli chcesz zrobić cokolwiek innego, prawdopodobnie będziesz musiał przerobić kod.

Szczególnym przypadkiem jest sytuacja, gdy MCU używa biblioteki szeregowej, która oczekuje, że przerwania będą działały wystarczająco często, aby obsłużyć otrzymane pojedyncze znaki.Przy 115 200 bodów (wysoka prędkość szeregowa często używana w celu zminimalizowania czasu pobierania) między znakami jest mniej niż 100 µs.Jeśli zablokujesz przerwania na dłużej, ryzykujesz utratę wprowadzonych znaków.

Zasadniczo zrób absolutne minimum w ISR.W twojej aplikacji rozsądnym rozwiązaniem byłoby przerwanie co ms, które zwiększa i sprawdza wartość licznika.Jestem pewien, że możesz wypracować odpowiednią logikę, aby ustawić i przetestować licznik, aby uzyskać 200 ms między włączaniem i wyłączaniem zdarzeń.

Dave Tweed
2019-07-11 17:49:14 UTC
view on stackexchange narkive permalink

W najgorszym przypadku ISR może działać aż do ponownego wystąpienia następnego przerwania tego samego typu.

Ale ogólnie rzecz biorąc, spędzanie więcej czasu w ISR, niż jest to absolutnie konieczne, jest złą praktyką projektową, ponieważ w ogóle uniemożliwia to uruchomienie całego innego kodu.To duży problem w przypadku czegokolwiek innego niż trywialne programy.

Powiedziałbym, że w najgorszym przypadku ISR może działać w nieskończoność, zapobiegając ponownemu wystąpieniu kolejnego IRQ.
@DmitryGrigoryev: W tym przypadku miałem na myśli „najgorszy przypadek” w kategoriach braku natychmiastowej awarii systemu.
Brethlosze
2019-07-11 17:51:50 UTC
view on stackexchange narkive permalink

Chociaż praktyka polega na przydzielaniu minimalnych możliwych cykli wykonywania w przerwach i poza innymi ogólnymi specyfikacjami sprzętowymi, nie ma ograniczeń technicznych dotyczących ich zwiększania, jeśli nie ma żadnych innych przerw do wykonania.

W attachInterrupt () Dokumentacja Arduino:

Ogólnie rzecz biorąc, ISR powinien być możliwie krótki i szybki. Jeżeli twój Sketch używa wielu ISR, tylko jeden może działać na raz, inne przerwania zostaną wykonane po zakończeniu bieżącego zlecenia zależy to od priorytetu, jaki mają. millis () opiera się na przerwaniach liczyć, więc nigdy nie będzie wzrastać wewnątrz ISR. Od opóźnienia () wymaga przerwania do działania, nie zadziała, jeśli zostanie wywołany wewnątrz ISR. Funkcja micros () działa początkowo, ale zacznie działać nieprawidłowo po 1-2 SM. delayMicroseconds () nie używa żadnego licznika, więc będzie działać jako normalne.

Mając 25 możliwych przerw w tej rodzinie procesorów, zaleca się traktowanie ich jak punktualne zdarzenia, aby umożliwić wystąpienie innych przerw.

Chociaż opóźnienie w ISR jest ogólnie złym pomysłem, pytanie wykorzystuje coś, co wydaje się być `_delay_ms ()` avr-gcc, które jest oparte na cyklach w przeciwieństwie do funkcji Arduino `delay () ', która opiera się na przerwaniu timera.
Dmitry Grigoryev
2019-07-12 13:45:51 UTC
view on stackexchange narkive permalink

Z technicznego punktu widzenia nie jest zabronione nawet rozpoczęcie nieskończonej pętli w przerwaniu, więc nie ma górnego limitu czasu wykonania ISR. Jednak przerwania są najbardziej przydatne, gdy chcesz, no cóż, przerwać normalny przepływ programu, aby wykonać krótkie działanie, które należy wykonać natychmiast , a kwalifikatory „krótkie” i „natychmiastowe” są naturalnie powiązane: jeśli twój najdłuższy ISR zajmuje 1 ms, to przychodzące przerwanie o tym samym priorytecie będzie miało czas odpowiedzi 1 ms. Tak więc w istocie czas wykonania ISR jest ograniczony przez pożądany czas odpowiedzi IRQ .

Jeśli twój program spędza dużo czasu czekając na przerwanie, łatwiejsze może być całkowite porzucenie przerwań i użycie odpytywania, co znacznie ułatwia programowanie.

Istnieją przypadki, w których możesz nadużywać przerwań, aby uruchamiać mniej lub bardziej regularny kod. Jednym z przykładów może być zaimplementowanie priorytetu zadania: zadanie o niskim priorytecie jest uruchamiane z głównej pętli, podczas gdy zadanie o wyższym priorytecie jest okresowo wyzwalanym przerwaniem czasowym. Odbywa się to zwykle na MCU z kilkoma poziomami priorytetów IRQ, dzięki czemu system może nadal mieć regularne ISR w razie potrzeby.

AaronD
2019-07-12 03:21:12 UTC
view on stackexchange narkive permalink

Masz jednordzeniowy, jednowątkowy procesor. Oznacza to, że w danym momencie robi dokładnie jedną rzecz. Jeśli twoja aplikacja wymaga od tego kilku rzeczy, to kod musi być zaprojektowany tak, aby przełączał się między nimi wszystkimi. Może to być tak banalne lub złożone, jak chcesz.

Zwykle procesor kręci się wokół głównej pętli, robiąc wszystko, co tam jest, i to wszystko dobrze i dobrze, dopóki nie nastąpi przerwanie. Sprzęt przerwań w zasadzie wymusza wywołanie funkcji do odpowiedniego ISR, mimo że nie ma dla niego instrukcji wywołania w głównej pętli. Z tej nieprzewidywalności wywodzi się większość reguł pisania ISRów.

Niezależnie od tego, jaki czas spędzasz w ISR, jest to czas, w którym główna pętla zostaje wstrzymana w oczekiwaniu na powrót ISR. Jeśli główna pętla jest jedyną, która resetuje aktywny zegar watchdoga (bardzo dobra praktyka), wówczas watchdog nie zostanie zresetowany w tym czasie. Jeśli watchdog przekroczy limit czasu, spowoduje to twardy reset. Podobnie jak reset zewnętrzny, ale z różnymi flagami, które można sprawdzić podczas uruchamiania. To prawdopodobnie „awaria”, o której słyszałeś.


Bardzo dobrą praktyką jest używanie watchdoga i resetowanie go tylko przy każdym przejściu wokół głównej pętli. Zmusza to do pisania kodu, który pozostaje responsywny. Jeśli musisz na coś poczekać, możesz ustawić wydarzenie (zakończony czas, kolejna otrzymana postać itp.) I przejść dalej. Sprawdzaj okresowo, czy wystąpiło to zdarzenie lub ustaw kolejne przerwanie na jego zakończenie, a następnie wróć do niego. W międzyczasie kontynuuj wszystko, co robiłeś.

Moja główna struktura wygląda zwykle tak:

  #include "module1.h"
#include „module2.h”

void main (void)
{
    //ogólny
    //żeton
    //Ustawiać

    mod1_init ();
    mod2_init ();

    // wyczyść flagi przerwań
    // włączenie globalnego przerwania

    podczas gdy (1)
    {
        // wyczyść watchdog

        mod1_run ();
        mod2_run ();
    }
}
 

A moje moduły wyglądają tak:

  void modX_init (void)
{
// sprzęt i zmienna init tylko dla tego modułu
    // nie używaj przerwań, jeśli odpytywanie jest wystarczająco dobre
}

void modX_run (void)
{
    jeśli (POLLED_INTERRUPT_FLAG)
    {
        POLLED_INTERRUPT_FLAG = 0;

        // nieblokujący kod „ISR”
    }
}

void ISR modX_ISR (nieważne)
{
    // OK, to wymaga * natychmiastowej * odpowiedzi
    // Spędź tutaj absolutnie minimalny czas i wyjdź
}
 

Sygnatury funkcji nie muszą być void , ale większość z nich tak. Czasami w jednym module mam trochę czasu, który jest również używany przez inny, i przydatne jest użycie wartości zwracanej z jednej modX_run () i argumentów innego (lub jakiejś podstawowej logiki) do nawiązać połączenie. Na przykład:

  if (DMX_run ()) // zawiera własne taktowanie i zwraca true na początku każdego interwału 30 Hz, w przeciwnym razie false
{
    I2C_start (); // Ramki I2C są synchronizowane z DMX
}
I2C_run (); // po uruchomieniu ramka I2C działa swobodnie aż do zakończenia
 

Jeśli przestudiujesz arkusz danych, może się okazać, że sprzętowe urządzenia peryferyjne można masować, aby robić to, co chcesz, bez jakiejkolwiek interwencji procesora.

Powszechnie jest na przykład generowanie impulsu wyjściowego. Włącz go, ustaw urządzenie peryferyjne, aby je wyłączało jakiś czas później i zapomnij o tym. Zwykle znajduje się w tym samym obszarze co PWM.



To pytanie i odpowiedź zostało automatycznie przetłumaczone z języka angielskiego.Oryginalna treść jest dostępna na stackexchange, za co dziękujemy za licencję cc by-sa 4.0, w ramach której jest rozpowszechniana.
Loading...