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
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.
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.
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);
> 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.
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.
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.
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
> 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.
> 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.
> 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.
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
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
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.