Forum: Compiler & IDEs Zeitmessung spinnt


von Jens (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen..

Seit geraumer Zeit versuche ich eine Zeitmessung im Auto von 0 auf 100
zu programmieren. Es hat auch schon geklappt. Nun bin ich (um ADC und
TWI fertig zu haben) auf den MEGA8535 umgestiegen und habe dabei auch
gleich den Takt auf 8MHz angehoben, Timer umgestellt usw..
Auf jeden Fall funktioniert das nichtmehr!

Ich nutze den Timer/Counter2 um alle 2ms einen interrupt zu starten.
Mit diesem Interrupt habe ich schon eine Uhr programmiert, welche im
Rahmen der Genauigkeit(1s auf 40min falsch) lief. Also ist mit dem
Interrupt alles richtig.

Jetzt habe alles andere Funktionen rausgeschmissen und im Interrupt
SIGNAL(SIG_OUTPUT_COMPARE2)
{
if((kmh>0)&&(kmh<101)){zeit2ms_mess++;}
}
gelassen.
Im Hauptprogramm läuft noch eine Endlosschleife, welche mir die
zeit2ms_mess im format XX,XXSEK ausgibt. siehe Quellcode

Wenn ich nun an meinem Signaleingang Impulse gebe komme ich auf maximal
20kmh. Also müßte die Ausgabe zählen, wenn ich aufhöre stehen bleiben
und dann wieder zählen, wenn ich Impulse geb. Es zählt aber bis
00,35SEK und bleibt dort, wenn ich aufhöre Impulse zu geben, gehts
wieder auf 0 zurück..

Der angehängte Quellcode enthält natürlcih noch viel unnützes und macht
manche Sachen vielleicht nicht ganz sauber. Das kommt halt daher, daß
ich alles rausgeschmissen habe und jetzt schon eine Weile daran ohne
Erfolg rumdoktor.. Prinzipiell müßte es aber doch so funktionieren,
Wenigstens die Zeit zählen

Ich hoffe jemand kann mir da weiterhelfen, bin da so langsam am
verzweifeln!
Vielen Dank
Jens

von Volkmar (Gast)


Lesenswert?

Hallo Jens,

ist eigentlich ganz einfach, ist nämlich das FAQ-Topic #1 (tschuldige,
ist aber nun mal so). Du mußt die variable zeit2ms_mess als
"volatile" deklarieren. Also so:

volatile unsigned int zeit2ms_mess;

Nur so weiß der AVR-GCC daß diese Variable auch außerhalb des normalen
Programmablaufs (zB im Interrupt) verändert werden kann.

Dies gilt natürlich auch für alle anderen Variablen die Du zB in den
Interrupts verwendest.

Was sonst noch fehlt, ist das Handling drumherum, aber vielleicht
hattest Du das einfach auch zur Vereinfachung entfernt. Wie zB.
- Nach einer Messung auf Null setzen
- Derzeit zählt er weiter wenn Du wieder unter 101km/h kommst
- ...

Volkmar

von Jens (Gast)


Lesenswert?

Danke für die Antwort aber mit volatile habe ich es gerade geteset und
es ist das gleiche Scheißspiel.. Bis 350ms (00,35SEK) und dann wieder
abwärts..
Dann müßte die Uhr(die den gleichen 2ms timer nutzte), kmh-Zahl und die
impulzahlen bzw gefahrenen kilometern eigentlich auch nicht
funktionieren? Die werden aber alle sauber dargestellt!
Hab ehrlich gesagt noch nie etwas mit volatile deklariert..

Ja das handling habe ich jetzt mehrmals verändert und hat mit der
damals funktionierenden fast nichtsmehr gemeinsam.
Wenn er nichtmal bis 351ms zählt kann man sowas schlecht testen und es
macht auch keinen Spass jedesmal alles komplett durchzudenken.

von Jens (Gast)


Lesenswert?

ok, das Programm oben kann so nicht funktionieren, weil das
obligatorische strcpy(ausgabe,""); am Anfang fehlt und der string
immer länger wird, das display aber nur die ersten 8 zeichen
ausgibt...
ich habe alle variablen volatile gemacht. Im aufteilen(..) auch ein
unsigned int genommen usw.. hat alles nichts gebracht..

