Forum: Mikrocontroller und Digitale Elektronik Tacho und Kilometer


von Peter R. (fraeggle)


Angehängte Dateien:

Lesenswert?

Hallo Leute
Ich habe versucht einen Tacho mit Kilometerzähler zu bauen.
Als Prozessor kommt ein 8515 mit 2*16 LCD zum Einsatz. Über Tasten wird 
der Umfang der Reifen eingegeben und Trip kann zurückgesetzt werden. Die 
aktuellen Daten werden bei Power off gespeichert. Ich habe noch einen 
kleinen Fehler drin, den ich aber nicht herausbekomme. Vielleicht hat 
jemand einen Rat?? Je höher die Geschwindigkeit, desto mehr "springt" 
die Anzeige.
(z.B. zwischen 118 und 122 km/h). Versuche auch ein DOGS 102*64. Klappt 
aber noch nicht. (Naja fange auch erst mit Mikroproz an....)

: Verschoben durch User
von Uwe (de0508)


Lesenswert?

In welchem C Dialekt ist das geschrieben ?

Ich sehe LCD Ausgaben und Berechnungen in den ISR, sowie ein 
delay_ms(1000);. Jedes delay blockiert dein Programm in seiner 
Ausführung und es kann nicht mehr auf ext. Ereignisse reagieren.

Vom Systemher würde ich alle ISR so kurz als möglich machen und per 
Event Flag (1Bit) dem Hauptprogramm (main) das Ereignis mitteilen.

Dann kann man dort in aller Ruhe reagieren.

In der Main kann über eine Zustandsmachine, der serieller Prozess 
abgebildet werden, ohne dass man auf ext. Ereignisse Interrupt 
verzichtet und dass man überhaupt noch ein delay in der main() benötigt 
!

TASTER müssen entprellt werden, sonst erzeugen sie dir viele Interrupts 
bei schließen und öffnen des Selben.

_

von Uwe (de0508)


Lesenswert?

Hallo,

solche Berechnungen müssen gecastet werden
1
speed=((circ/PULSE_TURN)*SPEED_MULTIPLIER)/((count);

Und hier meckert dein Compiler nicht ?

Zähle mal die Klammern !

von Peter R. (fraeggle)


Angehängte Dateien:

Lesenswert?

Hi Uwe Sorry war noch die ältere ( zuviel Klammern). Erstellt wurde das 
mit Codevision. Die LCD Ausgabe und der Delay beim INT1 habe ich 
deswegen so gemacht, weil dies eh nur im Stand und beim Ausschalten der 
Zündung vorkommen sollte. Das mit den Tasten hast du Recht, wobei ich 
Trip und DIAMETER Key ja deswegen auf 500 ms bzw 1000ms gedrückt halten 
gemacht habe, um ein versehentliche drücken zu unterdrücken. Deine Info 
mit übergeben der Parameter und rechnen im Main muss ich mal sehen, wie 
ich das umsetzte.
Bin halt Anfänger..... :-)) Danke Dir auf alle Fälle für die Infos.
Gruss Peter

von Peter R. (fraeggle)


Lesenswert?

Mir fällt auch gerade auf, das ich dies eigentlich bei Codesammlung 
posten wollte. Ich glaub dann schliessen wir das hier und ich mach einen 
Neuen im Bereich Codesammlung auf.... Vielleicht kann ein Admin den auch 
verschieben ? :-))

von Uwe (de0508)


Lesenswert?

Sollt dann der Code nicht fehlerfrei sein?
Ich kann ihn zumindest nicht übersetzen.

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Peter R. schrieb:
> Mir fällt auch gerade auf, das ich dies eigentlich bei Codesammlung
> posten wollte.

Ist denn das was du da postest, FERTIGER code, von den andere Nutzen 
ziehen könnten? Dann ist er bei "Codesammlung" gut aufgehoben. 
Code-Leichen, und Codesegmente, welche mal funktionierender Code werden 
wollen, haben in der Codesammlung nichts verloren.

