Hi, ich trete gerade auf der Stelle. Wie formatiere ich in C eine Zahl
oder einen String?
Meine Variable (int_8) kann den Inhalt 0 bis 100 annehmen.
Aus 0 bis 100 soll 0.0 bis 10.0 werden (am besten noch rechtsbündig,
aber das ist das kleinere Problem).
Also z. B.:
0 -> 0.0
5 -> 0.5
10 -> 1.0
15 -> 1.5
50 -> 5.0
100 -> 10.0
Das Ergebnis soll dann in einem String stehen, den ich als String
weiterverarbeite. Ich will es NICHT auf dem Bildschirm ausgeben.
itoa kann nur Integer
ftoa und gcvt kennt offenbar mein Compiler nicht. Ich arbeite mit
AVR-Studio 4.19.
sprintf(result,"%f",num) funktioniert bei mir auch nur mit Integer
Mein Wissensstand entspricht leider meinem Nicknamen.
Newbie schrieb:> sprintf(result,"%f",num) funktioniert bei mir auch nur mit Integer
Doch, mit den richtigen Compiler/Linker Einstellungen geht das.
Die finden sich in der AVR Libc doku.
Newbie schrieb:> Meine Variable (int_8) kann den Inhalt 0 bis 100 annehmen.>> Aus 0 bis 100 soll 0.0 bis 10.0 werden (am besten noch rechtsbündig,> aber das ist das kleinere Problem).
Das ist aber kein Fließkomma, sondern Festkommaarithmetik.
Newbie schrieb:> Hi, ich trete gerade auf der Stelle. Wie formatiere ich in C eine Zahl> oder einen String?>> Meine Variable (int_8) kann den Inhalt 0 bis 100 annehmen.Newbie schrieb:> Mein Wissensstand entspricht leider meinem Nicknamen.
Tja, das sehe ich. Aber keine Angst, man lernt mit der Zeit dazu - aber
nur dann, wenn man gewillt ist, die Dinge verstehen zu lernen.
Zunächst merke, daß deine Variable signed char Werte von -128 bis +127
annehmen kann. Wenn du da nur die Werte 0 bis 100 zu benutzen gedenkst,
ist das deine Sache.
Als nächstes beißt sich deine Vorstellung über den Dezimalpunkt bzw.
gebrochenen Teil deiner Zahl mit der landläufigen Vorstellung, daß man
in einem Byte nur Integerzahlen unterbringen kann. Es geht im Prinzip
alles, aber bei einer Zahlenbasis von 10 wird es nicht wirklich schön.
Das kommt daher, daß es leichter ist, den Bits in dem Byte eine
ganzzahlige Wertigkeit zuzuordnen, wenn die Zahlenbasis eine Potenz von
2 ist.
Das einfachste und überschaubarste ist bei deinem Vorhaben also, die
Ziffernfolge durch Subtraktion zu ermitteln:
1. Schritt: Festlegen des Vorzeichens und Betrag der Zahl bilden
2. Schritt: Festlegen, ob die erste Ziffer eine 1 oder eine 0 ist und
ggf. 100 abziehen
3. Schritt: Ermitteln der zweiten Ziffer durch wiederholtes Abziehen von
10, bis die Zahl gerade noch nicht negativ wird
4. Schritt: die dritte Ziffer ergibt sich durch den übrig bleibenden
Rest, der 0..9 sein kann.
5. "Versäubern" der drei Ziffern und des Vorzeichens nach deinem Gusto.
Normalerweise wil man ein '+' nicht immer vor jeder positiven Zahl
sehen. Ebenso will man zumeist nicht '03' sehen, sondern nur '3'. Bei
deiner Ausgabe willst du aber einen Dezimalpunkt vor der letzten Stelle
sehen. Also muß da die '0' direkt vor dem Dezimalpunkt stehen bleiben.
Das sind alles recht einfache Überlegungen, die dir aber den Ablauf
einer Ausgabekonvertierung erklären können. Nun ja, wenn du es
wenigstens einigermaßen klug programmierst, dann wird das Ganze
wahrscheinlich viel weniger Maschinencode erzeugen, als wenn du sowas
wie sprintf einbindest. Und du hast damit wieder etwas mehr gelernt.
W.S.
Leider bin ich noch nicht durchgestiegen. Ansätze hätte ich sogar
verschiedene.
Meine Idee wäre jetzt gewesen den String zu zerlegen und einen Punkt
einzufügen. In anderen Programmiersprachen kinderleicht (eine Zeile).
Aber hier hänge ich bei jeder zweiten Zeile, weil man in C für jeden
Furz selber eine Funktion schreiben muss. Entweder stimmte der Typ
nicht, die Variable war nicht oder falsch deklariert oder eine andere
Fehlermeldung folterte mich :(
Nur den String an einer bestimmten Position in zwei Teile zerlegen, ein
Riesending. Hab es nicht richtig hinbekommen. Am Ende kamen seltsame
Ergebnisse raus...
Beim Beispiel
https://www.mikrocontroller.net/articles/Festkommaarithmetik schaffe ich
es leider nicht das Ergebnis an mein Display zu übergeben, weil ich
einfach nicht weiß wie. Im Listing sind übrigens auch Fehler (frac statt
flag).
Ich weiß, dass man nicht einfach irgendwas zusammenklatschen sollte,
ohne es zu verstehen. Aber ich brauche das eigentlich nur, um den
prellenden Pollin-Encoder nutzen zu können, der mit dem Beispielcode aus
dem Forum super läuft. Der rastet halt mechanisch gut ein. Die anderen
Encoder gehen alle so leicht, man verstellt sie leicht beim Drücken.
Mein Code oder besser mein Versuch ist noch viel zu bruchstückhaft um
ihn hier zu zeigen. Aber danke für die Denkanstöße, die mir später
sicher noch nützlich sind.
> Aber hier hänge ich bei jeder zweiten Zeile, weil man in C für jeden> Furz selber eine Funktion schreiben muss.
Deshalb ist C so klein, schnell und hardwarenah. :)
Und das was du da willst sind eigentlich die banalsten Grundlagen.
Und da hilft auch nicht lesen im Internet sondern ein Buch das einem
alles mal strukturiert vorbetet/erklaert und das man durcharbeitet.
Olaf
Meine Idee wäre jetzt gewesen den String zu zerlegen und einen Punkt
einzufügen.
1
#include<stdio.h>
2
#include<stdint.h>
3
#include<assert.h>
4
5
char*toString(char*target,size_tsize,int8_tvalue)
6
{
7
assert(value<=100&&value>=0);
8
assert(size>=5);
9
10
snprintf(target,size,"%03d",value);
11
target[3]=target[2];
12
target[2]='.';
13
if(target[0]=='0')
14
target[0]=' ';
15
16
returntarget;
17
}
18
19
intmain()
20
{
21
charbuf[5];
22
23
printf("%s\n",toString(buf,sizeofbuf,1));
24
printf("%s\n",toString(buf,sizeofbuf,10));
25
printf("%s\n",toString(buf,sizeofbuf,100));
26
}
Newbie schrieb:> In anderen Programmiersprachen kinderleicht (eine Zeile).> Aber hier hänge ich bei jeder zweiten Zeile, weil man in C für jeden> Furz selber eine Funktion schreiben muss. Entweder stimmte der Typ> nicht, die Variable war nicht oder falsch deklariert oder eine andere> Fehlermeldung folterte mich :(
Nun ist es aber auch in vielen anderen Programmiersprachen so, dass
Variablen deklariert und vom richtigen Typ sein müssen, damit es
funktioniert.
EAF schrieb:> Doch, mit den richtigen Compiler/Linker Einstellungen geht das.> Die finden sich in der AVR Libc doku.
Ich zitiere einfach nochmal EAFs Antwort... die einzig zielführende
bisher.
Und um es zu präzisieren:
In AVR Studio:
1) Projekteinstellungen => Toolchain => Linker => General =>
[x] "Use vprintf library" aktivieren
2) Projekteinstellungen => Toolchain => Linker => Misc =>
"-lprintf_flt" in dem Eingabefeld für die Linkerflags anhängen.
> Ich zitiere einfach nochmal EAFs Antwort... die einzig zielführende> bisher.
Nicht zwangslaeufig. Der Grund warum printf embedded nicht immer
vorhanden ist, oder nur rudimentaer ist sein Speicherverbrauch. Kann man
manchmal machen, manchmal nicht. Man muss sich halt ueber die Folgen
klar sei.
> Meine Idee wäre jetzt gewesen den String zu zerlegen und einen Punkt> einzufügen.
Es sind immer viele Loesungen denkbar. Ich wuerde einfach nur den String
bis zu der Stelle ausgeben wo man einen Punkt haben will, dann den Punkt
ausgeben und dann den Rest.
Die Sache ist halt die, ein String mit Punkt ist groesser wie einer ohne
und alles nach dem Punkt muss verschoben werden. Da muss man wieder
Speicher haben damit jonglieren, kopieren, kontrollieren das man Grenzen
nicht ueberschreitet.
Kann man machen, kann sogar notwendig sein, kann man aber vielleicht
auch vermeiden.
Olaf
Newbie schrieb:> Meine Idee wäre jetzt gewesen den String zu zerlegen und einen Punkt> einzufügen. In anderen Programmiersprachen kinderleicht (eine Zeile).> Aber hier hänge ich bei jeder zweiten Zeile, weil man in C für jeden> Furz selber eine Funktion schreiben muss.
So so.
Kann es sein, dass du dich einfach nicht auskennst ?
Mehrere einzeilige Lösungen wurden gezeigt.
Insgesamt versuchen die Leute hier Losungen zu zeigen, die gleich den
richtigen String erzeugen, und nicht später noch Teile davon
verschieben.
Gibt es bei dem AVR - C keine Arrays bzw. Float - Arrays ?
Einfach ein Array von 0 - 101 nummerieren und dann jedes
Element * 0.1 und gleich an einen String daran fügen.
Dann hast du es halt in Einerschritten :
0 -> 0.0
1 -> 0.1
2 -> 0.2
3 -> 0.3
4 -> 0.4
5 -> 0.5
usw.
Wenn du nur 0.5er Schritte brauchst, kannst du die ja erst mit
Modulo rausfiltern und dann an den String setzen.
Heinz B. schrieb:> Gibt es bei dem AVR - C keine Arrays bzw. Float - Arrays ?> Einfach ein Array von 0 - 101 nummerieren und dann jedes> Element * 0.1 und gleich an einen String daran fügen.
OMG! Was für ein Käse! Nur Experten unterwegs . . .
Newbie schrieb:> Ich weiß, dass man nicht einfach irgendwas zusammenklatschen sollte,> ohne es zu verstehen. Aber ich brauche das eigentlich nur, um den> prellenden Pollin-Encoder nutzen zu können,...
Wieder mal etwas, das ich so nicht mag. Ich halte viel mehr davon, die
verschiedenen Dinge nicht zusammenzuklatschen und dann noch um zurühren,
sondern sie schön getrennt zu machen.
Also zunächst ein Treiber für deinen Drehgeber (incl. ISR), der nichts
weiter macht, als beim Betätigen des DG drei bis vier veschiedene
Botschaften zu erzeugen: rechtsrum, linksrum, gedrückt und ggf.
wiederlosgelassen. Das hat noch gar nix mit irgendwelchen Zahlen zu tun.
Sodann ein Programmteil, das auf derartige Botschaften reagiert und z.B.
bei rechtsrum oder linksrum eine Zählzelle rauf- oder runterzählt. Das
hat zwar mit Zahlen zu tun, aber noch gar nix mit
Ausgabekonvertierungen.
Sodann ein anderer Programmteil, der aus einer an ihn übergebenen Zahl
bzw. einem Zählerstand eine darstellbare Zeichenfolge macht. Das wäre
dann der Ausgabekonverter.
Schlußendlich irgend eine tatsächliche Ausgabefunktion, z.B. über einen
UART, die Zeichenfolgen ausgibt, so daß man sie lesen kann.
Teile deine Softwareteile in funktionale Stücke, so daß du die getrennt
benutzen und zuvor getrennt testen kannst. Das wäre mein Rat an dich.
W.S.
Rolf M. schrieb:> Erfordert allerdings auch float-Support und damit für einen AVR ziemlich> viel Flash.
Ein ATmega8 sollte es schon sein (belegt etwa 3,6kB).
Newbie schrieb:> Leider bin ich noch nicht durchgestiegen. Ansätze hätte ich sogar> verschiedene.>
Mach das, was W.S. dir empfohlen hat. Wenn dir die Vorgehensweise nicht
klar ist, erstelle zuerst ein Flussdiagramm.
Die ganzen anderen Vorschläge mit obskuren Stringmanipulationen usw.
solltest du vergessen. Zitat: "wenn du es wenigstens einigermaßen klug
programmierst, dann wird das Ganze wahrscheinlich viel weniger
Maschinencode erzeugen, als wenn du sowas wie sprintf einbindest. Und du
hast damit wieder etwas mehr gelernt."
Dirk B. schrieb:> Rolf M. schrieb:>> char* toString(char* target, size_t size, int8_t value)>> Wie wird da sichergestellt, dass in target[4] ein '\0' steht?
Darum kümmert sich snprintf() selbstständig.
Rolf M. schrieb:> Dirk B. schrieb:>> Rolf M. schrieb:>>> char* toString(char* target, size_t size, int8_t value)>>>> Wie wird da sichergestellt, dass in target[4] ein '\0' steht?>> Darum kümmert sich snprintf() selbstständig.
Wenn ich Zeile 21 in
Newbie schrieb:> Meine Variable (int_8) kann den Inhalt 0 bis 100 annehmen.>> Aus 0 bis 100 soll 0.0 bis 10.0 werden (am besten noch rechtsbündig,> aber das ist das kleinere Problem).
1
externint_8i;
2
chars[5]=" 0.0";
3
4
if(i<0){s[0]='<';}// "<0.0" wenn gewünscht im Fehlerfall
5
elseif(i<100){s[1]+=i/10;// " X. "
6
s[3]+=i%10;// " .x"
7
}
8
else{s[0]='1'}// "10.0"
9
if(i>100){s[3]='+*;}// "10.+" wenn gewünscht im Fehlerfall
Dirk B. schrieb:> Wenn ich Zeile 21 in char buf[] = "snprintf schreibt maximal size> Zeichen";> ändere, kommt aber ziemlicher Mist raus.
Du hast natürlich recht. Das kommt davon, wenn man das morgens schnell
noch zwischen Tür und Angel macht. Ich überschreibe ja das \0 von
snprintf, also muss man das wieder neu anhängen.
Jobst Q. schrieb:> ... unsigned char val
Das war aber nicht die Fragestellung. Wenn man einem Newbie etwas
vorkaut, statt ihm hilft, SELBST etwas zu lernen und eine Lösung zu
finden, dann sollte man schon exakt sein.
Dieter R. schrieb:> Jobst Q. schrieb:>>> ... unsigned char val>> Das war aber nicht die Fragestellung. Wenn man einem Newbie etwas> vorkaut, statt ihm hilft, SELBST etwas zu lernen und eine Lösung zu> finden, dann sollte man schon exakt sein.
Wer hilft ihm denn hier, "SELBST etwas zu lernen"? Wie soll das gehen
ohne Beispiele, wie man es machen kann.
0 bis 100 passt genauso gut in einen unsigned char. Aber warum sollte
eine Lösung nur für den Fragesteller passen?
Da muss ich Jobst Q. recht geben. In der Tat lerne ich aus den
Beispielen, auch wenn manche nicht zu meinem Problem passen. Um etwas zu
verstehen muss ja erst mal etwas funktionierendes da sein. Wenn ich mir
nur Befehl für Befehl ansehe, weiß ich immer noch nicht, wie es zusammen
funktioniert.
Nach dem ich in angemessener Zeit nicht weiterkam, habe ich mein
Programm heute in Luna AVR geschrieben. Obwohl ich noch nie damit
gearbeitet habe, hatte ich die Software in einem Tag komplett fertig.
Die Encoder-Lib funktioniert gut, sogar Pollin-Encoder läuft
einwandfrei. Echt cool. Ich wollte mein Projekt einfach fertig bekommen.
Die Hardware ist ja auch noch unvollständig und bis Ende März brauche
ich sie wirklich.
Für C habe ich mir jetzt erst mal ein Buch bestellt:
AVR Mikrocontroller - Programmierung in C: Eigene Projekte selbst
entwickeln und verstehen von Heimo Gaicher