mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik String aufsplitten in 40 Einzelwerte


Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo C-Freunde und Forumsmitglieder,

ich möchte eigentlich nur einen String der 40 Integerwerte beeinhaltet, 
die jeweils mit ";" abgetrennt sind aufteilen in 40 einzelne 
Integerwerte.
Also "A[LEERZEICHEN]wert1;wert2;....;....;"


Beispiel:   string = "A 
1000;2000;3000;4000;5000;6000;7000;8000;5100;5200;5300;5400;5500;5600;57 
00;5800;10000;11000;12000;13000;14000;15000;16000;17000;18000;1;2;1;2;1; 
2;1;2;"

mein code ist bis jetzt soweit, dass er per uart-interrupt alle zeichen 
in einen string "string" hineinschreibt und erst bei "RETURN" springt er 
in die Funktion "remote()" zum auswerten.

[c]
void remote( void )      //RS-232
{

  // Ein Return ist eingetroffen. Damit ist der String vollständig
  string[f] = '\0';         // erst mal einen sauberen C-String daraus 
machen

  befehl = strtok(string, trennzeichen);    // dann zerteilen
  wert[1] = strtok(NULL, trennzeichen);
  k=2;
  for(t=0;t<40;t++)
  {
  wert[k] = strtok(NULL, strichpunkt);
  empfang[k] = atoi(wert[k]);
  k++;
  }

            if  (strcmp(befehl, "A") == 0)      //Befehl 3
            {

              messbereich[1] = empfang[1];
              messbereich[2] = empfang[2];
              messbereich[3] = empfang[3];
              messbereich[4] = empfang[4];
              messbereich[5] = empfang[5];
              messbereich[6] = empfang[6];
              messbereich[7] = empfang[7];
              messbereich[8] = empfang[8];

              abgleichwert[1] = empfang[9];
              abgleichwert[2] = empfang[10];
              abgleichwert[3] = empfang[11];
              abgleichwert[4] = empfang[12];
              abgleichwert[5] = empfang[13];
              abgleichwert[6] = empfang[14];
              abgleichwert[7] = empfang[15];
              abgleichwert[8] = empfang[16];

              test = messbereich[1];
              testa = messbereich[2];
              testb = messbereich[3];
            }
}
[c/]

nun sollte doch zumindest in dem Arrays "messbereich" und "abgleichwert" 
etwas drinstehen. die variable ändert sich aber nicht.

noch ne frage geht es, dass ich einen String-Array mache (siehe 
wert[..])

danke für eure hilfe!!!!1
martin

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>alle zeichen in einen string "string" hineinschreibt


Und warum nicht gleich in die int-Array?
Etwa so:
volatile int16_t values[..];

