mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interrupt- und Speicherproblem mit Mega8


Autor: Patrick (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: tastendrücker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rein aus Interesse: In welchem Bereich soll die Stoppuhr eingesetzt 
werden?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Versuchs mal mit dem ATMega168. Ist soweit pinkompatibel mit dem
Atmega8 und hat 16k Speicher.

Wie versucht du den Interrupt abzuschalten?

MfG Spess

Autor: ecslowhand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mehr Flash ??? Nimm einen MEGA168, der hat 16k. Immerhin das doppelte. 
Zudem ist der PIN-kompatibel, jedoch NICHT(!) CODE-kompatibel.

Autor: ecslowhand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieder einer schneller.....Mist

Autor: Patrick (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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).

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieder Einer, der meint, das Benutzen einer Hochsprache erspart den 
Blick ins Datenblatt des Controllers (wie funktionieren Interrupts im 
Detail)...

;-)

...

Autor: Pat F. (breaker87)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

...

Autor: tastendrücker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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?

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Überholverbot??

;-)

...

Autor: Pat F. (breaker87)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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

...

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Pat F. (breaker87)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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.

Autor: Pat F. (breaker87)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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



Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

...

Autor: Pat F. (breaker87)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Pat F. (breaker87)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Pat F. (breaker87)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
UP

Autor: Ronny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ;)

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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


Autor: Falk (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@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. ;-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.


Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.


Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@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:
void handleMenue()
{
  enum tZustand AlterZustand = 99;
   
  while(1)
  {
    if( Zustand != AlterZustand ) {
      LCD_puts( M1[Language][Menues[Zustand].TextNr], M1[Language][2]);
      AlterZustand = Zustand;
    }

    if( Links ) {
      Zustand = Menues[Zustand].beiLinks;
      delay( globalDelay );
    }

    else if( Rechts ) {
      Zustand = Menues[Zustand].beiRechts;
      delay( globalDelay );
    }

    else if( Back ) {
      Zustand = Menues[Zustand].beiBack;
      delay( globalDelay );
    }

    else if( Enter ) {
      if( Menues[Zustand].Call != NULL ) {
        Menues[Zustand].Call();
      }
      Zustand = Menues[Zustand].beiEnter;
      delay( globalDelay );
    }
  }
}

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:
enum tZustand {
    zOptionen, zMessen, zDrucken, zLoschen, zViewTimes,     // Die Zustände im Hauptmenü
    zSprache, zFormat, zAmbiLight,                        // Die Zustände im Optionen Submenu
    zDeutsch, zEnglisch,                                 // Optionen - Sprache
    zAbsolut, zDifferenz,                                // Optionen - Format
    zAmbiOn, zAmbiOff,                                   // Optionen - AmbiLight
    zMessung,                                           // Die Zustände im Messen Submenu
    zFrageLoschen                                       // Die Zustände im Lööschen Submenu
 
};

/********************************************************************/

typedef void(*Funktion)(void);

struct MenuEntry {
  uint8_t       TextNr;
  enum tZustand beiLinks;
  enum tZustand beiRechts;
  enum tZustand beiBack;
  enum tZustand beiEnter;
  Funktion      Call;
};

struct MenuEntry Menues[] = {

    // Nr des Textes    Neuer Zustand  Neuer Zustand  Neuer Zustand  Neuer Zustand   Funktion die
    //                  Links gedr.    Rechts gedr.   Back gedr.     Enter gedr.     bei Enter
    //                                                                               aufgerufen wird
    {        3,         zViewTimes,    zMessen,       zOptionen,     zSprache,        NULL },             // Optionen
    {       10,         zOptionen,     zDrucken,      zOptionen,     zMessung,        messungReadyOne },  // Messen
    {       12,         zMessen,       zLoschen,      zOptionen,     zDrucken,        drucken },          // Drucken
    {       14,         zDrucken,      zViewTimes,    zOptionen,     zFrageLoschen,   NULL },             // Löschen
    {       25,         zLoschen,      zOptionen,     zOptionen,     zViewTimes,      viewTimes },        // View Times

    {        4,         zAmbiLight,    zFormat,       zOptionen,     zDeutsch,        NULL },             // Sprache
    {        7,         zSprache,      zAmbiLight,    zOptionen,     zAbsolut,        NULL },             // Format
    {       29,         zFormat,       zSprache,      zOptionen,     zAmbiOn,         NULL },             // AmbiLight


    {        5,         zEnglisch,     zEnglisch,     zSprache,      zSprache,        toGerman },         // Deutsch
    {        6,         zDeutsch,      zDeutsch,      zSprache,      zSprache,        toEnglish },        // Englisch

    {        8,         zDifferenz,    zDifferenz,    zFormat,       zFormat,         formatAbsolut },    // Absolut
    {        9,         zAbsolut,      zAbsolut,      zFormat,       zFormat,         formatDifferenz },  // Differenz

    {       23,         zAmbiOff,      zAmbiOff,      zAmbiLight,    zAmbiLight,      ambiOn },           // AmbiLight On 
    {       24,         zAmbiOn,       zAmbiOn,       zAmbiLight,    zAmbiLight,      ambiOff },          // AMbiLight Off

    {       18,         zMessung,      zMessung,      zMessen,       zMessen,         messungReadyZero }, // Messung

    {       15,         zFrageLoschen, zFrageLoschen, zLoschen,      zLoschen,        loschen },          // Löschen
};

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:
enum tLanguage {
  lGerman,
  lEnglish
};
Die entsprechende Sprachvariable wird dann so definiert:
enum tLanguage  Language;


Wozu das ganze?
Nun. Jetzt kann ich im Programm schreiben:
  Language = tGerman;
das ist im Grunde völlig gleichwertig deinem
  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
   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).

Autor: Pat F. (breaker87)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!!!

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Pat F. (breaker87)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Falk Brunner (falk)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Pat F. (breaker87)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?
     hundertstelR =  hundertstel % 100; //hundertstel
     sekunden  = hundertstel / 100; //ganze sekunden
     sekundenR = sekunden % 60; //sekunden
     minuten   = sekunden / 60; //ganze minuten
     minutenR  = minuten % 60; //minuten
     stunden   = minuten / 60; //ganze Stunden
     
     sprintf(uebergabe_zeit, " %02d:%02d:%02d,%02d ",stunden,minutenR,sekundenR,hundertstelR);

Genauso hier:
      sprintf(time2, "%i.", laeuferNR);
      strcat(time2, uebergabe_zeit);

Wie schaffe ich es sonst, die Läufernummer einzubauen?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Patrick F.

>Hab jetzt den neuen Quelltext rübergeladen --> funktioniert nicht...
>Die Messung startet jetzt nicht mal...

Woran erkennst du das?

MFg
Falk

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Taster am Interrupt ist nicht gut, Taster prellen und lassen Dein 
Programm Amok laufen.

...

Autor: Pat F. (breaker87)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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... ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.