-         

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 14

Thema: Problem mit Timer0

  1. #1
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.05.2005
    Ort
    Stuttgart
    Beiträge
    260

    Problem mit Timer0

    Anzeige

    Hio. Ich versuch mich gerade an den Timern. Allerdings gibt's da ein kleines Problem. Ich verwende den Timer0 (8-Bit) eines ATMega32. Mit dem Tool rnAvr hab ich den Wert für OCR0 ausrechnen lassen. Jetzt schon mal die erste Frage: Wie ist die Formel zum berechnen von OCR0? Bei 7372800Hz und 1000 Interrupts pro Sekunde bekomme ich für OCR0 141 (mit einem Vorteiler von 64). Ich generiere dann im Programm “Output Compare0 Interrupts”. Dann hab ich noch ne extra Methode zum schlafen, welche mit dem Timer zusammenarbeitet. Nur schläft mein Programm bei einer Einstellung von 1 Sekunde über 40 Sekunden! Warum? Schaut euch doch bitte den Code an und sagt mir was falsch ist. (Hinweis: Das ist nur ein kleiner Ausschnitt. Wenn ihr den Code mit einem Atmega testen wollt müsst ihr ggf. ein paar Header-Dateien einbinden.) Kann es vielleicht sein, dass OCR0 nicht richtig berechnet ist? Das wichtige hab ich mit // eingerahmt.
    Danke!


    Code:
    uint8_t cmd;
    
    volatile uint32_t countTimer0;
    volatile uint32_t tmpCountTimer0;
    
    SIGNAL(SIG_OUTPUT_COMPARE0)
    {
    	countTimer0++;
    	tmpCountTimer0++;
    }
    
    inline void sleep_millisec(uint16_t milliseconds)
    {
    	//  tmpCountTimer0 wird in der ISR oben inkrementiert
    	tmpCountTimer0 = 0;
    	while(tmpCountTimer0 < milliseconds)
    		asm volatile ("nop");		// Nichts tun
    }
    
    
    int main(void)
    {
    	// Initializes the timer Timer0: ////////////////////////////////////////////////////
    	TCCR0 = (1<<WGM01) | (1<<CS01) | (1<<CS00);	// CTC und Prescaler 64
    	OCR0 = 141;	// Mit rnAVR berechnet
    	TIMSK |= (1<<OCIE0);	// Interrupt aktivieren
    	////////////////////////////////////////////////////////////////////////////////
    	
    	//  Initialize USART and enable interrupts:
    	usart_init();
    	sei();
    	
    	// Mainloop:
    	for(;;) {
    		cmd = usart_recieveChar();
    		
    		switch(cmd) {
    			case 's':	rncontrol_ledon(0);				// Diese Funktion aktiviert eine LED
    						sleep_millisec(1000);
    						rncontrol_ledoff(0);		// Diese Funktion deaktiviert eine LED
    			case 'd':	rncontrol_ledon(0);
    						sleep_millisec(2000);
    						rncontrol_ledoff(0);
    			case 'l':	rncontrol_ledon(0);
    						sleep_millisec(15000);
    						rncontrol_ledoff(0);
    		}
    	}
    	
    	
    	return 0;
    }

    Gruß
    Lutz

  2. #2
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Mach doch einmal den Test sozusagen zu Fuß. D.h.:

    Direkt in der SIGNAL-Routine zählst du UND vergleichst mit 1000, und direkt dort drehst du auch die LED's mal an und aus. Ob das Blinken etwa 1 sec. braucht, kannst du gut abschätzen. Mir scheinen die RnAVR-Werte plausibel.

    Mehrbytige Felder in der ISR zählen und im non-ISR mode vergleichen ist so eine Sache.
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  3. #3
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.05.2005
    Ort
    Stuttgart
    Beiträge
    260
    Mehrbytige Felder in der ISR zählen und im non-ISR mode vergleichen ist so eine Sache.
    Beim Asuro geht das genau so!

    Hat mir denn niemand einen eigenen Codeausschnitt? Und: Wie berechne ich den OCR0-Wert?

  4. #4
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Ich häng' da einen Code rein von einem Timer, der alle mS einmal tickert. Das ist ingesamt ein etwas komplexeres Projekt, aber das mit dem Timer kann man schon erkennen.
    Die Werte sind für 8 MHZ, ist ja nicht soweit weg von deinen 7372800Hz
    h-file
    Code:
    #ifndef __BACK_DEF
    #define __BACK_DEF 1
    
    #define F_CPU 				8000000 
    #define USART_BAUD_RATE 	9600 
    #define USART_BAUD_SELECT 	(F_CPU/(USART_BAUD_RATE*16l)-1) 
    
    
    #define  TIME0_c_MS_PRE	3   // prescale
    #define  TIME0_c_MS_CNT	131  // preload
    
    ......
    Code:
    // --------------------------------------------------- 
    //   TIME Interrupt
    // --------------------------------------------------- 
    SIGNAL (SIG_OVERFLOW0) 
    {       
       TCNT0			= TIME0_c_MS_CNT;
       sTime0.wCurr--;
       if (!sTime0.wCurr)
       {
    		sTime0.wCurr	= sTime0.wCount;
    		sTime0.bFlag	|= TIME0_M_TICK;
        }
    }
    // --------------------------------------------------- 
    TIME_DEF* TimeInit(unsigned short Count)
    { 
    	sTime0.bFlag		= 0;
    	sTime0.wCount		= Count;
    	sTime0.wCurr		= Count;
    	TCCR0			= TIME0_c_MS_PRE;
    	TCNT0			= TIME0_c_MS_CNT;
    	TIMSK			|= (1 << TOIE0);
    	return((TIME_DEF*)&sTime0);
    }
    Ich attache auch noch ein XLS-Sheet zum ausrechnen der diversen Werte.
    Is für internen Gebrauch, also ein bißchen mitdenken mußt du schon, wie es zu bedienen ist.
    Es zeigt dir die möglichen alternativen an.


    EDIT: seh auch schon, wo dein Fehler liegt: du mußt in der Signal routine den Preload-Wert nachladen
    Angehängte Dateien Angehängte Dateien

  5. #5
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.05.2005
    Ort
    Stuttgart
    Beiträge
    260
    [quote]
    EDIT: seh auch schon, wo dein Fehler liegt: du musst in der Signal routine den Preload-Wert nachladen
    [/quote}

    Also so:

    Code:
    SIGNAL...
    ...
    OCR0 = 141;
    ...
    ...
    ?

    Gruß
    Lutz

  6. #6
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Halt, stop, retour: Ich bin überhaupt am falschen Dampfer (--> Matschbirne).
    Du machst ja keinen klassischen Timer, sondern Compare-Match .
    Da ist erstens das mit dem Nachladen zu vergessen.
    Aber auch das Rechnen stimmt dann so nicht. (das ist für counter-overflow)
    Der Wert 141 heißt ja, von dort zählt er rauf bis 255 und dann schnackelt der TIMER
    Beim Counter match zählt er von 0 -> OCR0 und löst dann aus.
    d.h. statt 141 gelten bei dir 256 - 141 ---> also 115.
    und nachladen brauchst du nix.

    Das erkärt aber nicht einen Differenz 1 sek <--> 40 sekunden

    da muß ich mal im DS nachlesen.

    'Tschuldige nochmals.
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  7. #7
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.05.2005
    Ort
    Stuttgart
    Beiträge
    260
    Hio.

    Halt, stop, retour: Ich bin überhaupt am falschen Dampfer (--> Matschbirne).
    Du machst ja keinen klassischen Timer, sondern Compare-Match .
    Da ist erstens das mit dem Nachladen zu vergessen.
    Aber auch das Rechnen stimmt dann so nicht. (das ist für counter-overflow)
    Der Wert 141 heißt ja, von dort zählt er rauf bis 255 und dann schnackelt der TIMER
    Beim Counter match zählt er von 0 -> OCR0 und löst dann aus.
    d.h. statt 141 gelten bei dir 256 - 141 ---> also 115.
    und nachladen brauchst du nix.

    Das erkärt aber nicht einen Differenz 1 sek <--> 40 sekunden

    da muß ich mal im DS nachlesen.

    'Tschuldige nochmals.
    . Ich hab da auch net immer drangedacht. Hab dann am Schluss beides getestet und bin jetzt wieder beim klassischem Timer (Overflow) .

    Hier mein neuer Code

    ISR:
    Code:
    SIGNAL(SIG_OVERFLOW0)
    {
    	TCNT0 = 141;
    	countTimer0++;
    	tmpCountTimer0++;
    }
    Und die Initialisierung:
    Code:
    // Initializes the timer Timer0
    TCCR0 |= (1<<CS00) | (1<<CS01);
    TCNT0  = 141;
    TIMSK |= (1<<TOIE0);
    Jetzt hab ich ein doch ziemlich komisches Testergebnis. Lasse ich den Mikrocontroller 15 Sekunden schalfen geht das sehr genau. D. h. der µC schläft exact 15 Sekunden! Lasse ich ihn dagegen nur eine oder zwei Sekunden schlafen dauert das teilweise über 20 Sekunden. Komisch: Wenn er zwei Sekunden schläft ist er schneller fertig (ca. 20 Sekunden) als wenn ich ihn nur eine Sekunde schlafen lass (ca. 25 Sekunden). Woran kann das liegen??

    Gruß
    Lutz

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Zitat Zitat von luma
    Zitat Zitat von PicNick
    Mehrbytige Felder in der ISR zählen und im non-ISR mode vergleichen ist so eine Sache.
    Beim Asuro geht das genau so!
    Eben nicht. Ein Vergleich auf 16-Bit-Wert ist mindestebns 2 Befehle lang. Auch beim Asuro. Wenn zwischen diesen beiden Befehlen ein Interrupt auftaucht, der den zu testenden Wert verändert, hast du ein Problem. Zwar nur seeeehr selten, aber du hast es. Hier sogar recht wahrscheinlich, weil du ausser nop und vergleichen nix machst. Das gilt ebenso für das Setzen solcher Werte.

    inline void sleep_millisec(uint16_t milliseconds)
    {
    // tmpCountTimer0 wird in der ISR oben inkrementiert
    tmpCountTimer0 = 0;
    while(tmpCountTimer0 < milliseconds)
    asm volatile ("nop"); // Nichts tun
    Code:
       while (1) {
          uint16_t tmp;
          cli();
          tmp = tmpCountTimer0;
          sei();
          if (tmp < milliseconds)
             return;
       }
    Oder du machst es über ein Flag wie von PicNick vorgeschlagen.
    Disclaimer: none. Sue me.

  9. #9
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Man könnt' aber (oder sollte) vor dem Non-Isr Vergleich ein "cli()" und danach ein "sei()" setzen. das sollte helfen. Das machen auch die meisten kompiler, wenn sie 16-Bit werte verfummeln (z.B. Stack u. Framepointer)
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  10. #10
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.05.2005
    Ort
    Stuttgart
    Beiträge
    260
    Hio. Ich hab noch ein paar Fragen zu den Timern. Wieso les ich im AVR-GCC Tutorial, dass ein 8-Bit Timer eine Auflösung von 256 hat? Der Timer kann doch bis maximal 255 hoch zählen. Was ist mit den 16-Bit Timern?

    Dann hab ich noch dieses kleine Programm. Das schläft zwar, aber immer zwei Sekunden, obwohl es nur eine Sekunde schlafen sollte…

    Code:
    // Variable which is used for Timer0
    volatile uint8_t countTimer2;
    
    // ISR for handling the Timer/Counter2 Compare Match interrupt
    SIGNAL(SIG_OUTPUT_COMPARE2)
    {
       countTimer2++;
    }
    …
    // Initializes the timer Timer2 (Prescaler=64 | CTC)
    TCCR2  = (1<<CS22) | (1<<WGM21);
    OCR2   = 115;
    TIMSK |= (1<<OCIE2);
    …
    /**
     * Sleeps the given time. For t=1 the function Sleeps 1 ms.
     */
    inline void rncontrol_sleep(uint8_t t)
    {
    	// countTimer2 wird in der ISR oben inkrementiert
    	countTimer2 = 0;
    	while (countTimer2 < t);
    }
    
    
    /**
     * Sleeps the given milliseconds. 
     */
    inline void rncontrol_sleep_millisec(uint16_t msec)
    {
    	uint16_t i;
    	for(i=0; i<msec; i++) {
    		rncontrol_sleep(1);
    	}
    }
    ...
    rncontrol_sleep_millisec(2000);
    Wenn ich diesen Umweg hier mach, dann funktioniert’s aber:

    Code:
    // Initializes the timer Timer2 (Prescaler=1 | CTC)
    TCCR2  = (1<<CS20) | (1<<WGM21);
    OCR2   = 73;
    TIMSK |= (1<<OCIE2);
    …
    /**
     * Sleeps the given time. For t=100 the function Sleeps 1 ms.
     */
    inline void rncontrol_sleep(uint8_t t)
    {
    	// countTimer2 wird in der ISR oben inkrementiert
    	countTimer2 = 0;
    	while (countTimer2 < t)
    		asm volatile("nop");
    }
    
    
    /**
     * Sleeps the given milliseconds. 
     */
    inline void rncontrol_sleep_millisec(uint16_t msec)
    {
    	uint16_t i;
    	for(i=0; i<msec; i++) {
    		rncontrol_sleep(100);
    	}
    }
    ...
    rncontrol_sleep_millisec(2000);
    Gruß
    Lutz

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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