Forum: Mikrocontroller und Digitale Elektronik integer Variable als Kommazahl


von pio (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen.

Ich möchte auf einem GLCD einen Spannungswert anzeigen lassen. Bis 2 
Stellen hinter dem Komma.
Beispiel: 5,74V

Aus der Funktion readADC() bekomme ich eine uint16_t Variable.

Wie kann ich das machen.?

Danke euch.

: Verschoben durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Du könntest Deinen Int in Text umwandeln lassen und das Komma an der 
passenden Stelle in den Text einfügen.

Bestimme also nach dieser Zeile

itoa(result,buffer1,10);

die Länge des erzeugten Strings und verschiebe die letzten beiden 
Zeichen um eines und füge davor ein Komma ein.

Mit dem Resultat kannst Du dann so weiter verfahren wie bisher.

von Teo D. (teoderix)


Lesenswert?

Mach zB: 574mV drau's und statt das "m" hinten, vorne ein "," 
anzeigen lassen ;)

von Falk B. (falk)


Lesenswert?

Siehe Festkommaarithmetik.

Mods, bitte den Thread verschieben.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Falk B. schrieb:
> Mods, bitte den Thread verschieben.

Ich geb' mir ja schon Mühe, hinter all den nichtlesenkönnenden 
aufzuräumen, aber manchmal fällts mir dann auch nicht sofort auf.

von pio (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Du könntest Deinen Int in Text umwandeln lassen und das Komma an der
> passenden Stelle in den Text einfügen.
>
> Bestimme also nach dieser Zeile
>
> itoa(result,buffer1,10);
>
> die Länge des erzeugten Strings und verschiebe die letzten beiden
> Zeichen um eines und füge davor ein Komma ein.



wie soll ich die Variable aufsplitten.?

1002 zum Beispiel (10,02)

wenn ich dort ein Komma nach der 10 schreibe, entfällt die 2.Null

von Latschen S. (Gast)


Lesenswert?

pio schrieb:
> Hallo zusammen.
>
> Ich möchte auf einem GLCD einen Spannungswert anzeigen lassen. Bis 2
> Stellen hinter dem Komma.
> Beispiel: 5,74V
>
> Aus der Funktion readADC() bekomme ich eine uint16_t Variable.
>
> Wie kann ich das machen.?
>
> Danke euch.

Folgendes angenommen:

De kleinste Einheit die dein ADC wandeln kann (LSB Wert) ist 1 mV.

Dann bekommst du in deinem Fall einen (unsigned) Integer Wert 5740.
Diesen Wert dividierst du mit 1000.  Das Resultat (5) wandelst
du nach ASCII und schiebst den WERT in  die 1. Stelle einer
Zeichenkette (auch Array genannt).
Darauffolgend belegst du das Array mit dem "," (0x2c).

Jetzt wird es spannend:

Als nächsten Schritt führst du eine "MODULO" Division durch 1000 durch.
Hier wird der "Rest" (750) als Wert zurückgegeben.

Das geschied folgender maßen:
Es wird die gleiche Division wie oben durchgeführt, jedoch wird das 
Ergebnis "5" mit 1000 multipliziert (5000) und dann vom ursprünglichen 
Wert (5740)
abgezogen und es bleibt 740 übrig.

Nachdem du nur 2 Kommastellen benötigst, dividierst du den Wert einfach 
durch 10.
Die 74 wandelst du einfach in eine 2 stellige Ascii Zeichenfolge um
und  hängst sie nach dem Komma in der Zeichenkette dran.

In einem Kochbuch würde stehen:

Man gibt die Zutaten (Array, ADC Werte, Gewürze und Funktionen)
in einen "C" Topf kocht es richtig auf,
und nach einer Stunde bekommt man eine Zeichenkette perfekt geignet
zum garnieren eines "LCD" Tellers ;-)

Sepp

von Georg G. (df2au)


Lesenswert?

pio schrieb:
> wenn ich dort ein Komma nach der 10 schreibe, entfällt die 2.Null

Du musst erst Platz schaffen für das Komma, nicht einfach drüber bügeln.

von pio (Gast)


Lesenswert?

Latschen S. schrieb:
> Dann bekommst du in deinem Fall einen (unsigned) Integer Wert 5740.

wo genau kommt nun die 5740 her.?

result geht bei mir von 0...1023

von pio (Gast)


