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

[Atmega8][C] uprocesor sam się resetuje?

Marcin1326 28 Paź 2008 17:09 3416 8
REKLAMA
  • #1 5676409
    Marcin1326
    Poziom 13  
    Witam,
    Chciałem zrobić opóźnienia w programie dla Atmega8. Wykorzystałem przerwania, ale przy symulacji programu w AVR Studio okazuje się że program po około 260 mikro sekundach resetuje się(wraca do funkcji main() ). Nie jet to spowodowane raczej watchdogiem bo jest on wyłączony. Czy ktoś potrafi mi powiedzieć dlaczego tak się dzieje? Aha, oczywiście skompilowany program nie działa poprawnie także na "fizycznym" procesorze.

    Program:
    
    
    #include <inttypes.h>
    #include <stdio.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    //----------------------------------------------
    
    uint8_t podtryb;
    volatile uint16_t time;
    
    //-------------------------------------------
    
    void opoznienie8ms(uint16_t t);
    void podlacz_koncowke_pwm(void);	//podłącza odłącza końcówkę OC0A do PORTU 
    void odlacz_koncowke_pwm(void);		//odłącza końcówkę OC0A od PORTU
    
    //--------------------------------------------
    
    	void opoznienie8ms(uint16_t t)
    	{
    	time = t;
    	for(;time != 0;)
    		{
    		PORTD |= 1<<7;   //Po kilku przebiegach pętli for następuje reset (skok do funkcji main() ) !!!!!!!!!!!!!!!!!
    		PORTD &= ~(1<<7);
    		}
    	}
    
    
    void podlacz_koncowke_pwm()
    { 
    TCCR1A |= 1<<COM1A1;
    }
    
    		void odlacz_koncowke_pwm()
    		{
    		TCCR1A &= ~(1<<COM1A1) & ~(1<<COM1A0);
    		}
    
    
    int main (void)
    {
    //Konfiguracja portów
    DDRB = 0b00000110; 
    DDRD = 0b11100000;
    
    	//Konfiguracja PWMa
    	TCCR1A |= 1<<WGM10;// FastPWM 8BIT
    	TCCR1B |= 1<<WGM12;
    
    	TCCR1B |= 1<<CS11; //Divide 8
    	TIMSK |= 1<<OCIE1A;
    	
    	OCR1A = 120;
    
    //Konfiguracja przerwania przepełnienia licznika
    TCCR0 |= 1<<CS02; // divide 256
    TIMSK |= 1<<TOIE0; // odblokowanie przerwania przepełnienia
    	
    	sei(); //Globalne odblokowanie przerwań
    
    
    //=============== PROGRAM WŁAŚCIWY =====================
    for(;;)
    {
    
    PORTB &= ~(1<<2);
    podlacz_koncowke_pwm();
    
    opoznienie8ms(100);
    
    odlacz_koncowke_pwm();
    PORTB &= ~(1<<1);
    PORTB |= 1<<2;
    
    opoznienie8ms(100);
    
    }
    return 0;
    }
    
    //Przerwanie występujące co około 8,1ms; jest to przerwanie generujące opóźnienia
    
    SIGNAL(SIG_OVERFLOW0)
    {
    if(time != 0) --time;
    }
    
    
    
    
  • REKLAMA
  • Pomocny post
    #2 5677374
    ZlyDotyk
    Poziom 19  
    Włączyłeś przerwanie od "Timer Compare" (OCIE1A) które nie jest obsłużone.
  • REKLAMA
  • #3 5677689
    Marcin1326
    Poziom 13  
    ZlyDotyk : Pomogło. Dzięki Ci wielkie! Nie wiem jak mogłem to przeoczyć! :)
  • REKLAMA
  • #4 5677903
    BoskiDialer
    Poziom 34  
    Marcin1326: Tak na marginesie pomyśl o zapewnieniu atomowego dostępu do zmiennej "time" - jeśli pomiędzy zapisem pierwszego a drugiego bajtu pojawi się przerwanie, to mogą się dziać różne dziwne rzeczy (tutaj co najwyżej opóźnienie inne niż oczekiwane). Tak jak wpisanie do "time" można raz rozwiązać atomowo (zapisanie SREG, cli(), operacja i odtworzenie SREG), tak ciągłe blokowanie do odczytu będzie problematyczne i lepiej chyba dać jednobajtową flagę informującą o wyzerowaniu się zmiennej "time" lub nawet tą samą flagą blokować, aby w przerwaniu nie była aktualizowana zmienna "time". Nie jest to co prawda błąd krytyczny, ale może powodować małe, spontaniczne zmiany w opóźnieniach.
  • #5 5684127
    Marcin1326
    Poziom 13  
    BoskiDialer: rzeczywiście były dość częste zmiany w opóźnieniach, ale zmieniłem zmienną time na 8bitową i teraz wszystko jest OK :). A jak się robi atomowy dostęp do zmiennej?
  • #6 5684262
    BoskiDialer
    Poziom 34  
    Atomowy dostęp do zmiennej, tak jak napisałem: "zapisanie SREG, cli(), operacja i odtworzenie SREG":
    unsigned char old_sreg = SREG;
    cli();
    // jakieś instrukcje
    SREG = old_sreg;

    W tym przypadku przy wartościach do 255 nie powinny pojawić się żadne różnice w opóźnieniach, dopiero wpisywanie wartości większej od 255 może powodować zmiany opóźnień:
    - wystąpienie przerwania po zapisaniu górnego bajtu, przed wpisaniem dolnego (dolny bajt jest zapisywany jako ostatni) - wpisywanie wartości np 0x0123 będzie w przerwaniu widziana jako 0x0100 (częściowy zapis), zmniejszona do 0x00FF, w kodzie głównym zaktualizowana do 0x0023 - już 256 przebiegów mniej. Ten przypadek jest najmniej prawdopodobny.
    - wystąpienie przerwania pomiędzy odczytami kolejnych bajtów (dolny bajt jest odczytywany jako pierwszy): time==0x0100, program odczyta dolny bajt (0), przerwanie zmniejszy time do 0x00FF, program odczyta górny bajt (0), wartość to zero i zostanie przerwana pętla - ten przypadek jest najbardziej prawdopodobny.

    Moje rozwiązanie bez operacji atomowych było by takie:
    volatile uint8_t delay_active;
    volatile uint16_t time;
    
    SIGNAL(SIG_OVERFLOW0) 
    {
      if(delay_active)
      {
        if(--time == 0)
          delay_active = 0;
      }
    }
    
    void opoznienie8ms(uint16_t t) 
    { 
      time = t;
      delay_active = 1;
      while(delay_active)
      {
        // jakiś kod
       } 
    }
  • REKLAMA
  • #9 7110516
    Konto nie istnieje
    Poziom 1  
REKLAMA