- LiTime Speicher und Akkus         
Ergebnis 1 bis 6 von 6

Thema: Probleme bei der Frequenzauswertung

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.10.2005
    Ort
    Zürich
    Beiträge
    117

    Probleme bei der Frequenzauswertung

    Anzeige

    Praxistest und DIY Projekte
    Hallo Zusammen

    Um die Geschwindigkeit eines Modellautos zu messen arbeite ich mit einem Weg-Impuls-Geber.

    Nun habe ich jedoch noch einige Probleme mit der Software. Das folgende Modul funktioniert ganz gut, muss jedoch irgendwo noch einen Bug haben, da es in zufälligen Abständen (zwischen wenigen hunder Millisekunden und einigen Minuten) zu Fehlauswertungen kommt. freqGet() liefert dann irgend einen komisch Wert, welcher am häufigsten 0 ist. Dabei wird die Frequenz zurzeit noch von einem Rechteckgenerator geliefert. An diesem sollte es also nicht liegen.

    Damit man den Code schneller versteht hier ein paar grundsätzliche Dinge:

    Das Signal liegt am Analogkomperator, welcher mit einem Kondensator noch einwenig geglättet wird. Getriggert wird bei 2.5V. Das Signal ist ein Rechteck von 0-5V.
    Um zusätzlich noch entprellen zu können wird der Analog Comparator Interrupt beim auftreten eines Interrupts kurz deaktiviert und einwenig später vom Timer wieder aktiviert.
    timGet() liefert ein DWord (32 Bit langer unsigned Typ). Dieses zählt auf dem Systemtakt hoch und überläuft nach ca. 9min einfach.


    Ich komme bei diesem Problem schon seit geraumer Zeit nicht weiter. Finden vielleicht jemand von euch den Fehler?

    Code:
    /// includes --------------------------------------------------------------------
    #include <normlib.h>
    #include <interrupt.h>
    #include "avr.h"
    #include "tim.h"
    #include "out.h"
    #include "dataTable.h"
    #include "data.h"
    #include "freq.h"
    
    // global variables ------------------------------------------------------------
    byte freqPulsLedFlag;
    byte freqEnable;
    
    // local definitions -----------------------------------------------------------
    
    // local variables -------------------------------------------------------------
    static word  actFreq;
    static dword t0,tI1; //timestamp of last puls
    static dword dt;     //delta t
    static byte  signal;
    static byte  preload;
    static dword pLedTime;
    
    // global function implementation ----------------------------------------------
    void freqInit(){
      TCCR0=BV(CS02)|BV(CS00); // activate Timer 0, prescaler /1024
      preload=dataGetByte(DATATABLE_AC_TCNT0); //preload  of Timer0
    
      // Enable Analog Comparator, Enable Analog Comparator Interrupt
      if(dataGetByte(DATATABLE_AC_EDGE))
        ACSR=BV(ACIS0)|BV(ACIS1); //rising Edge
      else
        ACSR=BV(ACIS1);           //falling Edge
    
      cbi(ACSR,ACD);   //Enable Analog Comparator
      sbi(ACSR,ACIE);  //Enable Analog Comparator Interrupt
      
      actFreq        =0;
      signal         =FALSE;
      freqPulsLedFlag=TRUE;
      freqEnable     =TRUE;
      pLedTime       =(F_CPU/1000)*dataGetWord(DATATABLE_PULS_LED_FREQ);
    }
    word freqGet(){
      return actFreq;
    }
    void freqUpdate(){
      if(!freqEnable)
        return;
      cli();
      dword t1=tI1;
      sei();
      if(t0!=t1){
        signal=TRUE;
        if(t1<t0)
          dt=-t0+t1;
        else
          dt=t1-t0;
        if(dt<((dword)(10*F_CPU/0xFFFF)))
          actFreq=0xFFFF;
        else
          actFreq=(word)((dword)(10*F_CPU)/dt);
        t0=t1;
        if(freqPulsLedFlag)    
          outClear(OUT_PULS);
      }
      if(!signal){
        actFreq=0;
        return;
      }
      if(t0==t1){
        dword t2=timGet();
        dword dtN;
        if(t2<t0)
          dtN=-t0+t2;
        else
          dtN=t2-t0;
        if(dtN>dt){
          actFreq=(word)((dword)(10*F_CPU)/dtN);
        }
      }
      if(timReached((dword)F_CPU,t0))
        signal=FALSE;
      if(freqPulsLedFlag&&timReached(pLedTime,t0))
        outSet(OUT_PULS);
    }
    
    // interrupt routines ----------------------------------------------------------
    ISR(ANA_COMP_vect){
      tI1=timGet();
      cbi(ACSR,ACIE);  //disable Analog Comparator Interrupt
      TCNT0=preload;   //preload Timer0
      sbi(TIMSK,TOIE0);//enable Timer 0 Interrupt  
    }
    ISR(TIMER0_OVF_vect){
      sbi(ACSR,ACI);   //clear Analog Comparator Interrupt Flag
      sbi(ACSR,ACIE);  //enable Analog Comparator Interrupt
      cbi(TIMSK,TOIE0);//disable Timer 0 Overflow Interrupt
    }
    
    // EOF -------------------------------------------------------------------------
    Danke für eure Hilfe!

    Gruss
    cumi

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Das Problem hast du schon genannt: timGet()
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.10.2005
    Ort
    Zürich
    Beiträge
    117
    Meinst du?
    Hier noch die Implementation von timGet();

    Ich habe übriegens noch die Variabeln volatile deklariert. Daran liegt es jedoch nicht (nur).
    Code:
    // includes --------------------------------------------------------------------
    #include <normlib.h>
    #include <interrupt.h>
    #include "tim.h"
    
    // local variables -------------------------------------------------------------
    volatile static word overrun;
    
    // global function implementation ----------------------------------------------
    void  timInit(){
      overrun=0;
      b_setH(TCCR1B,CS10); //activate timer, no prescaling
      b_setH(TIMSK,TOIE1); //activate Overflow Interrupt
    }
    dword timGet(){
      byte sregSav=SREG; 
      cli();
      dword tmp=(((dword)overrun<<16)&0xFFFF0000)|(((dword)TCNT1)&0x0000FFFF);
      SREG=sregSav;
      return tmp;
    }
    dword timGetDifUp(dword *t0){
      dword t1=timGet();
      dword res;
      if(t1<(*t0))
        res=-(*t0)+t1;
      else
        res=t1-(*t0);
      *t0=t1;
      return res;  
    }
    dword timGetDifNUp(dword t0){
      dword t1=timGet();
      if(t1<t0)
        return -t0+t1;
      return t1-t0;
    }
    byte timReached(dword t,dword t0){
      if(timGetDifNUp(t0)>=t)
        return TRUE;
      return FALSE;
    }
    
    // interrupt routines ----------------------------------------------------------
    ISR(TIMER1_OVF_vect){
      overrun++;  
    }
    
    // EOF -------------------------------------------------------------------------
    Code:
    /// includes --------------------------------------------------------------------
    #include <normlib.h>
    #include <interrupt.h>
    #include "avr.h"
    #include "tim.h"
    #include "out.h"
    #include "dataTable.h"
    #include "data.h"
    #include "freq.h"
    
    // global variables ------------------------------------------------------------
    byte freqPulsLedFlag;
    byte freqEnable;
    
    // local definitions -----------------------------------------------------------
    
    // local variables -------------------------------------------------------------
    static word  actFreq;
    static dword t0;
    volatile static dword tI1; //timestamp of last puls
    static dword dt; //delta t
    static byte  signal;
    static byte  preload;
    static dword pLedTime;
    
    // global function implementation ----------------------------------------------
    void freqInit(){
      TCCR0=BV(CS02)|BV(CS00); // activate Timer 0, prescaler /1024
      preload=dataGetByte(DATATABLE_AC_TCNT0); //preload  of Timer0
    
      // Enable Analog Comparator, Enable Analog Comparator Interrupt
      if(dataGetByte(DATATABLE_AC_EDGE))
        ACSR=BV(ACIS0)|BV(ACIS1); //rising Edge
      else
        ACSR=BV(ACIS1);           //falling Edge
    
      cbi(ACSR,ACD);   //Enable Analog Comparator
      sbi(ACSR,ACIE);  //Enable Analog Comparator Interrupt
      
      actFreq        =0;
      signal         =FALSE;
      freqPulsLedFlag=TRUE;
      freqEnable     =TRUE;
      pLedTime       =(F_CPU/1000)*dataGetWord(DATATABLE_PULS_LED_FREQ);
    }
    word freqGet(){
      return actFreq;
    }
    void freqUpdate(){
      if(!freqEnable)
        return;
      cli();
      dword t1=tI1;
      sei();
      if(t0!=t1){
        signal=TRUE;
        if(t1<t0)
          dt=-t0+t1;
        else
          dt=t1-t0;
        if(dt<((dword)(10*F_CPU/0xFFFF)))
          actFreq=0xFFFF;
        else
          actFreq=(word)((dword)(10*F_CPU)/dt);
        t0=t1;
        if(freqPulsLedFlag)    
          outClear(OUT_PULS);
      }
      if(!signal){
        actFreq=0;
        return;
      }
      if(t0==t1){
        dword t2=timGet();
        dword dtN;
        if(t2<t0)
          dtN=-t0+t2;
        else
          dtN=t2-t0;
        if(dtN>dt){
          actFreq=(word)((dword)(10*F_CPU)/dtN);
        }
      }
      if(timReached((dword)F_CPU,t0))
        signal=FALSE;
      if(freqPulsLedFlag&&timReached(pLedTime,t0))
        outSet(OUT_PULS);
    }
    
    // interrupt routines ----------------------------------------------------------
    ISR(ANA_COMP_vect){
      tI1=timGet();
      cbi(ACSR,ACIE);  //disable Analog Comparator Interrupt
      TCNT0=preload;   //preload Timer0
      sbi(TIMSK,TOIE0);//enable Timer 0 Interrupt  
    }
    ISR(TIMER0_OVF_vect){
      sbi(ACSR,ACI);   //clear Analog Comparator Interrupt Flag
      sbi(ACSR,ACIE);  //enable Analog Comparator Interrupt
      cbi(TIMSK,TOIE0);//disable Timer 0 Overflow Interrupt
    }
    
    // EOF -------------------------------------------------------------------------

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    schwer zu sagen...

    Steht signal vielleicht auf FALSE?

    In timGetDifNUp() und anderen Stellen versuchst du Betrag zu berechnen. Nehmen wir mal an, wir wollen den Betrag für 8-Bit berechnen.

    a = 0x80 = -128 und b = 0, es ist also a < b

    if (a < b) c = b-a

    => c = 0x80 = -128 < 0

    Analog bei breiteren Typen
    Disclaimer: none. Sue me.

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.10.2005
    Ort
    Zürich
    Beiträge
    117
    Was meinst du mit Signal auf FALSE? Da schau ich nicht ganz durch.

    Also wegen dem Betrag. Also ich rechne mit dword, das ist ein 32-Bit langer unsigned Integer. Ja ich weiss, ich solte ev. einmal die Typenbezeichnung der AVR-Lib-c, oder wie die genau heisst, übernehmen.
    Und weil der unsigned ist kann der nicht negativ werden. Ich möchte nicht wirklich den Betrag ausrechnen sondern etwas anderes:
    timGet gibt ja einen Time-Spamp zurück, welcher die Zeit in Systemtakten seit dem boot angiebt. Dieser Timestamp überläuft jedoch so nach ca. 9min (dann sind 2^32 Takte vorbei). Dies ist jedoch nicht weiter tragisch, da ich sowieso nur Zeitunterschiede messen möchte. Diese können dann einfach nicht länger als 9min sein.
    Wenn nun t1 (der Timestamp beim aufrufen von timGetDifNUp) grösser als t0 (der alte Timestamp) ist, kann ich einfach t1-t0 rechnen. Wenn nun, was jedoch sehr selten passiert (nur alle 9min), t1<t0 ist, ist der Zähler gleich überlaufen, seit t0 gesetzt wurde. Daher muss ich doch 2^32-t0+t1 rechen um den Zeitunterschied zwischen t0 und t1 zu kriegen, oder?

    Habe ich da in der Implementierung einen Fehler?

    Die obige Implementation ist ja äquivalent zu dieser. Hier sieht man es jedoch etwas besser:
    Code:
    dword timGetDifNUp(dword t0){
      dword t1=timGet();
      if(t1<t0)
        return (dword)0xFFFFFFFF-t0+t1;
      return t1-t0;
    }
    Ganz vielen Dank für deine Hilfe Georg-Johann!

    Gruss
    cumi

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Zitat Zitat von cumi
    Was meinst du mit Signal auf FALSE? Da schau ich nicht ganz durch.
    *g* Was deine Variablen machen und wozu die da sind, solltest du schon wissen... Wenn signal auf FALSE ist word ja actFreq=0.

    Vielleicht ist es besser, die Variable nicht überlaufen zu lassen sondern immer direkt den Happen abzuziehen und nur den Zeitunterschied zurückzuliefern.
    Disclaimer: none. Sue me.

Berechtigungen

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

LiFePO4 Speicher Test