Forum: Compiler & IDEs String in Int umwandeln, damit rechnen und wieder zurückkonvertieren


von Steffen O. (derelektroniker) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo,
ich hänge immernoch an meiner GPS- Geschwindigkeitsanzeige. Inzwischen 
klappt die Kommunikation über UART tadellos, aber die Auswertung des 
Strings noch nicht ganz.
Und zwar empfange ich vom GPS- Empfänger die Geschwindigkeit in Knoten, 
und speichere sie, in der als char initialisierten Variable, empfangen 
ab.
Anschliessend will ich die Variable nach int konvertieren, damit ich sie 
zum Umrechnen in km/h mit 1,85 multiplizieren kann.
Wenn das geschehen ist, muss sie jedoch wieder nach char konvertiert 
werden, da sie mit der Funktion lcd_string(string) auf einem LCD 
ausgegeben werden soll. Bei dem ganzen Vorgang sollen die beiden 
Nachkommastellen erhalten bleiben, und es soll möglichst schnell 
geschehen, weshalb ich auf Bibliotheksfunktionen verzichtet habe, und 
versucht habe, die Konvertierung von Hand zu machen. Allerdings klappt 
das nicht so ganz wie erwünscht, wenn der Empfänger 0.00 Knoten schnell 
ist, und auch 0.00 sendet (was der Mega8 auch empfängt), dann zeigt das 
LCD das an, was auf dem Bild zu sehen ist.
Also die Formatierung stimmt, die Werte jedoch nicht.....

Hier mal mein Code zum Konvertieren und Rechnen:
1
empfangen[0] = uart_getchar();  //Per UART die Daten com GPS- Empfaenger
2
empfangen[1] = uart_getchar();  //empfangen
3
empfangen[2] = uart_getchar();
4
empfangen[3] = uart_getchar();
5
....
6
                                 //Wenn empfangen[1] ein Komma ist (was ja
7
if(empfangen[1] == '.')          //bei einer einstelligen Geschwindigkeit
8
{                                //der Fall ist)
9
empfangen[1] = empfangen[2];     //Das Komma "rausmachen"
10
empfangen[2] = empfangen[3];
11
knoten = empfangen[0]*1000 + empfangen[1]*100 + empfangen[2]*10 +  empfangen[3];                    //Die char- Werte in einer int speichern
12
mh = knoten*185;                 //Von Knoten nach mh umrechnen
13
ausgabearry[0] = mh/100000 + '0';  //Die ints wieder in char speichern
14
ausgabearry[1] = '.';
15
ausgabearry[2] = mh/10000 - (ausgabearry[0]*10) + '0';
16
ausgabearry[3] = mh/1000 - (ausgabearry[0]*100) - (ausgabearry[2]*10) + '0';
17
lcd_string("Geschwindigkeit:");
18
set_cursor(1,2);
19
lcd_string(ausgabearry);          //Auf dem LCD ausgeben
20
}

Ich hoffe ihr könnt mir helfen.

Gruß, Steffen

von tuppes (Gast)


Lesenswert?

Beim Auswerten der empfangenen Zeichen die '0' abziehen, die du vor der 
Ausgabe wieder draufaddierst:

knoten = (empfangen[0]-'0') * 1000 + ......

Und was hat knoten für einen Datentyp? Müsste schon long sein, sonst 
gibts einen Überlauf nach der Multiplikation mit 185000.

von Matthias (Gast)


Lesenswert?

knoten = empfangen[0]*1000 + empfangen[1]*100 + empfangen[2]*10 + 
empfangen[3];


Ich glaube, das geht so nicht, weils eigentlich chars sind. Wenn in 
empfangen[1] zB ne 8 steht, kommt bei *100 800 raus... char ist 8Bit und 
geht damit nur bis 256. Du baust damit Überläufe, du kaum kontrollierbar 
sind.

Versuchs ma mit "Atoi", aka Ascii to Integer. Damit geht das (benutz ich 
auch um werte ausm string rauszuziehen).

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ich hab mh und knoten als unsigned int initialisiert.
Die von die genannten Veränderungen hab ich nun mal durchgeführt, nun 
dieht die betreffende Zeile so aus:
1
knoten = (empfangen[0]-'0')*1000 + (empfangen[1]-'0')*100 + (empfangen[2]-'0')*10 + (empfangen[3]-'0');

Allerdings kommt auf dem LCD nun 0.PP, wenn der gesendete String 0.00 
ist, und bei irgendeiner Geschwindigkeit kommt immer 0.XX (X sind 
irgendwelche großen Buchstaben). Ich will da ja aber Zahlen haben.....

@Matthias: Wenn ich mit atoi konvertiere, bleiben dann die 
Nachkommastellen erhalten? Also ich konvertier dann empfangen in knoten, 
und der Rest bleibt so, wie er ist, oder?

Gruß, Steffen

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ich hab jetzt mal anstatt der im vorherigen Post genannten Zeile das 
hier eingefügt:
1
knoten=atoi(empfangen);

Allerdings immernoch das Gleiche wie vorhin, ich es kommt das hier: 0.XX 
(X sing irgendwelche großen Buchstaben).

Gruß, Steffen