> Ich glaub dann schliessen wir das hier und ich mach einen
> Neuen im Bereich Codesammlung auf....

Welchen Sinn und nutzen sollte es machen, hier einen Thread zuzumachen, 
um dort einen identischen Tread aufzumachen? Außer den geneigten Leser 
mit auseinander driftenden Threads zu nerven oder zu verwirren, fällt 
mir kein weiterer Zweck ein, den Thread nochmal neu irgendwo aufzumachen

> Vielleicht kann ein Admin den auch verschieben ? :-))


Ja, nämlich dann wenn es funktionsfähiger "vorführbarer" Code ist (siehe 
oben). Ok, nach offtopic oder /dev/nulll kann auch nicht 
funktionsfähiger Code rein ;-)

von Uwe (de0508)


Lesenswert?

Hallo,

mindestens ein Problem wurde nicht gelösst.

Hier wird mit 8Bit gerechnet und warum dann der cast ?
speed ist doch 32 Bit groß.
1
speed=(unsigned int) ((circ/PULSE_TURN)*SPEED_MULTIPLIER)/count;

Wie verhalten sich Variable, wenn Sie per ISR verändert werden und in 
anderen Programmteilen auch angefasst werden?
Unter avr gcc gibt es "volatile" zur Beschreibung dieses Sachverhaltes.

von Karl H. (kbuchegg)


Lesenswert?

Uwe S. schrieb:
> Hallo,
>
> mindestens ein Problem wurde nicht gelösst.
>
> Hier wird mit 8Bit gerechnet

Es wird schon 16 Bit gerechnet. Das ist erst mal bis zum Beweis des 
Gegenteils kein Problem.

   (circ/PULSE_TURN)*SPEED_MULTIPLIER
.. ist natürlich eine Rechenreihenfolge, die durch die vorgezogene 
Division dazu prädestiniert ist, Genauigkeit zu verschenken.

   23 / 5 * 8

ergibt nun mal 32, wohingegen

  23 * 8 / 5

eine 36 ergibt. Das exakte Ergebnis wäre 36.8

Ich würde mir auch mal den 'count' ausgeben lassen um zu sehen in 
welchem Zahlenbereich sich die ganze Sache hier bewegt. Und dann mal ein 
wenig mit dem Taschenrechner die Berechnungen kontrollieren wobei man 
die speziellen Gegebenheiten der int-Rechnerei ins Kalkül ziehen muss.


> Wie verhalten sich Variable, wenn Sie per ISR verändert werden und in
> anderen Programmteilen auch angefasst werden?
> Unter avr gcc gibt es "volatile" zur Beschreibung dieses Sachverhaltes.

Volatile ist eine Sache. Obwohl ich nicht denke, dass der Compiler hier 
großartig die Zugriffe wegoptimieren kann. Was aber natürlich im Raum 
steht, ist der atomare Zugriff auf speed. (bzw. eben der nicht atomare 
Zugriff)

von hosentraeger (Gast)


Lesenswert?

und ein
1
delay_ms(1000);

in einer Interrupt Routine wuerde ich auch
nicht unbedingt haben wollen...

hosentraeger

von Uwe (de0508)


Lesenswert?

Hallo Karl-Heinz,

wie war das mit der Definition von |circ|:
1
unsigned char circ;
 somit wird die Division als 8 Bit durchgeführt, das Ergebnis ist auch 8 
Bit.

Natürlich stimmt dein Beispiel, und ich ziehe auch erst die 
Multiplikationen vor die Division, solange ich keine Datentyp Überlauf 
erhalten.

_

von Karl H. (kbuchegg)


Lesenswert?

Uwe S. schrieb:
> Hallo Karl-Heinz,
>
> wie war das mit der Definition von |circ|:
1
unsigned char circ;
> somit wird die Division als 8 Bit durchgeführt, das Ergebnis ist auch 8
> Bit.

