Forum: Mikrocontroller und Digitale Elektronik Empfangene Daten in Ascii bzw in Dez bzw in Hex umwandeln


von Markus (Gast)


Lesenswert?

HI Leute,

ich bin ein absoluter Arduino Anfänger und bräuchte jetzt eure Hilfe. 
Mit C, habe ich ein bisschen im laufe meines Studiums programmiert, aber 
ist schon etwas her.

Ich habe 2 Arduino UNO mit 2 Funkmodule, damit möchte ich von einem zum 
anderen Daten schicken. Der Empfänger soll diese Daten dann als Dez oder 
ASCII, und Hex und Binär ausgeben.
Erst einmal nur von Dez in ASCII oder umgekehrt.

Beispiel: Empfangen wurde 65
Ausgabe:
65
ASCII Code: A

Ich habe schon einiges ausprobiert.

Ich habe versucht, die Daten in int umzuwandeln, das habe ich nicht ganz 
hinbekommen.

Ich habe auch versucht, jede Möglichkeit von Dez in ASCII umzuwandeln 
mit entsprechende if Anweisung, das ist aufwendig und hat nicht 
geklappt.
Wenn ich z.b. 11 empfangen habe, gibt der mir den ASCII von 1 raus.

Ich weiß nicht mehr weiter und ich hoffe, ihr könnt mir weiter helfen.

Vielen Dank schon mal im voraus.



Sketch des Empfängers
1
#include <SPI.h>
2
3
#include "RF24.h"
4
5
#include <stdio.h> 
6
7
#include <stdlib.h>
8
9
10
int ledR = 4;
11
12
int ledG = 2;
13
14
RF24 radio(9, 10);
15
16
const uint64_t pipes[2] = {
17
18
0xF0F0F0F000LL, 0xF0F0F0F0FFLL};// Adressen der Empfangs-und Sendekanäle
19
20
21
22
void setup(){
23
24
Serial.begin(9600);
25
26
radio.begin();
27
28
radio.setDataRate(RF24_250KBPS); // Übertragungsrate
29
30
radio.setChannel(100); // Kanalnummer von 0 bis 127
31
32
radio.setRetries(15,15); // Anzahl der Versuche und die Zeit zwischen den Versuchen
33
34
radio.openWritingPipe(pipes[1]); // Offene Kanal
35
36
radio.openReadingPipe(1, pipes[0]); // Öffnen Sie eine der 6-Kanal-Empfang
37
38
radio.startListening(); // Beginnen Sie zu hören
39
40
pinMode(ledR, OUTPUT);
41
42
pinMode(ledG, OUTPUT);
43
44
45
}
46
47
void loop(){
48
49
if(Serial.available()){
50
51
char data[32] = "";
52
53
54
55
byte i = 0;
56
57
while(Serial.available()){
58
59
data[i] = Serial.read(); //erhalten Daten von der seriellen.
60
61
i++;
62
63
delay(2);
64
65
}
66
67
data[i] = 0;
68
69
radio.stopListening();
70
71
radio.write(&data, 32); //und senden sie an Arduino № 2
72
73
radio.startListening();
74
75
}
76
77
if(radio.available()){
78
79
char data[32] = "";
80
81
82
//int ascii=data[32]; ein versuch es umzuwandeln
83
84
85
digitalWrite(ledG, HIGH); 
86
delay(150);
87
digitalWrite(ledG, LOW);
88
89
90
radio.read(&data, 32); //zurück, ein Paket von Arduino № 2 akzeptieren
91
92
Serial.println(data); // und geben es zurück zur Show
93
94
95
if (data[0] == '0') 
96
{
97
  Serial.println("ASCII Code  dazu ist "); 
98
  Serial.println("NUL");
99
  }
100
101
102
if (data[0] == '1' ) 
103
{
104
  Serial.println("ASCII Code  dazu ist "); 
105
  Serial.println("SOH");
106
  }
107
108
if (data[0] == '11') 
109
{
110
  Serial.println("ASCII Code  dazu ist "); 
111
  Serial.println("VT");
112
  }
113
114
115
116
}
117
118
119
120
}

: Bearbeitet durch User
von innerand i. (innerand)


Lesenswert?

Das Terminal interpretiert von der Seriellen kommenden Daten 
grundsätzlich als ASCII, dafür braucht man also überhaupt nichts 
umwandeln.

Für den Rest siehe: http://arduino.cc/en/Serial/Println

von Maxx (Gast)


Lesenswert?

Markus schrieb:
> if (data[0] == '0')
> {
>   Serial.println("ASCII Code  dazu ist ");
>   Serial.println("NUL");
>   }
>

Nein. '0' == 48 == 0x30 != 0

> if (data[0] == '1' )
> {
>   Serial.println("ASCII Code  dazu ist ");
>   Serial.println("SOH");
>   }

Nein. '1' == 49 == 0x31 != 1

> if (data[0] == '11')
> {
>   Serial.println("ASCII Code  dazu ist ");
>   Serial.println("VT");
>   }

