Forum: Mikrocontroller und Digitale Elektronik 2 "ASCII/Zeichen" in einen (Hexadezimalen) wandlen


von Hans Maier (Gast)


Lesenswert?

Hallo,

bin Anfänger auf dem Gebiet Atmel AVRs und "kämpfe" mich durch die 
ersten Aufbauten und C-Codes. LED leuchten lassen, Taster (mit 
Entprellung ;=)), LED mit PWM dimmen klappt ganz gut, jetzt geht es dann 
die USART. Senden von "normalen" ASCII Zeichen ist kein Problem, nur 
Steuerzeichen und ähnliches will (teilweise) nicht so recht.
Hatte deshalb die Idee, je ein Byte in zwei Nibbles (4-Bit) aufzuteilen 
und diese dann in ASCII umzuformen und zu versenden, auf dem uC dann 
diese ASCII Zeichen wieder in ein Byte umwandeln. Also so was:
PC will H=0x48 senden > sendet 4=0x34 und 8=0x38 an uC > uC wandelt die 
beiden Bytes wieder in 0x48 um.
Und genau am ersten und letzten Schritt hapert es, d.h. wie bekomme ich 
aus
0x00 0x00 > 0x00
0x00 0x01 > 0x01
...
0x46 0x45 > 0xFE
0x46 0x46 > 0xFF
und andersrum in C (AVR-GCC mit AVRStudio).
Macht man das was ich möchte (beliebige Zeichen per USART übertragen) 
evtl. komplett anders? Freue mich über jeden tipp und Codeschnipsel.

Vielen Dank,

Hans

von Jörg B. (manos)


Lesenswert?

0x00 soll wahrscheinlich 0x30 heißen... (ASCII "0").
Eine Möglichkeit wäre, von dem ASCII-Wert 48 abzuziehen. Wenn das 
Ergebnis größer 9 ist noch mal 7 abziehen.
Erster Wert ins Ergebnis, 4x links shiften und dann den 2. Wert 
zuaddieren.

von Karl H. (kbuchegg)


Lesenswert?

Hans Maier wrote:
> Hallo,
>
> Und genau am ersten und letzten Schritt hapert es, d.h. wie bekomme ich
> aus
> 0x00 0x00 > 0x00
> 0x00 0x01 > 0x01
> ...
> 0x46 0x45 > 0xFE
> 0x46 0x46 > 0xFF

Hast du die 'Hex-Buchstaben' als ASCII Buchstaben kodiert?
Das verkompliziert das ganze ein wenig.

D.h. wir fangen mal damit an eine Funktion zu schreiben,
die aus einem Zeichen den entsprechenden Wert macht
und dabei berücksichtigt, dass es nur Ziffern 0-9 und
A, B, C, D, E, F geben kann

uint8_t ToDigit( char Code )
{
  if( Code >= 'A' )
    return Code - 'A' + 10;
  return Code - '0';
}

Mit dieser Hilfsfunktion ist es dann etwas einfacher:
Du nimmst das erste Zeichen und lässt dir die entsprechende
Ziffer ausrechnen. Dasselbe für die zweite Ziffer und dann
werden beide miteinander kombiniert

uint8_t ToNumber( char Code1, char Code2 )
{
  return ToDigit( Code1 ) << 4  +
         ToDigit( Code2 );
}

> Macht man das was ich möchte (beliebige Zeichen per USART übertragen)
> evtl. komplett anders?

Ja. Man überträgt sie einfach. Ohne irgendwelche Umkodierereien.
Schwierigkeiten gabs früher eigentlich nur bei Fernübertragungen
über Telefon, da man nie so genau wusste, ob auf der Strecke
dazwischen nicht irgendeine 7-Bit Teilstrecke lag.
Aber das ist lange her und mitlerweile kein Thema mehr.

von Uhu U. (uhu)


Lesenswert?

Wandeln einer Hex-Ziffer zH:

unsigned ASCIIhex2Bin(char zH) {
   unsigned z = zH - '0';
   if (z > 9)
      z = z - 7;
   return z;
}

Dann eine Schleife zur Wandlung mehrerer Ziffern:

char Input[] = "48";
int resultat = 0;
for (char *pC = Input; *pC; pC++)
   resultat = (resultat << 4) + ASCIIhex2Bin(*pC);

