Forum: Mikrocontroller und Digitale Elektronik Wandlung von einem char (Dezimalzahl) in Integer


von Dirk Meyer (Gast)


Lesenswert?

Hallo,

mache gerade meine ersten Gehversuche mit einem Atmel und dem Microchip 
Studio. Habe einen ATMega88 per serieller Schnittstelle und USB Wandler 
am PC hängen und möchte darüber mit dem uC "sprechen", also Befehle 
übermitteln. Nutze dafür die Lib von Andy Gock 
(<https://github.com/andygock/avr-uart>;) und das klappt auch soweit ganz 
gut.
Hänge allerdings an einer Typumwandlung, bzw. stehe da auf dem 
Schlauch... Ich würde gerne ein char in einen int umwandlen mit Hilfe 
der atoi funktion, aber daran scheitere ich immer. Folgendes Konstrukt 
habe ich (könnt auch alles haben, aber sind sind zig Seiten Code):
1
char str[16];
2
// Zaehler der die Laenge des aktuell empfangenen Kommandos vom USART enthaelt
3
unsigned char command_count;
4
// Puffer fuer einen Befehl der ueber die USART Schnittstelle empfangen wird anlegen
5
unsigned char command_from_uart[MAX_UART_CMD_LENGTH];
6
// LED(Nr.) auf den sich das aktuelle Kommando bezieht
7
int cmd_led;
8
9
while-Schleife/main
10
{
11
// lese ein Zeichen ein
12
c = uart_getc();
13
// speichere das aktuell empfangene Zeichen ab und haenge es an das Ende des empfangenen Strings/Kommandos an
14
command_from_uart[command_count] = c;
15
// pruefe ob ein ENTER empfangen wurde oder die max. erlaubte Laenge erreicht wurde
16
if ((command_from_uart[command_count] == CHAR_NEWLINE) || (command_count == MAX_UART_CMD_LENGTH))
17
{
18
// Kommandos und Rueckgaben sind wie folgt aufgebaut:
19
//    $LxP=y     "Power"-Kommando um die LED x [1...4] entweder aus (y=0) oder an (y=1) zu schalten
20
//    $LxD=zzz   "duty-cycle"-Kommando um fuer LED x [1...4] den duty cycle auf zzz [0...100] Prozent zu setzen
21
// teste ob der Beginn fuer ein gueltiges Kommando empfangen wurde
22
if ((command_from_uart[0] == '$') && (command_from_uart[1] == 'L'))
23
{
24
  // teste ob das "Power"-Kommando empfangen wurde
25
  if ((command_from_uart[3] == 'P') && (command_from_uart[4] == '='))
26
  {
27
    // Debugging
28
    uart_puts("cmd:");
29
    uart_puts(command_from_uart);
30
    uart_puts("\r\n");
31
32
    // waehle die LED aus
33
    cmd_led = atoi(command_from_uart[2]);
34
35
    // Debugging
36
    itoa (cmd_led, str, 10);
37
    uart_puts("str1:");
38
    uart_puts(str);
39
    uart_puts("\r\n");
40
  }
41
}
42
}
Wenn ich nun via hterm (oder auch putty) die Zeichen
1
$L3P=1\n
eingebe, so erhalte ich die folgende Ausgabe:
1
cmd:$L3P=1<\n><\r><\n>
2
str1:0<\r><\n>
3
63 6D 64 3A 24 4C 33 50 3D 31 0A 0D 0A 73 74 72 31 3A 30 0D 0A
Frage ich innerhalb des Codes die Variable cmd_led ab, so schlägt ein 
Vergleich auf 3 fehl. Prüfe ich command_from_uart[2] auf '3', so ist das 
erfolgreich. Da ich später aber gerne auch benachbarte LEDs schalten 
möchte, würde ich gerne einen int haben (um einfach cmd_led++ o.ä. 
nutzen zu können und nicht mit chars hantieren zu müssen). Hätte aber 
gedacht, dass die atoi Funktion mir den char 0x33 (also die '3') in 
einen 0x03 (also 3) umwandelt. Wo ist mein Denkfehler, bzw. wie macht 
man es richtig? Könnte auch "einfach" von command_from_uart[2] immer 
0x30 abziehen und hätte dann meinen Zahlenwert, aber das würde weniger 
Fehler abfangen (also wenn da Buchstaben stehen würden o.ä.). Von daher 
würde mich interessieren warum atoi so nicht funktioniert.

Danke und Gruß, Dirk

von Rolf M. (rmagnus)


Lesenswert?

Dirk Meyer schrieb:
> Hänge allerdings an einer Typumwandlung, bzw. stehe da auf dem
> Schlauch... Ich würde gerne ein char in einen int umwandlen mit Hilfe der
> atoi funktion, aber daran scheitere ich immer.

Mit atoi kann man kein einzelnes Zeichen in einen int wandeln, sondern 
nur einen ganzen String.

> cmd_led = atoi(command_from_uart[2]);

Das kann so nicht klappen, denn atoi erwartet einen Zeiger auf einen 
nullterminierten String. Du übergibst aber einen char, der dann als 
Zeiger interpretiert wird. Wenn dein Compiler dir dazu keine Warnung 
ausgibt, solltest du die Warnungs-Einstellungen hochschrauben.

Dirk Meyer schrieb:
> Könnte auch "einfach" von command_from_uart[2] immer
> 0x30 abziehen

Besser: '0'.

> und hätte dann meinen Zahlenwert, aber das würde weniger
> Fehler abfangen (also wenn da Buchstaben stehen würden o.ä.).

Warum nicht einfach vorher abfangen? (if (!isdigit(command_from_uart[2]) 
/* fehler */ ). atoi bietet übrigens auch keine Möglichkeit, einen 
Fehler zu erkennen.

von Dirk Meyer (Gast)


Lesenswert?

Hallo Rolf,

danke dir für die Hilfe. Dachte atoi fügt hier automatisch ein \0 an um 
aus dem char einen nullterminierten String zu machen.
Werde mir dann wohl selber etwas bauen: 0x30 bzw. '0' abziehen und dann 
schauen ob das Ergbnis zw. 0 und 9 ist.

Gruß, Dirk

von Peter D. (peda)


Lesenswert?

Dirk Meyer schrieb:
> Dachte atoi fügt hier automatisch ein \0 an

"atoi" macht genau das, was in der Doku dazu geschrieben steht und nicht 
mehr.

In bestimmten Fällen fügt der Compiler an vorinitialisierte Strings ein 
\0 an.

"Dachte" ist beim Programmieren immer ein schlechter Ratgeber.
"Wissen" oder "Doku lesen" ist der richtige Weg.

von Dirk Meyer (Gast)


Lesenswert?

Peter D. schrieb:
> "Dachte" ist beim Programmieren immer ein schlechter Ratgeber.
> "Wissen" oder "Doku lesen" ist der richtige Weg.

Hallo Peter,

da arbeite ich dran, also am "Wissen". Und nein, der Fehler passiert mir 
nicht noch einmal...
Hatte mich immer nur an Beispielen orientiert und weniger auf die Doku 
gestürzt, da wurden teilweise auch chars übergeben. Das dies als Zeiger 
aufgefasst wird: tja, verloren...

Gruß, Dirk

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.