ISR (Uart-Empfang)
{
 static uint8_t idx = 0;
        uint8_t   x = udr;

if ( x >= 16#30 ) || ( x<= 16#30 )
{
  values[idx]:= (  ( 10 * values[idx] ) + ( x - 16#30 )  );
}
else if ( x == ';' )
{
  idx++;
}

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

wie sieht denn die initialisierung der Felder/Arrays aus die du 
verwendest?

Zum Thema String-Array: In C gibt es keine richtigen Strings. Ein 
"String" ist nichts anderes als ein Vektor aus char. Du kannst ein 
"String-Array" im Prinzip erstellen, indem du ein Array aus Zeigern auf 
die Strings machst. Über die Zeiger kommst du dann wieder zum String.

Thomas

Autor: Tom M. (tomm) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin 567 schrieb:
> befehl = strtok(string, trennzeichen);    // dann zerteilen
> wert[1] = strtok(NULL, trennzeichen);
...
>   wert[k] = strtok(NULL, strichpunkt);

Du verwendest den Delimiter nicht konsistent und vertraust blind auf die 
Rückgabewerte von strtok(). Beides würde ich als erstes mal bereinigen.

Weiter würd' ich zeitig nach int konvertieren, die ganze Sache in nen 
hübschen loop packen und nicht mit defines geizen, statt mehrererere 
Arrays zu führen. Wieviel RAM haste eigentlich auf deinem MC?


> noch ne frage geht es, dass ich einen String-Array mache (siehe
> wert[..])

Wiewas?

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo zusammen

Prozessor: at90can128
10Mhz

der string wird ja auch noch für andere funktionen benutzt 
beispielsweise um kurze befehle wie "U IST" oder "I SOLL" einzulesen.
würde zwar dann anderst auch gehen aber jetzt hab ichs schon so weit 
hingebracht, da muss doch dann der rest auch gehn.

hier sämtliche variablen:

[c]
float Strom;
int ADCWert;
int empfang[50],abgleichwert[9], adckorrektur[9], messbereich[9], 
eemessbereich[9], eeabgleichwert[9], eeadckorrektur[9], eefaktor[9];
unsigned char f, i, g, t, k, zeichen, merker=1, durchzahler=1, puffer, 
buffer, einstellen=0, abgleichmerker=0;
char kal=0, schutz=0, acdc=0, abgl=0, scan=0, adck=0, zugang=0;
int Messwert[9], faktor[9], test, testa, testb;
int z,y,x,v,q,r,p,w;


//für RS-232 Übertragung----------
unsigned char size;
char counter = 1;
char zahler = 1;
unsigned char indeks = 1;
char next[10];
char sendestring[100];
char string[20];
char *wert[40], *befehl;
const char strichpunkt[] = ";";
const char trennzeichen[] = " ";
//--------------------------------

[c/]

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin 567 schrieb:
> char *wert[40];
[...]
> k=2;
>   for(t=0;t<40;t++)
>   {
>   wert[k] = strtok(NULL, strichpunkt);
>   empfang[k] = atoi(wert[k]);
>   k++;
>   }

Hier läuft der Index von wert (k) bis 42.  Maximal zulässiger Index ist 
aber 39.  Du schreibst also wild in den Speicher.

Woanders:
>              messbereich[1] = empfang[1];

empfang wird erst ab Index 2 beschrieben, in empfang[1] steht also 
zuverlässig undefiniertes Zeugs.

Es fällt auch auf, dass Du Indices immer ab 1 laufen lässt.  Ob das 
System hat, weil Dir nicht klar ist, dass der kleinste Index in C 0 
heißt und nicht 1, kann ich nicht beurteilen.

Bezüglich mangelnder Fehlererkennung, z.B. bei strtok, wurde schon das 
Nötige gesagt.  Du riskierst, wild in Adresse 0 herumzufuhrwerken, 
spätestens bei Übertragungsstörungen.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du schon mal gedebugged?
Evtl wird nie die IF-Bedingung erfüllt.

Bitte versuche den Code hier entsprechend zu formatieren ;)

Thomas

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hast du schon mal gedebugged?

Was ist das denn? Zeitliche Vorsteinzeit?

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also ich kann schon debuggen

er geht in die if bedingung rein

die 3 "test"-variablen bleiben jedoch unverändert egal was ich schicke

also ich habe schon ein programm, dass den string per Com schickt, das 
funktioniert auf jeden fall, weil ich es mit einem nullmodem-kabel 
einmal im Kreis geschickt hab

sieht im Hyperterminal folgendermaßen aus:

A 
10;100;1000;1;20;200;2000;2;30;300;3000;1;40;400;4000;2;50;500;5000;1;60 
;600;6
000;2;70;700;7000;1;80;800;8000;2;



Verteilung des strings im code folgendermaßen:
START
A
[LEERZEICHEN]
messbereich[1]
abgleichwert[1]
adckorrektur[1]
faktor[1]
messbereich[2]
abgleichwert[2]
...
....
.....
faktor[8]
ENDE

Autor: Thomas K. (tomthegeek)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

ich habe den Code mal ausprobiert und bin auf folgendes gekommen:

1. Die Definition der Variable string[20] ist mit einer Länge von 20 um 
einiges zu kurz. Du solltest dir über die maximale Länge Gedanken machen 
und diese hier einsetzten. (Ich hab hier mal 255 verwendet, aber ich 
weiß ja nicht was du alles reinschreiben willst ;))

2. Ich habe einen Teil deines Codes (insbesondere den Teil mit der 
for-Schleife) mal durch folgendes ersetzt:
befehl = strtok(string, trennzeichen);    // dann zerteilen
  do
  {
    wert[t] = strtok(NULL, strichpunkt);
    empfang[t] = atoi(wert[t]);
    t++;
   }while(empfang[t-1] != NULL);

   if  (strcmp(befehl, "A") == 0)      //Befehl 3
   {
       // hier kommt der Rest ....
   }

Bei mir funktioniert es so ;)

Gruß Thomas

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Thomas

habe deinen code eingefügt
bekomme aber ein warning bei folgender zeile:

while(empfang[t-1] != NULL);

..:250: warning: comparison between pointer and integer


geht das trotzdem??

Autor: Thomas K. (tomthegeek)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mh seltsam, diese Warning schmiss er bei mir nicht, obwohl der Compiler 
natürlich Recht hat.
Müsste
   }while(wert[t-1] != NULL);
