-         

Ergebnis 1 bis 4 von 4

Thema: Verständnisfrage bei Timer-(Interrupt)

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    27.01.2004
    Beiträge
    9

    Verständnisfrage bei Timer-(Interrupt)

    Anzeige

    Hi,
    ich habe erst neu mit Microcontroller / Robotik angefangen und arbeite mich nun langsam durch den Stoff und hier durchs Forum .
    Nun hatte ich ein Problem, konnte dieses zwar Lösen, verstehe aber nicht warum nicht beides funktioniert.

    Funktion:
    Es soll LED3 (PB3) blinken. Nach ca. einer Minute soll die LED0 (PB0) leuchten, nach einer weiteren Minute dann LED0 aus und LED1 (PB1) an usw.
    Ergebnis Code1:
    LED3 blinkt wie gewünscht, aber die andere LEDs blinken von Anfang an auch ganz wild und unvorhersehbar.
    Ergebnis Code2:
    Nach etwas probieren (Interrupts während den IF-Anweisungen ausschalten usw.) hab ichs dann wie in Code2 geändert und nun tut es.


    Nun hoffe ich, dass mir jemand von euch sagen kann warum. Es müsste doch egal sein, ob ich die Sekunden in der Hauptschleife oder dem Interrupt hochzähl, hauptsache ich deklariere die Variable als volatile, damit der Compiler das richtig umsetzt.

    Wenn es jemand Testen will, ich arbeite mit einem NiboBee.

    (Die stellen, welche sich unterscheiden sind mit " // <<----- Unterschied" markiert)
    Code1 (funktioniert nicht):
    Code:
    #include <avr/io.h>					// allgemeine Headerdatei
    #include <stdint.h>					// für standardisierten Typen z.B. int8_t
    #include <avr/interrupt.h> 	// fuer sei() => Aktivieren, cli() => ausschalten und ISR():
    
    // Prototypen
    void Timer0_init(void);
    
    // Globale Variable
    volatile uint16_t blink_hz = 0;
    volatile uint8_t blink = 0;
                                      // <<----- Unterschied
    int main(void)
    {
    	// IO's init
    	Timer0_init();
    	DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3);	// LED's
    
    	// Variable
    	volatile uint8_t sek = 0;             // <<----- Unterschied
    
    	// Globale Interrupts erlauben
    	sei();
    
    	while(1)
    	{
    		if(blink)
    		{
    			PORTB |= (1<<PB3);
    			sek++;                         // <<----- Unterschied
    		}
    		else PORTB &= ~(1<<PB3);
    		if (sek > 59 && sek < 119) PORTB |= (1<<PB0);
    		else PORTB &= ~(1<<PB0);
    }
    	return 0;
    }
    
    
    /*************
    	Funktionen
    **************/
    // Timer 1ms
    void Timer0_init(void)
    {
    	TCCR0 =  (1<<WGM01);						// Timer im CTC-Modus
    	TCCR0 |= (1<<CS00) | (1<<CS01);	// Prescaler auf 64
    	OCR0 = 234;											// um ca. 1ms zu erreichen
    	TIMSK |= (1<<OCIE0);						// Interrupt "TIMER0_COMP_vect" aktivieren
    }
    
    /*************
    	Interrupts
    **************/
    
    ISR (TIMER0_COMP_vect)
    {
    	blink_hz++;
    
    	switch (blink_hz)
    	{
    		case 499: blink = 1;  			       break;               // <<----- Unterschied
    		case 999: blink = 0; blink_hz = 0; break;
    		default: break;
    	}
    
    }
    Code2 (funktioniert):
    Code:
    #include <avr/io.h>					
    #include <stdint.h>					
    #include <avr/interrupt.h>
    // Prototypen
    void Timer0_init(void);
    
    // Globale Variable
    volatile uint16_t blink_hz = 0;
    volatile uint8_t blink = 0;
    volatile uint8_t sek = 0;             // <<----- Unterschied
    
    int main(void)
    {
    // IO's init
    	Timer0_init();
    	DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3);	// LED's
    
    	// Globale Interrupts erlauben
    	sei();
    
    	while(1)
    	{
    		if(blink)
    		{
    			PORTB |= (1<<PB3);
                  // <<----- Unterschied
    		}
    		else PORTB &= ~(1<<PB3);
    		if (sek > 59 && sek < 119) PORTB |= (1<<PB0);
    		else PORTB &= ~(1<<PB0);
    }
    	return 0;
    }
    
    
    /*************
    	Funktionen
    **************/
    // Timer 1ms
    void Timer0_init(void)
    {
    	TCCR0 =  (1<<WGM01);						// Timer im CTC-Modus
    	TCCR0 |= (1<<CS00) | (1<<CS01);	// Prescaler auf 64
    	OCR0 = 234;											// um ca. 1ms zu erreichen
    	TIMSK |= (1<<OCIE0);						// Interrupt "TIMER0_COMP_vect" aktivieren
    }
    
    /*************
    	Interrupts
    **************/
    
    ISR (TIMER0_COMP_vect)
    {
    	blink_hz++;
    
    	switch (blink_hz)
    	{
    		case 499: blink = 1;  sek++;       break;               // <<----- Unterschied
    		case 999: blink = 0; blink_hz = 0; break;
    		default: break;
    	}
    
    }
    greez

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    25.03.2006
    Ort
    Darmstadt
    Alter
    26
    Beiträge
    522
    In Deinem ersten Listing wird sek in der 1-Phase von blink ständig, d.h. bei jedem Durchlauf der while-Schleife inkrementiert. Da die Schleife mit einigen 100 kHz läuft, dauert es keine Millisekunde, bis sek die 120 überschritten hat, sobald blink auf 1 ist.

    In Deinem zweiten Listing wird sek erst bei jedem 1000sten Timer0 Compare Interrupt inkrementiert, also alle 1000 ms, was ja auch richtig ist.

    MfG Mark

    PS: nur die Variablen, die sowohl im Hauptprogramm als auch in ISRs verwendet werden, müssen volatile sein. In allen anderen Fällen ist es nur Verschwendung von Laufzeit.

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    27.01.2004
    Beiträge
    9
    ah...stimmt. Hatte das im ISR erst anders gelöst und es deshalb wahrscheinlich übersehen. Danke für die Hilfe.
    Hab den Wald vor Bäumen nicht gesehen

    Und danke für den Tipp mit volatile.
    Gibt es eine Möglichkeit eine Variable auch erst im ISR zu deklarieren und diese dann hochzählen (hier dann "blink_hz") oder muss ich diese als globale Variable speichern?

    greez

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    03.04.2005
    Beiträge
    181
    Hallo,
    Variablen die als static definiert werden überleben das Verlassen und Wiedereintreten in die Funktion.
    Das wäre für blink_hz die saubere Lösung

    Bernhard

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •