Forum: Compiler & IDEs Strings in C die zweite


von flyingwolf (Gast)


Lesenswert?

es war zu schön um wahr zu sein. Auf dem mega128 lief das folgende
Progamm super, nun, portiert auf einen mega 32 kommt nur noch mist
raus.
Die Aufgabe ist es, die zeichen seriell zu übertragen. Dabei ist dem
Empfänger eine '1' ein 6uS ein-Impuls und 94uS aus und eine 0 100uS
0.
Via Interrupttimer erzeuge setze ich alle 100uS "interruptcheck = 1"

Die Auswertung macht


void se_data(char data) //ein Zeichen aus data in den Displayspeicher
schreiben
{
int i;
extern volatile char interruptcheck;

while(interruptcheck == 0) asm("NOP"); //solange das Bit nicht
gesetzt ist, passiert nix

if (data == '1')
  {
  setbit(PORTC,PC5);
  for (i=6; i>0; i--) asm("NOP"); // halte den Zustand über 6 Takte
  clearbit(PORTC,PC5);
  }
  interruptcheck = 0;
}

und serviert werden die Zeichen von
    i2=1;


while (i2 < 69 )
    {
    se_data(sestring[i2++]);  // einzelnes Zeichen schicken
    }

und so sehen die Zeichen aus...



switch(data[i1])
  {
  case '1': bluefn();
sprintf(sestring,"100000000001111111000010110111100101100010001010010010 
0101111100000");
break;
case '2': bluefn();
sprintf(sestring,"100000000001111111000011010111100110111011001000001010 
0101111100000");
break;
case '3': bluefn();
sprintf(sestring,"100000000001111111000010010111100100101010001100011010 
0101111100000");
break;
 ...

bluefn ist dabei genau so ein Monstrum wie sestring
das kann man sicherlich einfacher und weniger speicherfressend
gestalten, oder?
Aber wie?

von Peter (Gast)


Lesenswert?

Was heisst "Mist", bzw. kannzt Du den Fehler etwas genauer definieren?
Die Code-Schnipsel sehen ansich "vernünftig" aus, doch solange Du
nicht den gesammten Code postest, kann Dir nur schwer weiter geholfen
werden...

Gruss Peter

von chris (Gast)


Lesenswert?

hi,
benutzt du den internen Takt ? Falls ja, sind vielleicht beiden Takte
unterschidelich?
  Chris

von Karl H. (kbuchegg)


Lesenswert?

Das halte ich mal für ein Gerücht:

> for (i=6; i>0; i--) asm("NOP"); // halte den Zustand über 6 Takte

1. Wenn Dein Compiler schlau ist, dann optimiert er das
   komplett weg da es für ihn keinen Effekt hat
   -> zumindest i auf volatile setzen

2. Das da 6 Takte rauskommen ist eheer unwahrscheinlich.
   Die komplette Schleifensteuerung braucht eben auch seine
   Zeit.

von Karl H. (kbuchegg)


Lesenswert?

Deine Servierschleife ist auch Unsinn.
In C wird mit 0 zu zählen angefangen!
D.h. die erste '1' wir überhaupt nicht ausgegeben.
Dafür greifst du auf das Zeichen mit der Indexnummer
68 im String zu. Das ist aber immer das abschliessende
'\0' Zeichen, das jeden String abschliesst.

Anstatt da lang rumzuzaehlen, mach doch die Ausgabeschleife
so:

  i2 = 0;
  while( sestring[i2] )
  {
    se_data( sestring[i2++] );  // einzelnes Zeichen schicken
  }

Vorteil: Du brauchst nichts abzuzählen, die Schleife richtet
         sich automatisch nach der tatsächlichen Stringlänge

Wenn Dein Compiler nicht so auf Zack ist, kannst Du ihm auch
noch etwas unter die Arme greifen:

  i2 = 0;
  while( (c = *(sestring + i2++)) != '\0' )
    se_data( c );

Aber bevor Du das tust, solltest Du in C schon firm sein.

von Peter (Gast)


Lesenswert?

Um genau 6 Zyklen zu warten, dürfen die NOP's natürlich nicht in einer
Schleife stehen, ist natürlich klar.

//----------------------------------
// Delay for six CPU cycles
/----------------------------------
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
asm ("NOP");
//----------------------------------

Um ganz sicher zu sein kann man auch {asm volatile ("NOP")}
schreiben, doch ich nehme an, dass asm() Statements nie wegoptimiert
werden!

Peter

von Karl H. (kbuchegg)


Lesenswert?

> bluefn ist dabei genau so ein Monstrum wie sestring
> das kann man sicherlich einfacher und weniger speicherfressend
> gestalten, oder?
> Aber wie?

Sicher kann man.
Zunaechst mal kannst Du den sprintf ganz einfach loswerden:

> sprintf(sestring,

"1000000000011111110000101101111001011000100010100100100101111100000");

Das hier ist identisch zu:

  strcpy( sestring, "..........dein String .....");

Nur duerfte das etwas schneller ablaufen.
Dann. Wenn ich mir Deine Strings so ansehe, dann sehe ich, dass
die alle in weiten Teilen gleich aufgebaut sind. Das kann man
sofort benutzen:


  strcpy( sestring, "1000000000011111110000101101111001" );

  switch( data[i] ) {
    case '1':
      strcat( sestring, "01100010001010010" );
      break;

    case '2':
      strcat( sestring, "10111011001000001" );
      break;

    case '3':
      strcat( sestring, "00101010001100011" );
      break;

    ...
  }

  strcat( sestring, "0100101111100000" );

  /* erst jetzt ist sestring, vollstaendig fertig und
     kann uebertragen werden */

Damit bist Du die Monster los.
Vielleicht lehne ich mich jetzt etwas zuweit aus dem Fenster,
aber ich denke mal, dass diese Bitsequenzen irgendwelche Befehle
bedeuten. d.h. ich wuerde mir da mal mittels define ein paar
Konstante machen:

#define  COMMAND_A             "1000000000011111"
#define  COMMAND_IRGENDWAS     "1100001011011110"
#define  COMMAND_WAS_ANDERES_1 "0110001000101001"
...

und dann mit denen arbeiten:

  strcpy( sestring, COMMAND_A );
  strcat( sestring, COMMAND_IRGENDWAS );

  switch( data[i] ) {
    case '1':
      strcat( sestring, COMMAND_WAS_ANDERES_1 );
      break;

    case '2':
      strcat( sestring, COMMAND_WAS_ANDERES_2 );
      break;

    case '3':
      strcat( sestring, COMMAND_WAS_ANDERES_3 );
      break;

    ...
  }

  strcat( sestring, COMMAND_ENDE );

und holla. Plötzlich wird das ganze schon lesbarer.
Ich weiss jetzt nicht, welchen Wertebereich data[i] überstreicht.
Eventuell könnte man den ganze switch-case Block durch
einen simplen Arrayzugriff ersetzen:

#define  COMMAND_A             "1000000000011111"
#define  COMMAND_IRGENDWAS     "1100001011011110"
#define  COMMAND_WAS_ANDERES_1 "0110001000101001"

const char* Commands[] = {
      COMMAND_WAS_ANDERES1,      /* '1' */
      COMMAND_WAS_ANDERES2,      /* '2' */
      COMMAND_WAS_ANDERES3,      /* '3' */
      ...
};


  strcpy( sestring, COMMAND_A );
  strcat( sestring, COMMAND_IRGENDWAS );
  strcat( sestring, Commands[ data[i] ] );
  strcat( sestring, COMMAND_ENDE );

Das ist doch schon was. Lesbar, kurz und wartungsfeundlich.

von flyingwolf (Gast)


Lesenswert?

erst mal vielen dank an alle
warum die 6 Nops ca. 6 Zyklen ausmachen weiss ich nicht. Es
funktioniert nur mit mehr als 6 NOPs, sind es weniger, wird es wohl
tatsächlich wegoptimiert.
(damit hätte ich auch diese Frage geklärt)
Defakto hatte ich knapp 70 solcher monströsen Strings in der
Case-Schleife angelegt und da ist der Speicher übergelaufen.
ich habe nun die Nacht damit zugebracht die Start- und Stop-Sequenzen
abzutrennen und den Rest in Hex umzudandeln und den dann Bitweise durch
den Port zu schieben. Klappt, und dass Programm ist von 45 hex. kbyte
auf 5 hex kbyte geschrupft.

von Roland P. (pram)


Lesenswert?

Da der Compiler erst mal jeden String ins Ram lädt braucht das gleich n
haufen Speicher
Man kann die Strings dann auch ins Flash verlagern.
Steht im GCC-Tutorial Kapitel 17

Gruß
Roland

von peter dannegger (Gast)


Lesenswert?

"das kann man sicherlich einfacher und weniger speicherfressend
gestalten, oder?"


Aber sicher.
Es tut mir in der Seele weh, wenn man Bits in Strings speichert, sind
ja nur schlappe 700% Overhead.

Wenn es nur um die Lesbarkeit des Quelltextes geht, es gibt Macros, um
ein Byte in Bitschreibweise darzustellen bzw. für den AVR-GCC war man
der Meinung, es direkt in den Compiler mit aufzunehmen (0b11111111).
Dann sind pro String nur noch 9 Bytes nötig und die kann man auch im
Flash ablegen.


Wie genau müssen denn die 6µs und 94µs sein ?
Mit irgendwelchen C-Loops ist das ne ziemlich unsichere Sache.
Ich würds entweder mit Inline Assembler oder mit Timer machen.


Peter

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.