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

Dlaczego przerwanie timera w ATmega8 nie działa? Dioda na PB1 nie świeci

pubus 19 Kwi 2005 19:23 10085 18
REKLAMA
  • #1 1419751
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 139
    Ocena: 32
    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);
    }
  • REKLAMA
  • Pomocny post
    #2 1419866
    Viperus
    Poziom 14  
    Posty: 75
    Pomógł: 6
    Ocena: 5
    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.
  • REKLAMA
  • #3 1419902
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    
    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 :
    
    SIGNAL (SIG_OVERFLOW)
    {
    PORTB^=(1<<PB1);
    }
    
    

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

    Pozdrawiam
    Piotrek
  • #4 1419928
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 139
    Ocena: 32
    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... :)
  • #5 1419930
    tajwoj
    Poziom 26  
    Posty: 560
    Pomógł: 106
    Ocena: 102
    Hej,
    Spróbuj tego:
    
    #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
  • #6 1420016
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 139
    Ocena: 32
    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...?.?.?
  • REKLAMA
  • #8 1420086
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 139
    Ocena: 32
    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...
  • REKLAMA
  • #9 1420090
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    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ż :?:
  • #10 1420418
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 139
    Ocena: 32
    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...?.?.?
  • #11 1420461
    Viperus
    Poziom 14  
    Posty: 75
    Pomógł: 6
    Ocena: 5
    Polecam ten programik, prosty, łatwy i przyjemny ;)
    a policzyć możesz np. tak: 1024*256/1000000=0,262144s
    Pozdrawiam, Grzesiek.
    Załączniki:
    • kalk.exe (224 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #12 1420499
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 139
    Ocena: 32
    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...?.?.?
  • #14 1420680
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    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]) :
    #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
  • #15 1421424
    Viperus
    Poziom 14  
    Posty: 75
    Pomógł: 6
    Ocena: 5
    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?
    #define T0dly ((Int0_Pulse_ms*F_CPU)/(msDiv*Scl0))

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

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

    Grzesiek.
  • #16 1421643
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    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]) :
    #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.
  • #17 1423893
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    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 :
    .
    .
    .
    #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
  • #18 1424071
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 42
    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.
  • #19 1425894
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    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

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemu z działaniem przerwania timera w mikrokontrolerze ATmega8, gdzie dioda podłączona do pinu PB1 nie świeci podczas przepełnienia timera. Głównym błędem było użycie niepoprawnej nazwy procedury obsługi przerwania – zamiast SIGNAL(SIG_OVERFLOW) należy użyć SIGNAL(SIG_OVERFLOW0) dla timera 0. Poprawne ustawienie rejestru TCCR0 na wartość 0x05 (preskaler 1024) jest kluczowe dla prawidłowego działania przerwania. Wskazano również, że instrukcja PORTB ^= (1
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA