www.mikrocontroller.net

Forum: Compiler & IDEs Strings in C die zweite


Autor: flyingwolf (Gast)
Datum:

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

Autor: Peter (Gast)
Datum:

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

Autor: chris (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Peter (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: flyingwolf (Gast)
Datum:

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

Autor: Roland Praml (pram)
Datum:

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

Autor: peter dannegger (Gast)
Datum:

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

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.