Forum: Mikrocontroller und Digitale Elektronik PIC: Zeitmessung - float Addition scheitert


von Ma!k (Gast)


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?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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.

von jetzt (Gast)


Lesenswert?

Float is in den meisten Faelle unnoetig. Rechne in Millisekunden und 
behalte das Komma.

von X4U (Gast)


Lesenswert?

Ma!k schrieb:
> Hat jemand eine Idee warum die zwei float Werte nicht addiert werden
> können?

Ist das der gesamte Code?

von San L. (zwillingsfreunde)


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.

von jetzt (Gast)


Lesenswert?

>(float)TimeCount

kommt aus dem Nichts.
Insgesammt sehr merkwueriger code. Die Timeconst ist zwei mal drin.

von Amateur (Gast)


Lesenswert?

Möglicherweise fehlen nur die Bibliotheken. Is' 'ne linke Sache.

von Daniel A. (daniel-a)


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

von Peter II (Gast)


Lesenswert?

Daniel A. schrieb:
> Wenn unsigned int 16 bit gross ist, wird dass immer 0 ergeben, weil
> unsigned int / float = unsigned int

???

int / float sollte doch float ergeben.

von Ma!k (Gast)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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...

von Teo D. (teoderix)


Lesenswert?

Float Berechnungen, ohne FPU, dauern doch ziemlich lange!
Tackert Dir da nich der Timer-Interrupt dazwischen?
War da nich mal was "Atomar"?

von Daniel A. (daniel-a)


Lesenswert?

In solchen fällen  versuche ich meistens verschiedene 
optimierungsoptionen. Wenn das Problem Immernoch besteht versuche ich 
ein Minimalbeispiel zu erstellen. Andernfalls suche ich nach 
Speicherüberlaufen oder änlichem.

von jetzt (Gast)


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.

von Mike (Gast)


Lesenswert?

Ma!k schrieb:
> Hat jemand eine Idee warum die zwei float Werte nicht addiert werden
> können?

Was willst du bei der Aktion überhaupt mit Float?
Welchen Dynamikbereich erwartest du, dass du auf Kosten der Genauigkeit 
die Dynamik vergrößerst?

von Ma!k (Gast)


Lesenswert?

Ok, also wir haben jetzt die float Operationen komplett weggelassen und 
alles mit int bzw. long berechnet. Jetzt funktioniert das Programm auch 
ohne Probleme.

Danke für eure schnelle Hilfe.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ma!k schrieb:
> Jetzt funktioniert das Programm auch ohne Probleme.
Ich würde an deiner Stelle trotzdem untersuchen, was denn das Problem 
war. Nächsten Monat tappst du wieder rein...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.