Erst das umbenennen der "zeit2ms_mess" variable in "s" im editor
durch finden und ersetzen hat die geschichte zum laufen gebracht!!
Zumindest auf dem Schreibtisch mal..
Meine Uhrvariable heisst zeit2ms_trip und die läuft doch auch?
Kann mir jetzt bitte einer erklären warum das so ist..

gruss
Jens

von Volkmar (Gast)


Lesenswert?

Wundert mich jetzt auch, daß es mit den anderen Variablen funktioniert.
Eventuell hängt es mit der eingestellten Optimierung zusammen. Aber das
Du die Variable umbenennen musstest, wundert mich schon. Da kann ich Dir
wohl auch nicht weiterhelfen.

Volkmar

von Jens (Gast)


Angehängte Dateien:

Lesenswert?

So, jetzt bin ich ein bischen Probe gefahren und schon gibs die nächsten
Absonderheiten:

im interrupt von der kmh berechnung steht
if(kmh>maxkmh){maxkmh=kmh;}
Ansonsten mache ich nichts mit dem maxkmh außer halt ausgeben..
Im Auto zeigt mir maxkmh aber selstamerweise die aktuelle
Geschwindigkeit an, also als ob die if schleife nicht gilt und gleich
maxkmh=kmh gemacht würde.

Genauso speichert er die bestzeit im 0 auf 100 rennen nicht richtig ab.
der code:
if(zeit_0100<bestzeit_0100){bestzeit_0100=zeit_0100;zeittemp=205;}
Also er zeigt an, daß ich eine neue Bestzeit gefahren bin (das bedeutet
das zeittemp=205), aber speichert diese offensichtlich nicht ab.. Alle
Variablen als volatile.

Gibt es da wirklich eine compiler option, die sowas so brutal
wegoptimiert? Mit opt=3 oder s oder gar 0 funktionuckelt es allerdings
auch nicht.Habe meine makefile sicherheitshalber angefügt.

Ich blick das echt nicht. Ist bestimmt irgendein saudummer Fehler..
Bitte sagts mir, verlier langsam echt die Lust hier..

gruss
Jens

von Jens (Gast)


Lesenswert?

Also ich habe wieder maxkmh in mkmh umbenannt (replace) und siehe da, es
tut was es tun soll! Das mit der Bestzeit kann ich nicht testen, weil
ich noch nicht im Auto damit war.

Ich habe den Eindruck das der Atmel die Variable automatisch wieder auf
0 zurückgesetzt hat. Also das die if schleife schon greift, aber maxkmh
eben immer automatisch abgefallen ist, so wie die 350ms auch von allein
wieder auf 0 ist, obwohl sie hätten stehen bleiben müssen?!

Habe WinAVR 20040404, also auch das neuste, im AVR libc z.B. steht der
atmega8535 als [untested].. Kann es sein, daß es deswegen zu Problemen
kommen kann und ich einfach auf ein neues update warten muß?
Oder habe ich ein Virus im Atmel ;)

Hat wirklich keiner irgendeine Idee, warum das so ist?

gruss Jens

von Volkmar (Gast)


Lesenswert?

Die Anmerkung "atmega8535 [untested]" kann in dieser Hinsicht
eigentlich keine Auswirkung haben. Mich wundert schon, daß eine
Umbenennung der Variablen es zum Funktionieren bringt. Ich hatte da
bisher keine Probleme. Scheint mir so, als ob es einen Namenskonflikt
gibt. Ist aber nur eine Vermutung.

Volkmar

von Jens Peter (Gast)


Lesenswert?

Also der Fehler ist auch wirklich reproduzierbar!
ich habe das gleiche Programm einmal mit maxkmh kompiliert und dann mit
mkmh! Die Version mit mkmh funktioniert, die mit maxkmh nicht. Auch wenn
ich von mkmh wieder in maxkmh umbenenne, funktioniert es wieder nicht.
Wenn ich die .lss Dateien anschauen, sind die exakt gleich groß. Beide
scheinen auch alles gleich zu machen. Der einzige Unterschied, der mir
aufgefallen ist, war, daß die Variablen eben in anderen Adressen
standen.

Beim funktionierenden:
mkmh: 0x0216 0x0215
dabei kmh in 0x0209 und 0x020A
beim nicht funktionierenden:
maxkmh:0x020A 0x0209
dabei kmh in 0x020C 0x020B

Die Adressen werden aber nur benutzt, wenn wirklich maxkmh
gebrauch/verändert wird. Also da pfuscht nichts zwischendrin mal rein.
(soweit ich diese vielen Zeilen assembler überblicken kann)

