Probleme mit String der HEX-Zahlen senden soll

Gast #425380
Lesenswert?

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
Persönliche Seite #425387
Lesenswert?

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:
1
unsigned long int daten[13];
2

3
fwrite((void *) daten, sizeof (unsigned long int), 13, stdout);
Gast #425488
Lesenswert?

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
#425497
Lesenswert?

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).
1
  long Data[13];
2
  unsigned char* DataPtr;
3

4
  .... Data befüllen
5

6
  DataPtr = (unsigned char*)Data;  
7
  for( i = 0; i < sizeof( Data ); ++i ) {
8
    putc( *DataPtr );
9
    DataPtr++;
10
  }
Gast #425502
Lesenswert?

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.
Gast #425506
Lesenswert?

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.
Gast #425514
Lesenswert?

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!
#425537
Lesenswert?

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.
(Firma: Promaxx.net) #425571
Lesenswert?

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 !!!!
#425615
Lesenswert?

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! :-)
#425621
Lesenswert?

Ich habe jetzt folgendes versucht, siehe Vorschlag von kbucheg weiter 
oben.

Schnittstelle RS232 ist definiert und getestet mit MTTY / Binterm.
ms zählt Millisekunden

Jetzt hätte ich erwartet, das ich folgende Werte ausgegeben bekomme:

00 00 00 01 00 00 00 02 usw.

Mache ich da gerade einen Gedankenfehler?

   long data[13];
   unsigned char* DataPtr;

void main()
{
   DataPtr = (unsigned char*)Data;

   Data[0]=0;
   Data[1]=1;
   Data[2]=2;
   Data[3]=3;
   Data[4]=4;
   Data[5]=5;
   Data[6]=6;
   Data[7]=7;
   Data[8]=8;
   Data[9]=9;
   Data[10]=10;
   Data[11]=11;
   Data[12]=12;

   while(TRUE)
   {
         if (ms>20) {
         ms=0;
         for (i=0;i<sizeof(Data);i++){
            putc(*DataPtr++);
            DataPtr++;
         }
   }
Persönliche Seite #425623
Lesenswert?

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.
#425652
Lesenswert?

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 ) );
    }
  }
}
#425685
Lesenswert?

> 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
void Transmit( long* data, int dataSize )
2
{
3
  int i;
4

5
  for( i = 0; i < dataSize; ++i ) {
6
    putc( ((unsigned char*)data) + 3 );
7
    putc( ((unsigned char*)data) + 2 );
8
    putc( ((unsigned char*)data) + 1 );
9
    putc( ((unsigned char*)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:
1
    Transfer( Data, sizeof( Data ) / sizeof( *Data ) );

  
#425815
Lesenswert?

Ich habe es jetzt auf diese Art und Weise gelöst.
Danke für die Unterstützung!

   unsigned int32 data[13];
   unsigned char* DataPtr;


void Transmit( int32* data, int dataSize )
{
  int i;
  char j[4];
  DataPtr = (unsigned char*)data;

  for( i = 0; i < 52; ++i )
     {
      j[3]=*DataPtr++;
      j[2]=*DataPtr++;
      j[1]=*DataPtr++;
      j[0]=*DataPtr++;
      i=i+3;
      putc (j[0]);
      putc (j[1]);
      putc (j[2]);
      putc (j[3]);}
}
void main
{
      DataPtr = Data;
      Transmit (data, sizeof(data));
}
#425976
Lesenswert?

> 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!
#425978
Lesenswert?

> 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.
#426094
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren