Forum: Mikrocontroller und Digitale Elektronik Probleme mit String der HEX-Zahlen senden soll


von Joachim Bargsten (Gast)


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

von Rufus Τ. F. (rufus) Benutzerseite


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

von Joachim Bargsten (Gast)


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

von Karl heinz B. (kbucheg)


Lesenswert?

Wie gibst du jetzt deine Bytes aus (mit welcher Funktion)?

von Karl heinz B. (kbucheg)


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
  }

von Joachim Bargsten (Gast)


Lesenswert?

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.

von Florian (Gast)


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.

von Florian (Gast)


Lesenswert?

Nachtrag: Also ich denke, daß liegt an den Stringfunktionen, die zu 
lange brauchen.
BTW: Wieso wird das nicht im richtigen Forum diskutiert?

von Joachim Bargsten (Gast)


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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

@Florian:

38400 Baud entsprechen 3840 Zeichen pro Sekunde. Also 260 µsec pro 
Zeichen ... Du hast mit der Bitdauer gerechnet, die beträgt 26 µsec.

von Joachim Bargsten (Gast)


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!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

So irrsinnig deplaziert ist das nicht, ins gcc-Forum gehört das Thema 
genaugenommen nicht, da kein gcc verwendet wird.

von Karl heinz B. (kbucheg)


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.

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


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 !!!!

von Joachim B. (jkbargsten)


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! :-)

von Joachim B. (jkbargsten)


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++;
         }
   }

von Joachim B. (jkbargsten)


Lesenswert?

Nachtrag: ich bekomme anstatt dessen folgende Werte ausgegeben ohne 
erkennbare Wiederholung.

D7 BD 83 58 43 A0 E3 91 F1 05 A5 CF F1 38 31 24 FD 24 F7 7F 2C 85 2B DC 
8E C5 DD .....

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Karl heinz B. (kbucheg)


Lesenswert?

>         for (i=0;i<sizeof(Data);i++){
>            putc(*DataPtr++);
>            DataPtr++;
>         }

Du inkrementierst den Pointer 2-mal pro
Schleifendurchlauf.

von Karl heinz B. (kbucheg)


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

von Joachim B. (jkbargsten)


Lesenswert?

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?

von Karl heinz B. (kbucheg)


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

  

von Joachim B. (jkbargsten)


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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

1
for( i = 0; i < 52; ++i )


Das geht in die Hose.

Besser:
1
for( i = 0; i < 13; ++i )

Desweiteren kannst Du Dir auch die Zuweisungen sparen:
1
for (i = 0; i < 13; i++)
2
{
3
  putc(DataPtr[3]);
4
  putc(DataPtr[2]);
5
  putc(DataPtr[1]);
6
  putc(DataPtr[0]);
7
  DataPtr += 4;
8
}


von Karl heinz B. (kbucheg)


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!

von Karl heinz B. (kbucheg)


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.

von Joachim B. (jkbargsten)


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.

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