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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.