von Uhu U. (uhu)


Lesenswert?

> Ja. Man überträgt sie einfach. Ohne irgendwelche Umkodierereien.
> Schwierigkeiten gabs früher eigentlich nur bei Fernübertragungen
> über Telefon, da man nie so genau wusste, ob auf der Strecke
> dazwischen nicht irgendeine 7-Bit Teilstrecke lag.
> Aber das ist lange her und mitlerweile kein Thema mehr.

Da wäre ich vorsichtig, denn es gibt Treiber, die Steuerzeichen
interpretieren. Z.B, wenn mit dem X-on/X-off - Protokoll übertragen 
wird.

Dann bleibt eine Binärübertragung einfach hängen, wenn zufällig X-off 
geschickt wird.

Es gibt jedoch eine effizientere Methode, als die Umcodierung in 
ASCII-Hex: Escapesequenzen.

Die Idee ist dieselbe, die auch in C-Strings benutzt wird:

   "abc\"def"

Der Backslash, das Escape-Zeichen sagt, daß das folgende Zeichen seine 
Sonderbedeutung verliert.

Bei Binärübertragung könnte man z.B. das Nutzzeichen in ein gültiges 
ASCII-Zeichen umwandeln. Das Escape sagt dem Empfänger, daß er das 
nächste Zeichen zurückwandeln muß; das Escape wird eifach weggeworfen.

Soll ein Escape übertragen werden, muß ein extra Escap davorgesetzt 
werden.

von Bobby (Gast)


Lesenswert?

Andersrum:

Das Mindestmaß an Protokoll ist es,
nur solche Zeichen zu versenden,
die das Gegenüber auch versteht.

Also informiert man sich vorher,
welches Protokoll der Partner verwendet,
und richtet sich danach.

von Uhu U. (uhu)


Lesenswert?

Auf der sicheren Seite ist man auf jeden Fall, wenn nur gültige 
ASCII-Zeichen übertragen werden. Das sollte man immer dann tun, wenn das 
Gerät auf der Gegenseite nicht bekannt ist.

von Hans Maier (Gast)


Lesenswert?

Hallo,

vielen Dank für eure Tipps und Anregungen.
Ja, 0x00 sollte 0x30 0x30 sein, 0x01 ist 0x30 0x31 usw. Da passt ihr 
schon besser auf als ich, sorry.
Ja, die 'Hex-Buchstaben' sind als ASCII Buchstaben kodiert. Das (blöde?) 
Hyperterminal von Windows spinnt immer rum, wenn Sonderzeichen 
eintreffen. Habe am PC zwei serielle Schnittstellen. Auf der einen 
spreche ich mit einem eigenen C Programm mit dem uC, auf der anderen 
habe ich (wahlweise) RxD oder TxD dieser Kommunikation "gespiegelt", 
kann also "lauschen" und Fehler rausbekommen. Insofern würde auch eine 
Escapesequenz nichts bringen, da Hyperterminal die (glaube ich 
zumindest) einfach ignoroert. Insofern wollte/habe ich die Zeichen 
einfach auf 0x30...0x39 für 0...9 und 0x41...0x46 für A bis F 
beschränkt.
Vielen Dank, bin nun ein ganzes Stück weiter. Ist zwar "nur" Spielerei, 
aber es bringt Spaß ;=)
Bastele jetzt an einer Stringerkennung auf uC Seite. Wenn alles 
fehlerfrei ankommt, klappt das mit strcmp auch einwandfrei, aber wenn 
ich (bewusst) ein Zeichen verfälsche, gibt es ständig Folgefehler, argh.
Angenommen meine "Kommandos" sind alle 8Byte lang (also nach "meiner" 
Umwandlung nur noch 4 Byte) und ich empfange einmal nur 7Bytes, dann 
gibt es Probleme... Verwirft man dann irgendwann die 7Bytes und sagt dem 
PC: bitte neu senden? Das Problem ist momentan, dass der uC dann halt 
ständig "Schrott" empfängt...
Muss mir da mal ein Protokoll o.ö. Kommandos überlegen ohne extra 
Hardware zu benutzten.

Hans

von Karl H. (kbuchegg)


Lesenswert?