C Regeln.
Gerechnet wird nicht kleiner als int.

Es sei denn der Compiler kann beweisen, dass sich das Ergebnis nicht 
ändert, wenn er anstelle einer vollständigen int Berechnung nur ein 
8-Bit Anteil berücksichtigt. Bei dem Beweis wird er sich hier aber 
schwer tun.
Und natürlich: Es sei denn der Compiler weicht hier vom C-Standard ab.

Aber selbst dann greifen hier die beiden Begründungen nicht

#define PULSE_TURN  12

   ....  circ/PULSE_TURN


12 ist ein int. Damit wird hier unsigned char durch int dividiert. Und 
damit als int Division ausgeführt. Du musst immer die Datentypen beider 
Operanden berücksichtigen. Auch numerische Konstanten haben einen 
Datentyp.

von Peter R. (fraeggle)


Angehängte Dateien:

Lesenswert?

UUPS so eine folgenschwere Diskusion wollte ich gar nicht auslösen.
Ich habe nochmal mit dem Code experimentiert.
Der jetzige Code funktioniert am besten......... ich habe alle möglichen 
Variationen probiert. Das Dingen zeigt bis etwa 150 Hz ca. 90Km/h ohne 
Probleme an. Aber danach "springt" die Anzeige um ca 3-4 Km/h.
Ich glaube fast, es liegt an der Geschwindigkeit des Timer1.
Die Kilometer als solches werden auf alle Fälle richtig.

hosentraeger schrieb:
> und ein
> delay_ms(1000);
>
> in einer Interrupt Routine wuerde ich auch
> nicht unbedingt haben wollen...
Wenn du nach siehst, ist diese Routine NUR für den Fall von Power Off 
zum "sicheren" Speichern der Daten und nichts anderes. D.H. du stellst 
dein Auto ab und machst es aus.

Karl Heinz Buchegger schrieb:
> Ich würde mir auch mal den 'count' ausgeben lassen um zu sehen in
> welchem Zahlenbereich sich die ganze Sache hier bewegt. Und dann mal ein
> wenig mit dem Taschenrechner die Berechnungen kontrollieren wobei man
> die speziellen Gegebenheiten der int-Rechnerei ins Kalkül ziehen muss.

Hallo Karl-Heinz. Wie gesagt, bin ich Mikro-Proz- und Programier- 
Anfänger.
Wenn du mir einen Tipp geben könntest, wie ich das am besten ausgeben 
lassen kann??
Achso an Uwe:
Geschrieben mithilfe des Codewizzard und Compiliert von/mit Codevision.
Freewareversion. (Ich weiß es gibt besseres aber ich fange erst an. :-)) 
)

Und bitte mich nicht steinigen.

von Uwe (de0508)


Lesenswert?

Hallo Peter,

wir sehen, Du nimmst unsere Anmerkungen ernst und willst etwas lernen.
Das finden wir gut und unterstützen Dich.

von Karl H. (kbuchegg)


Lesenswert?

Peter R. schrieb:

> Wenn du mir einen Tipp geben könntest, wie ich das am besten ausgeben
> lassen kann??

Ähm.
Du hast eine Anzeige, auf der du momentan deine km/h ausgibst.
Da wird sich doch noch ein Eckerl finden, auf dem du den count ausgeben 
lassen kannst.

von Peter R. (fraeggle)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ähm.
> Du hast eine Anzeige, auf der du momentan deine km/h ausgibst.
> Da wird sich doch noch ein Eckerl finden, auf dem du den count ausgeben
> lassen kannst.

Äh wie war das mit dem Wald und den Bäumen. ich werde einfach die untere 
Zeile nehmen und dort vorrübergehend Trip und ODO ersetzen, dann habe 
ich vielleicht auch einen Vergleich zur aktuellen Speed. Wird aber 
wahrscheinlich erst am WE etwas.
Gruss Peter

von Peter R. (fraeggle)


Angehängte Dateien:

Lesenswert?

An Karl-Heinz und Uwe:
Sakrischen Dank für die Denkanstöße.
Es funktioniert einwandfrei. Hab den Timer auf 125kHZ eingestellt und 
(Uwe ich bin lernfähig....) bei dem Interrupt1 soweit möglich alles 
raus.
Hab nach anweisung von Karl-Heinz mal alle "wichtigen" Parameter der 
Reihe nach aufs Display geschrieben und dann mit Rechner und Papier 
weitergemacht.
Was jetzt natürlich toll wäre: Ich hab hier ein 102*64 LCD, aber ich 
hab, zumindest im Moment, keine Peilung wie ich das hier reinkriege. 
Vielleicht kann mich ja jemand freundlicherweise tatkräftig 
unterstützen.


An den Admin:  Nun könntest du das in Codesammlung verschieben :-))

von Karl H. (kbuchegg)


Lesenswert?

Peter R. schrieb:

> Hab nach anweisung von Karl-Heinz mal alle "wichtigen" Parameter der
> Reihe nach aufs Display geschrieben und dann mit Rechner und Papier
> weitergemacht.

Machs nicht so spannend.
Und?
Hat es dich weiter gebracht, wo in deiner Programm-Berechnung der Hund 
sitzt?

> An den Admin:  Nun könntest du das in Codesammlung verschieben :-))

Immer langsam mit den jungen Pferden :-)

von Karl H. (kbuchegg)


Lesenswert?

Das hier

>         timer=overflow*65536+count;

solltest du auf jeden Fall mit einer DEI/SEI Klammerung versehen. 
Während diese Berechnung läuft, darf dir auf keinen Fall ein Interrupt 
dazwischenfunken. Sonst stammen count und overflow nicht mehr aus 
derselben Messung.

von Karl H. (kbuchegg)


Lesenswert?

Das mit dem lcd_clear() ist so eine Sache.

Eigentlich willst du genau das nämlich nicht tun, weil sonst dein 
Display flackert. Wenn immer möglich, willst du eigentlich auf dem LCD 
nur über bestehenden Text drübermalen.

Wenn du aber schon lcd_clear benutzt, dann schieb es so dicht wie 
möglich an die eigentliche Ausgabe ran. Zwischen deinem clear und dem 
tatsächlichem Neubeschreiben hast du Berechnungen, noch dazu in Floating 
Point. Die kosten Zeit. Zeit in der das LCD ... leer ist, ehe es neu 
beschrieben wird. Und das siehst du dann auch als kurzen Flackerer.

Aber eigentlich solltest du dein Schirmbild möglichst statisch machen. 
Es macht nicht viel Sinn, in jedem Durchlauf durch die Hauptschleife zb 
den Text "km/h" wieder neu hinzuschreiben, wenn er ohnehin schon am LCD 
steht (und nur deswegen hingeschrieben werden muss, weil du vorher das 
LCD komplett gelöscht hast)

von Peter R. (fraeggle)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Es macht nicht viel Sinn, in jedem Durchlauf durch die Hauptschleife zb
> den Text "km/h" wieder neu hinzuschreiben

MMhh, wenn ich den LCD_Clear aber rausmache (Nur einmal beim Start), 
habe ich plötzlich (je nach Geschwindigkeit) mehrere Zahlen, da die 
Geschwindikeit ja vorne anfängt und 2 bis (im Moment durch kommastelle) 
4 stellig ist. Deswegen dachte ich ja daran, das Display durch 
dispint>2000 zu "verzögern".

von Karl H. (kbuchegg)


Lesenswert?

Peter R. schrieb:

> MMhh, wenn ich den LCD_Clear aber rausmache (Nur einmal beim Start),
> habe ich plötzlich (je nach Geschwindigkeit) mehrere Zahlen, da die
> Geschwindikeit ja vorne anfängt und 2 bis (im Moment durch kommastelle)
> 4 stellig ist.

Ein Tip:
Es ist der Lestauglichkeit extrem zuträglich, wenn auf einer Anzeige die 
Einerstelle immer an derselben Position auftaucht!

D.h. deine Ausgabe sollte nicht sein

   +---------------------------+
   | Geschwindikeit: 78.5 km/h |

   +---------------------------+
   | Geschwindikeit: 9 km/h    |

sondern die Einzelteile haben fixe Positionen (die Einer sind immer an 
der gleichen Stelle)

   +---------------------------+
   | Geschwindikeit: 78.5 km/h |

   +---------------------------+
   | Geschwindikeit:  9.0 km/h |


Das heißt: es genügt wenn du die nicht benutzten Positionen, an der 
sonst nicht gezeigte führende 0-en stehen, mit Leerzeichen übermalst. Du 
kannst auch den Zahlenbereich als ganzes vor der Ausgabe der Zahl erst 
mal mit Leerzeichen komplett übermalen und so frei bekommen. Aber 
eleganter ist natürlich wenn du nur soviele Leerzeichen vor der Zahl 
ausgibst, dass die Einerstelle wieder an dieselbe Position kommt. Und 
das ist ja bei einem Tacho nicht so schwer. Schneller als 999.9 km/h 
wirst du ja selten fahren. D.h. es kann nur maximal 2 unterdrückte 
führende 0-en geben.


Gerade bei Dingen, auf die man nur kurz draufsehen kann, ist es enorm 
wichtig, dass am LCD dieselben Dinge immer an derselben Position 
auftauchen ohne dass man mit dem AUge lange suchen muss. Wenn deine 
Anzeige bei Zwischenwerten ständig zwischen 9.9 und 10.0 hin und 
herspringt und jedesmal der Dezimalpunkt da links/rechts rutscht, dann 
wird dir dein Benutzer in kurzer Zeit an die Gurgel springen.

von Peter R. (fraeggle)


Lesenswert?

Äusserst überzeugendes Argument.....
Hab auch mal 
http://www.mikrocontroller.net/articles/FAQ#Wie_kann_ich_Zahlen_auf_LCD.2FUART_ausgeben.3F 
angeschaut, aber irgendwie steh ich da auf dem Schlauch. Vielleicht 
brauch ich auch erst mal ein paar Tage....
Oder du könntest mir ein Beispiel geben. Wenn ich es richtig gelesen 
hab, wäre sprint auch nicht gerade die Wahl für mein vorhaben.

von Uwe (de0508)


Lesenswert?

Hallo,

was hilft ist diese Routine von Peter (PeDa):

Beitrag "Formatierte Zahlenausgabe in C"

Hier ist meine angepasste Version:

Beitrag "Re: Variablenwert auf LCD ausgeben"

von Karl H. (kbuchegg)


Lesenswert?

Peter R. schrieb:
> Äusserst überzeugendes Argument.....
> Hab auch mal
> 
http://www.mikrocontroller.net/articles/FAQ#Wie_kann_ich_Zahlen_auf_LCD.2FUART_ausgeben.3F
> angeschaut, aber irgendwie steh ich da auf dem Schlauch. Vielleicht
> brauch ich auch erst mal ein paar Tage....
> Oder du könntest mir ein Beispiel geben. Wenn ich es richtig gelesen
> hab, wäre sprint auch nicht gerade die Wahl für mein vorhaben.

Würd ich so nicht sagen.
Solange du deine Ausgabegeschwindigkeit sowieso drosseln musst (und das 
musst du, denn mehr als 3 bis 5 Updates in der Sekunde kann sowieso kein 
Mensch verarbeiten) UND du den Speicher hast, spricht nichts dagegen 
sprintf zu benutzen. Für nicht verbrauchten Flash kriegst du kein Geld 
zurück.

von Peter R. (fraeggle)


Angehängte Dateien:

Lesenswert?

Karl Heinz Buchegger schrieb:

>
> Würd ich so nicht sagen.
> Solange du deine Ausgabegeschwindigkeit sowieso drosseln musst (und das
> musst du, denn mehr als 3 bis 5 Updates in der Sekunde kann sowieso kein
> Mensch verarbeiten) UND du den Speicher hast, spricht nichts dagegen
> sprintf zu benutzen. Für nicht verbrauchten Flash kriegst du kein Geld
> zurück.

Hallo Karl-Heinz. Nach langer Ruhepause noch eine Frage. Ich habe 
sprintf genommen. Was ich aber im Moment nicht ganz verstehe ist 
folgendes:
ich springe mit lcd_gotoxy(0,0); doch  1te Zeile ganz links??? mit dem 
nachfolgenden Befehl sprintf((g_temp)," %3s", tempstr); 
lcd_puts(g_temp);
bleibt aber immer die erste Stelle frei, soll heißen, die Null der Km 
steht
immer an 4ter Stelle. Genauso wie Trip.???
Ansonsten bin ich bis jetzt "stolz" auf mich, dass ich soweit mit eurer 
hilfe gekommen bin.

Gruss Peter

von Karl H. (kbuchegg)


Lesenswert?

Peter R. schrieb:
> Karl Heinz Buchegger schrieb:

> bleibt aber immer die erste Stelle frei, soll heißen, die Null der Km
> steht
> immer an 4ter Stelle. Genauso wie Trip.???

Hier steht

       sprintf((g_temp)," %3s", tempstr);
                         ****

* Als erstes soll in den Ausgabestring ein Leerzeichen eingefügt werden.
* Danach soll ein String ausgegeben werden, ...
* Wobei dieser String in ein (gedachtes) Ausgabefeld der Breite 3
  eingepasst werden soll
* Wie bei allen anderen Ausgaben, gilt für printf: Wenn der
  tatsächlich auszugebende Wert NICHT in die im Formatstring
  angegebene Feldbreite hineinpasst, sondern zu klein ist, dann wird
  die Ausgabe rechtsbündig in das Feld gestellt und links mit
  Füllzeichen aufgefüllt. Im Falle eines Strings sind das nun
  mal Leerzeichen.


In Summe führt das dazu, dass
* In der Zeile auf jeden Fall erst mal 1 Leerzeichen ausgegeben wird.
* Ein String "0" in einem Feld der Länge 3, dann eben als "  0" erzeugt
  wird
* Und damit kommt die 0 an die Cursorposition 4 zu liegen.

von Karl H. (kbuchegg)


Lesenswert?

Wenn du sowieso nur am Vorkommaanteil interessiert bist, ist es ein 
bischen von hinten durch die Brust ins Auge, wenn du vorher mittels ftoa 
dir einen String erzeugen lässt und dann den String mittels sprintf in 
ein Feld einpassen lässt
1
        ftoa(speed, 0, tempstr);
2
        lcd_gotoxy(0,0);
3
        sprintf((g_temp)," %3s", tempstr);   
4
        lcd_puts(g_temp);

so, ist es wesentlich einfacher
1
        sprintf( g_temp," %3d", (int)speed);   
2
        lcd_gotoxy(0,0);
3
        lcd_puts(g_temp);

(Im Grund ist es auch dann einfacher, wenn du Nachkommastellen haben 
willst
1
        sprintf( g_temp," %3.0f", speed);   
2
        lcd_gotoxy(0,0);
3
        lcd_puts(g_temp);

von Peter R. (fraeggle)


Lesenswert?

Karl-Heinz du bist mir unheimlich. Keine 6 Minuten und du Antwortest. 
Vielen Dank für den Tip. Hab ihn schon verwirklicht. Bin gerade dabei 
noch RPM
"rein zu bauen".

Danke Dir Sakrisch.
Schönen Abend.
Gruss Peter

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