Nein '11' = 0x3131 (Endianess sensitiv, wenn nicht gerade beide chars 
identisch wären!) und vom Typ her NICHT char (Es braucht sogar 2 chars 
um "reinzupassen") Jedoch data[0] vom Typ char ist. (data[0] == '11') 
ist daher immer false.



Du hast den Unterschied zwischen der Darstellung und dem Wert noch nicht 
verstanden. Besorge dir ein C Buch.


Char ist übersetzt Zeichen. D.h bei '11' hast du mehr als ein Zeichen 
(Zwei). Hingegen ist 11 eine Zahl. Jedes Zeichen im ASCII Zeichensatz 
hat eine Zahl zugeordnet (Tabelle). 'A' ist z.B. der 65 Zugeordnet. d.h. 
wenn du eine Zahl 65 erhälst kannst du nach dem ASCII Standard annehmen, 
dass es als Zeichen ein 'A' repräsentiert.

Dein Compiler kennt den Standard auch. Daher wandelt er implizit 'A' in 
65 und du kannst so Vergleiche ausführen. Da 65 mit 'A' assoziiert ist 
kannst du dir leicht vorstellen, dass 65 NICHT '65' ist. Daher ist auch 
'11' nicht 11.

Angenommen char ist 8 bit Breit auf deinem System:
1
uint8 AsciiWert(char zeichen)
2
{  
3
  return (uint8)zeichen ;
4
}
5
6
char AsciiZeichen(uint8 wert)
7
{  
8
  return (char)wert;
9
}

Und dann mach mal eine Ausgabe mit Serial.println was die folgenden 
Vergleiche ergeben:

AsciiWert('0') == 0
AsciiWert('0') == 0x30
AsciiWert('0') == 48
AsciiWert('11') == AsciiWert('12')
AsciiWert('11') == AsciiWert('21')
AsciiWert('11') == AsciiWert('1')
AsciiWert('11') == 0x31
AsciiZeichen(AsciiWert('11')) == '11'

Und überlege mal warum welches Zeile wahr ist und welche warum nicht 
wahr.

von Markus (Gast)


Lesenswert?

Ich danke euch erst mal für die schnelle Antwort.

Ich habe mir das bereits angeguckt.

innerand innerand schrieb:
> Für den Rest siehe: http://arduino.cc/en/Serial/Println

Das Funktioniert ganz gut, bis auf, das der nur das erste Zeichen nimmt 
und als ASCII umwandelt.
logisch, wenn man es auch so macht
ascii = data[0] ;


da hast du recht

Maxx schrieb:
> Du hast den Unterschied zwischen der Darstellung und dem Wert noch nicht
> verstanden

hast du vielleicht ein link parat?

und ein link, wie ich dies lösen könnte


ich dank euch

gruß Markus

von Markus (Gast)


Lesenswert?

Maxx schrieb:
> AsciiWert('0') == 0

falsch


Maxx schrieb:
> AsciiWert('0') == 0x30
> AsciiWert('0') == 48

richtig



wenn man nur das erste zeichen betrachtet, dann

Maxx schrieb:
> AsciiWert('11') == AsciiWert('12')

richtig


Maxx schrieb:
> AsciiWert('11') == AsciiWert('21')

falsch


Maxx schrieb:
> AsciiWert('11') == AsciiWert('1')

richtig


Maxx schrieb:
> AsciiWert('11') == 0x31

richtig


Maxx schrieb:
> AsciiZeichen(AsciiWert('11')) == '11'

falsch

von Quack (Gast)


Lesenswert?

Lege die Arduinos beiseite. Probiere die Umwandlung von Zahlen in Text 
und zurueck mit einem C-Programm am Rechner aus. Wenn du das im Griff 
hast, dann machst du das auf dem Arduino. Und erst dann baust du den 
Funkkrempel ein. Du handelst dir sonst zu viele Probleme auf einmal ein!

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:

> hast du vielleicht ein link parat?

Da gehts weniger um einen Link, bzw. ums lösen sondern um das 
Verständnis.

Alles in einem Computer sind Zahlen!
Was diese Zahlen darstellen, das entscheidet derjenige, dem man die Zahl 
vorwirft.

Hat man ein Byte, dann kann dieses Byte Zahlen von 0 bis 255 aufnehmen. 
Zuzm Beispiel kann ein Byte den Wert 65 haben.

Diese 65 können jetzt zb für 65 Schnitzel stehen.

Schickt man dieses Byte, mit dem Wert 65 aber an ein Terminal, dann 
passiert etwas ganz anderes. Das Terminal interpretiert diese 65 als den 
Code eines Zeichens. Kriegt es ein Byte mit dem Wert 65, dann malt es in 
einem Kasten genau jene Pixel an, so dass dein Gehirn dort ein 'A' 
liest.