Lesenswert?

Georg G. schrieb:
> Du musst erst Platz schaffen für das Komma, nicht einfach drüber bügeln.

das ist richtig. aber wie kann ich die variable so auseinander nehmen.?

von Peter II (Gast)


Lesenswert?

pio schrieb:
> das ist richtig. aber wie kann ich die variable so auseinander nehmen.?

einfach stelle 5 auf stelle 6, stelle 4 auf stelle 5. Kann doch nicht so 
schwer sein.

buffer1[7] = 0;
buffer1[6] = buffer1[5];
buffer1[5] = buffer1[4];
buffer1[4] = ',';

von Latschen S. (Gast)


Lesenswert?

pio schrieb:
> wo genau kommt nun die 5740 her.?
>
> result geht bei mir von 0...1023

Ich sagte ja nur "angenommen"

Du müsstest halt den "LSB" Wert wissen,
(der kleinste werd den der ADC liefert)

dann kann man das Ganze ja nochmals durchexerzieren.


Sepp

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Bevor hier mit festen Arrayindices gearbeitet wird, sollte zuerst die 
Länge des Strings überprüft werden.

Denn der kann ja auch durchaus kürzer sein als fünf Zeichen ...

von pio (Gast)


Lesenswert?

Latschen S. schrieb:
> Du müsstest halt den "LSB" Wert wissen,
> (der kleinste werd den der ADC liefert)

was bedeutet lsb wert? wo finde ich den?

der kleinste wert ist doch 0 oder.?

von B. S. (bestucki)


Lesenswert?

Rufus Τ. F. schrieb:
> Bevor hier mit festen Arrayindices gearbeitet wird, sollte zuerst die
> Länge des Strings überprüft werden.
>
> Denn der kann ja auch durchaus kürzer sein als fünf Zeichen ...

Korrekt. Auch alle Werte < 100 müssen separat behandelt werden, da 
führende Nullen hinzugefügt werden müssen.


Aus deinem Code:
1
result /= 102,3; //10V anzeigen
Dies wird nicht das tun, was du dir erhoffst. Du benutzt hier den 
Kommaoperator und result wird durch 102 geteilt. 102.3 wäre richtig, 
falls du Fliesskommazahlen benutzen willst.

GCC wirft bei diesem Ausdruck auch eine Warnung:
1
warning: right-hand operand of comma expression has no effect [-Wunused-value]

von pio (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Denn der kann ja auch durchaus kürzer sein als fünf Zeichen ...


1,45V
10,00V

5 bzw 6 strings

von pio (Gast)


Lesenswert?

Be S. schrieb:
> GCC wirft bei diesem Ausdruck auch eine Warnung:warning: right-hand
> operand of comma expression has no effect [-Wunused-value]

die Meldung bekomme ich nicht

von Latschen S. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Denn der kann ja auch durchaus kürzer sein als fünf Zeichen

Mackst du voll krass eine Nüll in letzte Ztelle - und alles ist
String paletti ;-)

von B. S. (bestucki)


Lesenswert?

pio schrieb:
> die Meldung bekomme ich nicht

Schalte -Wall und -Wextra ein.
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html


Ich empfehle dir folgendes Vorgehen:
1. Letzte dezimale Ziffer ermitteln (Modulo-Operator).
2. Ziffer in einen String schreiben.
3. Zahl durch 10 teilen.
4. Springe zu 1. wenn Zahl ungleich null ist.

Somit hast du schon mal die Zahl in einen String gewandelt, die Zeichen 
sind jedoch in der falschen Reihenfolge gespeichert:
5. Reihenfolge der Zeichen im String umdrehen.

Wenn du das geschafft hast, erweiterst du deinen Algorithmus so, dass 
der String immer eine Mindestlänge von 3 hat. Du fügst also führende 
Nullen an.

Anschliessend veränderst du deine Funktion wieder, so dass immer an 3. 
Stelle (Index 2) ein Komma eingefügt wird.

Optional: Den Algorithmus so verändern, dass die Anzahl Kommastellen 
parametrierbar ist.

Schreibe dir eine Funktion dazu und teste diese auf deinem PC. Dann ist 
alles schon mal einfacher, da du die ganze Sache mit dem uC und ADC 
erstmal vergessen kannst.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

pio schrieb:
> 1,45V
> 10,00V

