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

Atmega8 - Odblokowanie globalnych przerwań hamuje pracę mikrokontrolera

brzydal91 20 Lis 2011 23:41 2444 12
  • #1 10163703
    brzydal91
    Poziom 12  
    Szanowni Forumowicze,
    staram się z byle błahostką tutaj nie pojawiać, ale niestety natrafiłem na problem w trakcie programowania µC z którym nie potrafię sobie poradzić.
    Ćwiczę programowanie w C i od kilku dni testuję Timery na Atmega8. Udało mi się zaprogramować je na wszystkie znane mi sposoby. Niestety po zmianie programu i konfiguracji na płytce prototypowej natrafiłem na pewien błąd.
    Kiedy odblokowuję globalne przerwania takim poleceniem:
    
    SREG = _BV(7);
    

    µC nie wykonuje w ogóle programu. Całość wygląda następująco:
    
    #define F_CPU 1000000ul
    
    #include <avr/io.h>
    
    #include <avr/interrupt.h>  
    
    #include <util/delay.h>  
    
    
    unsigned char flag_timer_1 = 0;
    
    
    
    ISR(TIMER2_COMPA_vect)
    
    {
    
    	flag_timer_1 = 1;
    
    } // interrupt
    
    
    
    int main(void)
    
    {	
    
    	TCCR1B |= (1 << CS10);   //ustaw timer1 z preskalerem 1
    
    	TCCR1B |= (1 << WGM12);   //ustaw timer1 w tryb CTC 
    
    	OCR1A=10000;   
    
    	TIMSK= (1 << OCIE1A);   //zezwolenie na przerwania dla CTC 
    
    	SREG = _BV(7);
    
    
    	unsigned char counter = 0x00;
    
    	DDRD = 0xFF;
    	PORTD = 0xff;
    
    	DDRC = 0xFF;
    
    	while(1)
    
    	{
    
    	}	
    
    
    return 0;
    
    } // main
    

    W efekcie powinienem uzyskać stan wysoki na porcie D oraz stan niski na porcie C. Dzieję się tak dopiero gdy zakomentuję linijkę podaną wyżej.
    Najgorsze w tym wszystkim jest to, że ten oto program działał dzień wcześniej na tym samym µC. Atmega jest sprawna bo gdy wyłączam przerwania to wszystko działa jak należy. Czy ktoś coś z tego rozumie?
  • #2 10163748
    Fredy
    Poziom 27  
    pomyliłes timery, zrobiłeś przerwanie od timera 2 a włączyłeś timer 1.
  • #3 10163788
    brzydal91
    Poziom 12  
    Teraz mam taki kod dotyczący ustawień TIMER1
    
    ISR(TIMER1_COMPA_vect)
    
    {
    
    	flag_timer_1 = 1;
    
    } // interrupt
            TCCR1A |= (1 << CS10); //ustaw timer1 z preskalerem 1
    
    	TCCR1A |= (1 << WGM12);   //ustaw timer1 w tryb CTC 
    
    	OCR1A = 10000;   
    
    	TIMSK |= (1 << OCIE1A);   //zezwolenie na przerwania dla CTC 
    
    	SREG |= _BV(7);
    

    A w pętli while
    
    if(flag_timer_1 == 1)
    	{
    		if(led == 1)
    		{
    		PORTD = 0x80;
    		led++;
    		PORTC = 0x08;
    		}
    		if(led == 2)
    		{
    		PORTD = 0x40;
    		led++;
    		PORTC = 0x02;
    		}
    		if(led == 3)
    		{
    		PORTD = 0x20;
    		PORTC = 0x01;
    		led = 1;
    		}
    	flag_timer_1 = 0;
    	}
    

    Niestety wszystko wskazuje na to, że nie działa przerwanie, a raczej że dalej robię coś źle. Widzi ktoś błąd?

    [EDIT]
    Rozwiązałem problem. Dla potomnych napiszę co zauważyłem.
    Nie jest to pierwszy kiedy zauważyłem że w warunkach (if(...)) kiedy porównujemy wartość zmiennej z jakąś liczbą to lepiej jest tę liczbę zapisać w postaci szesnastkowej. Polecam też inicjalizować zmienne wartością w postaci HEX.
    oto poprawny kod:
    
    #define F_CPU 1000000ul
    
    #include <avr/io.h>
    
    #include <avr/interrupt.h>  
    
    
    volatile unsigned int flag_timer_1 = 0x00;
    
    
    
    ISR(TIMER1_COMPA_vect)
    
    {
    
    	flag_timer_1 = 0x01;
    
    } // interrupt
    
    
    
    int main(void)
    
    {	
    TCCR1B=(1 << CS10 | 1<< WGM12);   //ustaw timer1 z preskalerem 64 //ustaw timer1 w tryb CTC
    OCR1A=6000;   //do ilu liczy timer1 dla odmierzenia 1s
    SREG=(1 << 7);   //zezwolenie na przerwania
    TIMSK=(1 << OCIE1A);   //zezwolenia na przerwania dla CTC 
    
    
    	unsigned int led = 0x01;
    
    	DDRD = 0xFF;	
    	DDRC = 0xFF;
    
    	while(1)
    
    	{
    
    	// Przerwanie TIMER1
    	if(flag_timer_1 == 0x01)
    	{
    		if(led == 0x01)
    		{
    		PORTD = 0x80;
    		led++;
    		PORTC = 0x08;
    		}
    		else
    		if(led == 0x02)
    		{
    		PORTD = 0x40;
    		led++;
    		PORTC = 0x02;
    		}
    		else
    		if(led == 0x03)
    		{
    		PORTD = 0x20;
    		PORTC = 0x01;
    		led = 0x01;
    		}
    	flag_timer_1 = 0x00;
    	}// Przerwanie TIMER1
    
    
    	}	
    
    
    return 0;
    
    } // main
    
    
    
    
    
    
    
  • #4 10163973
    dondu
    Moderator na urlopie...
    brzydal91 napisał:
    Rozwiązałem problem. Dla potomnych napiszę co zauważyłem.
    Nie jest to pierwszy kiedy zauważyłem że w warunkach (if(...)) kiedy porównujemy wartość zmiennej z jakąś liczbą to lepiej jest tę liczbę zapisać w postaci szesnastkowej. Polecam też inicjalizować zmienne wartością w postaci HEX.

    Do złych wniosków dochodzisz. Kompilator dokładnie tak samo postrzega liczbę dziesiętną 1 jak i szesnastkową 0x01. Gdyby było inaczej, taki kompilator należałoby od razu wywalić do kosza.

    Twój problem polegał na braku VOLATILE przy definicji zmiennej globalnej flag_timer_1 wykorzystywanej w przerwaniu i pętli głównej. W ostatnim kodzie tę definicję, już masz i dlatego program zaczął działać.

    A dla potomnych, zamiast Twoich domysłów zostawmy wiedzę, dlaczego VOLATILE stosować trzeba: http://mikrokontrolery.blogspot.com/2011/04/problemy-c-volatile.html

    I drobne uwagi:
    - zamiast operowania na bicie I rejestru SREG tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    stosuj odpowiednio:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    - wywal return 0; z main() bo do niczego nie jest potrzebne.
  • #5 10164158
    brzydal91
    Poziom 12  

    mogę usunąć i dalej będzie kod działał, bo tak miałem. Program działa dokładnie tak samo. Zwracam honor i przyznaję, że teraz kiedy zmieniam HEX na DEC działa również tak samo. Widocznie pora o której to wczoraj pisałem już była za późna i nie dostrzegłem innych problemów. Pojawił się natomiast kolejny, oto kod:
    
    #define F_CPU 1000000ul
    
    #include <avr/io.h>
    
    #include <avr/interrupt.h>  
    
    
    
    unsigned int flag_timer_0 = 0, flag_timer_1 = 0;
    
    int wynik_10 = 0, wynik_1 = 0, wynik_100 = 0;
    
    unsigned short int top = 200;
    
    
    
    ISR(TIMER1_COMPA_vect)
    
    {
    
    	flag_timer_1 = 1;
    
    } // interrupt
    
    
    
    ISR(TIMER0_OVF_vect)
    
    {
    
    	flag_timer_0 = 1;
    
    } // interrupt
    
    
    //Rozbijanie liczby na trzy cyfry
    
    void display(unsigned int disp)
    
    {
    
    	wynik_100 = disp / 100;
    
    	wynik_10 = disp / 10;
    
    	wynik_10 = wynik_10 % 10;
    
    	wynik_1 = disp % 10;
    
    }
    
    
    
    int main(void)
    
    {	
    
    	TCCR2 = (1 << WGM20 | 1 << COM20 | 1 << COM21 | 1 << CS20 | 1 << CS21); //PWM phase correct
    
    	OCR2 = top; // 200
    
    	
    
    	TCCR1B=(1 << CS10 | 1<< WGM12);   //ustaw timer1 z preskalerem 1; tryb CTC
    
    	OCR1A = 30000;   
    
    	TIMSK = (1 << OCIE1A);   //zezwolenia na przerwania dla CTC 
    
    
    
    	TCCR0 = (1 << CS01); //Timer0
    
    	TCNT0 = 0x68;
    
    	TIMSK |= (1 << TOIE0 | 1 << TOIE2);
    
    
    
    	sei();
    
    
    
    	unsigned int led = 0x01;
    
    
    
    	DDRD = 0xFF;	
    
    	DDRC = 0xFF;
    
    	DDRB = 0xFF;
    
    
    
    	while(1)
    
    	{
    
    
    	//Przerwanie TIMER1
    
    	if(flag_timer_1 == 1)//Zwiększaj wartość TOP aż do 255
    
    	{
    
    	top++;
    
    		if(top > 0xFF)//Jeśli TOP == 255, to wyzeruj
    
    		top = 0x00;
    
    	OCR2 = top;
    
    	flag_timer_1 = 0x00;
    
    	}//TIMER1
    
    	
    
    	display(top);// Podziel liczbę na trzy cyfry
    
    
    	// Przerwanie TIMER0
    
    	if(flag_timer_0 == 1)
    
    	{
    		//Multipleksowanie trzech wyswietlaczy 7-segmentowych
    
    		TIFR |= (1 << TOV0);
    
    		if(led == 0x01) //Wyswietlacz jednosci
    
    		{
    
    		PORTD = 0x80;
    
    		led++;
    
    		PORTC = wynik_1;
    
    		}
    
    		else
    
    		if(led == 0x02) //Wyswietlacz dziesiatek
    
    		{
    
    		PORTD = 0x40;
    
    		led++;
    
    		PORTC = wynik_10;
    
    		}
    
    		else
    
    		if(led == 0x03) //Wyswietlacz setek
    
    		{
    
    		PORTD = 0x20;
    
    		PORTC = wynik_100;
    
    		led = 0x01;
    
    		}
    
    	flag_timer_0 = 0x00;
    
    	}// Przerwanie TIMER1
    
    
    
    	}	
    
    
    
    return 0;
    
    } // main
    
    
    
    
    
    

    Mój problem polega na tym, że TIMER1 oraz TIMER2 nie chcą działać równocześnie. Kiedy mam w kodzie linijkę:
    
    TCCR2 = (1 << WGM20 | 1 << COM20 | 1 << COM21 | 1 << CS20 | 1 << CS21);
    

    To Timer1 przestaje działać, nie zgłasza przerwania. Jeśli tę linijkę zakomentuję to TIMER1 działa bez zarzutu, ale nie mam wtedy PWM.

    Jest potrzebne, ponieważ funkcja main() w moim przypadku jest typu

    i musi coś zwracać. Inna sprawa, że może być typu

    i wtedy było by to niepotrzebne. Pozdrawiam
  • #6 10164585
    pawel_mr
    Poziom 15  
    brzydal91 napisał:

    volatile
    mogę usunąć i dalej będzie kod działał, bo tak miałem. Program działa dokładnie tak samo.

    Ja Ci radzę, dopisz to volatile bo zaraz będzie kolejny post, że program nie widzi zmian wartości zmiennych. Każda zmienna globalna zmieniana w przerwaniu powinna być volatile, chyba, że jesteś pewien, że wykorzystujesz ją tylko w przerwaniu (a wtedy nie musi być globalna).
  • #7 10164612
    dondu
    Moderator na urlopie...
    brzydal91 napisał:
    Jest potrzebne, ...

    Nie jest potrzebne ponieważ ten fragment kodu nigdy się nie wykona i jest pomijany przez kompilator.

    A co do volatile, to skoro nie chcesz posłuchać mojej rady, to posłuchaj kolegi pawel_mr.
  • #8 10164703
    brzydal91
    Poziom 12  
    Już kilka razy to napisałem napiszę po raz kolejny. Dopisałem

    Nie ma różnicy w działaniu programu. Prosiłem o pomoc w związku z Timer1 i Timer2, dlaczego działa mi albo pierwszy albo drugi. Macie jeszcze jakieś pomysły? Czy tylko brak volatile na początku kodu zauważyliście?
  • #9 10165175
    zumek
    Poziom 39  
    brzydal91 napisał:
    ... Macie jeszcze jakieś pomysły? ...

    Myśl, myśl, myśl w trakcie pisania kodu.
    Już po raz drugi w tym temacie, popełniasz ten sam "szkolny" błąd.

    Kod: text
    Zaloguj się, aby zobaczyć kod
  • #12 10166550
    Konto nie istnieje
    Poziom 1  
REKLAMA