D.h. aber auch, dass man eine Zahl in einem Byte nicht einfach ausgeben 
kann, weil ein Terminal diese Zahl ja als den Code eines bestimmten 
Zeichens auffassen würde.
Will man das erreichen, dann muss man die 65 zerlegen, in die 6 und die 
5 und die dafür zuständigen Codes für die zugehörigen Zeichen zum 
Terminal übertragen. In dem Fall wäre das die 54 (der ASCII Code für das 
zeichen '6') und die 53 (der ASCII COde für das Zeichen '5'). Das 
Terminal empfängt ein Byte mit dem Wert 54 und malt daraufhin in das 
Rechteck diejenigen Pixel schwarz an, so dass sich für dein Gehirn das 
Zeichen '6' formiert. Mit dem nachfolgenden Byte kriegst das Terminal 
den Wert 53, den es wieder so umsetzt, dass es in das nächste Rechteck 
die Pixel für '5' schwarzt anmalt. In Summe liest dein Gehirn damit dort 
die 65. Aber die 65 wurden zu keinem Zeitpunkt zum Terminal geschickt. 
Was geschickt wurde ist der Code für das Zeichen '6' und der Code für 
das Zeichen '5'.

Jetzt hab ich aber eingangs gesagt: Alles in einem Computer ist eine 
Zahl. Auch ein
1
 char c = 'A';
führt letzten Endes dazu, dass für c ein Byte im Speicher reserviert 
wird und in diesem Byte wird die Zahl 65 abgelegt (der ASCII Code für 
'A').

Auf der anderen Seite hast du schon gesehen, dass es einen fundamentalen 
Unterschied gibt, je nachdem wie ich die 65 zur Ausgabe schicke. In dem 
einen Fall erscheint auf der Ausgabe ein 'A', im anderen Fall erscheinen 
auf der Ausgabe die Zeichen '6' und '5'.
Wie wird das entschieden?

Der springende Punkt liegt im Datentyp. Der Compiler weiß implizit, dass 
er bei einem Datentyp von char eine Ausgabefunktion benutzen muss 
(println) die einen char Datentyp akzeptiert. Und diese Ausgabefunktion 
übergibt das in c gespeicherte Byte einfach so an das Ausgabegerät.
Daher kann ich schreiben
1
  char c = 'A';
2
  println( c );
3
4
bzw.
5
6
  char c = 65;
7
  println( c );
und erhalte in beiden Fällen ein 'A' auf dem Bildschirm. Denn die vom 
Compiler ausgewählte Funktion println, die einen char akzeptiert, die 
macht genau das: sie sendet das Byte, welches sie zu übertragen hat, so 
wie es ist zur Ausgabe. Und in beiden Codefällen steht in c der Wert 65 
drinnen. Im ersten Fall habe ich den Wert 65 angegeben, indem ich 'A' 
geschrieben habe und mich darauf verlassen habe, dass der Compiler da 
schon den entsprechenden ASCII Code dafür einsetzen wird. Im zweiten 
Fall hab ich die 65 direkt hingeschrieben. Im Endergebnis macht das 
keinen Unterschied. Im Byte c steht das Bitmuster für die Zahl 65. Wird 
dieses Byte so wie es ist an ein Ausgabegerät geschickt, dann malt 
dieses Ausgabegerät die Pixel für ein 'A' schwarz an.

Hingegen macht ein
1
  int c = 65;
2
3
  println( c );

etwas völlig anderes. Jetzt ist c vom Datentyp int. Und in dem Fall 
kommt eine andere Funktion println zum Zug. Nämlich eine, die einen int 
übernimmt. Und die funktioniert anders. Anstatt den wert (die 65) so wie 
er ist, zum Ausgabegerät zu senden, zerlegt sie den Wert in die 
Einzelteile und sendet die Zeichen für '6' bzw. '5' zum Ausgabegerät. 
Dadurch steht dann am Ausgabegerät nicht ein 'A' sondern '6' und '5' und 
dein Gehirn macht da dann wieder die 65 draus.

Der entscheidende Unterschied ist der Datentyp bzw. das du den Datentyp 
so gewählt hast, dass genau das passiert, was du haben willst.


Preisfrage:
was werde ich am Ausgabegerät sehen, wenn ich schreibe
1
  char c = 65;
2
3
  println( (int)c );

bzw. was sehe ich, wenn ich schreibe
1
  int c = 65;
2
3
  println( (char)c );

: Bearbeitet durch User
von Markus (Gast)


Lesenswert?

Vielen dank für die ausführliche Erklärung Karl Heinz.

Jetzt verstehe ich was der Computer bzw. µC macht.

Verstanden habe ich das, nur weiß ich nicht, wie ich das umsetzen soll, 
wenn mehr als nur ein Zeichen empfangen werden.

Beispiel:
Empfangen wird NUL
Ausgegeben werden soll 0 und nicht 78 von N.

Ich denke, das ich dafür mehr als eine Variable brauchen werde, aber ich 
habe keinen Schimmer, wie ich es umsetzten soll.


Zur deiner Preisfrage

Karl Heinz schrieb:
> Preisfrage:
> was werde ich am Ausgabegerät sehen, wenn ich schreibe

wenn
(int)c
die Umwandlung von cahr in int ist

und wenn
(char)c
die Umwandlung von int in char ist

dann würde ich sagen, dass da das heraus kommt

zu 1: 65 (als char -> A, als int -> 65)
zu 2: A (als int -> 65, als char -> A)


ich danke euch bzw dir.

ich mach mich jetzt auf der suche, bin trotzdem dankbar, wenn ihr mir 
weiterhin hilft.

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.