- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 5 von 5

Thema: Timer Interrupt - Pausen - Dauer

  1. #1
    Erfahrener Benutzer Begeisterter Techniker Avatar von M1.R
    Registriert seit
    02.06.2007
    Ort
    Freiburg
    Beiträge
    213

    Timer Interrupt - Pausen - Dauer

    Anzeige

    Powerstation Test
    Hallo,

    auf folgende Weise versuche ich Pausen zu programmieren und eine Dauer zu ermitteln (Atmega 32, 8Mhz):
    Zu Beginn wird ein Zähler gestartet der jede Millisekunde um 1 weiterzählt.

    Code:
    #define preloader 131
    volatile uint32_t zaehler;
    
    ISR(TIMER0_OVF_vect)  // wird jede ms ausgeführt
    {
    	TCNT0 = preloader;
    	zaehler++;
    }

    die Funktion für die Pause sieht so aus:
    Code:
    void pause(uint16_t wert)		//millisek eingeben max 65535
    {
    	uint16_t ende=zaehler+wert;
    	while (zaehler<ende);
    }
    die Funktion für die Dauer so:
    Code:
    uint32_t dauer(void)		
    {
    	uint16_t wert=zaehler-start_zeit;
    	return wert;
    }
    das Testprogramm:
    Code:
    //test45
    
    #include "loeffler.h"
    #include "uart.h" //fleury
    
    /*****************************************************************************/
    void SerPrint (char *data)
    {
      unsigned char i = 0;
      while (data [i] != 0x00)	uart_putc (data [i++]);
    }
    /****************************************************************************/
    void PrintInt (int wert)
    {
      char text [7]; 
      itoa (wert, text, 10);
      SerPrint (text);
    }
    /****************************************************************************/
    
    int main(void)
    {
        loeffler_init();	
    	
    	uint8_t i;
    	uint16_t pausen[21];
    	led_rechts(rot);
    	led_links(rot);
    	for(i=0; i<20; i++)
    	{
    		start_zeit=zaehler;
    		pause(1000);
    		pausen[i]=(dauer());
    	}
    	led_rechts(gruen);
    	led_links(gruen);
    	uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
    	SerPrint("\n\r");
    	for(i=0; i<20; i++)
    	{
    		SerPrint("\n\r");
    		PrintInt (i);
    		SerPrint("\t"); 
    		PrintInt (pausen[i]);
    	}
    	while(1);
        return(0);
    }
    die ermittelten Pausenwerte sollten nun theoretisch jew. 1000 ms sein.

    Das Ergebnis sieht aber so aus:

    Code:
    0       1000
    1       1000
    2       1000
    3       840
    4       1000
    5       1000
    6       1000
    7       1000
    8       864
    9       1000
    10      1000
    11      1000
    12      1000
    13      864
    14      1000
    15      1000
    16      1000
    17      1000
    18      864
    19      1000
    warum geht das so nicht?
    Wäre schön, wenn mir jemand weiterhelfen könnte.

    Gruss
    M.

  2. #2
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Die Zugriffe auf die Variable Zähler sind nicht atomar. Es kann also passieren, das high und low Bytes nicht zusammengehören.
    Zugriffe auf Zaehler müßte man also immer in CLI / SEI einschließen.

    Damit die Zeiten besser stimmen sollte man beim Timer wenn irgendmöglich den CTC modus wählen, dann summieren sich Verzögerungen beim ISR-aufruf nicht auf.

  3. #3
    Erfahrener Benutzer Begeisterter Techniker Avatar von M1.R
    Registriert seit
    02.06.2007
    Ort
    Freiburg
    Beiträge
    213
    Vielen Dank für deine Antwort.

    Leider sind meine Programmierkenntnisse (noch) ziemlich rudimentär, daher kann ich deiner Erklärung nicht so ganz folgen.
    Zitat Zitat von Besserwessi
    Die Zugriffe auf die Variable Zähler sind nicht atomar. Es kann also passieren, das high und low Bytes nicht zusammengehören.
    Zugriffe auf Zaehler müßte man also immer in CLI / SEI einschließen.
    Der Begriff "atomar" sagt mir nichts. Liegt das Problem darin, dass ein Interrupt auftritt, wenn der Zugriff auf die Variable noch nicht fertig ist?
    Damit die Zeiten besser stimmen sollte man beim Timer wenn irgendmöglich den CTC modus wählen, dann summieren sich Verzögerungen beim ISR-aufruf nicht auf.
    Warum stimmen die Zeiten im CTC Modus besser?

    Durch Einfügen von CLI und SEI sind die Ergebnisse schon mal besser geworden.
    Nun werde ich noch versuchen in den CTC Modus umzustellen.

    Gruss
    M.

  4. #4
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Dein Code hat noch ein paar andere Probleme.

    Wieso ist ende in der Funktion pause 16 Bit groß, wo doch zaehler 32 Bits hat? Wie soll die Funktion irgendetwas Sinnvolles machen, wenn zaehler gerade größer als 65536 ist? Und wenn du ende auf 32 Bit änderst, hast du immer noch das Problem, dass die Funktion einen Überlauf nicht berücksichtigt.

    Wieso soll dauer einen 32 Bit Wert zurückgeben, wo doch dem Code nach anscheinend die maximale Dauer auf 16 Bit beschränkt sein soll (und effektiv auch nur ein 16 Bit Wert zurückgegeben wird)?

    Und wenn beides (Pause und Dauer) auf maximal 16 Bit beschränkt sein soll, warum ist dann zaehler überhaupt 32 Bit groß? 16 Bit würden dann auch reichen.
    MfG
    Stefan

  5. #5
    Erfahrener Benutzer Begeisterter Techniker Avatar von M1.R
    Registriert seit
    02.06.2007
    Ort
    Freiburg
    Beiträge
    213
    Zitat Zitat von sternst
    Dein Code hat noch ein paar andere Probleme.

    Wieso ist ende in der Funktion pause 16 Bit groß, wo doch zaehler 32 Bits hat? Wie soll die Funktion irgendetwas Sinnvolles machen, wenn zaehler gerade größer als 65536 ist? Und wenn du ende auf 32 Bit änderst, hast du immer noch das Problem, dass die Funktion einen Überlauf nicht berücksichtigt.

    Wieso soll dauer einen 32 Bit Wert zurückgeben, wo doch dem Code nach anscheinend die maximale Dauer auf 16 Bit beschränkt sein soll (und effektiv auch nur ein 16 Bit Wert zurückgegeben wird)?

    Und wenn beides (Pause und Dauer) auf maximal 16 Bit beschränkt sein soll, warum ist dann zaehler überhaupt 32 Bit groß? 16 Bit würden dann auch reichen.
    Danke!
    Ist natürlich falsch!
    Ich werde es ändern in:
    uint32_t ende und
    uint32_t wert
    Wenn ich mich nicht verrechnet habe, läuft mein Zähler bei 32 Bit erst nach ca. 50 Tagen über, und solange hält der Akku von meinem Roboter eh nicht.

    Gruss
    M.

Berechtigungen

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

LiFePO4 Speicher Test