Gibt es beim mega8535 evtl irgendwelche Besonderheiten, die ich
beachten müßte?

Ich hoffe damit kann jemand etwas anfangen ;)
gruss Jens Peter (hier gibs soviele Jens hab ich gemerkt)

von Jens Peter (Gast)


Lesenswert?

Servus..

Also um das aufzuklären.

der string ausgabe[] wurde im Programm größer als geplant, so daß es
die Variable, welche im Speicher direkt nach dem string liegt
überschreibt. So kamen dann halt irgendwo Phantasiewerte rein..

Ich hoffe das wars jetzt wirklich ;)

Vielen Dank nochmal an Volkmar ohne den ich diesen Fehler wohl noch
ewig gesucht hätte!!!

von nobody0 (Gast)


Lesenswert?

Du solltest nur sichere Funktionen verwenden, also

fgets      statt     fget
calloc     statt     malloc
strncat    statt     strcat
strncpy    statt     strcpy
snprintf   statt     sprintf
strncmp    statt     strcmp
vsnprintf  statt     vprintf

dann gibt't nämlich auch weniger exploits.
In ein Prettyprinting-Skript habe ich deshalb Warnungen eingebaut, die
warnen, wenn eine der kritischen Funktionen im Sourcecode ist.

von Jörg Wunsch (Gast)


Lesenswert?

Naja, "it depends".  Gerade bei Controllern kommt es schnell mal auf
die verfügbaren Ressourcen (Codegröße, Rechenzeit) an, so daß ich
diesen Hinweis nicht allgemein stehen lassen würde.  Wenn ich mir
einen Puffer mit malloc() geben lasse, den ich anschließend fülle,
warum soll ich ihn vorher von calloc() noch plattmachen lassen?  Ist
doch schade um die Arbeit, wenn danach das Ergebnis von calloc()
zunichte gemacht wird.  calloc() als lame excuse, sein Stringende
nicht ordentlich abzuschließen, würde ich ohnehin nicht unterstützen
wollen.  Das hieße ja, schlampige Programmierung nur durch andere
Methoden zu flicken, statt sie gleich gar nicht erst schlampig werden
zu lassen.

Gleiches gilt für die diversen str* Funktionen ohne `n' drin: wenn
man
weiß, was man tut, kann man die auch nehmen.  strlcat/strlcpy sind
zuweilen ohnehin ein besserer Ersatz als strncat/strncpy.

Einzig der Benutzung von fgets() statt gets() würde ich
uneingeschränkt zustimmen, da man die mögliche Fehlersituation bei
gets() aufgrund seines Lesens von stdin fast nie unter Kontrolle
bekommen kann.

von nobody0 (Gast)


Lesenswert?

Also malloc wird sehr selten auf MCs verwendet; da sollte calloc statt
malloc nur wirklich keinen nennenswerten Unterschied machen. Außerdem
bekommt man durch calloc eine Initialisierung und nicht nullterminierte
strings bekommt man dadurch (sofern die vor dem allozierten Bereichsende
enden) nullterminiert.
Wenn man ein paar Funktionen nimmt, die einige Fehler beseitigen oder
limitieren, bringt das schon etwas. Schließlich gibt's Fehler ja nicht
nur in der Implementation sondern auch in Hardware und der
Spezifikation.
Deshalb überprüfe ich beispielsweise in einer Warteschleife nicht ob
der Endwert erreicht wurde, sondern ob der Wert größer gleich dem
Endwert ist.

von Jörg Wunsch (Gast)


Lesenswert?

> Also malloc wird sehr selten auf MCs verwendet; da sollte calloc
> statt malloc nur wirklich keinen nennenswerten Unterschied machen.

Ah, Du kennst Dich aus.  Interessant.

> Außerdem bekommt man durch calloc eine Initialisierung und nicht
> nullterminierte strings bekommt man dadurch (sofern die vor dem
> allozierten Bereichsende enden) nullterminiert.

Genau gegen diese Variante schlampiger ,,ganz genau weiß ich auch
nicht, wo mein String zu Ende ist, aber calloc() wird's schon
richten'' Programmierung habe ich mich oben gewandt.  Die kaschiert
letztlich nur die Bugs des Programmierers.

Aber da Du Dir nicht mal 'nen Namen leisten kannst, ist das für mich
EOD.

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.