Das sind die gewünschten Ergebnisse, nicht das, was itoa geliefert hat.

Und was ist, wenn der ADC den Wert 13 liefert?

Dann steht im mit itoa erzeugten String nur "13" drin.

Latschen S. schrieb:
> Mackst du voll krass eine Nüll in letzte Ztelle - und alles ist
> String paletti

Du hast noch nicht mal kapiert, wo das Problem liegt.


Also: Der ADC liefert den Wert 13.

itoa macht daraus den String "13"

Im Speicher sieht das also so aus:

buffer1
[0] = '1'
[1] = '3'
[2] = '\0'
[3] = undefiniert1
[4] = undefiniert2
[5] = undefiniert3
[6] = undefiniert4
[7] = undefiniert5

Peter II schrieb:
> buffer1[7] = 0;
> buffer1[6] = buffer1[5];
> buffer1[5] = buffer1[4];
> buffer1[4] = ',';

Wird das angewendet, sieht das Resultat so aus:

buffer1
[0] = '1'
[1] = '3'
[2] = '\0'
[3] = undefiniert1
[4] = ','
[5] = undefiniert2
[6] = undefiniert3
[7] = '\0'

Das ist vom gewünschten Ergebnis

"0.13"

irgendwie ziemlich weit entfernt, nicht?

von Latschen S. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Du hast noch nicht mal kapiert, wo das Problem liegt.

Doch, doch !

Ich reibe mir hier nur die Augen,
und beobachte  wie die "Mücke" immer grösser wird und zum ..

Sepp

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

pio schrieb:
> das ist richtig. aber wie kann ich die variable so auseinander nehmen.?

Anstatt:
1
    result += ADCW;
2
  }
3
  // ADC wieder deaktivieren
4
  ADCSRA &= ~(1<<ADEN);
5
  
6
  result /= 3;
7
  result /= 102,3; //10V anzeigen
8
  return result;
9
}        
10
}

 Rechne so:
1
    result += ADCW;
2
  }
3
  // ADC wieder deaktivieren
4
  ADCSRA &= ~(1<<ADEN);
5
  
6
  result /= 3;
7
//  result /= 102,3; //10V anzeigen
8
  return result;
9
}

 Und dann in main()
1
 uint8_t Ganz =  result / 400;
2
 uint8_t Dez = (result % 400) >> 2;

 Und dann schreibe formatiert Ganz + "." + formatiert Dez.

 EDIT:
 Formatiert, damit du dein LCD nicht jedesmal löschen musst.

: Bearbeitet durch User
von pio (Gast)


Lesenswert?

die methode von Latschen Sepp (lase) funktioniert sehr gut.

allerdings verstehe ich nicht, warum ich bloß bis 2,5V messen kann am 
adc.
ich habe einfach nur ein poti mit 5v am eingang dran.
hat das was mit der Referenzspannung zu tun.? glaube schon. aber wie 
kann ich es anders machen.?

wenn ich die interne referenz ausschalte, was muss ich dann 
hardwaremäßig am AREF Pin machen.?

von pio (Gast)


Lesenswert?

fehler gefunden.
ich habe den kondensator zwischen + und aref gehabt.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

pio schrieb:
> die methode von Latschen Sepp (lase) funktioniert sehr gut.

 Da haben sich 2 gefunden.
 Einer, der keine Ahnung hat und einer, der nichts versteht.

von W.A. (Gast)


Lesenswert?

pio schrieb:
> fehler gefunden.
> ich habe den kondensator zwischen + und aref gehabt.

Da gehört eine Drossel zwischen.

Jetzt kennst du den Unterschied zwischen Drossel und Kondensator :-)

von W.A. (Gast)


Lesenswert?

W.A. schrieb:
> Da gehört eine Drossel zwischen.

Sorry, das war Bockmist.

Die Drossel gehört zwischen "+" und AVCC (oder wie auch immer der Pin 
bei denem Prozessor heißt). An ARef gehört ein Kondensator gegen Masse 
und üblicherweise sonst gar nichts, zumindest bei einem ATmega. Wenn du 
deine Versorgungsspannung als Referenz verwenden willst, kannst du die 
über die richtige Stellung der Register auswählen.

von Bernd N (Gast)


Lesenswert?

