Hallo Zusammen
Ich habe ein Problem einen String zu senden der folgende informationen
enthält.
Beispiel:
Der String besteht aus 13 Words.
Jeweils vier Bytes enthalten eine Information!
Die Werte werden fortlaufend gesendet ich habe Sie nur der
Übersichtlichkeit halber untereinander geschrieben. Es handelt sich um
HEX-Zahlen.
21 4F 53 44
81 81 81 81
81 81 81 80
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
02 8F 40 00
80 00 00 00
00 00 00 00
00 00 00 00
85 92 43 01
03 03 03 03
Mein Problem ist jetzt, wie bekomme ich diese Words zusammengesetzt und
möglichst schnell übertragen, da ich die Informationen alle 20ms senden
muss.
Die Baudrate beträgt 38400.
Ich habe es versucht mit putc(0x**), das dauert zu lange.
printf("%c%c....",byte[0],byte[1]....); dauerte auch zu lange
Gibt es einen Trick aus den einzelnen HEX-Zahlen einen String zu bilden
um diesen dann zu senden?
Über Tipps wäre ich sehr dankbar.
Gruss Joachim
Eine Hexcodierung und Übertragung der Daten als Klartext scheidet
aufgrund der resultierenden Datenmenge aus.
13 Werte à 4 Bytes sind 52 Bytes.
Die als hexcodierter String sind 104 Bytes.
Die Übertragungsdauer von 104 Bytes mit 38400 Baud (bei 8n1) beträgt
etwa 27 msec ...
Also bleibt nur eine rein binäre nichtcodierte Übertragung möglich.
Da anscheinend Dein Speicher als Array vorliegt, kannst Du
beispielsweise fwrite verwenden:
Hallo Rufus
Danke für Deine Hinweise.
Es ist richtig, ich muss die rein binäre nichtcodierte Übertragung
verwenden.
Ich verwende zum progammieren den PCWH Compiler für den 18f4680. Dort
finde ich leider keine fwrite Funktion. Gibt es vielleicht eine andere
Funktion die man verwenden kann?
Ach ja, mein Project dient dazu einen Neigungssensor der Daten via
CANopen sendet umzurechnen in das oben angegebene Protokoll.
Gruss Joachim
AH, sehs grade.
Oben hast du putc erwähnt. Damit sollte das gehen.
Wie hast du deine 4 Bytes jeweils gespeichert?
Ich geh mal davon aus, dass du ein Array von long (?) hast
(long wegen der 4 Bytes).
Ich habe es mit printf und putc versucht beides würde nicht zum Erfolg,
da die Übertragung zu lange dauerte.
printf("%LX,%LX...",word[0],word[1],...);
Funktionierte auch nicht.
Hm. verstehe da was nicht. Wieso sendest Du nicht die einzelnen Bytes?
Das sind 52. Wieso als String?
Außerdem verstehe ich gerade nicht, wie rufus auf 27ms kommt. Bei 38400
Bit/s und 8N1 (10 Bit je Byte) komme ich auf 0,026 ms/Byte und 2,7 ms
für 104 Byte. Denkfehler?
Egal wie, ist es Zufall, daß da so viele Zeichen nacheinander gleich
sind oder kommt das öfter vor? Dann könnte man an einen ganz einfachen
Komprimierungsalgorithmus denken.
Habe gerade gesehen, das Du noch etwas nachgetragen hast.
Das sieht recht vielversprechend aus.
Leider kann ich es erst morgen wieder unter Realbedingungen testen.
Ich werde berichten ob es zum Erfolg geführt hat.
Vielleicht sollte ich mich doch noch einmal mehr mit Zeigern
beschäftigen.
Die Bytes enthalten Infos zu
21 4F 53 44 ist die Anfangskennung
Roll
Pitch
Windrichtung
Geschwindigkeit
UTC-Zeit
und weitere
03 03 03 03 ist die Endkennung
Ich habe zum testen bis auf einen Wert alle anderen auf null gesetzt.
Kleine Frage, in welches Forum hätte ich die Frage schreiben sollen,
damit ich beim nächsten Mal die Frage richtig plazieren kann!
Finde auch das das Forum schon in Ordnung ist.
> Nachtrag: Also ich denke, daß liegt an den Stringfunktionen, die zu> lange brauchen.
Nun ja. printf() ist schon eine umfangreiche Funktion.
Allerdings bist du mit ziemlicher Sicherheit I/O gebunden.
Das heist der Zeitbedarf wird hauptsächlich durch die
eigentlich Zeit für die Übertragung der Bytes bestimmt.
Da kannst du nebenbei noch massig 'teuflisch schwierige
quadratische Gleichungen lösen' ohne dass du das gross merkst.
20 ms sind für einen Prozessor eine laaaaaaaange Zeitdauer.
Hä ?
Bin ich nur blöd ? So ein einfaches Problem mit einer C-Funktion
unbekannten Umfanges zu lösen ? Strings ?
Es geht anscheinend darum, 52 Bytes in 20ms zu übertragen bei 38400
Baud.
Rein rechnerisch ist Zeit für 76 Bytes.
Also nehme ich ein Byte und sende es - und wenn der Buffer wieder frei
ist, sende ich das nächste. Da wird kein String gebastelt.
OK - es soll in C sein - dann hat man evtl. ein Zeitproblem ! (Weil man
ja nicht weiß, was der C-Compiler so alles reincompiliert.)
Ich würde dem C-Compiler alle Zeit (in 20ms!) lassen, um den Buffer
aufzubauen, und dann kann eine Assembler-Routine im schnellen Interrupt
mal den Hardware-UART bestücken. Was kann da Zeit kosten, 52 Bytes zu
bewegen ? Das sollte auch mit ATMELs schnell gehen ;-)
Reduce to the max !!!!
Ich verwende einen 18f4680, wie schon oben erwähnt. Für diesen Prozessor
habe ich eine Platine mit neun angesteuerten LED´s, einer
CAN-Schnittstelle, einer RS232 Schnittstelle und 6 nach außen geführten
Ausgängen/Eingängen.
Ok, ich sehe ein das ich nicht umbedingt einen String basteln muss um
die Daten zu bewegen.
Das mit der Assembler Routine würde mich interessieren, ist es ein
großer Aufwand das zu integrieren? Meine letzten Assembler
Programmierungen liegen schon gut 16 Jahre zurück! :-)
Ich halte es für unwahrscheinlich, daß putc signifikant langsamer ist
als eine handgeschriebene Assemblerroutine.
Auch kann ich mir nicht vorstellen, daß
1
for(i=0;i<52;i++)
2
putc(buffer[i]);
in Assembler codiert wesentlich schneller sein soll als das
resultierende Compilat. So irrwitzig schlecht sind C-Compiler nicht.
Das Problem wird an einer anderen Stelle liegen.
Ausserdem musst du den DataPtr wieder auf den Anfang des Arrays
zurückstellen, ehe der nächste Ausgabedurchgang anfängt. Ansonsten
wandert der sukzesive durch den ganzen Speicher :-)
Data[11]=11;
Data[12]=12;
while(TRUE)
{
if (ms>20) {
ms=0;
DataPtr = (unsigned char*)Data;
for (i=0;i<sizeof(Data);i++){
putc(*DataPtr++);
}
}
Am besten steckst du das alles in eine eigene Funktion, dann
kann dir das nicht passieren.
void Transmit( long* data, int dataSize )
{
unsigned char* dataPtr = (unsigned char*)data;
int i;
for( i = 0; i < dataSize; ++i )
putc( *dataPtr++ );
}
int main()
{
Data[0] = ....
....
while( 1 ) {
if( ms > 20 ) {
ms = 0;
Transmit( Data, sizeof( Data ) );
}
}
}
Das sieht jetzt schon viel besser aus!
Ich musste nur Long durch int32 ersetzen.
Jetzt habe ich nur noch das kleine Problem, das die Daten in umgekehrter
Reihenfolge pro Word übertragen werden. Das sollte ich aber hinbekommen,
oder gibt es da einen speziellen Trick?
> Jetzt habe ich nur noch das kleine Problem, das die Daten in umgekehrter> Reihenfolge pro Word übertragen werden
Autsch.
Ich habs befürchtet.
Kannst du das empfangsseitig regeln?
Ansonsten musst du den Pointer in seiner jetzigen Form aufgeben und
die Simplizität ist dahin. Na ja, soooo schlimm ist das
auch wieder nicht:
1
voidTransmit(long*data,intdataSize)
2
{
3
inti;
4
5
for(i=0;i<dataSize;++i){
6
putc(((unsignedchar*)data)+3);
7
putc(((unsignedchar*)data)+2);
8
putc(((unsignedchar*)data)+1);
9
putc(((unsignedchar*)data)+0);
10
data++;
11
}
Jetzt musst du halt durch Umstellen der putc die richtige
Reihenfolge einstellen.
Achtung: dataSize gibt jetzt nicht mehr die Länge in
Bytes, sondern in Elementen an.
Aufrufseitig heist das dann:
> Das geht in die Hose.
Das stimmt schon.
Schau mal in die Schleife hinein. Da gibt es noch
ein verträumtes i = i + 3
Aber Rufus hat recht. Mit solchen Aktionen schiest
man sich normalerweise selbst ins Knie.
Also entweder so, wie Rufus das aufgezeigt hat,
also mit einer Konstanten (in dem Fall 13) in der
for Schleife. oder aber, wenn dir die 52 sympatischer
sind:
for( i = 0; i < 52; i += 4 ) {
j[3]=*DataPtr++;
j[2]=*DataPtr++;
j[1]=*DataPtr++;
j[0]=*DataPtr++;
putc (j[0]);
putc (j[1]);
putc (j[2]);
putc (j[3]);}
}
und keiner Manipulation von i in der Schleife!
Oder aber so wie man das richtig macht: Nämlich so,
dass in der Funktion gar kein Zahlenwert mehr vorkommt!
Genau zu diesem Zweck hab ich nämlich den Parameter
dataSize eingeführt: Damit eben Transmit nicht wissen
muss wie gross das Array ist. Irgendwann ändert sich
nämlich die Arraygröße. Vieleicht nicht heute und vielleicht
auch nicht morgen. Vielleicht bist sogar es gar nicht du, der
sie ändert. Aber wenn sie sich ändert, dann wette ich mit dir
um was du willst, dass zunächst vergessen wird, die 52 (oder 13)
an die neuen Gegebenheiten anzupassen. In diesem Fall kann
ich dir nur wünschen: Frohes Debuggen!
> Oder aber so wie man das richtig macht:
Und genau zu diesem Behufe, hab ich dir die
fertige Funktion gepostet. Die berücksichtigt
das nämlich alles, ist um ca. 50% weniger
Tippaufwand als deine Version und, wenn ich
mich nicht sehr täusche, läuft auch schneller
ab, da keine Umkopieraktionen stattfinden.
Danke für sehr gute Unterstützung.
Ich habe die Funktion jetzt auch angepasst, so dass Sie unabhängig von
der Größe des Arrays ist.
Mein Problem ist zur Zeit noch, das ich immer noch etwas Schwierigkeiten
habe mit Zeigern und Pointern. Ich arbeite aber dran.
Vielleicht hat ja jemand einen Tipp, wo man etwas darüber nachlesen
kann, am besten mit Beispielen.
Mir ging es im ersten Ansatz darum zu sehen, ob ich die Daten auch
wirklich in der Zeit senden kann.
Mittlerweile habe ich jetzt auch den CANbus eingebunden und die Werte
die von einem Sensor ankommen werden umgewandelt und ins Array
eingebunden.