Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Obsługa przerwania timera w ATmega8 avr-gcc

pubus 19 Kwi 2005 19:23 9635 18
  • #1 19 Kwi 2005 19:23
    pubus
    Poziom 30  

    Przekopałem już niejedno forum i na każdym z nich robią to na inną modłe...
    Ale co bym nie tworzył to i tak nie działa...
    Uprościłem program do min i nic...
    Prosze niech ktoś mnie oświeci co jest nie tak...
    Aha do portu PB1 podłączona dioda żeby było wiadomo, że coś się dzieje...

    #include<avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <inttypes.h>

    #define F_CPU 1000000

    unsigned int c=0, s=0;

    int main(void)
    {

    TCCR0 = 0b00000111; //(1 << CS02) | (1 << CS00); prescaler na 1024
    // TIFR |= (1 << TOV0);
    TIMSK |= (1 << TOIE0); // aktywne przerwanie overflow
    // timer_enable_int(_BV(TOIE1));
    TCNT0 = 0;
    sei();

    sbi(DDRB,PB1);

    for(;;);

    return(0);
    }


    SIGNAL (SIG_OVERFLOW)
    {
    sbi(PORTB,PB1);
    }

    0 18
  • Pomocny post
    #2 19 Kwi 2005 19:58
    Viperus
    Poziom 13  

    Witam, jeśli to nie pomyłka przy przepisywaniu to powinno być:
    SIGNAL (SIG_OVERFLOWx)
    gdzie x to jeden lub zero w zależności o który timer Ci chodzi.

    Pozdrawiam, Grzesiek.

    0
  • #3 19 Kwi 2005 20:08
    zumek
    Poziom 39  

    Code:

    SIGNAL (SIG_OVERFLOW)
    {
    sbi(PORTB,PB1);
    }

    Twó kod się nie kompiluje , bo nie może :wink:
    SIG_OVERFLOW=przepełnienie , tylko co ma się przepełnić , czyżby czara goryczy ? :wink:
    SIG_OVERFLOW0 to będzie działać.Poza tym proponuję zmienić kod przerwania na :
    Code:

    SIGNAL (SIG_OVERFLOW)
    {
    PORTB^=(1<<PB1);
    }


    Procek przy obsłudze przerwania ,będzie zmieniał stan pinu PB1 na przeciwny.

    Pozdrawiam
    Piotrek

    0
  • #4 19 Kwi 2005 20:14
    pubus
    Poziom 30  

    Tak faktycznie brak tam 0 ale to nie zmienia nic...
    Program nie działa nadal...
    Ale co cikawe program kompiluje się bez błedu mimo braku 0 lub 1...

    Jupi... poprawka działa tylko to więcej czasu zajmuje niż mi się wydawało...
    To 0 znikneło wśród licznych prób i przeróbek i potem zapomniałem o nim...
    Dzięki ci dobry człowieku... :)

    0
  • #5 19 Kwi 2005 20:14
    tajwoj
    Poziom 23  

    Hej,
    Spróbuj tego:

    Code:

    #include<avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <inttypes.h>

    #define F_CPU 1000000

    unsigned int c=0, s=0;

    int main(void)
    {

      TCCR0 = 0x05; //(1 << CS02) | (1 << CS00); prescaler na 1024
      // TIFR |= (1 << TOV0);
      TIMSK |= (1 << TOIE0); // aktywne przerwanie overflow
      // timer_enable_int(_BV(TOIE1));
      TCNT0 = 0;
      sei();

     // DDRB=DDRB |= _BV(PB1);
        DDRB |= _BV(PB1);
      PORTB &= ~_BV(PB1);
      {
        for(;;)

        return(0);
      }
    }

    SIGNAL (SIG_OVERFLOW0)
    {
      PORTB |= _BV(PB1);
    }

    Poza tym co powiedzieli koledzy miałeś żle ustawiony TCCR0, a w komentarzu był dobrze.
    Pozdrowienia

    0
  • #6 19 Kwi 2005 20:40
    pubus
    Poziom 30  

    Dzięki wszystkim za zainteresowanie i pomoc...
    Mam jeszcze tylko pytanie...
    Zumek jakiego kompilatora używasz bo na WINAVR (avr-gcc) instrukcja
    PORTB^ = (1 << PB1); nie kompiluje się tylko wywwala
    timer.c:30: error: parse error before '=' token

    Czy to może z czymś innym związane...?.?.?

    0
  • #7 19 Kwi 2005 20:52
    tajwoj
    Poziom 23  

    Hej,
    Może zrób tak,

    Code:

    SIGNAL (SIG_OVERFLOW0)
    {
     // PORTB |= _BV(PB1);
       PORTB ^= _BV(PB1);
    }

    Pozdrowienia

    0
  • #8 19 Kwi 2005 20:58
    pubus
    Poziom 30  

    Hehehe...
    Proste a trudno wpaść na to...
    Ciemny jestem ale mnie olśniło...
    Wystarczyło zlikwidować spacje pomiędzy ^ a =....
    No wkażdym razie dzisiaj już nie powinienem myśleć za dużo... :wink:
    Dzięki chłopaki za pomoc...

    0
  • #9 19 Kwi 2005 20:58
    zumek
    Poziom 39  

    Używam WINAVR z gcc-avr v3.4.3 , a jako edytora PN lub AVRSIDE.
    Wkleiłem Twój kod , poprawiłem , standardowe makefile i ... ok.

    Pozdrawiam
    Piotrek

    PS
    He he ... spacja to też znak , nieprawdaż :?:

    0
  • #10 19 Kwi 2005 22:35
    pubus
    Poziom 30  

    Jednak zaczełem jeszcze kombinować...
    Jak policzyś po jakim czasie nastąpi przepełnienie???
    Wydaje mi się, że przy 1MHz wypada 1,5 cyklu na 1us...
    Przy preskalerze 1024 mamy, że tak powiem jedno tyknięcie po ~682,7us...
    Więc 682,7 * 255 wychodzi ~174ms ???

    Ale w praktyka tego nie potwierdza więc jak to jest...?.?.?

    0
  • #11 19 Kwi 2005 22:47
    Viperus
    Poziom 13  

    Polecam ten programik, prosty, łatwy i przyjemny ;)
    a policzyć możesz np. tak: 1024*256/1000000=0,262144s
    Pozdrawiam, Grzesiek.

    0
  • #12 19 Kwi 2005 22:58
    pubus
    Poziom 30  

    Dziękuje za kalkulatorek...
    Ale coś mi się cały czas nie zgadza...
    Wyszło mi, że przerwanie jest generowane co ~262ms...
    A przy programie jak wyżej dioda zapala się i gaśnie co ~4s...
    O co tu chodzi...?.?.?

    0
  • Pomocny post
    #13 19 Kwi 2005 23:11
    Viperus
    Poziom 13  

    To co sugerowal Tajwoj - źle ustawiłeś preskaler, powinno być:

    Code:

     TCCR0 = 0b00000101;

    0
  • #14 19 Kwi 2005 23:58
    LordBlick
    VIP Zasłużony dla elektroda

    Ponieważ kompilator też potrafi liczyć, mój pomysł jest taki (sprawdzony pod asm, być może w C potrzebne jeszcze poprawki) - potrzebujemy konkretny odstęp czasu, więc zadajemy go kompilatorowi, łącznie z wybranym preskalerem, po co się zastanawiać po jakim czasie nastapi przepełnienie, kiedy można to kontrolować (oczywiście w granicach zadanych przez częstotliwość zegara, skalę dzielenia częstotliwości tego zegara poprzez preskaler i pojemność TCNT0 [8bit]) :

    Code:
    #define F_CPU 1000000
    
    .
    .
    .
    .
    #define T0div1024 0x05
    #define T0div256 0x04
    #define T0div64 0x03
    #define T0div8 0x02
    #define T0div1 0x01
    #define T0stop 0x00
    #define T0div T0div64 // tu ustawiamy preskaler - wybieramy jeden z powyższych

    // sprytny sposób na ustawienie aktualnej skali preskalera
    #define Scl0 1024*(T0div==T0div1024)+256*(T0div==T0div256)+64*(T0div==T0div64)+8*(T0div==T0div8)+(T0div==T0div1)

    #define Int0_Pulse_ms 100 // A tu ustawiamy czas pomiędzy przerwaniami w ms

    #define msDiv 1000// milisecond divisor
    #define T0dly ((Int0_Pulse_ms*F_CPU)/(msDiv*Scl0))   

    #define T0cnt (0xFF-T0dly) // A tu mamy gotową obliczoną wartość do odświeżenia TCNT0 na początku
    .
    .
    .
    int main(void)
    {

       TCCR0 = T0div
    .
    .
    .

    SIGNAL (SIG_OVERFLOW0)
    {
       TCNT0=T0cnt
       PORTB |= _BV(PB1);
    }
    Bardzo łatwe do modyfikacji (nie grzebiemy w ciele procedury, a jedynie w nagłówku) i nie trzeba zawracać sobie głowy wartościami bitów, angażować kalkulatora, nawet oryginalnie w asemblerze... Co wy na to ? ;)
    Light'I

    0
  • #15 20 Kwi 2005 11:13
    Viperus
    Poziom 13  

    Witam.

    Cytat:
    Co wy na to ?

    Bardzo fajne, raz wklepać a potem używać, ale mam pytanko, co robi kompilator kiedy z tego dzielenia wychodzą części ułamkowe?
    Code:
    #define T0dly ((Int0_Pulse_ms*F_CPU)/(msDiv*Scl0))

    a co za tym idzie wyrażenie
    Code:
    #define T0cnt (0xFF-T0dly)

    też nie jest całkowite?
    Wybaczcie jeśli pytanie jest banalne. :)

    Grzesiek.

    0
  • #16 20 Kwi 2005 12:42
    fantom
    Poziom 31  

    Light'­­­­I napisał:
    Ponieważ kompilator też potrafi liczyć, mój pomysł jest taki (sprawdzony pod asm, być może w C potrzebne jeszcze poprawki) - potrzebujemy konkretny odstęp czasu, więc zadajemy go kompilatorowi, łącznie z wybranym preskalerem, po co się zastanawiać po jakim czasie nastapi przepełnienie, kiedy można to kontrolować (oczywiście w granicach zadanych przez częstotliwość zegara, skalę dzielenia częstotliwości tego zegara poprzez preskaler i pojemność TCNT0 [8bit]) :
    Code:
    #define F_CPU 1000000
    
    .
    .
    .
    .
    #define T0div1024 0x05
    #define T0div256 0x04
    #define T0div64 0x03
    #define T0div8 0x02
    #define T0div1 0x01
    #define T0stop 0x00
    #define T0div T0div64 // tu ustawiamy preskaler - wybieramy jeden z powyższych

    // sprytny sposób na ustawienie aktualnej skali preskalera
    #define Scl0 1024*(T0div==T0div1024)+256*(T0div==T0div256)+64*(T0div==T0div64)+8*(T0div==T0div8)+(T0div==T0div1)

    #define Int0_Pulse_ms 100 // A tu ustawiamy czas pomiędzy przerwaniami w ms

    #define msDiv 1000// milisecond divisor
    #define T0dly ((Int0_Pulse_ms*F_CPU)/(msDiv*Scl0))   

    #define T0cnt (0xFF-T0dly) // A tu mamy gotową obliczoną wartość do odświeżenia TCNT0 na początku
    .
    .
    .
    int main(void)
    {

       TCCR0 = T0div
    .
    .
    .

    SIGNAL (SIG_OVERFLOW0)
    {
       TCNT0=T0cnt
       PORTB |= _BV(PB1);
    }
    Bardzo łatwe do modyfikacji (nie grzebiemy w ciele procedury, a jedynie w nagłówku) i nie trzeba zawracać sobie głowy wartościami bitów, angażować kalkulatora, nawet oryginalnie w asemblerze... Co wy na to ? ;)
    Light'I

    Preprocesor niestety nie liczy tylko wstawia zdefiniowane makro.Takim sposobem "zarzniesz" mikrokontroler obliczeniami.Poza tym lepsza (szybsza) alternatywa przy mnozeniu przez liczby potegi 2 jest przesuniecie bitowe.

    0
  • #17 21 Kwi 2005 01:48
    LordBlick
    VIP Zasłużony dla elektroda

    Viperus napisał:
    Witam.
    Cytat:
    Co wy na to ?

    Bardzo fajne, raz wklepać a potem używać, ale mam pytanko, co robi kompilator kiedy z tego dzielenia wychodzą części ułamkowe?
    Część ułamkowa jest obcinana, bo i tak nie da się jej wpisać w 8-bitowy rejestr licznika. Chcąc osiągnąć jeszcze większą dokładność, można próbować na mniejszej skali preskalera (np. 256) i/lub większej pojemności licznika np. Timer1 - 16bit :
    Code:
    .
    
    .
    .
    #define Int1_Pulse_ms 100 // A tu ustawiamy czas pomiędzy przerwaniami w ms

    #define msDiv 1000// milisecond divisor
    #define T1dly ((Int1_Pulse_ms*F_CPU)/(msDiv*Scl1)) // Scl1 analogicznie jak Scl0

    #define T1cnt (0xFFFF-T1dly) // A tu mamy gotową obliczoną wartość do odświeżenia TCNT1L:TCNT1H na początku
    .
    .
    .
    .

    fantom napisał:
    Preprocesor niestety nie liczy tylko wstawia zdefiniowane makro.Takim sposobem "zarzniesz" mikrokontroler obliczeniami.
    Na prawdę się nie da popchnąć kompilatora jakimś "kijem", aby to przeliczył ? (#pragma ?) Nie chce mi się wierzyć... Jeśli jednak nie, to przepraszam, w takim razie wycofuję mój pomysł do krainy AVRasm (AVRStudio), gdzie preprocesor to poprostu przelicza i w rejestrach lądują prawidłowe, obliczone wartości... ;)
    fantom napisał:
    Poza tym lepsza (szybsza) alternatywa przy mnozeniu przez liczby potegi 2 jest przesuniecie bitowe.
    Przy założeniu, ze obliczenia dokonuje kompilator, nie widzę zbytniego powodu do optymalizacji tegoż. Nie widzę potrzeby komplikowania czytelności, gdyby jednak to nie mikrokontroler się pocił... Kolega nie zrozumiał chyba jednak moich intencji przy mnożeniu przez 1024 256, 16 itd. - zawsze tylko jedno wyrażenie logiczne jest prawdziwe (==1), a pozostałe fałszywe (==0), przez co "Scl0" będzie albo równy 1024 albo 256 albo 16... Tak przynajmniej traktuje sprawę preprocesorek od Atmela, wydało to mi się zbliżone do preprocesora w C.
    Pozdrawiam, Light'I

    0
  • #18 21 Kwi 2005 08:19
    fantom
    Poziom 31  

    Tez mi sie wydaje dziwne ze nie mozna tak zrobic ale niestety tak jest.Zrozumielem dokladnie o co ci chodzilo jako ze kiedys sam lamalem sobie glowe nad asmem ale w razie jakby chciec to zrobic w ten sposob lepiej jest dac przesuniecie bitowe bo bedzie ono efektywniejsze.

    0
  • #19 21 Kwi 2005 21:07
    LordBlick
    VIP Zasłużony dla elektroda

    fantom napisał:
    Tez mi się wydaje dziwne ze nie mozna tak zrobic ale niestety tak jest.Zrozumielem dokladnie o co ci chodzilo jako ze kiedys sam lamalem sobie glowe nad asmem ale w razie jakby chciec to zrobic w ten sposob lepiej jest dac przesuniecie bitowe bo bedzie ono efektywniejsze.
    Hmmm... a jeśli nawet to mikrokontroler miałby nawet obliczyć sobie to raz po resecie, to też by nie było takie głupie - wartość zegara i opóźnienie wpisane w jakimś miejscu w EEPROM...
    Co do przesunięć bitowych, to nie znalazłem innej bezwarunkowej reguły, aby odwzorować skończony ciąg : 5, 4, 3, 2, 1 na : 1024, 256, 64, 8, 1
    Light'I

    0