heißen.

Thomas

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Thomas,
habs nun ausprobiert, war ja klar dass wert hingehört, bin schon selber 
so doof, dass ich nix mehr eigenständig weiß!!
sorry

hier ist nun mal die ganze "remote" funktion, die bei einem "RETURN" 
aufgerufen wird.
der Debugger springt auch die "A" Bedingung an.
aber die 4 "test" Variablen bleiben leer.
void remote( void )      //Fernsteuerung über RS-232
{

  // Ein Return ist eingetroffen. Damit ist der String vollständig
  string[f] = '\0';         // erst mal einen sauberen C-String daraus machen



//---------------------------------------------------------------
befehl = strtok(string, trennzeichen);    // dann zerteilen
  do
  {
    wert[t] = strtok(NULL, strichpunkt);
    empfang[t] = atoi(wert[t]);
    t++;
   }while(wert[t-1] != NULL);



            if  (strcmp(befehl, "S") == 0)      //Befehl 1
            {
               if (strcmp(wert[1], "IST") == 0)
               {send_serial();}
            }


            else if  (strcmp(befehl, "W") == 0)      //Befehl 2
            {
               if (strcmp(wert[1], "IST") == 0)
               {
                
                indeks = 1;
                sendestring[0] = 'W';
                
                for (i=0;i<8;i++)
                {
                  zahler = 1;

                  for (t=0;t<4;t++)
                  {
                    switch (zahler)
                      {
                      case 1:  itoa(messbereich[indeks],next,10);
                          break;

                      case 2:  itoa(abgleichwert[indeks],next,10);
                          break;
        
                      case 3:  itoa(adckorrektur[indeks],next,10);
                          break;

                      case 4:  itoa(faktor[indeks],next,10);
                          break;
                      }

                    zahler = zahler + 1;
                    strcat(sendestring, next);
                    strcat(sendestring, strichpunkt);
                  }

                indeks = indeks +1;
                }

                itoa(Messwert[8],next,10);  //letzten Wert hinten (ohne ";") anfügen
                strcat(sendestring, next);

                size = strlen(sendestring);
                sendestring[size] = '\0';
  
                rprintfStr(sendestring);
                rprintfCRLF();
               



                  for(t=0;t<40;t++)              //RS232-String wird gelöscht
                  sendestring[t] = 0;  


               }
            }


            else if  (strcmp(befehl, "A") == 0)      //Befehl 3
            {

  
              messbereich[1]   = empfang[1];
              abgleichwert[1] = empfang[2];
              adckorrektur[1] = empfang[3];
              faktor[1]    = empfang[4];

              messbereich[2]   = empfang[5];
              abgleichwert[2] = empfang[6];
              adckorrektur[2] = empfang[7];
              faktor[2]    = empfang[8];

              messbereich[3]   = empfang[9];
              abgleichwert[3] = empfang[10];
              adckorrektur[3] = empfang[11];
              faktor[3]    = empfang[12];

              messbereich[4]   = empfang[13];
              abgleichwert[4] = empfang[14];
              adckorrektur[4] = empfang[15];
              faktor[4]    = empfang[16];

              messbereich[5]   = empfang[17];
              abgleichwert[5] = empfang[18];
              adckorrektur[5] = empfang[19];
              faktor[5]    = empfang[20];

              messbereich[6]   = empfang[21];
              abgleichwert[6] = empfang[22];
              adckorrektur[6] = empfang[23];
              faktor[6]    = empfang[24];

              messbereich[7]   = empfang[25];
              abgleichwert[7] = empfang[26];
              adckorrektur[7] = empfang[27];
              faktor[7]    = empfang[28];

              messbereich[8]   = empfang[29];
              abgleichwert[8] = empfang[30];
              adckorrektur[8] = empfang[31];
              faktor[8]    = empfang[32];

              test = empfang[1];
              testa = empfang[2];
              testb = empfang[3];
              testc = empfang[4];


            }




               f=0;
               for(g=0;g<20;g++)              //string wird gelöscht
             string[g] = 0;    
}


