Hey Leute!
Ich verwende meinen Mega8 in einer Zeitmessung, um Start- und
Stoppsignale per Lichtschranken auszuwerten...
Sobald nun der erste Läufer die Start-Lichtschranke passiert hat, soll
INT0 deaktiviert werden und INT1 dafür aktiviert werden... Das
Aktivieren von INT1 klappt problemlos, jedoch lässt sich INT0 nicht
deaktivieren... Bei jedem Startsignal stoppt dadurch die "Zeit" und das
Ergebnis wird verfälscht...
An INT0 hängt die Start- und an INT1 die Stopplichtschranke...
Ein weiters Problem ist, dass mein Flash zu klein wird... Gibt es eine
Möglichkeit, das Programm z.B. in einem externen Flash-speicher
auszulagern?
Wie kann ich soetwas realisieren?
Noch eine Frage: Die Zeiten die ich messe, werden nur im RAM gespeicher
--> dieser wird mir aber leider zu klein --> ab etwa 60 Zeiten "hängt
sich der µC auf"...
Ich hoffe ihr könnt mir weiterhelfen...
lg Patrick
@ Patrick
>Sobald nun der erste Läufer die Start-Lichtschranke passiert hat, soll>INT0 deaktiviert werden und INT1 dafür aktiviert werden... Das>Aktivieren von INT1 klappt problemlos, jedoch lässt sich INT0 nicht>deaktivieren... Bei jedem Startsignal stoppt dadurch die "Zeit" und das>Ergebnis wird verfälscht...
????
Sollten beide Interrupts immer aktiv sein? Der INT0 der
Startlichtschranke startet den Zähler, der Interrupt1 der STOP
Lichtscharanke stoppt den zähler.
>Ein weiters Problem ist, dass mein Flash zu klein wird... Gibt es eine>Möglichkeit, das Programm z.B. in einem externen Flash-speicher>auszulagern?
Nein, du kannst nur Daten auf externen Flash (I2C, SPI, parallel)
auslagern. Aber für ne Stopuhr sollten die meisten AVRs locker reichen.
>Noch eine Frage: Die Zeiten die ich messe, werden nur im RAM gespeicher>--> dieser wird mir aber leider zu klein --> ab etwa 60 Zeiten "hängt>sich der µC auf"...
Stack/Heap kollision? Wis speicherst duden deine Zeiten? Der MEGA8 hat
immerhin 1kB SRAM.
MFG
Falk
Hi
Versuchs mal mit dem ATMega168. Ist soweit pinkompatibel mit dem
Atmega8 und hat 16k Speicher.
Wie versucht du den Interrupt abzuschalten?
MfG Spess
Als danke mal für die vielen Antworten...
Die Stoppuhr soll für Zeitmessungen von Gruppenläufern (bis etwa 60
Läufer) geeignet sein...
Gestartet wird nur einmal über den INT0, gestoppt logischerweise bei
jedem Läufer (INT1)...
Die Zeiten sollen bis zu 2 Stunden betragen können...
Da ich jede Zeit in einem long - Array speichere, wird mir dieses
realtiv schnell sehr groß... Auch wenn ich nur die Differenz der Läufer
zu der Zeit des Ersten speichern würde, würde ich eine long-Variable
benötigen, da ich die Zeit auf Tausendstel genau haben will...
Es soll zu beginn nur INT0 "erlaubt" sein, bis der erste Läufer die
Lichtschranke passiert... Danach soll INT1 "freigegeben" werden um von
allen Läufern die Zeiten nehmen zu können...
Bisher habe ich versucht es so zu realisieren, dass ich einfach nach
einem Ereignis an INT0 per neudefinition INT0 dissable und INT1
enable...
Gibt's da ne andere Möglichkeit?
Habt ihr vorschläge, wie ich die Zeit "ressourcensparender" abspeichern
könnte?
Hab jetzt noch ein "Problem": Wie kann man zwei Strings
"zusammensetzen"? Habs mit strcat versucht, hat aber leider nicht
geklappt... (verwende CVAVR als Compiler)...
lg Patrick
Patrick wrote:
> Hab jetzt noch ein "Problem": Wie kann man zwei Strings> "zusammensetzen"? Habs mit strcat versucht, hat aber leider nicht> geklappt... (verwende CVAVR als Compiler)...
strcat ist schon das richtige Werkzeug.
Wie sieht denn dein Versuch konkret (in Code aus).
@ Patrick
>Die Stoppuhr soll für Zeitmessungen von Gruppenläufern (bis etwa 60>Läufer) geeignet sein...
Wie erkennst du die einzelnen Läufer? Oder muss da der Bedier die
richtige Tasten drücken?
>Die Zeiten sollen bis zu 2 Stunden betragen können...
Ja und? Das sagt noch GAR nichts über die ANZAHL von Zeiten, die
gespeichert werden müssen.
>Da ich jede Zeit in einem long - Array speichere, wird mir dieses>realtiv schnell sehr groß... Auch wenn ich nur die Differenz der Läufer>zu der Zeit des Ersten speichern würde, würde ich eine long-Variable>benötigen, da ich die Zeit auf Tausendstel genau haben will...
???
Was soll das? Nichtmal Hundertmetersprinter brauchen so eine Auflösung,
die begnügen sich mit 1/100 Sekunde.
>Es soll zu beginn nur INT0 "erlaubt" sein, bis der erste Läufer die>Lichtschranke passiert... Danach soll INT1 "freigegeben" werden um von>allen Läufern die Zeiten nehmen zu können...
Warum soll die zweite Lichtschranke gesperrt sein? Die ist doch räumlich
getrennt?
>Bisher habe ich versucht es so zu realisieren, dass ich einfach nach>einem Ereignis an INT0 per neudefinition INT0 dissable und INT1>enable...
Häää???
Du kanns während des Programms nichts "neudefinieren", das kannst du nur
einmal im Quelltext. Du kannst jedoch den INT1 deaktivieren und wieder
aktivieren. Dazu braucht es nur ein Bit imentsprechenden Register.
>Habt ihr vorschläge, wie ich die Zeit "ressourcensparender" abspeichern
Du musst erstmal sagen
- wieviel Zeitmessungen gespeichert werden sollen
- welche Genauigkeit wirklich gebraucht wird
- etc.
MfG
Falk
Wieder Einer, der meint, das Benutzen einer Hochsprache erspart den
Blick ins Datenblatt des Controllers (wie funktionieren Interrupts im
Detail)...
;-)
...
Falk wrote:
> Wie erkennst du die einzelnen Läufer? Oder muss da der Bedier die> richtige Tasten drücken?>
Das System besteht aus 4 Lichtschranken, bei denen jeweils 2 eine
LS-Einheit bilden (sind per &-Gatter verschalten)...
Die Start LS hängt an INT0 und soll gesperrt werden, sobald der 1.
Läufer diese Passiert hat... Dann soll die 2. LS-Einheit freigegeben
werden, welche an INT1 hängt... Sobald ein Läufer diese Einheit
passiert, wir durch die LS ein Impuls erzeugt, welcher dann am INT1
anliegt und die Zeit "stoppt" - also die Zeit des Läufers wird ins Array
geschrieben... Natürlich geht das so weiter, bis die Messung beendet
wird....
>>Die Zeiten sollen bis zu 2 Stunden betragen können...>> Ja und? Das sagt noch GAR nichts über die ANZAHL von Zeiten, die> gespeichert werden müssen.>
In den meisten Fällen werden mindestens 40 Läufer laufen und daher
sollten es schon 40 Zeiten sein...
>>Da ich jede Zeit in einem long - Array speichere, wird mir dieses>>realtiv schnell sehr groß... Auch wenn ich nur die Differenz der Läufer>>zu der Zeit des Ersten speichern würde, würde ich eine long-Variable>>benötigen, da ich die Zeit auf Tausendstel genau haben will...>> ???> Was soll das? Nichtmal Hundertmetersprinter brauchen so eine Auflösung,> die begnügen sich mit 1/100 Sekunde.
Wäre eine Überlegung wert, hier etwas zu ändern - die Vorgabe sind aber
1/1000 Auflösung...
> Warum soll die zweite Lichtschranke gesperrt sein? Die ist doch räumlich> getrennt?
Es soll die Erste (Start) Lichtschranke gesperrt werden, da bei einem
"fliegenden" Start von meheren Läufern ja nur einmal die Zeit gestartet
werden soll...
> Häää???> Du kanns während des Programms nichts "neudefinieren", das kannst du nur> einmal im Quelltext. Du kannst jedoch den INT1 deaktivieren und wieder> aktivieren. Dazu braucht es nur ein Bit imentsprechenden Register.
Damit meinte ich ja auch eine Änderung im Quelltext... Hab schon
versucht, die entsprechenden Register zu verändern... Hat aber leider
nicht funktioniert - also den INT0 "sperren"... Das enablen des INT1
klappt allerdings...
>>Habt ihr vorschläge, wie ich die Zeit "ressourcensparender" abspeichern>> Du musst erstmal sagen>> - wieviel Zeitmessungen gespeichert werden sollen
Eine Messung á 60 Läufer (am besten wären 100)
> - welche Genauigkeit wirklich gebraucht wird
Vl. reicht auch ein Hundertstel - muss ich noch klären...
lg Patrick
Schau Dir auch mal den ICP-Interrupt an. Der könnte hilfreich sein.
Den Int0 solltest Du sauber deaktivieren können, indem Du in seiner ISR
(also wenn er aufgetreten ist und abgearbeitet wird) das Bit 'int0' im
Register gicr deaktivierst. Da ein Läufer mehrere Interrupts auslösen
kann (er hat ja Arme und Beine, die nicht immer eng am Körper anliegen),
empfiehlt es sich auch noch ein zufällig erneut gesetztes intf0-Bit in
gifr durch Schreiben einer Eins zu löschen.
In einem Lichtschranken-Stopuhr-Projekt für vier Bahnen (4
Lichtschranken + Kontakt in Startpistole) mit Mega8 habe ich die
Lichtschranken wie Taster entprellt, was normalerweise für laufende
Menschen ausreichen sollte.
...
>Wäre eine Überlegung wert, hier etwas zu ändern - die Vorgabe sind aber>1/1000 Auflösung...
Schon mal die Ansprechzeit der Lichtschranke betrachtet? Könnte sein,
dass die viel größer ist als die von Dir angepeilte Genauigkeit.
Aber den (Un-)Sinn eines 2-Stunden-Rennens, bei dem nur der erste Läufer
den Start der Zeitmessung auslöst, dann aber die Zeit aller Läufer auf
1/1000 Sek. genau gemessen werden soll, soll mir mal einer erklären.
Das würde ja bedeuten, dass der n-te Läufer z. B. 1 Std. 47 Min 24,974
Sek nachdem der erste Läufer die Startlinie überquerte ins Ziel
gelaufen ist. Die eigentliche Start-Ziel-Laufzeit des n-ten Läufers hast
du doch dann garnicht. Warum dan so genau?
Ausserdem, wenn du nur ein Ziel hast, müssten ja alle Läufer schön der
Reihe nach durchs Ziel laufen, um für jeden eine Zeit zu ermitteln.
Oder habe ich da was falsch verstanden?
tastendrücker wrote:
>>Wäre eine Überlegung wert, hier etwas zu ändern - die Vorgabe sind aber>>1/1000 Auflösung...>> Schon mal die Ansprechzeit der Lichtschranke betrachtet? Könnte sein,> dass die viel größer ist als die von Dir angepeilte Genauigkeit.>> Aber den (Un-)Sinn eines 2-Stunden-Rennens, bei dem nur der erste Läufer> den Start der Zeitmessung auslöst, dann aber die Zeit aller Läufer auf> 1/1000 Sek. genau gemessen werden soll, soll mir mal einer erklären.>> Das würde ja bedeuten, dass der n-te Läufer z. B. 1 Std. 47 Min 24,974> Sek nachdem der erste Läufer die Startlinie überquerte ins Ziel> gelaufen ist. Die eigentliche Start-Ziel-Laufzeit des n-ten Läufers hast> du doch dann garnicht. Warum dan so genau?>> Ausserdem, wenn du nur ein Ziel hast, müssten ja alle Läufer schön der> Reihe nach durchs Ziel laufen, um für jeden eine Zeit zu ermitteln.>> Oder habe ich da was falsch verstanden?
Also das Problem ist, dass mein Projekt sowohl für z.B. 100m Einzellauf
als auch für 10km Gruppenlauf geeignet sein soll!
Ich will nicht die genaue Zeit jedes einzelnen haben (bei einem
Gruppenlauf) sondern die Zeit, die jeder vom "Gesamtstart" bis zu seinem
"Zieldurchlauf" braucht...
Beim Zieldurchlauf ist es wichtig, dass jeder Läufer eine "Wertung"
erhält... Falls jetzt mal doch 1-2 Zeiten zu viel genommen werden (wenn
jetzt 3 Läufer fast gleich durchs Ziel laufen) ist das nicht so
tragisch, da eine Kamera den Zieleinlauf filmt, um gewissheit über die
Platzierung zu erhalten...
Da ich für Start und Ziel LS verwende, heben sich die Ansprechzeiten
nahezu auf...
Wenn ich jetzt auf Hundertstel umstelle, benötige ich für 2 Stunden eine
Datentypgröße von 720.000 ...
Wie finde ich eine geeignete Type? Denn INT ist zu klein und LONG ist
etwas "oversize"...
lg Patrick
> ist das nicht so> tragisch, da eine Kamera den Zieleinlauf filmt, um gewissheit über die> Platzierung zu erhalten...
Bietet sich da nicht an, eine (große) digitale Zeitanzeige, die vom
Start eingeschaltet wird, so zu platzieren, dass sie von der Kamera
gesehen und mit aufgezeichnet wird? Dann hast zu zu jedem Teilnehmer,
der durchs Ziel läuft, die exakte Laufzeit auf dem Video.
> Wenn ich jetzt auf Hundertstel umstelle, benötige ich für 2 Stunden eine> Datentypgröße von 720.000 ...> Wie finde ich eine geeignete Type? Denn INT ist zu klein und LONG ist> etwas "oversize"...
Da würden 20 Bit reichen, das wäre mir aber zuviel Byte-Teilerei, ich
würde dann 24 Bit nehmen. Aber ich arbeite in ASM, eine Hochsprache
bietet das vermutlich nicht an.
Mein Stoppuhrprogramm war für einen Kinder-Sportverein gemacht worden.
Ich nutzte 16 Bit und hatte zwei verschiedene Auflösungen. 0,01 s
reichte mit etwas über 10 Minuten für die kurzen Distanzen und 0,05 s
reichte mit gut 54 Minuten für die etwas längeren Distanzen. Die Ausgabe
der im EEPROM gesammelten Daten über serielle Schnittstelle (auch mit
USB-Adapter) erfolgte im Klartext (ASCII), womit die unterschiedlichen
Auflösungen kompensiert wurden. Um das Vermischen der unterschiedlichen
Auflösungen zu vermeiden, wurden beim Ändern der Auflösung die Daten im
EEP gelöscht.
Das Programm ist zwar auch nicht das absolute Nonplusultra, aber
vielleicht schaust Du doch mal rein:
http://www.hanneslux.de/avr/stopuhr/index.html
...
@ Patrick F.
>In den meisten Fällen werden mindestens 40 Läufer laufen und daher>sollten es schon 40 Zeiten sein...
Und wieso has du dann ein Speicherproblem?
Wenn du deine Zeit als LONG (unit32_t) speicherst hast du ~
4.000.000.000 Zählstände, macht bei 1/1000 Sekunde Auflösung immer noch
~4.000.000s, sprich ~1111 Stunden Messzeit. Das reicht auch für nen
Marathon ;-)
>>Da ich jede Zeit in einem long - Array speichere, wird mir dieses>>realtiv schnell sehr groß... Auch wenn ich nur die Differenz der Läufer
Warum realtiv schnell relativ gross? Du brauchst ein Array von 40 LONGs,
das braucht 40x4 = 160 Byte, die hat der MEGA8 locker.
>Wäre eine Überlegung wert, hier etwas zu ändern - die Vorgabe sind aber>1/1000 Auflösung...
Halte ich zwar für Schmarn, aber was solls. Dem MEGA8 isses egal.
>Damit meinte ich ja auch eine Änderung im Quelltext... Hab schon>versucht, die entsprechenden Register zu verändern... Hat aber leider>nicht funktioniert - also den INT0 "sperren"... Das enablen des INT1>klappt allerdings...
Dann hast du die falschen Bits oder falschen Register erwischt. Nochmal
prüfen. Und bitte ordentliche Bitoperationen auf die Register anwenden.
@Hannes Lux
>Schau Dir auch mal den ICP-Interrupt an. Der könnte hilfreich sein.
Bein 1/1000 Sekunde reicht eigentlich ein Timer. Den braucht er sowieso.
>Wenn ich jetzt auf Hundertstel umstelle, benötige ich für 2 Stunden eine>Datentypgröße von 720.000 ...>Wie finde ich eine geeignete Type? Denn INT ist zu klein und LONG ist>etwas "oversize"...
Warum? Der braucht nur 4 Byte und gut. Man kann jetzt auch mit einem
selbstdefinierten 3 Byte Wert anfangen, aber wozu?
@Hannes Lux
>Bietet sich da nicht an, eine (große) digitale Zeitanzeige, die vom>Start eingeschaltet wird, so zu platzieren, dass sie von der Kamera>gesehen und mit aufgezeichnet wird? Dann hast zu zu jedem Teilnehmer,>der durchs Ziel läuft, die exakte Laufzeit auf dem Video.
Eben, so machen es auch die Profis (wenn gleich heute die Zeit
elekronisch ins Video eingeblendet wird.)
>Da würden 20 Bit reichen, das wäre mir aber zuviel Byte-Teilerei, ich>würde dann 24 Bit nehmen. Aber ich arbeite in ASM, eine Hochsprache>bietet das vermutlich nicht an.
C? Aber sicher. BASCOM? Keine Ahnung. Aber selbst für 100x4=400 Byte ist
im MEGA8 genug Platz.
MFG
Falk
Patrick F. wrote:
> Damit meinte ich ja auch eine Änderung im Quelltext... Hab schon> versucht, die entsprechenden Register zu verändern... Hat aber leider> nicht funktioniert - also den INT0 "sperren"... Das enablen des INT1> klappt allerdings...
Zeig doch mal etwas Code. Du hast einen Fehler gemacht und
wir können nicht riechen was du konkret gemacht hast.
So...
Im Anhang findet ihr meinen Quelltext - sehr gekürzt, sprich ohne
Menüführung, (Aus)Druckfunktion und sonstigen extras...
Einfach nur die Zeitmessung inkl. Initialisierung der Register, etc.
Bitte nicht erschrecken --> ich weiß, dass das alles andere als sauber
programmiert ist... Ich hab eben noch nicht so viel Ahnung...
lg Patrick
@ Partrick
Also ich fürchte, da sind einige Bugs drin.
Du verwendest verschiede Variablen (z.B. Läufernummer) in verschieden
Funtion/Interrupts. Diese müssen als volatile deklariert sein.
Weiterhin hast du ein paar kleine, aber wahrscheinlich böse
Array-Überläufe drin
>void MessungLaeufer(void)>{> //TCCR0=0x03;> if(n<=max_laeufer) {
Das MUSS heissen (n < max_laeufer), also KLEINER, und NICHT kleiner
Gleich, denn dein Array geht nur von 0..max_laeufer-1!
> zeitarray[laeuferNR]=zeit;> laeuferNR++;}> else if((n>max_laeufer) && !letzter)> {> zeitarray[laeuferNR]=zeit;> letzter=1;> }>}
So auf den ersten Blick sind deine Variablen nciht zu gross für den SRAM
(dann würde auch der Compiler streiken). Du hast also ein paar
Array-Überläufe drin. Vielleicht ist auch sprintf zu Stack-hungrig?
In Zeile 250 fehlt eine {
MfG
Falk
P.S. Wenn du das geradebiegen willst solltest du erstmal die
Formatierung auf ein ordentliches Nivau bringen, dann sieht man vieles
viel klarer. Und poste beim nächsten mal den VOLLSTÄNDIGEN Quelltext,
denn es sind meist Seiteneffekte, die dir in die Suppe spucken.
Danke schon mal für die Antwort...
Die Formatierung muss ich mir echt nochmal ansehen, denn schön langsam
wirds auch mir zu unübersichtlich...
Im Anhang ist jetzt mal der ganze Quelltext...
Ein weiters Problem ist, dass wenn nach dem Beenden der Messung ein
"Ereignis" an INT1 auftritt, startet der µC neu...
In der Menüführung sind die Punkte Einzellauf und Gruppenl noch nicht
fertig --> sprich funktionslos..
lg Patrick
@ Patrick F.
>Die Formatierung muss ich mir echt nochmal ansehen, denn schön langsam>wirds auch mir zu unübersichtlich...
Dann sei so nett und mach das und poste den ordentlich formatierten
Quelltext. Wir sind auch "nur" Leute die helfen wollen, keine
"Frontschweine" die die Kastanien aus dem Feuer holen.
MfG
Falk
> Ein weiters Problem ist, dass wenn nach dem Beenden der Messung ein> "Ereignis" an INT1 auftritt, startet der µC neu...
Den Start-Interrupt solltest Du durch einen Tastendruck (oder Menüpunkt)
freigeben und durch sein erstes Auftreten wieder deaktivieren. Dann kann
nix dazwischen funken.
...
Falk wrote:
> @ Patrick F.>>>Die Formatierung muss ich mir echt nochmal ansehen, denn schön langsam>>wirds auch mir zu unübersichtlich...>> Dann sei so nett und mach das und poste den ordentlich formatierten> Quelltext. Wir sind auch "nur" Leute die helfen wollen, keine> "Frontschweine" die die Kastanien aus dem Feuer holen.>> MfG> Falk
OK, wird gemacht...
wird aber etwas dauern...
Danke, dass du dir die Mühe machen willst!
Find ich total klasse...
lg Patrick
Hallo Leute!
Ich hab mir jetzt mal die Mühe gemacht, das ganze Programm mal
zu kommentieren und auch klarer zu gliedern...
Hätte ich früher oder später sowieso machen müssen (für die
Dokumentation...).
Hoffentlich findet man sich jetzt besser darin zurecht... Hab bisher
noch nie
so richtig ein Programm dokumentiert --> quasi mein erster "Versuch"...
Kurze Erklärung zur Hardware:
*µC ist der ATmega8-16PU
*Display ist ein 2x16 LCD
*INT0 und INT1 sind per Optokoppler an den Lichtschranken
angschlossen
*Drucker ist ein seriell-angesteuerter Bondrucker - an einem MAX232
Ich hoffe ihr könnt mir gute Tips geben, wie ich das Programm optimieren
und verbessern kann...
lg Patrick
Mal als alternativer Ansatz:
Die Uhr wird resetet,der 1. Puls an der Startzielschranke setzt die
interne Uhr auf 0:0:0.000.Jeder weitere Puls lässt den Megaxxx lediglich
die Zeitdifferenz errechnen.Wenn du dafür eine Capture/Compare-Einheit
nehmen kannst,geht das ganze sogar recht Resourcen schonend.Im Grunde
sicherst du nur Zeitstempel,die Anzahl der Ticks seit Rennbeginn.
Soweit ich weiß,ist die Anforderung im Profi-Bereich die Zeit eine
Stelle genauer an die Richter/Jury zu liefern als es letztendlich
bekannt gegeben wird.Und das bedeutet das man noch eine Stelle mehr
intern messen muß,um die Uhr für den Profieinsatz zugelassen zu
bekommen.Allerdings braucht man bei 1/10.000 Auflösung schon eine
verdammt genaue Taktquelle,ein simpler Quarz mit 30ppm oder so reicht da
nicht mehr ;)
@ Ronny
>intern messen muß,um die Uhr für den Profieinsatz zugelassen zu>bekommen.Allerdings braucht man bei 1/10.000 Auflösung schon eine>verdammt genaue Taktquelle,ein simpler Quarz mit 30ppm oder so reicht da>nicht mehr ;)
Warum?
30 ppm sind 1/33333, das ist noch dreimal genauer als deine 1/10000.
MFG
Falk
@Patrick
So, nach langer Bahnfahrt, hier nochmal ne Meldung von mir und ein
kleines Ostergeschenk.
Na das sieht doch WESENTLICH besser aus!
Da findet man Fehler im Handumdrehen (naja, nicht immer).
Nun mal zum Quelltext.
1) dein 1/100 Sekundentimer wird nicht genau laufen. Der Trick mit dem
Rücksetzen per Software funktioniert nur bei einem relativ grossem
Prescaler (8 ist zu wenig) und wenn andere Interrupts nicht aktiv sind
(oder garantiert SEHR kurz sind). Wenn nämlich deine CPU gerade einen
anderen Interrupt abarbeitet und der Timer Overflow eintritt, so braucht
die CPU garantiert mehr als 8 Takte (Prescaler ist 8) um in den Timer
Overflow Interrupt zu springen und den Timer neu zu laden. Hier solltest
du die Methode von Peter Danneger benutzen. Einfach per Output compare
nach jeweils 20000 Takten einen Interrupt generieren und den OCR Wert um
20000 erhöhen. Die OCR Funktion der IO Pins braucht man dazu nicht.
LINK Die genaue Sekunde.
2) Hier sind zwei Fehler
>/********************************************************************/> //Zeit des n-ten Laeufers stoppen\\>/********************************************************************/>void MessungLaeufer(void)>{> //TCCR0=0x03;> if(n< max_laeufer) {
n wird im ganzen Programm NIE beschrieben. Fehler beim Aufräumen?
Ausserdem ist der Vergleich auf <= FALSCH! Damit schreibts du die letzte
Zeite ausserhalb deines Arrays! Sollte es vielleicht heissen
if(laeuferNR< max_laeufer) {
> zeitarray[laeuferNR]=zeit;> laeuferNR++;}> else if((n>max_laeufer) && !letzter)> {> zeitarray[laeuferNR]=zeit;> letzter=1;
Das würde ich anders machen. So
if (n==max_laeufer) letzter=1;
3.)
>/********************************************************************/> //Messfunktion die durch INT0 und INT1 aufgerufen wird\\ >>/********************************************************************/>void Messfunktion()>{> // External Interrupt(s) initialization> // INT0: On> // INT0 Mode: Falling Edge> // INT1: Off> GICR|=0x40;> MCUCR=0x02;> GIFR=0x40;
Vorsicht. Man muss! erst die Flags löschen und dann erst den Interrupt
freigeben, andersherum hat es keinen Sinn! Also
GIFR=0x40;
GICR|=0x40;
MCUCR=0x02;
Das Löschen der Flags ist ein Vorsichtsmassnahme um das Interruptflag zu
löschen, welches durch eventuell eingetroffene Flanken gesetzt wurde.
> SetCursLCD(17); //Cursor an 17. Stelle des LCD's setzen> sprintf(text,"Warte auf Läufer");> LCD_putsA(0,text,2);> while (1)> {
Ist das richtig so? Damit kommst du nie mehr in dein Menu zurück?
> if(Messung_running && !Back)> {> if(laeuferNR<1)> { time_convert(zeit,1);> sprintf(text,"Warte auf Läufer");> delay(173);> LCD_putsA(0,text,2);> }> else if((laeuferNR >= 1) && (laeuferNR < max_laeufer))
Die zweite Bedingung ist überflüssig, sie ist immer wahr (muss immer
wahr sein!).
> { time_convert(zeit,1);> delay(173);> time_convert(zeitarray[(laeuferNR-1)],2);> }> }> else if((Back && Enter))> {> sprintf(text,"Wirlich beenden?");> sprintf(text1,"Back=N | Enter=J");> LCD_putsA(text,text1,0);> delay(globalTime);> if(Back)> {;}> else if(Enter)> {> // External Interrupt(s) initialization> // INT0: Off> // INT1: Off> MCUCR=0x00;> Messung_ready=0;> Menue(ViewTimes);
AUA!!!! Hier knallts! Du hast diese Routine in der Funktion Menue
aufgerufen, im Menuepunkt Messung. Du musst rekursiv zurückgehen! Was du
hier machst ist ein Kauderwelsch (Spaghetticode) das zu einem
Stackoverflow führt!
> }> }>> else if(laeuferNR >= max_laeufer)> {> Messung_ready=0;> // External Interrupt(s) initialization> // INT0: Off> // INT1: Off> MCUCR=0x00;
Das kannst du lassen. Schalte nur die Enables im GICR, das reicht!
> sprintf(text,"Zu viele Läufer!");> sprintf(text1,"Messung beendet");> LCD_putsA(text,text1,0);> delay(globalTime);> Menue(viewTimes);
Das gleiche hier! Stackoverflow!
> }> }>}>/********************************************************************/
OK, noch ein paar allgemeine Anmerkungen zum Programmieren.
Erstmal zum Thema Kommentare/saubere Formatierung. Es ist ein immer
wiederkehrender Irrtum zu glauben, dass man Zeit spart, wenn man ein
Programm nicht sofort sauber formatiert und kommentiert. In dem Moment
wo du den Code schreibst bist du am besten damit vertraut. Diese
temporäre Wissen musst du mit sinnvollen Kommentaren festhalten.
Der schnellste Weg eine Aufgabe zu lösen ist, es gleich ordentlich zu
machen!
Globale Variablen sollten sparsam verwendet werden. Wenn Variablen
zwischen Interrupts und normalen Funktion ausgetauscht werden, müssen
diese als volatile deklariert werden.
Vorsicht vor Arrayüberläufen! Arrays haben den Index
0..Anzahl_Elemente-1!
Enums und Funktionen gleich zu nennen und nur durch
Gross/Kleinschreibung eine Unterscheidung zu ermöglichen ist schlecht.
Funktionen, Enums etc. müssen sinnvolle, am besten hierarchische Namen
bekommen. Z.B. en_irgendwas für Enums, lcd_irgendwas für LCD
Zugriffsfunktionenen etc.
Deine Formatierung ist schon wesentlich besser. Aber die Struktur der
einzelnen verschachteleten IFs etc. kommt bisweilen noch nicht zum
Ausdruck. Z.B. so.
//***********Drucken***********\\
case Drucken:
if (!runLCD) {
LCD_puts(M1[lang][12], M1[lang][2]);
runLCD=1;
}
else
if (Rechts) {
delay(GlobalDelay);
Zustand = Loeschen;
runLCD=0;
}
else
if (Links) {
delay(GlobalDelay);
Zustand = Messen;
runLCD=0;
}
else
if (Enter) {
delay(GlobalDelay);
drucken(); //Drucken
LCD_puts(M1[lang][12], M1[lang][2]);
delay(globalTime);
runLCD=0;
}
break;
OK, ich hab mal alle Dinge die ich als Fehler erkannt habe in deinem
Code geändert, sind alle mit dem Kommentar Falk gekennzeichnet. Siehe
Anhang. Ich bin gespannt ob es jetzt läuft!
MfG
Falk
P.S. Die 16 MHz CPU Takt sind aber ein KLEIN wenig überdimensioniert.
Das Ganze würde mit 1 MHz problemlos laufen und die CPU würde noch zu
95% Däumchen drehen. ;-)
P.P.S. Naja, ganz so schlimm wie ich befürchtet hatte ist dein Programm
nicht. ;-)
Falk wrote:
> Deine Formatierung ist schon wesentlich besser. Aber die Struktur der> einzelnen verschachteleten IFs etc. kommt bisweilen noch nicht zum> Ausdruck. Z.B. so.>> //***********Drucken***********\\> case Drucken:> if (!runLCD) {> LCD_puts(M1[lang][12], M1[lang][2]);> runLCD=1;> }> else> if (Rechts) {> delay(GlobalDelay);> Zustand = Loeschen;> runLCD=0;> }> else> if (Links) {> delay(GlobalDelay);> Zustand = Messen;> runLCD=0;> }> else> if (Enter) {> delay(GlobalDelay);> drucken(); //Drucken> LCD_puts(M1[lang][12], M1[lang][2]);> delay(globalTime);> runLCD=0;> }> break;
Das würde ich so nicht unterschreiben.
Seine ursprüngliche if - else if Formatierung in diesem Bereich
war schon ok und ist durchaus vernünftig
if (!runLCD) {
LCD_puts(M1[lang][12], M1[lang][2]);
runLCD=1;
}
else if (Rechts) {
delay(GlobalDelay);
Zustand = Loeschen;
runLCD=0;
}
else if (Links) {
delay(GlobalDelay);
Zustand = Messen;
runLCD=0;
}
else if (Enter) {
delay(GlobalDelay);
drucken(); //Drucken
LCD_puts(M1[lang][12], M1[lang][2]);
delay(globalTime);
runLCD=0;
}
break;
So kommt besser zum Ausdruck, dass nur eine der 4 Möglichkeiten
zum Zug kommt und dass diese 4 Möglichkeiten alle auf einer
Stufe stehen. Es gibt keinen Grund hier die Einrücktiefe künstlich
in die Höhe zu treiben.
Was man aber machen könnte, ist nach gleichen Teilen in all
den Fällen zu suchen und die raus zu ziehen:
if (!runLCD) {
LCD_puts(M1[lang][12], M1[lang][2]);
runLCD=1;
}
else {
delay(GlobalDelay);
if (Rechts) {
Zustand = Loeschen;
}
else if (Links) {
Zustand = Messen;
}
else if (Enter) {
drucken(); //Drucken
LCD_puts(M1[lang][12], M1[lang][2]);
delay(globalTime);
}
runLCD=0;
}
Aber um ehrlich zu sein: Ich bin mit dem ganzen Menüaufbau
nicht wirklich glücklich. Das ist mir zuviel Code, der auch
noch schlecht zu warten ist. Da sollte man sich überlegen
mehr 'Intelligenz' in ein paar Menütabellen zu stecken,
die die Verknüpfung der Menüpunkte untereinander beschreiben.
@ Karl heinz Buchegger
>So kommt besser zum Ausdruck, dass nur eine der 4 Möglichkeiten>zum Zug kommt und dass diese 4 Möglichkeiten alle auf einer>Stufe stehen. Es gibt keinen Grund hier die Einrücktiefe künstlich>in die Höhe zu treiben.
Aber die IFs sind doch verschachtelt, über jeweiligen else Zweig.
Zeichne mal ein Struktogramm. Auch wenn letztendlich nichts anderes
übrig bleibt. Gleichberechtige Zweig sind bei mir in einem Switch.
Ausserdem kann man sich bei den else auch ins Knie schiessen, das alte C
Problem (Einzelanweiung oder Block). Dem kann man mit meiner Struktur
IMHO entgegen wirken.
>Aber um ehrlich zu sein: Ich bin mit dem ganzen Menüaufbau>nicht wirklich glücklich. Das ist mir zuviel Code, der auch>noch schlecht zu warten ist. Da sollte man sich überlegen
Jaja, sicher richtig, für den Moment aber erstmal OK. Sie dicken Bugs
müssen raus und es muss stabil laufen. Dann kann man über Kosmetik,
Schöngeist und Profilösungen reden.
MfG
Falk
Falk wrote:
> @ Karl heinz Buchegger>>>So kommt besser zum Ausdruck, dass nur eine der 4 Möglichkeiten>>zum Zug kommt und dass diese 4 Möglichkeiten alle auf einer>>Stufe stehen. Es gibt keinen Grund hier die Einrücktiefe künstlich>>in die Höhe zu treiben.>> Aber die IFs sind doch verschachtelt, über jeweiligen else Zweig.> Zeichne mal ein Struktogramm.
das macht nichts.
if
else if
else if
else
ist ein absolut übliches Idiom
> Auch wenn letztendlich nichts anderes> übrig bleibt. Gleichberechtige Zweig sind bei mir in einem Switch.
Das sind logisch gleichberechtigte Zweige!
In C hat man sich dafür eigene Schlüsselwörter erspart weil
es mit den vorhendenen einwandfrei abbildbar ist.
> Ausserdem kann man sich bei den else auch ins Knie schiessen, das alte C> Problem (Einzelanweiung oder Block).
Du meinst Pascal.
In C gibt es das dangling-else Problem in der Form nicht. In C
gehört jedes else immer zum letzten if, welches noch kein else
hat. Du konstruierst in der if - else if - else Leiter ein
Problem, das nicht existiert.
Falk wrote:
>>Aber um ehrlich zu sein: Ich bin mit dem ganzen Menüaufbau>>nicht wirklich glücklich. Das ist mir zuviel Code, der auch>>noch schlecht zu warten ist. Da sollte man sich überlegen>> Jaja, sicher richtig, für den Moment aber erstmal OK.
Da hast du sicherlich recht.
Ich werde mal was aufsetzen um ihm zu zeigen wie man
das einfacher lösen kann. Da fällt dann plötzlich 50%
vom Code weg :-)
Aber zuerst muss ich durch seine Menüstruktur durchsteigen.
@ Karl heinz Buchegger
>Du meinst Pascal.>In C gibt es das dangling-else Problem in der Form nicht. In C>gehört jedes else immer zum letzten if, welches noch kein else>hat. Du konstruierst in der if - else if - else Leiter ein>Problem, das nicht existiert.
Ich mein sowas
if (hallo)
tu_was();
else
tu_was_anderes();
mach_noch_mehr();
Das mach_noch_mehr() gehört nicht mehr zum else Zweig und wird immer
ausgeführt. Böse Falle IMHO.
MfG
Falk
Falk wrote:
> @ Karl heinz Buchegger>>>Du meinst Pascal.>>In C gibt es das dangling-else Problem in der Form nicht. In C>>gehört jedes else immer zum letzten if, welches noch kein else>>hat. Du konstruierst in der if - else if - else Leiter ein>>Problem, das nicht existiert.>> Ich mein sowas>> if (hallo)> tu_was();> else> tu_was_anderes();> mach_noch_mehr();>> Das mach_noch_mehr() gehört nicht mehr zum else Zweig und wird immer> ausgeführt. Böse Falle IMHO.
Ich versteh nicht.
Was hat das mit
if
else if
else if
else
zu tun?
Wenn in einem Zweig mehr als 1 Anweisung kommt, muessen die
Anweisungen in einen Block. Ja klar. Das ist aber immer so
und hat nichts mt Einrückungen bei if-else if-else zu tun.
if( A )
mach_was;
else if( B ) {
mach_was_anderes;
und das bitte auch noch;
}
else {
und jetzt mach was völlig anderes;
und das auch noch;
}
Geht nach derselben Regel:
Ist es nur 1 Anweisung - kein { } Block nötig
Sind es mehrere Anweisungen - in einem { } Block rein.
Ist völlig analog zum einfachen if - else Fall
@Patrick
Ich hab mal das Menüsystem überarbeitet. Wenn du noch Zeit
hast, kannst du dir das ja mal zu Gemüte führen. Ich hab
das Programm soweit abgespeckt, dass es sich nur um das
Menü kümmert und hab alles andere rausgeschmissen.
Im wesentlichen ist übrig geblieben:
Eine Struktur in der 1 Menüeintrag definiert wird.
Ein Menüeintrag besteht aus einem Verweis in die Texte,
sowie aus den Angaben für die Folgezustände wenn
Links/Rechts/Enter/Back gedrückt wird.
Bei Enter gibt es noch eine Spezialität: man kann eine Funktion
angeben, die aufgerufen wird, wenn an diesem Menüpunkt
Enter gedrückt wird.
Damit sieht die komplette Funktion, die das Menü behandelt
so aus:
Eigentlich sehr einfach.
Wenn eine Taste gedrückt wird, so wird in der Tabelle im
aktuellen Zustand nachgesehen, welcher neue Zustand sich
dadurch ergibt. Nur bei Enter gibt es einen Sonderfall:
Ist im Menü eine Funktion angegeben, so wird diese ausgeführt.
Die Tabelle, die das Menü komplett beschreibt (zumindest den
Teil, den ich aus deinem Code rekonstruieren konnte), sieht
so aus:
1
enumtZustand{
2
zOptionen,zMessen,zDrucken,zLoschen,zViewTimes,// Die Zustände im Hauptmenü
3
zSprache,zFormat,zAmbiLight,// Die Zustände im Optionen Submenu
Für neue Menüeinträge braucht man nur mehr die entsprechenden
Einträge in dieser Tabelle machen. Source Code mäßig ist
sonst nichts zu ändern.
Wie gesagt: Das ist eine gröbere Änderung in deinem Code.
Mach sie also erst wenn du praktisch fertig bist und noch
aufräumen willst.
Ein paar Kleinigkeiten hab ich dann noch gemacht. So ist
es ziemlich mühsam, wenn man bei der Textdefinition selbst
führende Leerzeichen einsetzen muss, damit der Text zentriert
wird. Das kann das Programm auch selbst berechnen und bevor
es den Text ausgibt eine entsprechende Anzahl Leerzeichen
davor setzen. Spart auch Speicher, weil ja die Texte kürzer
werden :-)
Ach ja, noch was:
Ich hab auch einen enum definiert:
1
enumtLanguage{
2
lGerman,
3
lEnglish
4
};
Die entsprechende Sprachvariable wird dann so definiert:
1
enumtLanguageLanguage;
Wozu das ganze?
Nun. Jetzt kann ich im Programm schreiben:
1
Language=tGerman;
das ist im Grunde völlig gleichwertig deinem
1
lang=0;// Sprache auf Deutsch stellen
nur mit dem Unterschied, dass ich keinen Kommentar brauche
(der daher auch nicht falsch sein kann). In meiner Version
ist der Programmtext sein eigener Kommentar. Die Kunst
des Kommentierens besteht darin es nicht tun zu muessen.
Dazu muss das Programm selbsterklärend sein. Eine Anweisung
wie
1
Language=lEnglish;
ist selbsterklärend. Das ist im Grunde nur eine etwas kürzere
Schreibweise von "// Sprache auf Englisch einstellen". Da aber
alles im Programmtext gesagt wird, was es dazu zu sagen gibt,
ist auch kein Kommentar mehr nötig (den du in deiner version
hauptsächlich nur deshalb brauchst, weil du nach 2 Stunden
nicht mehr weist ob 0 jetzt Englisch oder Deutsch war).
Hey Leute!
Also Falk und Karl Heinz, VIELEN DANK an euch beide! Echt stark, dass
ihr euch die Mühe gemacht habt, mir zu helfen! Von eurer "Sorte" sollte
es viel mehr Leute geben!
Muss jetzt zum Artz, werde aber danach das Programm testen und gleich
das Ergebnis posten...
lg Patrick
PS: Nochmal vielen Dank!!!
@ Patrick F.
>Muss jetzt zum Artz, werde aber danach das Programm testen und gleich>das Ergebnis posten...
Mach aber einen Schritt nach dem anderen. Teste erst mein Programm,
wenns läuft kannst du das Menü von Karl Heinz einbauen.
MFG
Falk
Falk Brunner wrote:
> @ Patrick F.>>>Muss jetzt zum Artz, werde aber danach das Programm testen und gleich>>das Ergebnis posten...>> Mach aber einen Schritt nach dem anderen. Teste erst mein Programm,> wenns läuft kannst du das Menü von Karl Heinz einbauen.>
Und nochmal die Warnung:
Das ist ein gröberer Umbau!
Sichere auf jeden Fall dein Projekt, bevor du da loslegst.
Du wirst den Code nicht 1:1 übernehmen können, da ich für
den gcc-Compiler geschrieben habe. Es geht ums Prinizip wie
man Menues machen kann, ohne dass das gleich in eine Code-Orgie
ausartet.
Auch müssten die Tabellen ins Flash ausgelagert werden.
Aber dazu hatte ich in der Nacht nicht mehr die Geduld.
Karl heinz Buchegger wrote:
> Falk Brunner wrote:>> @ Patrick F.>>>>>Muss jetzt zum Artz, werde aber danach das Programm testen und gleich>>>das Ergebnis posten...>>>> Mach aber einen Schritt nach dem anderen. Teste erst mein Programm,>> wenns läuft kannst du das Menü von Karl Heinz einbauen.>>>> Und nochmal die Warnung:> Das ist ein gröberer Umbau!> Sichere auf jeden Fall dein Projekt, bevor du da loslegst.> Du wirst den Code nicht 1:1 übernehmen können, da ich für> den gcc-Compiler geschrieben habe. Es geht ums Prinizip wie> man Menues machen kann, ohne dass das gleich in eine Code-Orgie> ausartet.> Auch müssten die Tabellen ins Flash ausgelagert werden.> Aber dazu hatte ich in der Nacht nicht mehr die Geduld.
@Karl heinz Buchegger
Den Menüumbau werd ich noch etwas ruhen lassen...
Am wichtigsten ist mir ja zur Zeit mal die Funktion...
Dazu gleich ein Problem: Nachdem die Messung gestartet wurde, werden
keine Zeiten mehr genommen...
@Falk:
Das mit der "Englischen" Menüfühurung war eine "HuschPfusch"
Geschichte... =o) Es war nicht wirklich geplant, die Sprache auswählen
zu können --> hab mir aber gedacht, dass es manchmal vl. nicht schaden
kann...
@All:
Könnt ihr mir ein Buch über die "Hardwarenahe" C-Programmierung
empfehlen?
Hab gemerkt, dass es mir sogar an den Grundkenntnissen stark mangelt...
lg Patrick
> Dazu gleich ein Problem: Nachdem die Messung gestartet wurde, werden> keine Zeiten mehr genommen --> INT1 reagiert nicht...
Ich würde dieses Problem mal in ein eigens Testprogram
isolieren und das getrennt von allen anderen behandlen.
Erst wenn du sicher bist, verstanden zu haben wie die Hardware
umkonfiguriert werden muss würde ich das dann am
eigentlichem Programm anwenden.
Testprogramm: irgendwas einfaches ala der eine
Interrupt schaltet eine LED ein, der andere wieder
aus
Deine Art und Weise wie du misst ist etwas ... na ja
unübersichtlich. Ich hatte bis jetzt nicht den Nerv
das genauer zu analysieren, was da in der Messfunktion
wirklich abgeht. Zudem kommt, dass solche Zuweisungen an
Konfigurationsregister
MUCRC = 0x40;
nicht gerade aussagekräftig sind, welches Bit denn da gesetzt
wird. Das solltest du mal aufdröseln.
@ Patrick
Soo, hier die neue Version mit einigen Änderungen. Ich hoffe es läuft
jetzt.
Kannst du das Programm simulieren?
Noch ein paar Anmerkungen. Du benutzt sehr oft sprintf um einfach einen
String zu kopieren. Das ist unnötig und verbraucht recht viel
Programmspeicher (Die Funktion sprintf ist relativ gross). du könntest
doch gleich denZeiger auf die Texte deiner LCD Ausgaberoutine übergeben.
Ebenso ist die Verwendung von sprintf zur Ausgabe von Dezimalzahlen
Overkill, ein itoa() ist kleiner und schneller.
Deine Tastenauswertung ist, naja, ausbaufähig. Du prüfst ob eine Taste
gedrückt ist, sinnvollerweise musst du aber den Übergang von nicht
gedrückt auf gedrückt detektieren und auswerten. Denn sonst rennt dir
dein Programm mit maximler Geschwindigkeit durch die Menüs. Das wird bei
dir im Moment nur durch die (bösen) Delays verhindert.
MfG
Falk
Falk Brunner wrote:
> @ Patrick>> Soo, hier die neue Version mit einigen Änderungen. Ich hoffe es läuft> jetzt.> Kannst du das Programm simulieren?
Simulieren nicht, aber direkt an der Hardware Testen... An meinen INT
eingänge habe ich jetzt mal zu testzwecken Taster angebracht - auf der
Eingangsseite der Optokoppler...
Hab jetzt den neuen Quelltext rübergeladen --> funktioniert nicht...
Die Messung startet jetzt nicht mal...
Bin gerade dabei, die Messfunktion neu zu erstellen - mit einer
Statemachine erstmal alles strukturieren und diesesmal erst dann
programmieren...
> Noch ein paar Anmerkungen. Du benutzt sehr oft sprintf um einfach einen> String zu kopieren. Das ist unnötig und verbraucht recht viel> Programmspeicher (Die Funktion sprintf ist relativ gross). du könntest> doch gleich denZeiger auf die Texte deiner LCD Ausgaberoutine übergeben.> Ebenso ist die Verwendung von sprintf zur Ausgabe von Dezimalzahlen> Overkill, ein itoa() ist kleiner und schneller.
itoa() kenn ich nicht... Werd aber gleich mal googlen und versuchen
deine Tipps zu übernehmen...
> Deine Tastenauswertung ist, naja, ausbaufähig.
Ist mir bekannt... Da wir aber in der Schule lediglich diese Methode zum
"Entprellen" kennengelernt haben, verwende ich eben diese...
> Du prüfst ob eine Taste> gedrückt ist, sinnvollerweise musst du aber den Übergang von nicht> gedrückt auf gedrückt detektieren und auswerten. Denn sonst rennt dir> dein Programm mit maximler Geschwindigkeit durch die Menüs. Das wird bei> dir im Moment nur durch die (bösen) Delays verhindert.
Hab leider (wie schon oben erwähnt) keine Ahnung wie ich das
bewerkstelligen kann/soll...
lg Patrick
EDIT:
Wie kann ich hier das spritf ersetzten? itoa wandelet mir doch nur z.B.
die integer Variable Stunden in einen (nichtformatierten) String um,
oder?
@ Patrick F.
>Hab jetzt den neuen Quelltext rübergeladen --> funktioniert nicht...>Die Messung startet jetzt nicht mal...
Woran erkennst du das?
MFg
Falk
Falk Brunner wrote:
> @ Patrick F.>>>Hab jetzt den neuen Quelltext rübergeladen --> funktioniert nicht...>>Die Messung startet jetzt nicht mal...>> Woran erkennst du das?>> MFg> Falk
Sobald ich meinen (mit hardware-entprellten) Taster betätige, startete
bisher immer die Zeitnehmung und wurde mir am Display angezeigt...
Jetzt startet aber keine Zeitnehmung, zumindest sehe ich nichts davon...
>Taster am Interrupt ist nicht gut, Taster prellen und lassen Dein>Programm Amok laufen.
ich verwende hierzu HARDWARE-ENTPRELLTE Taster... ;-)