- 3D-Druck Einstieg und Tipps         
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 21

Thema: Timer1 - Clear Timer on Input-Capture?

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    04.12.2006
    Beiträge
    32

    Timer1 - Clear Timer on Input-Capture?

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Timer1 ist ja u.a. auch zur Frequenzmessung gedacht und dafür möchte ich Ihn auch benutzen.

    CPU Frequenz und Prescaler sind für miene Frage ja nicht relevant.

    Wenn am ICP1 die flanke steigt soll ein Zeitstempel angelegt werden:
    TCCR1B &= (1<< ICES1);

    nun wäre es doch mehr als sinnvoll, wenn dieses Ereignis auch gleich den Timer zurücksetzt! Oder muss man in der Interrupt-Routine, die mit dem Input-Capture ausgelößt werden kann, den Timer "von Hand" reseten?
    Da gingen jedoch ein paar Takte verloren und der Gecapturte Wert währe immer ein bisschen zu klein.

    Beim rauf und runter lesen vom Atmega8535 Datenblatt hab ich nix gefunden!

  2. #2
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Ein zurücksetzen des Timers auf ein Externes Signal ist nicht vorgesehen. Für die Genaue Zeitmessung läßt man den Timer einfach weiterlaufen und mißt die Zeit für das Start und Stop Ereigniss getrennt. Man ließt das ICP resgister alle 2 mal aus. Einmal für den Start, und einmal für Stop. Dannach kann man die Differenz berechnen. Im RN-Wissen unter timer steht dazu ein Beispiel.

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    08.06.2009
    Beiträge
    41
    Hallo,
    das würde mich auch interessieren.
    Ich bräuchte den Timer zur Drehzahlbestimmung am Motor über Hall Sensor.
    Da habe ich im Grunde auch das selbe Problem, denn wie soll ich wissen, wie lange er für eine Umdrehung gebraucht hat, wenn der Timer nicht zurückgesetzt wird. Evlt. könnte man das noch mit der Differenz zwischen letzten Timerwert und aktuellem Timerwert ausrechnen. Dann hätte ich aber immer noch das Problem, dass eine Messung, nämlich die beim Overflow nicht stimmt.
    Wenn das Problem mit dem Overflow nicht wäre, müsste es über die Differenz gehen.
    Hat jemand eine Idee, wie man das lösen kann ?

    MfG
    Destrono

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    08.06.2009
    Beiträge
    41
    habe gerade gemerkt, dass ich zu langsam war mitm Posten.
    Es bleibt aber immer noch die Frage, ob bei der Differenzrechnung von neuer Wert - alter Wert während des Overflows nicht ein Fehler auftritt

  5. #5
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von Destrono
    Es bleibt aber immer noch die Frage, ob bei der Differenzrechnung von neuer Wert - alter Wert während des Overflows nicht ein Fehler auftritt
    Bei nur einem Overflow nicht. Und wenn mehrere Overflows auftreten können, muss man das so oder so zusätzlich berücksichtigen.
    MfG
    Stefan

  6. #6
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    Zitat Zitat von Destrono
    ... bräuchte den Timer zur Drehzahlbestimmung am Motor ...
    Ich weiß nicht, wieviele Lösungsmöglichkeiten es an Atmel-Megas bzw. in C gibt. Meine Lösung ist nur eine davon, sie läuft. Das Konzept stammt aus einer Zeit, in der meine C-Kenntnisse noch bescheidener als heute waren; es ist also sicher KEIN Optimum. Mir ist klar, dass die Zeitmessung mit Auslesen des aktuellen Counterstandes genauer wäre - wäre aber eben ein anderer Lösungsweg, den ich in der Konzeptphase nicht schaffte.

    Diese Zeitmessung hat als Zeitsignal einen 50 µs-Takt mit dem Timer2 am mega168/328 - damit brauche ich bei 20 MHz (wenn ichs grad richtig im Kopf habe) unter 5 % CPU-Zeit bzw. knapp 60 Maschinenbefehle (*.lls). In der ISR wird ein 2Byte-Counter hochgesetzt - theoretisch geht das also über 3 sec gut, praktisch zählt diese Uhr eine Sekunde bis der Counter zurückgesetzt wird. Ausgelesen wird diese Boardzeit in einer ISR, die vom extINT ausgelöst wird, der auf die steigende Flanke einer Gabellichtschranke mit vier Schlitzen an der Motorwelle anspricht. Max. Drehzahl des Motors unter 800 Hz, dh. weniger als 2400 Hz Interrupts an der Gabellichtschranke. Derzeit wird nur jeder zweite Interrupt gezählt, so als hätte die Encoderscheibe nur zwei Schlitze *ggg*. Die Timerinitialisierung setze ich als geläufig voraus. Die ISR für die Boardzeit sieht so aus:
    Code:
    /* ============================================================================== */
    /* ===  Nicht unterbrechbare ISR für timer2 ===================================== */
    /* Routine zählt hoch im Takt 20 kHz = 50 µs.    Der Zählerwert wird von den ISR für
    	EXT_INT0 und -INT1 ausgelesen und den Werten Iz_yseci zugewiesen ......   */
    ISR(TIMER2_COMPA_vect)          // Vektor 7
    {
      if (Izeit_1 < Izthrznt)       //Interrupt-Timer = 0 ... 19 999 ... (1 sec blink)
      {
        Izeit_1 ++;                 //  ###>>> Izeit_1 ist aktuell int16_t ==>>
      }    				//  Izeit_1 bleibt bis 32000 in der int16-Grenze
      else
      {                                        
        PORTC ^=  (1<<PC5);         // LED auf Port PC5/I2C/SCL toggeln
        Izeit_1 = 0;		// ansonsten: Rückstellen auf Null
        icntdwn = icntdwn + 1;      // Countdownzähler hoch(!!)zählen
        if (icntdwn <  0)           // Countdownzähler geht maximal 9 Std.
        icntdwn = 0;
        if (Iencdr0 == Ienc0alt) { Iz_diff0 = 0; }
      }     
    }         
    /* ============================================================================== */
    Nachteil: Bei hohen Drehzahlen habe ich Werte um 13 tupsi (Timer Units Per Sensor Interrupt) - das ist also recht grob für die Regelaufgabe. Eine Drehrichtungserkennung ist nicht möglich - das liegt aber nicht an der Zeitmessung. Eine Stillstandserkennung ist nicht so ohne weiteres möglich, derzeit wird ein hoher Zählerstand als Stillstand definiert.
    Vorteil: Es geht kein Zeitbruchstück verloren, übrige "Zeitbruchteile" werden der folgenden Messung zugeschlagen. Das dadurch auftretende Flattern des Zeitsignals durch diese Zeitbruchteile um den tatsächlichen Wert wird vom Regler ausgebügelt. Ausserdem wird dieser 50µs-Takt für andere Aktionen als Zeitsignal genutzt. Die toggelnde LED auf PC5 ist ein praktisches Signal für die Timerfunktion. Der ebenfalls mitlaufende Countdown icntdwn wird (ebenfalls) für Zeitmessungen benutzt, er geht theoretisch für Zeitmessungen bis 18 Stunden mit Sekundengenauigkeit.
    Ciao sagt der JoeamBerg

  7. #7
    Benutzer Stammmitglied
    Registriert seit
    08.06.2009
    Beiträge
    41
    Hallo,
    Danke an oberallgeier für die ausführliche Beschreibung. Leider habe ich das nicht ganz verstanden, weil mir die Kenntnisse für die Kontrollerinternen Vorgänge fehlen.
    Ich habe es jetzt mit der oben beschriebenen Methode versucht und bin gescheitert, da der Kontroller die Zeit für eine Umdrehung nicht richtig oder gar nicht berechnet.
    Als Tachosignal verwende ich einen Lüfter (ist im Grunde nichts anderes als ein Hallsensor).
    Verarbeitet wird das Signal über den Input Capture Interrupt. In der ISR wird dann auch gleich die Zeitdifferenz für aufeinanderfolgende Interrupts berechnet. Mein Atmega 16 läuft mit 8Mhz und als Prescaler für den Timer1 habe ich 1024 verwendet.
    Der Timer wird also mit einer Frequenz von 7812,5 erhöht.
    Folglich habe ich die Zeitdifferenz zweier aufeinanderfolgender Interrupts durch 7,813 geteilt, um auf die Millisekundendifferenz zu kommen.
    Nachdem ich feststellen musste, dass das nicht funktioniert habe ich die Rechnung vereinfacht und die Zeitdifferenz nur noch durch 7 teilen lassen. Auch dabei kommen keine vernünftigen Werte raus.
    Nebenbei lasse ich in der ISR auch die Anzahl der Interrupts (entspricht der Anzahl der Lüfterumdrehungen) hochzählen. Zumindest das macht er.

    Wenn ich den Lüfter mit der Hand drehe, dann bekomme ich ordentliche plausible Ergebnisse für die Zeitdifferenz. Wenn ich den Lüfter hingegen unter Strom setze, scheint der Kontroller nicht mehr hinterherzukommen und er zeigt für die Zeitdifferenz entweder 0 oder 36 ms an. Dieser Wert ändert sich auch nicht , wenn ich den Lüfter mit der Hand abbremse

    Hat jemand eine Idee, was ich ändern muss, damit das noch funktioniert?
    Den Code kann ich leider schlecht posten, da er aus mehreren Teilen besteht.

    Dann hätte ich noch eine Frage:
    Ich habe den Kontroller so programmiert, dass er die steigende Flanke des Tachosingals vom Lüfter für einen Input Captur Interrupt auswerten soll. Bei einem Wechsel von low auf high funktioniert das auch wunderbar, nur dummerweise registriert er auch beim Wechsel von high auf low gleich mehrere (bis zu 10 ) interrupts auf einmal
    Ich habe mir jetzt damit beholfen, einen Kondensator am Einganspin dranzuhängen. Damit ist das Problem behoben, aber ich kann mir vorstellen, dass ich bei hohen Drehzahlen Probleme bekommen könnte.
    Hat jemand eine Idee, woran das liegt?
    Das Problem, dass er Zeit für eine Umdrehung nicht richtig ausgibt hat nicht mit dem Kondensator zu tun, da das Problem auch ohne Kondensator besteht.

    MfG
    Destrono

  8. #8
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Das man mehrere Interrupts bei einer Flanke beim langsamen drehen bekommt kann an einer Art Prellen liegen. Die Lösung mit dem Kondensator ist schon nicht schlecht. Wenn der Kondensator klein genug ist, sollte es auch noch zu ziehmlich hohen Drehzahlen funktionieren. Eventuell müßte noch ein Widerstand vor den Kondensator, wenn der Ausgangswiderstand des Sensors sehr unsymetrisch ist.
    Wenn die Messung beim langsamen Drehen funktioniert, nicht aber wenn der Motor läuft, könnte das Porblem von Störungen vom Motor kommen, also eine Hardware Problem und keines in der Software.

    Ohne Code ist es schwer einen Fehler zu finden. Damit die Rechnung mit dem Überlauf richtig funktioniert, sollte man mit Variablem vom Typ Word rechnen. Könnte es sonst noch sein, das beim Auslesen des ISP registers was durcheinander gerät mir high/low Byte ? 36 ms würde gerade zu 256 Timer-schritten passen.

  9. #9
    Benutzer Stammmitglied
    Registriert seit
    08.06.2009
    Beiträge
    41
    Zitat Zitat von Besserwessi
    Wenn die Messung beim langsamen Drehen funktioniert, nicht aber wenn der Motor läuft, könnte das Porblem von Störungen vom Motor kommen, also eine Hardware Problem und keines in der Software.
    Hallo,
    danke für die Antwort. Ich habe den Kontroller wegen diesem Problem jetzt schon mindestens 20 mal mit einer abgeänderten Software geflasht und er geht immer noch nicht. Ich versuche das noch mal genauer zu beschreiben. Ich hatte den Lüfter mit den Input Capture Interrupt dran, dann noch einen Adc mit Poti und einen Timer der Sekunde für Sekunde nach oben zählt. Alle diese Werte habe ich dem Display ausgeben lassen. Da der Adc auch bei laufenden Lüfter auf jede kleinste Veränderung reagiert und sofort der richtige Wert am Display ausgegeben wird ( was in der while Schleife der main Funktion passiert) kann ich mir nicht vorstellen, dass der Kontroller überlsatet ist.
    Ich habe zur Sicherheit trotzdem den Code so abgeändert, dass nur noch der Input Capture Interrupt verarbeitet wird (also kein Adc mehr). Auch das hat nicht gebracht. Auch habe ich die Zeitdifferenz nicht mehr teilen lassen, sondern direkt auf dem Display ausgegeben und auch bringt keine Verbesserung, da er jetzt bei laufendem Lüfter für die Zeitdifferenz nur 256 oder 0 ausgibt
    Nebenbei habe ich auch noch eine Led toggeln lassen, wenn der Interrupt auftritt. Das funktioniert komischerweise wunderbar, denn wenn der Lüfter auf voller Drehzahl läuft, wird die Led praktisch gedimmt und wenn ich dne Lüfter mit der Hand abbremse kann man irgendwann bei langsamer Lüfterdrehzahl ein Blinken erkennen.
    Auch die Anzahl der Interrupts, die ich ebenfalls auf dem Display ausgeben lasse, werden vernünftig hochgezählt.
    Da ich noch Anfänger bin, was die Avrs betrifft, werde ich jetzt doch mal meinen Code ausschnittsweise posten:

    Hier die ISR:
    Ich lasse die Zeitdifferenz für eine Umdrehung erst nach 4 Interrupts berechnen, weil der Lüfter für eine Umdrehung 4 mal von low auf high wechselt. Sobald "difference_new" ihren Wert verändert, wird der neue Wert in der Hauptschleife auf dem Display ausgegeben.
    Code:
    ISR(TIMER1_CAPT_vect)     
    {
     PORTC ^= (1<< PC7); //PC7: Led
      if (test >9998){          // Test zählt die interrutps und gibt sie auf dem Display aus
    
             test = 1;}
             else { test ++;}
    
    
    
     if (calculate >= 3){
        timer_compare_new=  ICR1L;  
        timer_compare_new= ( ICR1H<< 8);
        difference_new = (timer_compare_new - timer_compare_old);
        timer_compare_old = timer_compare_new;
         calculate =0 ;
    
             }
    
       else{
        calculate  ++;}
    }
    Hier ein Auszug aus meinem headerfile, in dem die Variablen deklariert werden:
    Alle Variablen, die sowohl von der ISR als auch von den Funktionen aus der Main genutzt werden habe ich als volatile deklariert und ihnen in der Main Funktion, aber noch vor der while Schleife, den Wert 0 zugeordnet.
    Ist das in Ordnung mit volatile?
    Code:
     volatile uint16_t timer_compare_new;
     volatile uint16_t timer_compare_old;
     volatile uint16_t difference_new;
     uint16_t diff_old;
     volatile uint8_t calculate;
    Den Code aus der main Funktion spare ich mir, weil er ja bei langsamen Drehzahlen (nicht schneller, als man mit der Hand so nen Lüfter drehen kann) vernünftige Werte für die Zeitdifferenz liefert und auch bei laufenden Lüfter die Adc Werte sofort aktuallisiert hat, was darauf schließen lässt, dass die main Funktion noch ausreichend häufig durchlaufen wird, also nicht von Interrupts lahmgelegt ist.

    Würde mich sehr freuen, wenn ihr mir noch mal helfen könntet, da ich mit meinem Latein jetzt echt am Ende bin und schon viel Zeit in dieses Projekt investiert habe.

    MfG
    Destrono

  10. #10
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Code:
        timer_compare_new=  ICR1L; 
        timer_compare_new= ( ICR1H<< 8);
    Ist es Absicht, dass du den Wert aus ICR1L einfach "wegschmeißt" und nur den Wert aus ICR1H verwendest? Ich vermute mal nein, denn sonst würde es dich ja nicht wundern, dass du als Ergebnis nur 0 oder 256 bekommst.

    Warum machst du es dir nicht etwas einfacher, und verwendest "timer_compare_new= ICR1;".
    MfG
    Stefan

Seite 1 von 3 123 LetzteLetzte

Berechtigungen

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

12V Akku bauen