PIC: Zeitmessung - float Addition scheitert

Gast #3668575
Lesenswert?

Hallo,

wir arbeiten auf einem easypic v7 board mit einem pic 18f4520 und haben 
Probleme bei der Addition von float Werten.
Konkret soll eine Zeitmessung über einen Interrrupt an einem Port 
stattfinden. Da die Zeitmessung über den TimerInterrrupt maximal 8,3s 
läuft, speichern wir die Anzahl der Überlaufe in der 
Interruptserviceroutine. Der Timer funktioniert soweit und sowohl der 
einzelne gemessene Wert im Timer, als auch die Anzahl der Überlaufe sind 
korrekt.
Wenn wir jetzt die Anzahl der Überlaufe mit der Zeitkonstante 
multiplizieren und den Timermesswert zu dieser Zahl addieren wollen, 
hängt sich das Programm bei der Addition auf.
1
unsigned int TimerValue;
2

3
float TimeConstant = 8.388608f; //Zeitkonstante für TimerInterruptÜberlauf
4
float TimeBetweenEdge = 0.0f;   //Zeit zwischen zwei Interruptflanken
5

6
float TempTimer1 = 0.0f;
7
float TempTimer2 = 0.0f;
8

9
TimerValue = TMR0L;        //Aktuelle Zeit im Timer
10
TimerValue += TMR0H << 8;
11
TempTimer1 = (TimerValue / 65535.0f) * TimeConstant;
12

13
TempTimer2 = (float)TimeCount * TimeConstant; //Zeit der Überlaufe
14
         
15
TimeBetweenEdge = TempTimer1 + TempTimer2 ;  //geht nicht

Hat jemand eine Idee warum die zwei float Werte nicht addiert werden 
können?
Moderator (Firma: Titel) Persönliche Seite #3668587
Lesenswert?

Ma!k schrieb:
> TimeBetweenEdge = TempTimer1 + TempTimer2 ;  //geht nicht
WAS geht nicht?
Und WIE merkst du das?

> Hat jemand eine Idee warum die zwei float Werte nicht addiert werden
> können?
Hast du einen Grund, das an dieser Stelle unbedingt brauchen zu 
müssen?

> pic 18f4520
Merke: es ist i.A. keine gute Idee, auf einem 8-Bit uC ohne 
Coprozessor/FPU Fließkommazahlen zu verwenden.
#3668614
Lesenswert?

X4U schrieb:
> Ma!k schrieb:
>> Hat jemand eine Idee warum die zwei float Werte nicht addiert werden
>> können?
>
> Ist das der gesamte Code?

Ist die Frage ernst gemeint? Lies den Beitrag des TO's. Er beschreibt 
einerseits, dass der Timer Korrekt funktioniert, der Wert richtig 
gelesen werden kann und dass auch die ISR richtig aufgerufen wird.

Siehst du in diesem Teil des Codes irgendiene Initialisation? Siehst du 
ein Main? Denke, jeder der weiss was ein Controller zum funktionieren 
braucht, sieht auch direkt dass dies lediglich ein Ausschnitt sein kann.
#3668654
Lesenswert?

Ich glaube du hast dem Problem an der falschen stelle nachgejagt.

Ma!k schrieb:
> TempTimer1 = (TimerValue / 65535.0f) * TimeConstant;

Wenn unsigned int 16 bit gross ist, wird dass immer 0 ergeben, weil
unsigned int / float = unsigned int
unsigned x;x/UINT_MAX==0;
Timer value muss zu float gekastet werden. Wir sind hier nicht in Java!

Also so:
TempTimer1 = ((float)TimerValue / 65535.0f) * TimeConstant;
Oder besser:
TimeConstant * TimerValue / 65535.0f
Gast #3668717
Lesenswert?

Lothar Miller schrieb:
> WAS geht nicht?
> Und WIE merkst du das?

Wie oben beschrieben hängt sich das Programm bei folgender Zeile auf:
1
TimeBetweenEdge = TempTimer1 + TempTimer2;
Festgestellt wurde dies unter anderem im Debugger. Wenn ich die Addition 
zum Test einmal weglasse und nur TempTimer1 in TimeBetweenEdge 
reinschreibe werden da auch die richtigen Werte ausgegeben. Genauso 
funktioniert es für TempTimer2. Es scheitert also wirklich an der 
Addition.

jetzt schrieb:
> Float is in den meisten Faelle unnoetig. Rechne in Millisekunden und
> behalte das Komma.

Die Zeitmessung soll allerdings über mehrere Minuten laufen. D.h. ein 
unsigned int würde vom Wertebereich nicht mehr ausreichen. Also würde 
ich auf einen unsigned long int ausweichen?


X4U schrieb:
> Ist das der gesamte Code?

Nein das ist natürlich nicht der gesamte Code sondern nur der Teil in 
dem der Fehler auftritt.


jetzt schrieb:
>>(float)TimeCount
>
> kommt aus dem Nichts.

TimeCount ist die Anzahl der Timer-Überlaufe und wird in der ISR 
hochgezählt.


Daniel A. schrieb:
> Wenn unsigned int 16 bit gross ist, wird dass immer 0 ergeben, weil
> unsigned int / float = unsigned int
> unsigned x;x/UINT_MAX==0;
> Timer value muss zu float gekastet werden. Wir sind hier nicht in Java!
>
> Also so:
> TempTimer1 = ((float)TimerValue / 65535.0f) * TimeConstant;
> Oder besser:
> TimeConstant * TimerValue / 65535.0f

Mit dem jetzigen Code kommt auch schon wieder ein float raus und es 
steht da auch wirklich die richtige Zeit drin, also nicht 0. Selbst 
wenn, sollte eine Addition mit 0.0f kein Problem sein.
Moderator (Firma: Titel) Persönliche Seite #3668742
Lesenswert?

Daniel A. schrieb:
> gekastet werden. Wir sind hier nicht in Java!
Wir haben auch keine Kasten. Wir sind hier nicht in Indien!

Der Code an sich funktioniert tadellos:
http://codepad.org/5Pxlqyyj
Das Problem liegt woanders...

Ma!k schrieb:
> Die Zeitmessung soll allerdings über mehrere Minuten laufen. D.h. ein
> unsigned int würde vom Wertebereich nicht mehr ausreichen. Also würde
> ich auf einen unsigned long int ausweichen?
Richtig. So machen es alle Anderen auch.
Ein float braucht genau so viel Speicherplatz wie ein long, nur sind die 
Rechnungen mit floats wesentlich ineffizienter...
Gast #3668782
Lesenswert?

>TimeBetweenEdge = TempTimer1 + TempTimer2 ;
>TempTimer1 = (TimerValue / 65535.0f) * TimeConstant;
TempTimer2 = (float)TimeCount * TimeConstant; //Zeit der Überlaufe
>TimeBetweenEdge = TempTimer1 + TempTimer2 ;


Ist irgendwie Quatsch. Macht
TimeBetweenEdge = (TimerValue/65535.0f + (float)TimeCount) * 
TimeConstant

Zum einen kann man * Timeconst weglassen, das bingt nichts.

Falls man das wirklich etwas so will, dann rechnet man :
(long) TimeBetweenEdge = TimeCount << 16 + TimerValue; //als Timer 
Einheiten.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren