Hello, Guest the thread was called5.5k times and contains 50 replays

last post from lvr at the

C Kommastellen verwerfen

  • 0,5 kannst Du nicht in einem int speichern, da gehen nur ganze Zahlen.
    Sinn macht das ganze Thema ja nur, wenn Du mit Fließkommazahlen rechnest, die Du dann hinterher auf Ganzzahlen rundest, so war ja die Ausgangsfrage.


    Also evtl. so:

    Code
    1. float val = 0.5;
    2. int16_t valganz;
    3. valganz = val / 4;


    Jetzt wird 0.5 / 4 gerechnet, ergibt also 0.125. Das kannst Du nun mit einer der bereits genannten Methoden je nach Anforderung runden. Eine einfache Zuweisung an einen int (wie hier) schneidet einfach die Nachkommastellen ab, ergibt also in diesem Fall wieder 0.
    5.0 / 4 als anderes Beispiel würde 1.25 ergeben, auf int zugewiesen ergibt 1 usw...

  • ähm, ich glaub ich hab den Fehler gefunden.
    Hab mir da irgendwie selbst ein Ei gelegt.


    Jedenfalls ist die Zählung noch nicht so wie ich gerne hätte.
    Vielleicht hat dazu jemand einen Tipp.


    Diese Funktion hier zählt mir beim erreichen des Wertes 9999 wieder von vorne beginnend weiter, also 0:


  • Diese Funktion "zählt" doch gar nichts. Die wandelt die übergebenen Zahl "num", die max. 9999 groß sein darf in BCD-Code im Array digits[] um (das wohl global definiert ist). Praktisch um die Zahl irgendwie anzuzeigen, addiere z.B. ziffernweise jeweils 0x30 und Du hast ASCII-Zeichen.


    EDIT:
    Wenn Du also z.B. Print(1234) aufrufst, steht nachher in digits:
    digits[0] = 4;
    digits[1] = 3;
    digits[2] = 2;
    digits[3] = 1;
    Print zerlegt also eine Zahl in ihre dezimalen Ziffern.


    Wenn Du irgendwas hoch oder runterzählen willst, dann musst Du das außerhalb von Print() machen. Was genau soll denn das Programm machen?

  • Also:



    Das ganze wird ja auf einer Segmentanzeige angezeigt.
    Und soll wie ein Zählwerk das Rückwerts zählt funktionieren. Das ja auch nicht bei 0 stoppt sondern dann wieder bei 9999 beginnt rückwerts zu zählen.

  • Aha, langsam lichtet sich der Nebel...
    Es geht um ein Zählwerk mit einem Encoder. Der aktuelle Zählerstand steht in valganz und zur Anzeige teilst du den Wert vorher durch 4 (in val). Korrekt?
    Und was geht jetzt und was geht nicht?
    Mal angenommen die Encoder-Auswertung funktioniert (was ich momentan nicht überblicke), dann wird valganz beim Runterzählen irgendwann negativ. Das könnte Dein Problem sein.


    Du könntest folgendes versuchen:

    Code
    1. for (;;)
    2. {
    3. valganz += encode_read();
    4. if (valganz < 0)
    5. valganz += 10000;
    6. val = valganz / 4;


    oder so ähnlich.

  • Was lvr sagt - wobei ich den Test und das "+= 10000" allerdings auf val, nicht auf valganz anwenden würde.


    Sonstiges:


    In C ist das Ergebnis der Operation "Negativer Wert nach rechts geshiftet" undefiniert. Das wird hier vermutlich nicht das Problem sein, kann einem aber den Tag verderben. [AxelStoll] Muss man nur wissen [/AxelStoll].


    In Zeile 245 steht "if (val |= 0)" - ich weiß nicht, was Du da wolltest, aber das ist es vermutlich nicht.


    EDIT: Den Unterschied zwischen "&" und "&&" bzw. "|" und "||" kennst Du? Kommt in diesem Fall aufs Gleiche raus, aber normalerweise nimmt man in Fällen wie hier die logischen Operatoren (also die doppelten).
    Ach ja, und Du solltest an Deinen Variablennamen arbeiten, und mehr Kommentare schreiben. ;)

  • Ja, genau.
    Die Auswertung des Encoders funktioniert problemlos. In meinem Falle ist es jedoch kein Encoder der die Werte liefert sondern zwei Lichtschranken die mittels einer Scheibe ... Mehr dazu kommt noch.


    Dein Tipp ist schon der richtige Weg wie mir scheint, aaaaber, er zählt seltsamerweise nach 0 von 2500 rückwerts.


    Also:
    3
    2
    1
    0
    2500
    2499
    ...


    Ähm, Logo: 9999 / 4

  • Sind mir zu viele arithmetische Operationen, nur dafür, das möglichst tricky aussehen zu lassen :p


    Regel 2 der Real Programmers:


    - Real programmers don't comment their code. If it was hard to write, it should be hard to read.


    Der Code kann nicht der selbe sein .... man müsste sich aber mal den output anschauen um zu sehen was schneller ist ... bne/beq bzw. jmp sind recht lahm wenn ich mich da recht erinnere ...

  • ja, bitweise oder logische Verknüpfung.


    if (val |= 0) war genau das Problem das ich zuerst hatte.
    Im Falle eines Nullwertes sollte bei einem langem Tastendruck nichts passieren.


    Der Lange Tastendruck speichert den aktuellen Zählerstand in eine Variable. Was bei einem Nullwert nicht viel Sinn hätte.
    Das dürfte jetzt auch so funktioniren.


    Jedoch läuft die Zählung nun nicht korrekt.
    Das Zählen beim Vorspulen ist langsamer als beim zurückspulen.


    Hängt wohl jetzt mit dem


    if (val < 0)
    val += 10000;


    zusammen.


    Wieder falsch. Es liegt an der Datasette.
    Die dürfte schneller spulen wenn das Band auf einer Rolle weniger ist. In dem Falle beim zurückspulen. Also ich denke mal das es daran liegt.


    Zählen tut er korrekt.

  • wobei ich den Test und das "+= 10000" allerdings auf val, nicht auf valganz anwenden würde.


    Oh, natürlich. :drunk:


    In meinem Falle ist es jedoch kein Encoder der die Werte liefert sondern zwei Lichtschranken die mittels einer Scheibe ...


    Also ein selbstgebauter Encoder. ;)

  • Richtig. Sogar ein Selbstdrehender :)


    Ein kleiner Schönheitsfehler ist mir nun jedoch noch aufgefallen:
    Wen von 9999 nach 0 gezählt wird bleibt die 0 doppelt so lange stehen wie wenn ein wechsel von 0 auf 1 auf 2 auf 3 ... erfolgt.


    Beim zurückzählen wird's wohl genauso seind enke ich. Kann ich aber nicht 100% sagen da beim spulen natürlich das ganze recht schnell läuft.
    Bei PLAY merkt man es aber.


    Das liegt vermutlich daran weil -1 / 4 ebenfalls noch 0 ergibt.

  • if (val |= 0) war genau das Problem das ich zuerst hatte.
    Im Falle eines Nullwertes sollte bei einem langem Tastendruck nichts passieren.

    Verstehe ich das richtig, dass Du absichtlich "|= 0" schreibst, obwohl Du "!= 0" meinst?

  • Ich glaub es ist doch einfacher auf valganz zu testen, sonst springt zwar val beim Runterzählen über 0 wieder auf 9999, aber valganz bleibt ja negativ.
    Und wo ist eigentlich der Test auf positiven Überlauf 9999->0?


    Code
    1. valganz += encode_read();
    2. if (valganz < 0)
    3. valganz += 40000;
    4. else if (valganz > 39999)
    5. valganz = 0;
    6. val = valganz / 4;


    Oder hab ich jetzt wieder nen Denkfehler drin?

  • Eine Prüfung auf Überlauf gibt's in dem Sinne nicht.


    Das ganze wird ja nur durch diese Funktion hier begrenzt, soweit ich jetzt verstanden habe:



    Meinst du in deinem Beispiel wirklich 40000 und 39999 ?


    Da meckert der Compiler:
    ../main.c:236: warning: comparison is always false due to limited range of data type


    Und das Ergebnis ist ganz verstümmelt. Vor null kommt 3615.

  • Die Print() Funktion prüft nur auf > 9999 und bricht ab, wenn der Wert größer ist. Es wird dann einfach nichts angezeigt, der eigentliche Zähler macht aber weiter.


    Statt der > 39999 kannst Du auch auf >= 40000 prüfen, wenn Dir das besser gefällt, kommt aber auf's gleiche raus.


    OK, die Warnung liegt am Datentyp int16_t, der geht von -32768 bis +32767, kann also nie > 39999 werden. Der Compiler hat Recht. :-)
    Entweder auf int32_t ändern oder auf einen unsigned int, also uint16_t, der geht dann von 0 bis 65535. Da muss man aber die Abfrage auf Unterlauf ändern. Probiers zuerst mal mit int32_t.

  • Mit int32_t funktioniert.
    Dürfte nun soweit alles funktioniert. Habe jetzt sonst keine weiteren Mängel feststellen können.
    Werde ich Morgen aber nochmal intensiver testen.


    Dann gibt's auch ein Video dazu mit dem ganzen Aufbau.