Archiv verlassen und diese Seite im Standarddesign anzeigen : Eleganter Ersatz gesucht für Datenübertragung per uart in C
oberallgeier
20.02.2019, 18:19
Hallo C-Freaks
meine Lösung zur Übertragung von uint8_t-Werten per UART von einem Controller zum andern funktioniert, aber irgendwie finde ich sie nicht ansprechend.
char ab3[3]; // Übersetzungsfeld für Werteausgabe
while ( 1 ) // >>>> Dauerschleife
{ //
wmus ( 200); // Delays zu Testzwecken im Logikanalyzer
uputs0 ("\x5"); // 0b 0000 0101
wmus ( 50); //
ab3 [0] = 187;
ab3 [1] = 0;
uputs0 ( ab3 );
// uputs0 ("\128"); //
wmus ( 50); //
ab3 [0] = 73;
uputs0 ( ab3 );
} // Ende while ( 1 )
Es gibt ja die Möglichkeit im uart-String auch Zahlen als ASCII zu senden, beispielsweise, siehe oben
uputs0 ("\128");
Soweit ich weiß, geht das nicht mit (benannten) Variablen, es werden auf diese Weise nur Konstanten (hier \128 ) oktal oder hex (dann z.B. \x80) akzeptiert.
Oder gibts doch ne Möglichkeit ? ?
Danke für Hinweise und Hilfen
für Arduino zu PC habe ich eine Lösung entwickelt, die Werte werden übertragen per
VarName (der Token)
und arg (sein Wert als ASCII String),
beiden bilden zusammen eine Übertragungseinheit
(Übrigens funktioniert es genau so auch die Übertragung von html-strings von Arduino-esp8266-WebClients zu WebServern und weder zurück, per esp8266, die bei WifiServer.h integriert ist, für WebServer.h habe ich sie zusätzlich implementiert)
Jede Einheut wird übertragen als
"&VarName1=arg1;&varName2=arg2; &varName3=arg3;....\n"
Die Werte sind dabei strings, also Zahlen, die per itoa oder ftoa umgewandelt wurden.
'&' ist dabei das Startzeichen des VarNames, '=' das Ende und der Beginn des arg-Wert-Strings, ';' schließlich ist das Ende des arg-Wert-Strings und '\n' das Ende des gesamten msg-Strings..
Der Empfänger klambüsert dann wieder diesen String zu einzelnen Tokens auseinander und ordnet den einzelnen Zielvariablen des Empfängers die einzelnen Werte des Senders zu.
Suchst du so etwas? Wenn ja, kann ich dir den Code verlinken.
Vorteil: die Tokens können beliebig gruppiert werden und können auch nur beliebige Untermengen enthalten. Weiterhin besonders geeignet, wenn auch int und float übertragen werden sollen.
Holomino
21.02.2019, 00:44
Wenn Du nen Byte von Controller zu Controller schickst, willst Du das wirklich wandeln? Warum? Der Empfänger versteht das Datenformat doch auch nicht ohne Rückwandlung.
oberallgeier
21.02.2019, 10:10
für Arduino zu PC habe ich eine Lösung .. VarName .. arg .. zusammen eine Übertragungseinheit .. Suchst du so etwas .. kann ich dir den Code verlinken ..Gut! DAs klingt auf jeden Fall interessant. Das Angebot nehme ich gern an und bitte um den Link; danke im Voraus.
.. Wenn Du nen Byte von Controller zu Controller schickst, willst Du das wirklich wandeln ..Wenn ich Werte an einen Controller sende, sollte der auch mitgeteilt bekommen wofür oder wovon diese Werte sind. Mein ÖDNV (öffentlicher Daten-Nahverkehr) bei archie und andern Projekten läuft z.B. über ne UART- oder I²C-Kommunikation und insbes. z.B. beim I²C-Bus ist die Kommunikation für die angeschlossenen Teilnehmer "öffentlich". Es gibt einzelne Kommandobytes mit denen kurze Telegramme identifiziert werden; Beispiel "A", "T", "P", "p" etc. Die zugehörigen, verschiedenen Kommandos haben unterschiedliche Längen, die dem ersten Byte natürlich fest zugeordnet sind. In diesen Längen stecken zugehörige Daten, die das jeweilige Kommando benötigt. Mit diesen Telegrammen kann Controller-Controller-Kommunikation oder PC-Controller-Kommunikation gefahren werden. Selbst WLAN-Fernsteuerung von archie ist so (simpel) möglich - ein RasPi mit autostart eines Terminalprogramms wird an den Hauptcontroller angeschlossen, der RasPi läuft mit RDP und erhält von irgendwo auf der Welt übers Internet/WLAN die Kommandodaten . . .
Beispiel "p23400030" - aufgedrüselt p 2 3400 030 - übermittelt eine (neue) gewünschte Position an die ein Servo fahren soll: p .. KommandoID für Servoposition, 2 .. Servo Nr. 2, 3400 .. neue, gewünschte Servoposition, 030 .. gewählte Servospeed - etwa 15% der üblichen Servo-Fullspeed. Anderes Beispiel: "d" .. sende eine Liste von aktuellen Zustandsdaten eines Controllers an das Terminal. Beispiel "<<<" bzw. "<<>" : Fahre Links- oder Rechtskurve . . . jedes Kommando verändert die Geschwindigkeitsdifferenz der beiden Antriebe rechts und links.
Fazit: das erste Byte MUSS sich von allen andern Daten unterscheiden, um Kuddelmuddel zu verhindern.
Nun, siehe Eingangspost, will ich Entfernungen von meinem NaCo (NavigationsController) an den MoCo (MotorController) senden. Die Ultraschallsensoren messen Entfernungen bis an die sechs Meter in Zentimetern; bei der vorhandenen Speed reicht mir ein maximaler Horizont von fünf Metern - also Werte bis etwa 500. Das ist für ein Byte zu groß und ausserdem in den ersten ca. 20 cm nicht glaubwürdig und sowieso zu wenig. Also halbiere ich den Wert und erhalte nen Bereich z.B. von 10 bis 250 der als halbe Entfernung brauchbar ist - als Angabe in 2-cm-Einheiten. In den ersten Digits, genauer 1 bis 9, steckt die Kodierung der jeweils festgelegten Sensorgruppe (oder Einzelsensor) mit der auch die Anzahl Folgebytes feststeht. Die ASCII-Steuerzeichen 1 bis >10 sind bei mir noch nicht in Verwendung, hier machen sie dann Sinn und die KommandoID ist damit eindeutig von Parameter-Bytes unterscheidbar. Akzeptiert ? Verständlich ?
Oder du gehst hin und verwendest gleich ein richtiges Protokoll, dass die Übertragung von mehreren Bytes erlaubt.
Dabei kannst du prinzipiell zwei Varianten machen statisch oder dynamisch.
Statisch wäre z.B.
| Command | byte1 | ... | byte-n |
Anhand des Commands (das ein byte groß ist oder mehr wenn man mehr braucht) weißt du wie viele Datenbytes danach kommen müssen. Die kannst du dann entsprechend interpretieren.
Dynamisch hat man ein Längenfeld als erstes:
| Length | byte1 | ... | byte -n |
Die Daten muss man dann natürlich entsprechend interpretieren.
Das ganze binär zu übertragen hat den großen Vorteil, dass man weniger Bandbreite und Rechenleistung braucht als wenn man das in ASCII überträgt. Vorallem kann man auch so nette dinge machen wie: Man hat ein struct in dem alle Daten liegen: Übertragt das struct binär und kann die übertragenen Daten wieder direkt in das Struct casten. Dadurch spart man sich viel Aufwand beim Interpretieren.
Außerdem kann man ziemlich einfach noch eine Prüfsummen hinzufügen wenn man will.
hallo,
hier wäre der Arduino-Code:
https://github.com/dsyleixa/Borland-Cpp-Builder/blob/master/Projects/109_ArduinoCOM_RxTx/Arduino_BCB6_RxTx/Arduino_BCB6_RxTx.ino
und hier die UART-Routinen (+GUI) für den PC:
https://github.com/dsyleixa/Borland-Cpp-Builder/blob/master/Projects/109_ArduinoCOM_RxTx/Unit1.cpp
die wesentliche Funktion ist cstringarg() samt Hilfsfunktion strstrpos() , sie wird von beiden Plattformen benutzt:
//----------------------------------------------------------------------------
// tools
//----------------------------------------------------------------------------
int16_t strstrpos(char * haystack, char * needle) // find 1st occurance of substr in str
{
char *p = strstr(haystack, needle);
if (p) return p - haystack;
return -1; // Not found = -1.
}
//------------------------------------------------------------
char * cstringarg( char* haystack, char* vname, char* carg ) {
int i=0, pos=-1;
unsigned char ch=0xff;
const char* kini = "&"; // start of varname: '&'
const char* kin2 = "?"; // start of varname: '?'
const char* kequ = "="; // end of varname, start of argument: '='
char needle[TOKLEN] = ""; // complete pattern: &varname=abc1234
strcpy(carg,"");
strcpy(needle, kini);
strcat(needle, vname);
strcat(needle, kequ);
pos = strstrpos(haystack, needle);
if(pos==-1) {
needle[0]=kin2[0];
pos = strstrpos(haystack, needle);
if(pos==-1) return carg;
}
pos=pos+strlen(vname)+2; // start of value = kini+vname+kequ
while( (ch!='&')&&(ch!='\0') ) {
ch=haystack[pos+i];
if( (ch=='&')||(ch==';')||(ch==' ')||(ch=='\0') ||(ch=='\n')
||(i+pos>=strlen(haystack))||(i>TOKLEN-1) ) {
carg[i]='\0';
return carg;
}
if( (ch!='&') ) {
carg[i]=ch;
i++;
}
}
return carg;
}
cstringarg() gibt einen cstring zurück, der dem Teil entspricht, der hinter dem Gleichheitszeichen steht, also bei
char msg[100];
strcpy(msg, "&i=12;&myfloat=1234.56;&foo=8765; &bas="56473.563736";\n");
char cwert[20];
wird nach
cstringarg(msg, "i", cwert );
"12" in cwert[] zurückgegeben, Null-terminiert, und nach
cstringarg(msg, "myfloat", cwert );
entsprechend
"1234.56"
(ich hoffe, ich habe jetzt nicht noch einen c+p Fehler drin)
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.