logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[ATmega16][AVR-GCC] Zwłoka w obsłudze przerwania

speecu 20 Mar 2009 02:44 2318 5
  • #1 6306078
    speecu
    Poziom 11  
    Witam!

    Napisałem programik którym liczę ilość cykli procesora pomiędzy dwoma punktami programu, na zasadzie obliczenia różnicy pomiędzy dwiema wartościami licznika Timera1A ustawionego z preskalerem 1.

    Niedawno potrzebowałem zmierzyć ile cykli potrzebuje uC od momentu wystąpienia przerwania, a rozpoczęciem jego obsługi i stworzyłem takie coś.
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <zl8avr.h> //Odpowiednik "hd44780.h" + kilka dodatkowych funkcji obsługi wyświetlacza
    
    unsigned int mark[2]={0,0};// Zmienna do której wpisane zostaną odpowiednie wartości licznika
    
    
    int main (void){
    DDRD=255;
    LCD_Initalize();
    LCD_Clear();
    // Inicjalizacja obsługi przerwania INT0 na zboczu opadającym
    GICR |= _BV(INT0);
    MCUCR |= _BV(ISC01);
    // Uruchomienie licznika z preskalerem 1/1
    TCCR1B |= (1 << WGM12) | (1 << CS10);
    OCR1A = 65000;
    sei();
    PORTD|=(1<<2);
    
    PORTD&=~(1<<2);// Wyzwolenie przerwania opadającym zboczem
    
    // Ustawienie pierwszego pomiaru licznika
    mark[0]=TCNT1;
    
    while(1){}
    return 0;
    }
    
    SIGNAL (SIG_INTERRUPT0) {  // Wstawienie zamiast SIGNAL ISR nie robi różnicy
    mark[1]=TCNT1;// Ustawienie drugiego pomiaru licznika
    
    // Wyświetlenie różnicy na wyświetlaczu
    LCD_GoTo(0,0);
    LCD_liczba16(mark[1]-mark[0]);
    
    }


    Wiem, że istnieje zwłoka pomiędzy wystąpieniem przerwania, a jego obsługą (datekcja stanu pina, ustawienie flag, dokończenie wykonywanej instrukcji, zapisanie na stosie adresu powrotu z obsługi przerwania, itd.).
    I w związku z tym mam trzy pytania:
    1. Czy wynik 49 jest rzeczywistym czasem, który potrzebuje uC na uruchomienie obsługi przerwania, czy powinien być krótszy (kilkanaście, dwadzieścia kilka cykli)?
    2. Czy założenia pomiaru są poprawne, czy też robię gdzieś błąd, w wyniku czego występuje aż taka wartość zwłoki (jestem świadom różnicy 2 cykli na przypisanie TCNT1 do zmiennej)?
    3. Czy watchdog ma coś wspólnego z obsługą zewnętrznych przerwań (nie znam na tyle biegle angielskiego, aby dokładnie zrozumieć notę, ale jak się domyślam, należy brać go pod uwagę gdy chodzi o wybudzenie uC za pomocą INT0 z trybu Sleep)?

    Pozdrawiam
  • #2 6306110
    Dr.Vee
    VIP Zasłużony dla elektroda
    A nie łaska obejrzeć co za kod wygenerował kompilator? Poza tym jak to robisz, że najpierw wyzwalasz przerwanie, a później zapisujesz mark[0]? Dzięki temu w przerwaniu mark[0] == 0. Poza tym pomiędzy uruchomieniem timera1 i wyzwoleniem przerwania robisz dodatkowe, niepotrzebne rzeczy. Na dodatek do pomiaru wystarczy Ci timer0...

    Pozdrawiam,
    Dr.Vee
  • #3 6306719
    Konto nie istnieje
    Poziom 1  
  • #4 6307290
    Dr.Vee
    VIP Zasłużony dla elektroda
    atom1477 napisał:
    Dr.Vee: On użył Timera1 bo to ma być uniwersalna procedura pomiaru czasu.

    W takim razie najlepiej użyć input capture i nie będzie żadnych opóźnień.

    Pozdrawiam,
    Dr.Vee
  • #5 6307376
    _Robak_
    Poziom 33  
    A najlepiej sobie w AVR studio symulowac i zobaczyc ile co zajmuje :) Mozna porownac sobie roznice w asm i C.
  • #6 6307744
    speecu
    Poziom 11  
    Witam!

    Wielkie dzięki kolego atom1477 za wytłumaczenie mi dlaczego tak się dzieje i innym dlaczego tak zrobiłem, oszczędziło mi to pisania;) .
    Zrobiłem tak:
    mark[0]=TCNT1; 
    PORTD&=~(1<<2);// Wyzwolenie przerwania opadającym zboczem 
    _delay_ms(500);
    LCD_GoTo(0,0); 
    LCD_liczba16(mark[1]-mark[0]);
    while(1){} 
    return 0; 
    } 
    SIGNAL (SIG_INTERRUPT0) {
    mark[1]=TCNT1;// Ustawienie drugiego pomiaru licznika 
    }


    i wyszło 28.

    Dziekuję również innym za pomoc.
REKLAMA