> Hyperterminal von Windows spinnt immer rum, wenn Sonderzeichen
> eintreffen.

Von welchen Sonderzeichen reden wir?

> Muss mir da mal ein Protokoll o.ö. Kommandos überlegen ohne extra
> Hardware zu benutzten.

Ich denke das Wichtigste was du dir überlegen solltest ist:
läuft die Kommunikation textbasiert oder binär. Sind deine
Kommandos also lesbarer Text oder sind das irgendwelche binären
Codes.
Wenn die Kommandos lesbarer Text sind, solltest du eigentlich
keinerlei Probleme haben.

von Karl H. (kbuchegg)


Lesenswert?

> aber wenn ich (bewusst) ein Zeichen verfälsche, gibt es ständig
> Folgefehler, argh.

Dein Protokoll ist mies.
Du solltest dir zb überlegen, ob du nicht ein End-Of-Kommando
Zeichen einführst. Zb. in C ist das der ;
Das ermöglicht eine Neusynchronisierung. Wird ein Fehler
entdeckt, wird alles bis zum nächsten ; ignoriert. Erst nach
dem ; fängt das nächste Kommando an.

Da du anscheinend den µC von einem Terminal aus fernsteuern
willst, würde es sich anbieten den normalen Return \n dazu
zu verwenden.

von Uhu U. (uhu)


Lesenswert?

> Insofern würde auch eine Escapesequenz nichts bringen, da Hyperterminal
> die (glaube ich zumindest) einfach ignoroert.

Bitte alles lesen: Das Ende meines Postings befaßte sich damit:

> Bei Binärübertragung könnte man z.B. das Nutzzeichen in ein
> gültiges ASCII-Zeichen umwandeln. Das Escape sagt dem Empfänger, daß
> er das nächste Zeichen zurückwandeln muß; das Escape wird einfach
> weggeworfen.
>
> Soll ein Escape übertragen werden, muß ein extra Escape davorgesetzt
> werden.

Allerdings würde Hyperterminal den Rohtext anzeigen, incl. 
Escape-Zeichen.

Ob Hyperterminal der Übeltäter ist, wäre zu überprüfen. Der COM-Treiber 
von Windows ist ein mindestens genauso heißer Kandidat - es kommt auf 
die Einstellungen an.

von Hans Maier (Gast)


Lesenswert?

N'Abend,

erst mal ist alles "nur" eine Spielerei, also es steht keine (!) reale 
Anwendung dahinter. Wo mir die Probleme bei Hyperterminal aufgefallen 
sind, war bei der Ausgabe aller Zeichen (0x00...0xFF). Mit "normalem 
Text" geht es ja ohne Probleme.
Mein Protokoll ist momentan noch gar kein Protokoll, das soll erst noch 
kommen. Momentan hänge ich nur das empfangene Zeichen an einen String an 
und vergleiche diesen neuen String. Wenn das ganze mit einem 
"Vergleichsstring" übereinstimmt wird halt eine Aktion ausgeführt (wobei 
die Vergleichsstringe alle die gleiche Länge haben). Problem: ein 
falsches Zeichen dazwischen macht nichts (dann geht es in den default 
Zweig), ein fehlendes ist der Untergang... Deshalb möchte ich ja 
irgendwas in der Art

Starterkennung, Längenangabe (um z.B. nach X msec in einen Timeout zu 
laufen), Daten der Länge n, Checksumme (habe eine CRC16 Routine 
gefunden), Endezeichen

implementieren.
Die jetzige Lösung soll/ist nur eine Behelfskrücke. Das die nichts taugt 
durfte ich schon erfahren.

Danke für eure Hilfen,

Hans

von klaus (Gast)


Lesenswert?

Hallo,

google(t) mal nach "hercules setup utility" (unter ...), das kann hex 
senden und empfangen (*) und sogar vorbereitete "strings" senden. 
(...und ist freeware)

(*) rechte Maustaste im "Received/Sent data"-Fenster öffnet ein 
PullUp-Menü

Gruß Klaus

von klaus (Gast)


Lesenswert?

Nochmal Hallo,

das "(unter ...)" ist natürlich falsch!
Sollte mal sowas wie "(oder unter hw-group.com: 
hw-group.com/products/hercules/index_de.html)" werden.

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.