www.mikrocontroller.net

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


Autor: Joachim Bargsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
unsigned long int daten[13];

fwrite((void *) daten, sizeof (unsigned long int), 13, stdout);

Autor: Joachim Bargsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie gibst du jetzt deine Bytes aus (mit welcher Funktion)?

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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).

  long Data[13];
  unsigned char* DataPtr;

  .... Data befüllen

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


Autor: Joachim Bargsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Florian (Gast)
Datum:

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

Autor: Joachim Bargsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Bargsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

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

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht 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 !!!!

Autor: Joachim Bargsten (jkbargsten)
Datum:

Bewertung
0 lesenswert
nicht 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! :-)

Autor: Joachim Bargsten (jkbargsten)
Datum:

Bewertung
0 lesenswert
nicht 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++;
         }
   }

Autor: Joachim Bargsten (jkbargsten)
Datum:

Bewertung
0 lesenswert
nicht 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 .....

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich halte es für unwahrscheinlich, daß putc signifikant langsamer ist 
als eine handgeschriebene Assemblerroutine.
Auch kann ich mir nicht vorstellen, daß
for (i = 0; i < 52; i++)
  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.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

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

Du inkrementierst den Pointer 2-mal pro
Schleifendurchlauf.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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 ) );
    }
  }
}

Autor: Joachim Bargsten (jkbargsten)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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:
void Transmit( long* data, int dataSize )
{
  int i;

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

  

Autor: Joachim Bargsten (jkbargsten)
Datum:

Bewertung
0 lesenswert
nicht 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));
}

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
for( i = 0; i < 52; ++i )


Das geht in die Hose.

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

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


Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Bargsten (jkbargsten)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.