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

[ATmega64][C]Obsługa przerwania TIMER0

Co_pat 20 Gru 2009 23:04 4019 9
REKLAMA
  • #1 7416307
    Co_pat
    Poziom 15  
    Witam!

    Chciałem wykorzystać timer0 do dokładnego odmierzania czasu, jednak coś powoduje zawieszenie całego programu. Dzieje się tak gdy próbuję odczytać wartość zmiennej w obsłudze przerwania lub w pętli głównej programu. Przerwania od timera są na pewno obsługiwane ponieważ działa zmiana stanu portu w obsłudze przerwania. Kod wygląda następująco:
    
    
    //ZMIENNE GLOBALNE
    volatile unsigned long miliSekundy=0;           
    
    
    void Init(void){
    
        DDRA=0xFF;                                        //port A jako wyjscie
        DDRD=0x00;                                        //Potr D jako wejścia
        PORTD=0xFF;                                        //z podziagnieciem do Vcc
    
    
    }
    
    void InitTimer0()                            // Inicjalizacja Timera0 w trybie CTC do dokładnego odmierzania czasu
    {
      TCNT0 = 0x00;                                // Wyzerowanie zawartości rejestru Timera2
     
      /* Praca w trybie Clear Timer on Compare (CTC) */
      TCCR0 = 0x0a;                                // 0 0 0 0 1 0 1 1 - linia portu OC2 odcięta, tryb: CTC,
                                                //                     preskaler: 128;
                                                //                    Częstotliwość zegara: 16MHz/128 = 125kHz
      OCR0 = 125;                                // Porównania będą następować z częstotliwością: 125kHz/125 = 1kHz
                                                // czyli reset co 1ms
                           
      /* Aktywacja przerwań */
      Set(TIMSK, OCIE0);                        // Zezwolenie na przerwanie od porównania
      Set(SREG, 7);                                // Globalne zezwolenie na przerwania
    }
    
    
    
    int main(){
    
        Init();
        InitTimer0();
    
        Clr(PORTA,PA3);
        Set(PORTA,PA0);
        Set(PORTA,PA1);
    
    while(1){
    
    
    }}
    
    
    
    ISR(TIMER0_COMP_vect)    // Przerwanie występujące przy porównaniu (co 1ms)
    {
      ++miliSekundy;
    
       
        Flip(PORTA,PA2);                    //DZIAŁA
    
        /*
        if(miliSekundy>=100){
        miliSekundy=0;                        // NIE DZIAŁA
         Flip(PORTA,PA2);}
          */
    }


    Z góry dziękuję za pomoc jak i cenne wskazówki :-)
  • REKLAMA
  • #2 7416904
    zumek
    Poziom 39  
    Co_pat napisał:
    ... jak i cenne wskazówki :-)

    Pierwsza cenna wskazówka:
    
      /* Praca w trybie Clear Timer on Compare (CTC) */
      TCCR0 = 0x0a;                                // 0 0 0 0 1 0 1 1 - linia portu OC2 odcięta, tryb: CTC,
                                                //                     preskaler: 128;
    

    Nie zapisuj "nicniemówiącej" konfiguracji do rejestru - bo czymże jest to tajemnicze "0x0a" :?:
    Tak należałoby to zrobić, by osiągnąć zamierzony przez Ciebie tryb pracy:
    TCCR0=(1<<WGM01)|(1<<CS02)|(1<<CS00)

    I powiadam Ci, że w powyższym przykładzie do rejestru TCCR0 nie zostanie zapisane ani "0x0a", ani "0 0 0 0 1 0 1 1" - jak w komentarzu.

    Po wtóre: Nie uruchamiaj timera0 w trybie CTC, przed zapisem do OCR0, bo może się to na Tobie zemścić :D

    I na zakończenie: W załączonym fragmencie kodu, trudno będzie znaleźć przyczynę ... "awarii" ;)
  • REKLAMA
  • #3 7419681
    Co_pat
    Poziom 15  
    Wielkie dzięki za odpowiedź.
    Jeżeli chodzi o konfiguracje rejestru TCCR0 to wzorowałem się na pracy dyplomowej w której był taki zapis i działał poprawnie.

    Wcześniej nie używałem tego rodzaju zapisu.
    TCCR0=(1<<WGM01)|(1<<CS02)|(1<<CS00)

    Rozumiem, że w przyszłości jak będę konfigurował jakiś rejestr to należy to zrobić podobnie jak wyżej i np przy konfiguracji przerwania INT1 będzie to wyglądało następująco:
    EICRA=(1<<ISC31)  //generowanie przerwania opadającym zboczem
    EIMSK=(1<<INT1)   //odblokowanie przerwania od INT1
    

    ale to w przypadku "ustawiania" bitów, a jak będzie wyglądał ten zapis w przypadku "zerowania" bitu?

    Wracając do timera, zmiana zapisu nie pomogła, ale zauważyłem następującą zależność:
    
    
    //ZMIENNE GLOBALNE
    volatile unsigned long int miliSekundy;					//volatile stosować gdzy jest zmieniana wartosc zmiennej przez przerwanie
    volatile unsigned char switch_f; 					//flaga -> przycisk
    volatile unsigned long int ms;
    
    void Init(void){
    
    	DDRA=0xFF;										//port A jako wyjscie
    	DDRD=0x00;										//Potr D jako wejścia
    	PORTD=0xFF;										//z podziagnieciem do Vcc
    }
    
    void InitTimer0()								// Inicjalizacja Timera0 w trybie CTC do dokładnego odmierzania czasu
    {
    	TCNT0 = 0x00;								// Wyzerowanie zawartości rejestru Timera2
     	OCR0 = 125;	
    	/* Praca w trybie Clear Timer on Compare (CTC) */
    	TCCR0=(1<<WGM01)|(1<<CS02)|(1<<CS00);								// 0 0 0 0 1 0 1 1 - linia portu OC2 odcięta, tryb: CTC,
    												// 					 preskaler: 128;
    												//					 Częstotliwość zegara: 16MHz/128 = 125kHz
    								// Porównania będą następować z częstotliwością: 125kHz/125 = 1kHz
    												// czyli reset co 1ms
    							
    	/* Aktywacja przerwań */
    	Set(TIMSK, OCIE0);							// Zezwolenie na przerwanie od porównania
    	Set(SREG, 7);								// Globalne zezwolenie na przerwania
    }
    
    int main(){
    
    	Init();
    	InitSwitch();
    	InitTimer0();
    
    	Clr(PORTA,PA3);
    	Set(PORTA,PA0);
    	Set(PORTA,PA1);
    	miliSekundy=0;
    
    while(1){
       }
    }
    
    ISR(TIMER0_COMP_vect)	// Przerwanie występujące przy porównaniu (co 1ms)
    {
    	++miliSekundy;
    	ms = miliSekundy;
    
    	if(ms==1){
    		ms=0;						
    		Flip(PORTA,PA2);}
    }

    Jeżeli w obsłudze przerwania jest taki warunek:

    to widać,że dioda podłączona do portu świeci słabiej lecz gdy w warunku liczba jest większa od 1 dioda świeci mocnym światłem.
  • #4 7421403
    zumek
    Poziom 39  
    Co_pat napisał:
    ...
    Jeżeli w obsłudze przerwania jest taki warunek:

    to widać,że dioda podłączona do portu świeci słabiej lecz gdy w warunku liczba jest większa od 1 dioda świeci mocnym światłem.


    No to wniosek może być tylko jeden - Twój procek po zakończeniu obsługi przerwania, idzie w przysłowiowe krzaki :|

    Ponieważ nie wiadomo w jakim środowisku projektujesz, ani nie widać całego kodu, to pomoc jest raczej niemożliwa. Z tego co widzę, to będzie zapewne błąd w projekcie(makefile).
  • REKLAMA
  • #5 7422327
    Nagus
    Poziom 27  
    Program nie tyle idzie w krzaki, ale po prostu warunek nie ma szans się spełnić.
    Bez całości kodu trudno coś powiedzieć, bo z tych fragmentów wynika, że warunek (ms==1) może być spełniony raz na ok. 4 miliony sekund (zmienna miliSekundy nie jest nigdy zerowana, a tyle czasu zajmie przepełnienie zmiennej typu long int).

    Ogólnie:
    Do sterowania aktywnością przerwań służą funkcje sei() oraz cli(). Nie trzeba ręcznie grzebać w SREG.
    Stosując taki zapis:
    EIMSK = (1<<INT1)   //odblokowanie przerwania od INT1

    musisz mieć świadomość że zerujesz pozostałe bity rejestru EIMSK. Gdy chcesz ustawić tylko jeden bit lepiej użyć:
    EIMSK |= (1<<INT1)   //odblokowanie przerwania od INT1

    a kasowanie robi się podobnie:
    EIMSK &= ~(1<<INT1)   //odblokowanie przerwania od INT1
  • REKLAMA
  • #6 7434091
    Co_pat
    Poziom 15  
    Programuję w AVR Studio, nie tworzę mfile, a jedynie po utworzeniu nowego projektu w konfiguracji zmieniam następujące dane: Device: ATmega64 ,Frequency->16000000 Hz , Optimization: -Os. Jeżeli chodzi o pełen kod to właśnie cały podałem i właśnie to że w głównej pętli programu nic się nie znajduje może powodować takie działanie?
  • #7 7434551
    Fredy
    Poziom 27  
    Spróbuj wyzerować timero w przerwaniu.
  • #8 7436127
    Co_pat
    Poziom 15  
    Przez ostatnie 2h doszedłem do tego w czym tkwi problem zarówno w obsłudze przerwania od timera0 oraz od zewnętrznego INT1.
    Problem polega na tym że zmienna globalna którą wykorzystuję jako flagę istnieje tylko w obsłudze przerwania,flaga nie jest widoczna w głównej pętli programu lub po obsłudze przerwania resetuje się ATmega. Wywnioskowałem to gdy w obsłudze przerwania od INT1 ( przycisk) sprawdzałem wartość flagi, a następnie ją zwiększałem. Jeżeli przycisk był cały czas wciśnięty to flaga zwiększała wartość natomiast gdy przycisk pył wciśnięty na chwile to po ponownym wciśnięciu wartość flagi znów była równa zero.

    
    volatile unsigned char switch_f;                //flaga -> przycisk
    
    
    void Init(void){
    
       DDRA=0xFF;                              //port A jako wyjscie
       DDRD=0x00;                             //Potr D jako wejścia
       PORTD=0xFF;                            //z podziagnieciem do Vcc
    }
    void InitSwitch(void){
    EIMSK |=(1<<INT1);
    }
    
    int main(){
    
       Init();
       InitSwitch();
      
       Clr(PORTA,PA0);
       Clr(PORTA,PA1);  
       Clr(PORTA,PA2);
       switch_f=0;
    
    while(1){
       }
    }
    
    ISR(INT1_vect){
    flaga++;
    if(flaga>10) Set(PORTA,PA0);
    if(flaga>100) Set(PORTA,PA1);
    if(flaga>200) Set(PORTA,PA2);
    }
  • Pomocny post
    #9 7436132
    zumek
    Poziom 39  
    Nagus napisał:
    Program nie tyle idzie w krzaki, ale po prostu warunek nie ma szans się spełnić.

    Program idzie w krzaki, tylko nie z powodu "wadliwego" kodu, a z powodu złego ustawienia fusebitów, a w zasadzie jednego fusebitu - M103C
    I tak to jest, jak się nie zagląda do PDF-ka :D
  • #10 7436238
    Co_pat
    Poziom 15  
    Właśnie wszystko z tą ATmega 64 robię na podstawie pdf-a, mam z nią pierwszy raz do czynienia, ale o kompatybilności z 103 ustawianej przez producenta nie wiedziałem. Mam jednak taki problem: gdzie w AVR Studio mogę zmienić ten fusebit M103C?

    Dodano po 9 [minuty]:

    Znalazłem, nazywa się "CompMode" i po odznaczeniu wszystko działa jak należy. Wielkie dzięki wszystkim :-)
REKLAMA