Das Problem hast du schon genannt: timGet()
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?
Danke für eure Hilfe!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 -------------------------------------------------------------------------
Gruss
cumi
Das Problem hast du schon genannt: timGet()
Disclaimer: none. Sue me.
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 -------------------------------------------------------------------------
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.
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:
Ganz vielen Dank für deine Hilfe Georg-Johann!Code:dword timGetDifNUp(dword t0){ dword t1=timGet(); if(t1<t0) return (dword)0xFFFFFFFF-t0+t1; return t1-t0; }
Gruss
cumi
*g* Was deine Variablen machen und wozu die da sind, solltest du schon wissen... Wenn signal auf FALSE ist word ja actFreq=0.Zitat von cumi
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.
Lesezeichen