von holger (Gast)


Lesenswert?

>@Matthias: Wenn ich mit atoi konvertiere, bleiben dann die
>Nachkommastellen erhalten?

Ein int hat keine Nachkommastellen.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

holger wrote:
>>@Matthias: Wenn ich mit atoi konvertiere, bleiben dann die
>>Nachkommastellen erhalten?
>
> Ein int hat keine Nachkommastellen.

Stimmt, natürlich....
Also kann ich atoi nicht verwenden, da ich ja Nachkommastellen benötige.
Oder geht atoi auch mit double oder so? Aber wenn ich eben double 
verwende, wird das Programm wieder großer und langsamer, deswegen will 
ich nach Möglichkeit int verwenden....

Gruß, Steffen

von Thilo M. (Gast)


Lesenswert?

>geht atoi auch mit double oder so?

Heißt 'atod' und 'dtoa', steht alles in der libc vom WINAVR.

Ich benutze bei Messwerten ausschließlich double-Variablen, hatte bisher 
noch keine Timing- oder Geschwindigkeitsprobleme.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Hmmm, wenn ich die libc.a, einbinde, und atod folgendermaßen verwende:
1
knoten=dtoa(empfangen);

dann kommt folgender Fehler:
161: undefined reference to `dtoa'

Hab ich irgendwas übersehen? knoten ist eine double- Variable und 
empfangen eine char.

Gruß, Steffen

von Matthias (Gast)


Lesenswert?

Das atoi machst du fuer jede stelle des char-arrays einzeln... Atoi 
überprüft EIN ascii zeichen darauf, welchen Zahlenwert es hat und 
konvertiert diesen dann (ascii zeichen sind chars, also wieder 8bit).

also in etwa: knoten = atoi(empfangen[1]) + atoi(empfangen[2])+...

Wenn du auf nummer sicher gehen willst, dann machst du das ganze schritt 
fuer schritt, also so:

var1 = atoi(empfangen[1])
var2 = atoi(empfangen[2])
var3 = atoi(empfangen[3])

knoten = var1 + var2 + var3;

so kannst du mit dem debugger oder einer geeigenten Ausgabe gucken, ob 
die konvertierung funktioniert.

von Matthias (Gast)


Lesenswert?

Wenn ich mich recht erinnere, geht das ganze auch mit fprintf (oder wars 
sprintf??) damit kann man strings auch in integerwerte umfummeln, hab 
aber die  syntax nicht im kopf und das c-buch liegt natürlich auffe 
arbeit... Google mal printf-familie, da muesste was schlaues 
beirumkommen...

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Matthias wrote:
> also in etwa: knoten = atoi(empfangen[1]) + atoi(empfangen[2])+...
Ich habs jetzt mal so gemacht aber auf dem LCD kamen wieder nur 
Buchstaben....

> Wenn du auf nummer sicher gehen willst, dann machst du das ganze schritt
> fuer schritt, also so:
>
> var1 = atoi(empfangen[1])
> var2 = atoi(empfangen[2])
> var3 = atoi(empfangen[3])
>
> knoten = var1 + var2 + var3;
So werde ich es dann noch versuchen, vielleicht klappt das ja....

Zu printf: Mit sprintf habe ich es bereits versucht bin jedoch daran 
gescheitert.... Kann man mit sprintf auch immer nur ein Zeichen 
konvertieren?

Gruß, Steffen

von Matthias N. (vbchaos)


Lesenswert?

Weisst du ganz sicher, dass dein Char-Array nur Zahlen und den Punkt 
beinhaltet und nich doch irgendwelche anderen Zeichen?

von Simon K. (simon) Benutzerseite


Lesenswert?

Thilo M. wrote:
>>geht atoi auch mit double oder so?
>
> Heißt 'atod' und 'dtoa', steht alles in der libc vom WINAVR.

Ne, heißt dtostrf bzw. strtod / atof

http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html
Beitrag "float to string"

von Matthias (Gast)


Lesenswert?

Versuchs mal noch mit nem CAST dabei. Gerad mal nachgeschaut:
1
UINT8 result;
2
char array[5] = {1,2,3,4,5};
3
4
result = (UINT8) atoi ((char *) & (array[2]));

so gehts bei mir jedenfalls.

von Detlev T. (detlevt)


Lesenswert?

@Steffen O.
Sorry, aber dein Code ist ziemlicher Murks. Du ignorierst die Kodierung 
(ASCII) rechnest empfangen[3] gleich zweimal mit ein und gehst davon 
aus, dass ein einstelliger mph-Wert auch einen einstelligen kmh-Wert 
ergibt. Das muss ja schiefgehen.

Das einfachste wäre wohl, mit den schon genannten Bibliotheksfunktionen 
und Fließkommazahlen zu rechnen. Wenn es wirklich auf Geschwindigkeit 
ankommt, musst du dich noch einmal hinsetzen und den Algorithmus 
ordentlich ausarbeiten und nicht gleich mit dem Koden anfangen. 
Divisionen sollte man da zudem möglichst vermeiden.

von Jörg Stegemann (Gast)


Lesenswert?

Sorry, aber bei diesem Code weiss ich ja gar nicht, wo ich anfangen 
soll... Du hast offensichtlich keine Ahnung von Datentypen im 
allgemeinen noch von denen von C im Besonderen. Und dir zu helfen bringt 
auch nix, schliesslich ist es offensichtlich, dass du nicht mal ein 
C-Buch gelesen hast, so zur Vorbereitung. Und deswegen ist es sinnlos 
dir jetzt den richtigen Code zu geben, damit lernst du es dann ja doch 
nicht.

Wieso nimmst du nicht einfach Basic? Und lass bitte das Argument der 
Geschwindigkeit weg, wie oft pro Sekunde soll sich der Wert denn bitte 
ändern?!?

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

@vbchaos: Ja, das Array empfangen enthält nur die Zeichen, und eben den 
Punkt.

@Matthias: Danke für den Tip, werde ich dann gleich mal testen.

@Detlev T.: Ja, stimmt, ich rechne empfangen[3] noch mit ein, obwohl es 
das ja gar nicht mehr gibt - der Wert von empfangen[3] steht ja in 
empfangen[2]...
Ich hab eben ein bisschen rumprobiert, und das hab ich das dann einfach 
übersehen....

@Jörg Stegemann: Wieso denkst du, ich habe keine Ahnung von Datentypen? 
Ich habe sehr wohl ein C- Buch gelesen, und mir ist eigentlich auch 
alles klar, was darin behandelt wurde.
Wieso sollte ich auf Basic umsteigen? Ich hab jetzt mit C angefangen, 
und will auch dabei bleiben. Ich lerne eben noch und da kann man doch 
auch Fehler machen, oder?
Und wenn mir nun jemand den richtigen Code gibt, dann werde ich den 
nicht nur einfach reinkopieren, sondern ich schaue mir den dann genau 
an, und versuche zu verstehen, wie das funktioniert....

Gruß, Steffen

von Jörg Stegemann (Gast)


Lesenswert?

Es ist offensichtlich, dass du den Unterschied zwischen char und byte 
nicht kennst. Sonst wärst du nicht auf die Idee gekommen mit den ASCII 
Werten zu rechnen, oder? Dann hast du anscheinend auch keine Ahnung von 
den Wertelimits der verschiedenen Datentypen, denn die meisten deiner 
Rechnungen dürften für Overflows sorgen.

Und die Idee mit Basic ist einfach: In den meisten Basicvarianten kommt 
es auf den genauen Typ nicht an, die machen "automatisch" das Richtige. 
Und mir scheint das ist genau das, was du brauchst.

BTW: Ist dir z.B. klar dass du beim Setzen von "knoten" den letzten Teil 
(" + empfangen[3]") weglassen musst?

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Jörg Stegemann wrote:
> Es ist offensichtlich, dass du den Unterschied zwischen char und byte
> nicht kennst. Sonst wärst du nicht auf die Idee gekommen mit den ASCII
> Werten zu rechnen, oder? Dann hast du anscheinend auch keine Ahnung von
> den Wertelimits der verschiedenen Datentypen, denn die meisten deiner
> Rechnungen dürften für Overflows sorgen.
Hmmm, laut meinem C- Buch kann selbst eine, als unsigned int deklarierte 
Variable eine Zahl bis 4294967295 aufnehmen und die größte Zahl die bei 
meinen Rechungen rauskommen wird, ist eigentlich nicht größer....Ich hab 
ja auch noch double verwendet, da ist der Zahlenbereich noch größer!

> Und die Idee mit Basic ist einfach: In den meisten Basicvarianten kommt
> es auf den genauen Typ nicht an, die machen "automatisch" das Richtige.
> Und mir scheint das ist genau das, was du brauchst.
Ja, stimmt schon, aber ich will jetzt nicht plötzlich wegen sowas 
umsteigen. Und es ist ja nicht so, dass das unmöglich ist zu lernen, 
wenn ich noch ein bisschen Übung habe, klappt das bestimmt, da ist doch 
ein Umstieg völlig unnörig.

> BTW: Ist dir z.B. klar dass du beim Setzen von "knoten" den letzten Teil
> (" + empfangen[3]") weglassen musst?
Ja, hab ich im meinem vorherigen Post ja geschrieben, ist verbessert...

Naja, ich will hier jetzt auch nicht wegen so was rumdiskutieren, es 
stimmt, ich bin eben noch Anfänger, und habe so etwas noch nie 
gemacht....


Gruß, Steffen

von Johannes M. (johnny-m)


Lesenswert?

Steffen O. wrote:
> Hmmm, laut meinem C- Buch kann selbst eine, als unsigned int deklarierte
> Variable eine Zahl bis 4294967295 aufnehmen
Dann hast Du ein C-Buch für ein 32-Bit-System! Kleineren Systemen ist 
(unsigned) int i.d.R. 16 Bit breit, dementsprechend sind nur 65536 
unterschiedliche Werte möglich. Ein long int hätte auf der 
AVR-Plattform 32 Bit.

> ....Ich hab ja auch noch double verwendet,
double ist ein Gleitkommaformat! Das ist was ganz anderes.

> da ist der Zahlenbereich noch größer!
Auf einem AVR hat double 32 Bit, genauso viel wie ein long int.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Johannes M. wrote:
> Steffen O. wrote:
>> Hmmm, laut meinem C- Buch kann selbst eine, als unsigned int deklarierte
>> Variable eine Zahl bis 4294967295 aufnehmen
> Dann hast Du ein C-Buch für ein 32-Bit-System!
Ja, das könnte sehr gut sein, mein Buch beschäftigt sich mit dem 
Programmieren von PCs....
> Kleineren Systemen ist
> (unsigned) int i.d.R. 16 Bit breit, dementsprechend sind nur 65536
> unterschiedliche Werte möglich.
Aber selbst da müsste ich 350 Knoten schnell sein, damit in der Zeile:
1
mh = knoten*185;
ein int nicht mehr reicht.

> Ein long int hätte auf der
> AVR-Plattform 32 Bit.
>
>> ....Ich hab ja auch noch double verwendet,
> double ist ein Gleitkommaformat! Das ist was ganz anderes.

>> da ist der Zahlenbereich noch größer!
> Auf einem AVR hat double 32 Bit, genauso viel wie ein long int.
Ah, ok...
Also muss ich es als double initialisieren, da ich ja Nachkommastellen 
benötige (bei der Umwandlung mit Bibliotheksfunktionen).

Gruß, Steffen

von Detlev T. (detlevt)


Lesenswert?

@Steffen O.
Vorschlag für einen Algorithmus:

String vom GPS einlesen.
Schleife, die den String Zeichen für Zeichen in unsigned long umwandelt:
  Test auf Dezimalpunkt: Falls nein: variable *10 + <Zeichen> - '0';
                         Falls ja: darauffolgendes Zeichen umwandeln und 
Schleife abbrechen. (Oder noch zwei Zeichen) z.B. so:
1
unsigned long kmh = 0;
2
char * p = empfangen;
3
unsigned int cnt = 10; /* maximale Stellenzahl */
4
5
while(cnt--)
6
  {
7
    if((* p) == '.') cnt = 2; /* noch zwei Stellen und Schluss */
8
      else kmh = kmh * 10 + (* p) - '0';
9
    p++; 
10
  }
(Ein Dezimalpunkt mit einer entsprechenden Anzahl Nachkommastellen muss 
garantiert vorhanden sein!)

In der Variablen kmh hast du jetzt hunderstel Knoten.
Multiplizieren mit 185. In der Variablen sind jetzt zehntausendstel 
km/h.
Durch hundert teilen. In der Variablen sind jetzt hunderstel km/h
ltoa verwenden, um die Zahl wieder in einen String zu verwandeln.
Vor den letzten beiden Stellen (strlen) einen Dezimalpunkt einfügen.
Ausgeben.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ok, dank dir für deine Hilfe!
Ich wusste jetzt nicht, ob man mit itoa immer nur ein Zeichen 
konvertieren kann, oder nicht, und deshalb siehts jetzt mal so aus:
1
unsigned char empfangen[5], ausgabearry[10];
2
unsigned long kmh = 0;
3
char * p = empfangen;
4
unsigned int cnt = 10; /* muss ich hier die genau maximale Stellenzahl     angeben, oder kann das auch ein Wert sein, der dann noch ein wenig Reserve hat? */
5
....
6
empfangen[0] = uart_getchar();  
7
empfangen[1] = uart_getchar();
8
empfangen[2] = uart_getchar();
9
empfangen[3] = uart_getchar();
10
11
empfangen[1] = empfangen[2];
12
empfangen[2] = empfangen[3];
13
14
while(cnt--)
15
  {
16
    if((* p) == '.') cnt = 2; /* noch zwei Stellen und Schluss */
17
      else kmh = kmh * 10 + (* p) - '0';
18
    p++; 
19
  }
20
21
kmh=kmh*185;
22
kmh=kmh/100;
23
itoa(kmh,ausgabearry,10);
24
lcd_string(ausgabearry);

Bis jetzt hab ich noch keinen Dezimalpunkt, das kommt noch, ist aber zum 
Überprüfen jetzt nicht notwendig.....
Ich hab dann alles so umgeschrieben, und den Mega8 geflasht. Auf dem Lcd 
kommen nun immer irgendwelche Nachkommastellenlose Werte (ist ja auch 
klar, der Punkt fehlt ja noch), die aber immer irgendwie hin- und 
herschwanken, mal im negativen Bereich, mal im positiven. Und das, 
obwohl sich mein Empfänger mit 0.00 Knoten bewegt und dies der µC auch 
empfängt! (Habe schonmal empfangen ausgegeben, und da kann dann immer 
0.00)

Woran liegt das nun?

Vielen Dank schon einmal im Voraus.
Gruß, Steffen

von Detlev T. (detlevt)


Lesenswert?

@Steffen O.
1
empfangen[1] = empfangen[2];
2
empfangen[2] = empfangen[3];
Damit überschreibst du den Dezimalpunkt. Daher werden insgesamt 10 
Zeichen gewandelt, obwohl das array nur fünf Zeichen lang ist. Was immer 
auch dahinter im Speicher steht, wird mitgewandelt. Setze cnt am Anfang 
auf die Gesamtzahl der Stellen ohne Dezimalpunkt (in diesem Fall 3)

Zudem liest das Programm nur vier Zeichen ein, was für je zwei Vor- und 
Nachkommastellen plus Dezimalpunkt ist das zuwenig. Sendet der 
GPS-Empfänger kein Zeilenende (CR oder so?)

von Jörg Stegemann (Gast)


Lesenswert?

@Detlef

Deine maximale Stellenzahl ist 11 und dafür ist 2^32 etwas knapp.

@Steffen

Das stimmt nur, wenn der Compiler vorher alles richtig macht. Zum 
Beispiel ist es ein reiner Glücksspiel, ob bei "empfangen[0]*1000" das 
Richtige heraus kommt oder nicht.

von Jörg Stegemann (Gast)


Lesenswert?

BTW:

for( int Index = 0; Index < sizeof( empfangen); Index++)
{
   if( empfangen[ Index] == '.')
      continue;

   kmh = kmh * 10 + empfangen[ Index] - '0';
}

Das basiert auf meinem Verständnis von dem, was du erreichen willst. Ich 
habe keine Ahnung, was das Inputformat wirklich ist, deswegen kann es 
sein, dass der Code nicht immer funktioniert.

von Jörg Stegemann (Gast)


Lesenswert?

Achja, noch was :) Der geneigte Leser möge Checks wie isalpha() selbst 
einfügen.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Detlev T. wrote:
> @Steffen O.
>
1
> empfangen[1] = empfangen[2];
2
> empfangen[2] = empfangen[3];
3
>
> Damit überschreibst du den Dezimalpunkt. Daher werden insgesamt 10
> Zeichen gewandelt, obwohl das array nur fünf Zeichen lang ist. Was immer
> auch dahinter im Speicher steht, wird mitgewandelt. Setze cnt am Anfang
> auf die Gesamtzahl der Stellen ohne Dezimalpunkt (in diesem Fall 3)
Ok, hab ich nicht mitgedacht, bei meiner vorherigen Auswertung hab ich 
den Deziamlpunkt nicht gebraucht, aber bei deiner Version benötige ich 
ihn ja...

> Zudem liest das Programm nur vier Zeichen ein, was für je zwei Vor- und
> Nachkommastellen plus Dezimalpunkt ist das zuwenig. Sendet der
> GPS-Empfänger kein Zeilenende (CR oder so?)
Diese vier Zeichen sind Teil einer großen Strings, den der Empfänger 
sendet. Vor der geschwindigkeit steht ein E und ein , und wenn diese 
beiden Zeichen kamen, empfängt mein Programm die nächsten vier Zeichen, 
und schreibt sie in empfangen. Wenn ich eben weniger wie 10 km/h fahre, 
hat der String nur 3 Zeichen, fahre ich jedoch weniger als 100, aber 
mehr wie 9.99, hat der String 4 Zeichen, usw. Das wird aber an anderer 
Stelle schon ausgewertet, dann muss ich eben immer vor Schleife den Wert 
von cnt anpassen.

Gruß, Steffen

von Detlev T. (detlevt)


Lesenswert?

Jörg Stegemann wrote:
> Deine maximale Stellenzahl ist 11 und dafür ist 2^32 etwas knapp.

Hat ein Moment gedauert, bis ich verstanden habe, was du meinst. cnt=10 
war nur ein Beispiel. Genau wie du kenne ich nicht das Format, das der 
GPS-Empfänger ausgibt. Allerdings bricht meine Schleife ja zusätzlich 
nach zwei Nachkommastellen ab. Bei Geschwindigkeiten unter Mach 300 gibt 
es also noch keinen Überlauf. Das sollte reichen :)

von Detlev T. (detlevt)


Lesenswert?

@Steffen O.
Auf deutsch: Du hast immer genau zwei Nachkommastellen, aber eine 
wechselnde Anzahl Stellen vor dem Komma? Prima, dann umgehe doch einfach 
dieses "empfangen" und mache es doch einfach so:
1
unsigned long kmh = 0;
2
char c;
3
char cnt = 6; /* maximal 999 Knoten, aber eigentlich unwichtig */
4
5
while(cnt--)
6
  {
7
    c = uart_getchar();
8
    if(c == '.') cnt = 2; /* noch zwei Stellen und Schluss */
9
      else kmh = kmh * 10 + c - '0';
10
  }

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ok, ich habe nun die besagten zwei Zeilen rausgenommen, die den 
Dezimalpunkt überschrieben haben, und cnt auf 3 gesetzt. Wenn ich den µC 
dann neu flashe, erscheint für kurze Zeit wirklich eine 0, dann jedoch 
kommen wieder irgendwelche Zahlen. Woran liegt das nun schon wieder?

Der Empfänger gibt die Geschwindigkeit (in Knoten) in folgendem Format 
aus: X.XX (bei einer Geschw. unter 10), XX.XX (bei einer Geschw. unter 
100, über 9.99) und XXX.XX (bei einer Geschw. über 99.9, aber unter 
500).
Bei ca. 500km/h hat der Empfänger keinen Empfang mehr, aber das benötige 
ich eh nicht, so bis 200km/h sollte allemal ausreichen.

@Jörg Stegemann: Dein Beispiel sieht auch nicht schlecht aus, werde ich 
auch mal testen....

Gruß, Steffen

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

@ Detlev T.: Genau, immer zwei Stellen nach dem Komma, aber eine 
wechselnde Anzahl (max.3) vor dem Komma (Punkt).

von Detlev T. (detlevt)


Lesenswert?

Steffen O. wrote:
> Ok, ich habe nun die besagten zwei Zeilen rausgenommen, die den
> Dezimalpunkt überschrieben haben, und cnt auf 3 gesetzt. Wenn ich den µC
> dann neu flashe, erscheint für kurze Zeit wirklich eine 0, dann jedoch
> kommen wieder irgendwelche Zahlen. Woran liegt das nun schon wieder?

Wird kmh vor jedem neuen Einlesen(!) wieder auf 0 gesetzt?

cnt=3 ist zudem falsch, wie mir gerade auffällt. Den Dezimalpunkt muss 
man doch mitzählen.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Hmm, kmh wurde nicht immer auf 0 gesetzt, hab ich jetzt nachgeholt. Hab 
das ganze jetzt mal so geschrieben:
1
unsigned long kmh = 0;
2
char c;
3
unsigned int cnt = 4; /* maximale Stellenzahl */
4
unsigned char ausgabearry[10];
5
....
6
kmh = 0;
7
while(cnt--)
8
  {
9
    c = uart_getchar();
10
    if(c == '.'){ cnt = 2; }/* noch zwei Stellen und Schluss */
11
      else {kmh = kmh * 10 + c - '0';}
12
  }
13
14
15
kmh=kmh*185;
16
kmh=kmh/100;
17
itoa(kmh,ausgabearry,10);
18
lcd_string(ausgabearry);

Auf dem LCD kommt gar nichts :-(. Stimmt da was an der itoa nicht?

Vielen Dank schon einmal im Voraus.
Gruß, Steffen

von Detlev T. (detlevt)


Lesenswert?

cnt muss natürlich auch vor jeder Wandlung auf den entsprechenden Wert 
gesetzt werden.
itoa hat doch vorher funktioniert. (Sollte dass nicht ltoa sein?) Da 
hängt wohl was. Wie ist den uart_getchar() realisiert? Möglicherweise 
dauert die Berechnung dafür zu lange. Dann musst du die Werte doch erst 
einmal in ein Array einlesen und dann erst rechnen.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Hmmm, ja, stimmt itoa hat vorhin funktioniert....
Itoa wandelt eine als int deklarierte Variable in einen String um, ob 
das eben auch bei long funktioniert?
Also ltoa wird auch ohne Murren compiliert, also werde ich es damit mal 
versuchen.
cnt wird nun auch vor jeder Wandlung auf 4 gesetzt, also das passt.

uart_getchar() ist aus der Fleury lib, also uart_getchar() wartet bis 
Zeichen da sind, dann werden auch noch Sachen wie Buffer Overflow, Frame 
Error, usw. ausgewertet. Wenn ich es nur mit uart_getc() mache, dann 
wartet er nicht, bis ein Zeichen da ist. Also eigentlich müsste das 
passen, hat ja auch schon davor so funktioniert.
Ich kann die Änderungen leider erst in 15min testen.....

Gruß, Steffen

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Also, bei der Lösung, bei der das Empfangene in c gespeichert wird, 
kommt auf dem LCD nichts an. Ich werde jetzt nochmal die alter Routine 
testen, bei der ganz normal alles empfangene in empfangen gespeichert 
wird, und dann diese Variable ausgewertet wird.

Gruß, Steffen

von Hanns W. (hannsw)


Lesenswert?

Steffen O. wrote:
> ....
> kmh = 0;
> while(cnt--)
>   {
>     c = uart_getchar();
>     if(c == '.'){ cnt = 2; }/* noch zwei Stellen und Schluss */
>       else {kmh = kmh * 10 + c - '0';}
>   }
>
Täusche ich mich, oder passiert mit den Nachkommastellen nichts?
Wenn Du den Punkt findest, sagst Du "noch zwei Stellen addieren".
Deren erste muss dann aber durch 10 geteilt werden, die zweite durch 100 
etc!
1
kmh = 0;
2
nachKomma = false;
3
teiler = 1;
4
while(cnt--)   {
5
     c = uart_getchar();
6
     if(c == '.'){ 
7
          cnt = 2; /* noch zwei Stellen und Schluss */
8
          nachkomma = true;
9
}
10
     else {
11
          kmh = kmh * 10 + ( c - '0') / 10 ^(teiler++);
12
     }
13
   }

Und mit welchem cnt-Wert gehst Du in die while.loop?
Und wenn kein dezimal-Punkt kommt?

Gruß Hanns

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Hallo,
wenn die Geschwindigkeit in Knoten 4 Stellen mit Dezimalpunkt hat 
(X.XX), dann gehe ich mit cnt = 4 in die Schleife. Wenn sie 5 Stellen 
hat (XX.XX), dann eben mit cnt = 5.
Ein Dezimalpunkt kommt immer, da der Empfänger die Geschwingigkeit immer 
mit zwei Nachkommastellen ausgibt.
Du könntest Recht haben mit dem Teilen, ich werde das mal testen - Danke 
für den Tip!

Gruß, Steffen

von Hanns W. (hannsw)


Lesenswert?

Steffen O. wrote:
> Hallo,
> wenn die Geschwindigkeit in Knoten 4 Stellen mit Dezimalpunkt hat
> (X.XX), dann gehe ich mit cnt = 4 in die Schleife. Wenn sie 5 Stellen
> hat (XX.XX), dann eben mit cnt = 5.

Das bedeutet aber, daß den Wert als String bereits kennst, bevor Du 
einzelne
char umwandelst! DAnn kannst Du das ganze doch von hinten aufrollen:
Ganz rechts stehen die Hunderstel, davor die 10tel, dann komma, dann 
mindestens ein Einer, und manchmal ein Zehner! Oder?

> Ein Dezimalpunkt kommt immer, da der Empfänger die Geschwingigkeit immer
> mit zwei Nachkommastellen ausgibt.
> Du könntest Recht haben mit dem Teilen, ich werde das mal testen - Danke
> für den Tip!
  Idh denke, damit habe ich Recht, denn nach dem Komma kommen immer die 
10tel, dann 100tel i.e.   n / (10 hoch PositionNachDemKomma )
> Gruß, Steffen
Ebenso Hanns

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Hanns Weil wrote:
> Steffen O. wrote:
>> Hallo,
>> wenn die Geschwindigkeit in Knoten 4 Stellen mit Dezimalpunkt hat
>> (X.XX), dann gehe ich mit cnt = 4 in die Schleife. Wenn sie 5 Stellen
>> hat (XX.XX), dann eben mit cnt = 5.
>
> Das bedeutet aber, daß den Wert als String bereits kennst, bevor Du
> einzelne
> char umwandelst! DAnn kannst Du das ganze doch von hinten aufrollen:
> Ganz rechts stehen die Hunderstel, davor die 10tel, dann komma, dann
> mindestens ein Einer, und manchmal ein Zehner! Oder?

Ja, genau so ist es: Hundertstel, Zehntel, Dezimalpunkt, mindestens ein 
Einer, machmal noch ein Zehner, und manchmal auch ein Hunderter. Ich 
weiß davor, wie viel Stellen der String hat....


>> Ein Dezimalpunkt kommt immer, da der Empfänger die Geschwingigkeit immer
>> mit zwei Nachkommastellen ausgibt.
>> Du könntest Recht haben mit dem Teilen, ich werde das mal testen - Danke
>> für den Tip!
>  Idh denke, damit habe ich Recht, denn nach dem Komma kommen immer die
>  10tel, dann 100tel i.e.   n / (10 hoch PositionNachDemKomma )
Ja, das müsste eigentlich stimmen....
Eine Potenz schreibe ich in c doch so: Grundzahl^Hochzahl

Gruß, Steffen

von Matthias L. (Gast)


Lesenswert?

>Eine Potenz schreibe ich in c doch so: Grundzahl^Hochzahl

NEin.

Das ^ bedeutet in C xor.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Matthias Lipinsky wrote:
>>Eine Potenz schreibe ich in c doch so: Grundzahl^Hochzahl
>
> NEin.
>
> Das ^ bedeutet in C xor.

Ah, ok. Wie schreibe ich es dann?

von Matthias L. (Gast)


Lesenswert?


von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Hmmm, dann schreibe ich eben zur Übung eine kleine Potenzfunktion ;-)

von Hanns W. (hannsw)


Lesenswert?

Steffen O. wrote:
> Hmmm, dann schreibe ich eben zur Übung eine kleine Potenzfunktion ;-)

Ich würde mir meine Function nochmals überlegen:

- Ich hab die "Zahl" als String
- den will ich wandeln
- das mach ich in einer subroutine
- dort lese ich mit uart_getch() nochmals Zeichen ein, die ich alle 
schon habe?!
- Warum übergebe ich dann der Function nicht den bereits vorhanden 
string, und arbeite den ab?
- Da kannst DU dann von vorn oder hinten beginnen, den String zu 
verarbeiten.

-beginne ich von hinten, weiß ich VOR dem Komma IMMER, mit welchen 
FActor die einzelnen Zahl zu multiplizieren ist.
in etwas so. Wobei ich mal davon ausgehe, es handelt sich tatsächlich 
umne funktion )
1
double wandle_String_in_Double ( string theString ){
2
3
   double theReturn;
4
   int len;
5
   boolean nachkomma;
6
   int nPow;                    // Exponent zu 10
7
8
   theReturn = 0.00; 
9
   len = Laenge ( theString )
10
   nachkomma = true;
11
   nPow = 2;                   // beginne mit zweiter NAchkommastelle
12
13
   while ( nLaenge--) {
14
     wenn ( DezimalPunkt ) {
15
          nachkomma = false;
16
          nPow = 1;             // vorbereiten für Multiplikation
17
          continue;            // weiß, dass das nichtbeliebt ist
18
     }
19
     wandle den Buchstaben an Pos len in Int;
20
     wenn nachkomma, {
21
          teile durch 10 Hoch nPow;
22
          nPow --;
23
     }else {                  //Vorkommastellen
24
         multipliziere mit 10 hoch nPow;
25
         nPow++ ;
26
     }
27
     addier zu theReturn
28
    }
29
30
return theReturn;
31
}

so in etwa als Anregung
Hanns

von Detlev T. (detlevt)


Lesenswert?

@Hans Weil
1
kmh = kmh * 10 + ( c - '0') / 10 ^(teiler++);
Das kann nicht stimmen. Warum das eine mit 10 multiplizieren UND das 
andere noch dividieren? Bei dem zweiten Term kommt übrigens immer null 
heraus, da c-'0' eine Zahl zwischen 0 und 9 sein soll.

Meine Idee war es die long int Variable kmh als hunderstel(!) mph zu 
interpretieren und entsprechend damit zu rechnen, also faktisch als 
Fixkomma Zahl, die es nativ in C aber nicht gibt. Alternativ könnte man 
mit Fließkommazahlen arbeiten, was allerdings dem Wunsch von Steffen 
nach einer schnellen Verarbeitung entgegenläuft. Dann braucht man aber 
keine eigene Wandelroutine, sondern kann gleich die 
Bibliotheksfunktionen (atof, strtof) nehmen.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Vielen Dank erstmal an alle für eure Unterstützung!!!!

Hanns Weil wrote:
> Steffen O. wrote:
>> Hmmm, dann schreibe ich eben zur Übung eine kleine Potenzfunktion ;-)
>
> Ich würde mir meine Function nochmals überlegen:
>
> - Ich hab die "Zahl" als String
> - den will ich wandeln
> - das mach ich in einer subroutine
> - dort lese ich mit uart_getch() nochmals Zeichen ein, die ich alle
> schon habe?!

Ich lese keine Zeichen nochmal ein. Die Geschwindigkeit in Knoten wird 
vom GPS- Empfänger per UART empfangen, und anschliessend als String 
gespeichert. Und nun muss diese Zahl im String umgewandelt werden.

> - Warum übergebe ich dann der Function nicht den bereits vorhanden
> string, und arbeite den ab?

So will ich es doch machen.....

> - Da kannst DU dann von vorn oder hinten beginnen, den String zu
> verarbeiten.

Ja, genau.

> -beginne ich von hinten, weiß ich VOR dem Komma IMMER, mit welchen
> FActor die einzelnen Zahl zu multiplizieren ist.
> in etwas so. Wobei ich mal davon ausgehe, es handelt sich tatsächlich
> umne funktion )

 Es ist doch eigentlich egal, ob ich von vorne, oder von hinten beginne, 
da ich ja schon davor weiß, wie viel Zeichen vor_ und wie viele _nach 
dem Dezimalpunkt sind.

>
1
> 
2
> double wandle_String_in_Double ( string theString ){
3
> 
4
>    double theReturn;
5
>    int len;
6
>    boolean nachkomma;
7
>    int nPow;                    // Exponent zu 10
8
> 
9
>    theReturn = 0.00;
10
>    len = Laenge ( theString )
11
>    nachkomma = true;
12
>    nPow = 2;                   // beginne mit zweiter NAchkommastelle
13
> 
14
>    while ( nLaenge--) {
15
>      wenn ( DezimalPunkt ) {
16
>           nachkomma = false;
17
>           nPow = 1;             // vorbereiten für Multiplikation
18
>           continue;            // weiß, dass das nichtbeliebt ist
19
>      }
20
>      wandle den Buchstaben an Pos len in Int;
21
>      wenn nachkomma, {
22
>           teile durch 10 Hoch nPow;
23
>           nPow --;
24
>      }else {                  //Vorkommastellen
25
>          multipliziere mit 10 hoch nPow;
26
>          nPow++ ;
27
>      }
28
>      addier zu theReturn
29
>     }
30
> 
31
> return theReturn;
32
> }
33
>

Ja, das sieht schon nicht schlecht aus!
Ich werde es dann heute oder morgen mal coden, muss eben schauen, wann 
ich mal ein wenig Zeit finde.


Die Funktion zum Potenzieren hab ich übrigends spaßeshalber mal 
geschrieben, klappt wunderbar....

Gruß, Steffen

von Detlev T. (detlevt)


Lesenswert?

@Steffen O.
Wenn du dich also jetzt entschlossen hast, doch Fließkommazahlen zu 
verwenden, warum benutzt du nicht einfach die Funktion strtod? Oder 
erfindest du gern das Rad neu?

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Detlev T. wrote:
> @Steffen O.
> Wenn du dich also jetzt entschlossen hast, doch Fließkommazahlen zu
> verwenden, warum benutzt du nicht einfach die Funktion strtod? Oder
> erfindest du gern das Rad neu?

Nein, ich wollte eigentlich nicht mit Fließkommazahlen arbeiten. Mit dem 
"Das sieht doch gut aus" meinte ich nicht den kompletten Ausschnitt, 
sondern Teile daraus, die ich so übernehmen kann....

Sorry, für die Missverständnisse.

Gruß, Steffen

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.