Forum: Mikrocontroller und Digitale Elektronik Datentypen/ Ascii Problem


von easy-breazy (Gast)


Lesenswert?

hallo,
ich habe folgenden Code:

********************************************
void loop() {
  int farbe;

  if(Serial.available()>0){
    farbe=Serial.read();
    Serial.println(farbe,DEC);
    }

  if(farbe==49){
    digitalWrite(2,HIGH);
    }
********************************************

Wenn ich nun z.b. die 1 eingebe, kommt wird beim seriellen Monitor die 
49 angezeigt, wegen Ascii.
Wie mache ich es nun aber, dass er mir auch wirklich eine 1 anzeigt? 
Integer ist doch eigentlich der richtige Datentyp.

von Samuel C. (dragonsam)


Lesenswert?

Stell den "seriellen Monitor" auf ASCII um.

Noch ein Tipp:
49='1'

von easy-breazy (Gast)


Lesenswert?

habe gerade gesucht, aber leider nichts gefunden.

Kannst du mir erklären wie ich das umstell?

PS: hab einen arduino uno

von Karl H. (kbuchegg)


Lesenswert?

easy-breazy schrieb:

> Wenn ich nun z.b. die 1 eingebe

Du gibst aber nicht 1 ein. Du drückst die Taste, auf der '1' steht. Das 
ist eine Taste, wie jede andere auch, wie zb die Taste, auf der 'A' 
steht.
Nur weil dein Gehirn bei den Tasten mit den Ziffern automatisch eine 
Zahl daraus macht, heisst das nicht, dass das eine wäre! Eine '1' ist 
genauso ein "Buchstabe", wie es auch ein 'B' oder ein '#' ist. Jeder 
"Buchstabe" hat einen Code (den ASCII Code) und der wird versendet, wenn 
die Taste gedrückt wird.

> kommt wird beim seriellen Monitor die
> 49 angezeigt, wegen Ascii.

ganz genau.

> Wie mache ich es nun aber, dass er mir auch wirklich eine 1 anzeigt?
> Integer ist doch eigentlich der richtige Datentyp.

Das hilft dir nut nicht viel. Denn wenn du auf die Taste 'A' drückst, 
dann wird der Code 97 versendet. Und das ist ja wohl auch ein Integer.

(Langer Rede kurzer Sinn: in einem Computer ist alles eine Zahl. Ein 
Computer kann nur mit Zahlen operieren und mit sonst nichts anderem. 
Aber man kann natürlich für bestimmte Zahlen eine Bedeutung vereinbaren. 
Wie zb beim ASCII Code, der für Zahlenwert "Buchstaben" definiert, für 
die diese Zahlen jeweils stehen sollen).

Aber: Da dein Computer ja mit Zahlen umgehen kann, kann er natürlich 
damit rechnen oder aber auch Vergleiche damit anstellen
1
  if( Serial.available() > 0 ) {
2
    char nextCharacter = Serial.read();
3
    if( nextCharacter >= '0' && nextCharacter <= '9' ) {
4
      farbe = nextCharacter - '0';
5
      Serial.println( farbe, DEC );
6
    }
7
  }
8
9
  if( farbe == 1 )
10
    digitalWrite( 2, HIGH );
11
  else
12
    digitalWrite( 2, LOW );

von Samuel C. (dragonsam)


Lesenswert?

Andere Möglichkeit: Benutze nicht println sondern write, das schickt das 
reine Byte. println wandelt deine 49 in "49" um.

von Karl H. (kbuchegg)


Lesenswert?

PS: wenn du in deinem Programm '0' schreibst, dann ist das auch nichts 
anderes als eine Zahlenangabe. Der Compiler ersetzt '0' durch die 
entsprechende Code Zahl aus dem ASCII Code.

Ob du
1
  char c;
2
3
  c = '0';
4
  c = 48;
5
  c = 0x30;

schreibst, kommt alles aufs selbe raus. In die Variable c (die 1 Byte 
gross ist), wird das Bitmuster 0011 0000 gespeichert. Alle Anweisungen 
sind in diesem Sinne gleichwertig. Es sind nur unterschiedliche 
Schreibweisen für immer dasselbe Bitmuster. Und je nach Zusammenhang 
benutzt man dann die Schreibweise, die das gewollte am klarsten 
ausdrückt. Da ich hier
1
      farbe = nextCharacter - '0';
aus dem 'Buchstaben' (zb) '5' die Zahl 5 machen will, muss ich den ASCII 
Code für '0' abziehen. Der ASCII Code für '5' wäre 53, der ASCII Code 
für '0' wäre 48 und 53 - 48 ergibt die gewollten 5 (als Zahlenwert). Da 
mich aber der ASCII Code für '0' überhaupt nicht interessiert und ich 
mir den auch nicht merken will, schreibe ich nicht
1
      farbe = nextCharacter - 48;

sondern statt dessen eben
1
      farbe = nextCharacter - '0';
und der Compiler setzt den korrekten ASCII Code für mich ein. Zudem ist 
durch diese Schreibweise auch klarer, worum es hier geht. Bei den 48 
würde ich mich sofort fragen: Warum 48? Wo kommen die her?
So aber, durch die Verwendung von '0' ist sofort klar, was hier das Ziel 
der Übung ist.

von easy-breazy (Gast)


Lesenswert?

@KarlHeinz, dass mit der Ascii-Tabelle und dass jede Taste einen 
bestimmten Wert hat, habe ich eigentlich verstanden.

Allerdings bin ich es gewohnt in der Konsole zu programmieren und habe 
deshalb gerade das ganze nochmal in Visual Studio ausprobiert.

+++++++++++++++++++++++++++++++++++++++
int farbe=0;
scanf("%d", &farbe);
printf("farbe:%d\n", farbe);
+++++++++++++++++++++++++++++++++++++++

dieser Code ist ja vergleichbar zu dem von meinem arduino, allerdings 
gibt mir die Konsole nun auch eine 3 aus, wenn ich eine 3 eingebe.
Die Konsole würde mir bei einer 1 ja nur eine 49 geben, wenn ich als 
Datentyp char ausgewählt hätte.

von Karl H. (kbuchegg)


Lesenswert?

easy-breazy schrieb:

> dieser Code ist ja vergleichbar

Irrtum.
Nein er ist nicht vergleichbar.

scanf macht schon die ganze Wandlung, die du am Arduino selbst machen 
musst. Oder warum denkst du, musst du scanf das %d in der 
Formatieranweisung angeben?

Wenn überhaupt, dann wäre das hier vergleichbar
1
int farbe=0;
2
scanf("%c", &farbe);
3
printf("farbe:%d\n", farbe);

das entspricht noch am ehesten einem Serial.read

Aber eigentlich ist die noch bessere Übereinstimmung nicht der scanf, 
sondern der getc()

von c-hater (Gast)


Lesenswert?

easy-breazy schrieb:

> Wenn ich nun z.b. die 1 eingebe, kommt wird beim seriellen Monitor die
> 49 angezeigt, wegen Ascii.

Und genau das ist dann auch, was tatsächlich gesendet wird.

> Wie mache ich es nun aber, dass er mir auch wirklich eine 1 anzeigt?

Du bist ein Idiot, weil du nichtmal erkennst, was du eigentlich willst. 
Du willst nicht, daß dir der "Monitor" (was auch immer das sein mag, 
vermutlich irgendein Terminalprogramm) eine "1" (ASCII) anzeigt, du 
willst vielmehr, daß es eine binäre 1 sendet. Was auch immer es für für 
dieses sog. "nichtdruckbare" Zeichen (bzw. Steuerzeichen) auch anzeigen 
mag...

Ja, fuck, das hängt einfach vom verwendeten Terminalprogramm ab und ggf. 
der von diesem Programm aktuell verwendeten "Terminalemulation".

D.h.: Bevor du uns nicht mitteilst, wie dein Teminalprogramm heißt und 
welche Terminalemulation du verwendest, kann dir niemand wirklich 
weiter helfen...

von easy-breazy (Gast)


Lesenswert?

Stimmt hast Recht. Kann man also sagen Serial.read liest immer ein char 
ein?

Noch ein weiteres Problem:

++++++++++++++++++++++++++++++
switch(farbe){
    case 49: digitalWrite(2,HIGH);
             digitalWrite(3,LOW);
             digitalWrite(4,LOW);
             break;
    case 50: digitalWrite(2,LOW);
             digitalWrite(3,HIGH);
             digitalWrite(4,LOW);
             break;
     case 51: digitalWrite(2,LOW);
              digitalWrite(3,LOW);
              digitalWrite(4,HIGH);
              break;
     default: digitalWrite(2,LOW);
              digitalWrite(3,LOW);
              digitalWrite(4,LOW);
    }
++++++++++++++++++++++++++++++

Wenn man keine der 3 möglichen Zahlen eingibt, sollen alle Leds 
ausgehen.
Allerdings macht mir hier das default Probleme(ohne dies funktionierts). 
Wenn ich jetzt z.B. eine 1 eingebe, dass leuchtet led1 nur kurz auf und 
geht direkt wieder aus.
Gibt es bei switch case beziehungsweise bei default einen Unterschied 
zur Konsole? Sobald ich in cas 49 reingehe, sollte es ja garnicht mehr 
in default reingehen.

von easy-breazy (Gast)


Lesenswert?

@c-hater
Es gibt auch Leute, die einfach eine "schöne Ausgabe" haben wollen und 
da nicht irgendwelche hohen Zahlen haben will, mit denen nicht jeder was 
anfangen kann. Außerdem ist es eine Übung und da versucht man halt ein 
bisschen zu probieren.

von Karl H. (kbuchegg)


Lesenswert?

easy-breazy schrieb:
> Stimmt hast Recht. Kann man also sagen Serial.read liest immer ein char
> ein?

Weisst du, was mich an den Arduino Programmierern am meisten nervt?
Dass sie nicht in der Lage sind, ganz einfach mal die Doku zu lesen.

http://arduino.cc/en/Serial/read

> Allerdings macht mir hier das default Probleme(ohne dies funktionierts).
> Wenn ich jetzt z.B. eine 1 eingebe, dass leuchtet led1 nur kurz auf und
> geht direkt wieder aus.

Ganzes Programm.

> Gibt es bei switch case beziehungsweise bei default einen Unterschied
> zur Konsole?
Nein

Whrscheinlich hast du nur übersehen, dass du farbe nur dann ändern 
darfst, wenn auch wirklich ein Byte über die Schnittstelle reingekommen 
ist.

> Sobald ich in cas 49 reingehe, sollte es ja garnicht mehr
> in default reingehen.

Tja.
Was tippst du denn sonst noch so für Tasten auf deiner Tastatur. Merke: 
Auch ein 'Return' ist einfach nur eine Taste mit einem Code, der 
versendet wird, wenn du die Taste drückst. Wenn du nicht haben willst, 
dass dein Programm darauf reagiert, dann musst du das entsprechend 
programmieren!

von Karl H. (kbuchegg)


Lesenswert?

Und noch ein Tip:
Gerade am Anfang ist es oft eine gute Idee, wenn du dein Programm so 
schreibst, dass es dir mitteilt was es getan hat oder was es von der 
Schnittstelle bekommen hat.
1
...
2
  if( Serial.available() > 0 ) {
3
    char nextCharacter = Serial.read();
4
5
    Serial.print( "Nächstes Zeichen: (0x" );
6
    Serial.print( (int)nextChar, HEX );
7
    Serial.print( ")"
8
    Serial.println( nextChar );
9
10
    if( nextCharacter >= '0' && nextCharacter <= '9' ) {
11
      farbe = nextCharacter - '0';
12
      Serial.println( farbe, DEC );
13
    }
14
  }

Du hast ein Terminal zur Verfügung um dort Ausgaben machen zu können. 
Benutze es!

von easy-breazy (Gast)


Lesenswert?

Danke für eure Hilfe.

Wenn ich dies nun aber nicht mit Zahlen lösen möchte sondern mit "text", 
wie funktioniert dies? Wenn ich red eingebe soll die rote led leuchten.

Ich weiß aber nicht, wie ich z.B. red einlesen lassen kann.

von Karl H. (kbuchegg)


Lesenswert?

easy-breazy schrieb:
> Danke für eure Hilfe.
>
> Wenn ich dies nun aber nicht mit Zahlen lösen möchte sondern mit "text",
> wie funktioniert dies? Wenn ich red eingebe soll die rote led leuchten.
>
> Ich weiß aber nicht, wie ich z.B. red einlesen lassen kann.
1
'r' 'e' 'd' '\n'
2
             ^
3
             |
4
            Return deswegen, damit dein Programm erkennen kann
5
            wann deine Eingabe fertig ist. Du könntest ja auch
6
            das Wort redundant tippen.
4 Tastendrücke. 4 character die aus der Seriellen SChnittstelle 
rauskommen.
In einem String (zb in einem char-Array) sammeln und wenn der \n 
angekommen ist, weisst du, dass der String vollständig ist. und dann 
ganz normale Stringauswertung. So wie du das auf deinem Desktopsystem 
auch machen würdest. strcmp lässt grüßen.


Du denkst ein bischen zu viel Desktop!
Hier ist alles viel simpler. 1 Tastendruck ergibt ein Zeichen, dass auf 
Arduino Seite aus der Seriellen rauspurzelt. Darauf aufbauend musst du 
den Rest selber machen. Wie zb. solange Zeichen sammeln, bis du weisst, 
dass eine Zeile fertig übertragen wurde, und dann mit dem gesammelten 
etwas machen. Das was der scanf erledigt, musst du hier selber machen.
1
char    Input[40];
2
uint8_t InputCnt;
3
....
4
5
void loop()
6
{
7
  if( Serial.available() > 0 ) {
8
    char nextCharacter = Serial.read();
9
10
    if( nextChar == '\r' )
11
      ; // simply ignore it
12
13
    else if( nextChar != '\n' && InputCnt < 39 )
14
      Input[InputCnt++] = c;
15
16
    else {
17
      Input[InputCnt] = '\0';
18
      InputCnt = 0;
19
20
      Serial.print( "You typed: '" );
21
      Serial.print( Input );
22
      Serial.println( "'" );
23
24
      if( strcmp( Input, "red" ) == 0 ) {
25
        Serial.println( "** Turning on red light" );
26
        digitalWrite( 2, HIGH );
27
      }
28
29
      else if( strcmp( Input, "off" ) == 0 ) {
30
        Serial.println( "** Turning off everything" );
31
        digitalWrite( 2, LOW );
32
      }
33
34
      else {
35
        Serial.println( ">> Please type a command!" );
36
        Serial.println( ">>    red    turns red light on" );
37
        Serial.println( ">>    off    turns all lights off" );
38
      }
39
    }
40
  }
41
42
  .... restliche Programmlogik, die auch dann weiterlaufen soll
43
  .... wenn der langsame Benutzer Tasten drückt.
44
}

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.