1
// ADC Value integer to ASCII
2
void AdcValOut (uint16_t AdcValue)
3
{
4
    uint8_t AdcValArray [5];
5
    uint8_t m = 4;
6
7
    do {
8
        AdcValArray [m] = '0' + AdcValue %10;      // Berechnung der einzelnen Stellen sowie
9
        AdcValue /= 10;                            // Wandlung nach ASCII und abspeichern im
10
    } while (m--);                                 // Array
11
    while (m != 4) {                               // Anzahl der auszugebenden Stellen = 5
12
        lcdPutc (AdcValArray [++m]);               // Integer Wert ausgeben
13
        if (m == 0) lcdPutc ('.');                 // Dezimalpunkt setzen
14
    }
15
}

Aufruf sollte klar sein, wenn du den Wert 12345 übergibst dann sollte 
auf deinem Display 1.2345 zur Anzeige kommen. Wie du das Ganze jetzt auf 
2 oder 3 Stellen hinter dem Komma anpassen mußt findest du bestimmt 
heraus. Ebenso sollte klar sein wie das Komma verschoben werden kann.

Du solltest dir Modulo / ASCII etc. ansehen und dann wenigstens den Code 
verstehen lernen.

von Latschen S. (Gast)


Lesenswert?

pio schrieb:
> die methode von Latschen Sepp (lase) funktioniert sehr gut.

Na das freut einem !

Das sind genau die Feed-back's die einem dazu bringen
Beiträge zu schreiben und zu motivieren  :-)

Sepp

von Latschen S. (Gast)


Lesenswert?

Marc V. schrieb:
> Einer, der keine Ahnung hat und einer, der nichts versteht

Ich hoffe ja nur das Sie vom Sinus genau so viel verstehen wie
vom "(logarithmus)".

Glauben Sie wirklich dass man mit einen arroganten , abgehobenen Getue 
weiterkommt im Leben? :-(


Sepp

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Latschen S. schrieb:
> Glauben Sie wirklich dass man mit einen arroganten , abgehobenen Getue
> weiterkommt im Leben? :-(

 Wenn der Ausdruck:
1
 Wahrheit == (Arroganz & abgehoben)
 dann nein.

 Wie man ADC Wert mit 2.56V ARef einfach in Volt umwandelt habe ich
 weiter oben geschrieben.

 Wie man diesen Wert einfach auf einem Display anzeigt hat ihm Bernd N
 gezeigt:
 Bernd N schrieb: void AdcValOut (uint16_t AdcValue)

 Was in deinem Beitrag hier funktionieren soll:
> De kleinste Einheit die dein ADC wandeln kann (LSB Wert) ist 1 mV.
> Dann bekommst du in deinem Fall einen (unsigned) Integer Wert 5740.

 Oder hier:
> Mackst du voll krass eine Nüll in letzte Ztelle - und alles ist
> String paletti ;-)

 ist mir immer noch unklar.

: Bearbeitet durch User
von Latschen S. (Gast)


Lesenswert?

@Marc Vesely (logarithmus)

So wie es aussieht können Sie "Arroganz" und  "abgehoben"
Ihrem Charakter nicht richtig zuordnen.

Tja dann wolle mir mal gugge was das Archiv so her gib:

Anleitung:

* Hier am Seitenanfang oder -ende auf "Suchen" klicken
* Beiträge ->  -alle-
* Sortierung -> nach Relevanz
* Sucheingabe  -> "Marc Vesely"

Da popt  genau ein Beitrag (RGB LED Sequenzen) von Ihnen hoch.
(der Einzige, mit gerade mal 13 Antworten)

Genau im 4.Beitrag werden Sie dann ausfällig
(den Text erspar ich mir hier)

im 5.Beitrag dann die Antwort (von Didi S.):

Anfang >>

Ups,

jetzt wollte ich Dir doch gerade Schreiben, wie man einfach und
professionell aufregende Sequenzen erzeugen kann. So wie die Profis von
Bühnenshows es machen - doch dann las ich Deinen letzten Beitrag. Sorry,
jetzt habe auch ich keine Lust mehr. .......

Bei Deinem ----------- ---------- ist mir mein Bett nun lieber.

Träum süß!

<< Ende


Sepp

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Latschen S. schrieb:
> Da popt  genau ein Beitrag (RGB LED Sequenzen) von Ihnen hoch.
> (der Einzige, mit gerade mal 13 Antworten)

 LOL.
 Von suchen hast du also auch keine Ahnung ?

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.