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

[ATTINY2313][c]Przerwanie wywołane w innym przerwaniu

smajlas 29 Gru 2010 01:20 1293 1
REKLAMA
  • #1 8927493
    smajlas
    Poziom 12  
    Witam!
    Ze względu na niedokładność funkcji waitms(); postanowiłem uruchomić licznik TC1 w ATTINY2313.
    Ma to być obsługa pilota (prawdopodobnie JVC).
    Więcej danych:
    - ATTINY pracuje z częstotliwością 1MHz (wewnętrzny oscylator)
    - TC0 jest już zajęty innymi działaniami (w czasie obsługi pilota TC0 nie musi pracować)
    - czas, który chcę odczekać to 14700us (14,7ms)
    - moment, kiedy zaczynam odliczanie zaczyna się ze zboczem opadającym na wejściu PCINT0 (tam podłączony jest czujnik IR)

    Dlatego ułożyłem takie coś:

    
    SIGNAL(PCINT_vect) //obsługa przerwania generowanego z PCINT0----
    {
    PORTB ^= _BV(PB3); //żeby sprawdzić po jakim czasie znajdziemy się w przerwaniu - to jest znak na start
    
    PCMSK=0x00; //zablokuj przerwanie od pilota
    
    TCCR1B = 0x01;	//preskaler dla TC1 0x01 - CLK, 0x02 - CLK/8
    TCNT1H = 0xC6; // załadowanie do licznika TIMER1 wartości początkowych
    TCNT1L = 0x93; // określających częstotliwość występowania przerwania
    //hFFFF - hC693 = d14700
    
    TIMSK=0b10000000; 		//odblokuj TC1, zablokuj TC0
     //odblokuj TC1 z ustawionym czasem 14700us
    }
    
    SIGNAL(SIG_OVERFLOW1)//to przerwanie musi być wyzwolone jako pierwsza rzecz w obsłudze przerwania wywołanego
    //rozpoczęciem nadawania pilota
    {
    cli();
    TCCR1B = 0x04; //preskaler dla TC1 0x01 - CLK, 0x02 - CLK/8 0x04 - CLK/256
    TCNT1H = 0x00; // załadowanie do licznika TIMER1 wartości początkowych
    TCNT1L = 0x00; // określających częstotliwość występowania przerwania
    
    /*
    powyższe 3 linijki wstawiłem bo jak ich nie ma, to TCNT1H i L zwiększają się wywołując następne przerwanie, zanim to
    zostanie obsłużone do końca. W momencie wyjścia z tej obsługi program automatycznie do niej wraca (4 razy).
    */
    PORTB ^= _BV(PB2); //sprawdzenie czy tu jesteśmy:
     
    
    unsigned char msb, lsb;
    
    read_byte();
    read_byte();
    msb=read_byte();
    lsb=read_byte();
    //wszystkie cztery read_byte trwają około 55ms
    
    if(msb==0x70) //h70 i h80 to odpowiednie kody dla vol+ i vol-
    	{dfactor++;
    	//PORTB ^= _BV(PB2);
    	}
    if(msb==0xB0)
    	{dfactor--;
    	//PORTB ^= _BV(PB2);
    	}
    if (dfactor>=10) dfactor=0;
    if (dfactor<=0) dfactor=9;
    PCMSK=0x01; //odblokowanie przerwania od pilota (Pin Change Mask)
    TIMSK=0b00000010; //zablokowanie TC1, odblokowanie TC0
    
    sei();
    }
    
    


    Do PB2 i PB3 podłączone są diody, czasy załączania sprawdzam oscyloskopem. Niestety, zamiast 14700us PB2 włącza się 1,7ms po PB3. Ponadto opóźnienie nie jest wykonywane za każdym razem.
    Ponadto PB2 i PB3 zmieniają stan na przeciwny po około 50 - 54ms (cała "paczka" z pilota trwa ok.70ms)
    Proszę o sugestie.
  • REKLAMA
  • #2 8927737
    Andrzej__S
    Poziom 28  
    smajlas napisał:

    ...zamiast 14700us PB2 włącza się 1,7ms po PB3...

    Nie wiem, z jaką dokładnością mierzysz te 1,7ms, ale jako że 14,7ms/8=1,8375ms (czyli może być w granicach błędu pomiaru) sugerowałbym sprawdzenie, czy fuse bit CKDIV8 jest prawidłowo ustawiony. Po prostu wygląda na to, że masz 8MHz zamiast 1MHz.

    smajlas napisał:

    
    TCCR1B = 0x04; //preskaler dla TC1 0x01 - CLK, 0x02 - CLK/8 0x04 - CLK/256
    TCNT1H = 0x00; // załadowanie do licznika TIMER1 wartości początkowych
    TCNT1L = 0x00; // określających częstotliwość występowania przerwania
    
    /*
    powyższe 3 linijki wstawiłem bo jak ich nie ma, to TCNT1H i L zwiększają się wywołując następne przerwanie, zanim to
    zostanie obsłużone do końca. W momencie wyjścia z tej obsługi program automatycznie do niej wraca (4 razy).
    */ 
    


    Jeśli nie chcesz, żeby TCNT1 wywoływał przerwanie, to dlaczego go nie wyłączysz całkowicie (np. poprzez TCCR1B=0;) zamiast zmieniać preskaler?

    smajlas napisał:

    
    SIGNAL(SIG_OVERFLOW1)//to przerwanie musi być wyzwolone jako pierwsza rzecz w obsłudze przerwania wywołanego
    //rozpoczęciem nadawania pilota
    { 
    ......
    PCMSK=0x01; //odblokowanie przerwania od pilota (Pin Change Mask) 
    ......
    }
    


    Odblokowujesz, ale nie zauważyłem, gdzie je blokujesz (chyba, że wewnątrz funkcji read_byte()), bo przecież gdzieś powinieneś je zablokować. W innym przypadku, w czasie odbierania danych z pilota flaga PCIF zostanie ustawiona i po zakończeniu obsługi przerwania timera 1 program przejdzie do obsługi przerwania PCINT, co - jak przypuszczam - nie jest zamierzonym działaniem.
    Poza tym nie przedstawiłeś kodu funkcji read_byte(), więc trudno to dokładnie ocenić, ale generalnie stosowanie długo trwających funkcji (zawierających zapewne jakieś opóźnienia) wewnątrz procedury obsługi przerwania to zwykle nie najlepszy pomysł.
    No i stosowanie cli(); na początku obsługi przerwania oraz sei(); na końcu wprawdzie nie ma większego wpływu na działanie programu, ale jest zwyczajnie zbędne. Procesor robi to sam.

    P.S. Makro SIGNAL jest przestarzałe. W nowych programach zalecane jest stosowanie makra ISR zdefiniowanego w <avr/interrupt.h>.
REKLAMA