vielleicht kannst du was erkennen
übrigens danke für all deine bemühungen und das ausprobieren
bist ne ganz große hilfe für mich

martin!!!!!

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo tom

kommando zurück

es geht doch

eine kleine zeile hat noch gefehlt

"t=1;"    vor deine do-while-schleife



danke, danke
mit diesen string-operationen hatte ich schon mehrfach probleme
aber langsam bekomme ich es in den griff

danke nochmal du warst die größte hilfe seit langer zeit in diesem forum
martin!!!!

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

mein Problem ist zwar schon gelöst, aber ich hab trotzdem mal eine 
allgemeine Frage.

was bedeutet eigentlich das NULL in der Zeile:

wert[t] = strtok(NULL, strichpunkt);


Und wieso macht der prozessor dann mit dem richtigen String weiter?
Er weiß ja gar nicht welchen String er "token" soll oder?

nur mal so ne vertständnissfrage (klar gehts, aber ich würde es gern 
wissen)

da ich mich selber eigentllich noch zu den Anfängern zähle, würde mich 
das schon mal interessieren wieso man da NULL schreiben muss??

danke martin!!!

Autor: Thomas K. (tomthegeek)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Martin

laut http://www.cplusplus.com/reference/clibrary/cstring/strtok/ <-- 
übrigens eine sehr hilfreiche Seite wenns um solche Sachen geht, musst 
du nur beim ersten mal den String-Pointer angeben.
Wenn du dann den Befehl noch öfter benutzt, dann brauchst du ihn nicht 
mehr anzugeben, dann reicht ein einfaches NULL.
Sollte sich der String allerdings zwischenzeitlich ändern, bin ich mir 
nicht ganz sicher was passiert. Vermutlich "speichert" die funktion 
einfach einen Zeiger auf den String, dann müssten die Änderungen mit 
einwirken.

Gruß Thomas

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beim ersten Aufruf übergibt man keine NULL, sondern
den tatsächlichen String.
strtok merkt sich von Aufruf zu Aufruf in einer internen
Variable, wie weit es bisher kam, und wenn man es mit NULL aufruft,
wird dieser letzte Wert wiederverwendet.

Genau das ist der Grund, warum strtok nicht reentrant ist:
Wenn mehrere Threads gleichzeitig strtok verwenden, geht es schief.
Oder wenn man in einem Interrupt und außerhalb strtok benutzt.

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieder einiges klarer!!!
danke euch beiden!!!

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.