Forum: Mikrocontroller und Digitale Elektronik String aufsplitten in 40 Einzelwerte


von Martink11 M. (Firma: google) (martink11) Flattr this


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

von Matthias L. (Gast)


Lesenswert?

>alle zeichen in einen string "string" hineinschreibt


Und warum nicht gleich in die int-Array?
Etwa so:
1
volatile int16_t values[..];
2
3
ISR (Uart-Empfang)
4
{
5
 static uint8_t idx = 0;
6
        uint8_t   x = udr;
7
8
if ( x >= 16#30 ) || ( x<= 16#30 )
9
{
10
  values[idx]:= (  ( 10 * values[idx] ) + ( x - 16#30 )  );
11
}
12
else if ( x == ';' )
13
{
14
  idx++;
15
}

von Thomas (Gast)


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

von Tom M. (tomm) Benutzerseite


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?

von Martink11 M. (Firma: google) (martink11) Flattr this


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/]

von Hc Z. (mizch)


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.

von Thomas (Gast)


Lesenswert?

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

Bitte versuche den Code hier entsprechend zu formatieren ;)

Thomas

von Entwickler (Gast)


Lesenswert?

>Hast du schon mal gedebugged?

Was ist das denn? Zeitliche Vorsteinzeit?

von Martink11 M. (Firma: google) (martink11) Flattr this


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

von Thomas K. (tomthegeek)


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:
1
befehl = strtok(string, trennzeichen);    // dann zerteilen
2
  do
3
  {
4
    wert[t] = strtok(NULL, strichpunkt);
5
    empfang[t] = atoi(wert[t]);
6
    t++;
7
   }while(empfang[t-1] != NULL);
8
9
   if  (strcmp(befehl, "A") == 0)      //Befehl 3
10
   {
11
       // hier kommt der Rest ....
12
   }

Bei mir funktioniert es so ;)

Gruß Thomas

von Martink11 M. (Firma: google) (martink11) Flattr this


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

von Thomas K. (tomthegeek)


Lesenswert?

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

Thomas

von Martink11 M. (Firma: google) (martink11) Flattr this


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.
1
void remote( void )      //Fernsteuerung über RS-232
2
{
3
4
  // Ein Return ist eingetroffen. Damit ist der String vollständig
5
  string[f] = '\0';         // erst mal einen sauberen C-String daraus machen
6
7
8
9
//---------------------------------------------------------------
10
befehl = strtok(string, trennzeichen);    // dann zerteilen
11
  do
12
  {
13
    wert[t] = strtok(NULL, strichpunkt);
14
    empfang[t] = atoi(wert[t]);
15
    t++;
16
   }while(wert[t-1] != NULL);
17
18
19
20
            if  (strcmp(befehl, "S") == 0)      //Befehl 1
21
            {
22
               if (strcmp(wert[1], "IST") == 0)
23
               {send_serial();}
24
            }
25
26
27
            else if  (strcmp(befehl, "W") == 0)      //Befehl 2
28
            {
29
               if (strcmp(wert[1], "IST") == 0)
30
               {
31
                
32
                indeks = 1;
33
                sendestring[0] = 'W';
34
                
35
                for (i=0;i<8;i++)
36
                {
37
                  zahler = 1;
38
39
                  for (t=0;t<4;t++)
40
                  {
41
                    switch (zahler)
42
                      {
43
                      case 1:  itoa(messbereich[indeks],next,10);
44
                          break;
45
46
                      case 2:  itoa(abgleichwert[indeks],next,10);
47
                          break;
48
        
49
                      case 3:  itoa(adckorrektur[indeks],next,10);
50
                          break;
51
52
                      case 4:  itoa(faktor[indeks],next,10);
53
                          break;
54
                      }
55
56
                    zahler = zahler + 1;
57
                    strcat(sendestring, next);
58
                    strcat(sendestring, strichpunkt);
59
                  }
60
61
                indeks = indeks +1;
62
                }
63
64
                itoa(Messwert[8],next,10);  //letzten Wert hinten (ohne ";") anfügen
65
                strcat(sendestring, next);
66
67
                size = strlen(sendestring);
68
                sendestring[size] = '\0';
69
  
70
                rprintfStr(sendestring);
71
                rprintfCRLF();
72
               
73
74
75
76
                  for(t=0;t<40;t++)              //RS232-String wird gelöscht
77
                  sendestring[t] = 0;  
78
79
80
               }
81
            }
82
83
84
            else if  (strcmp(befehl, "A") == 0)      //Befehl 3
85
            {
86
87
  
88
              messbereich[1]   = empfang[1];
89
              abgleichwert[1] = empfang[2];
90
              adckorrektur[1] = empfang[3];
91
              faktor[1]    = empfang[4];
92
93
              messbereich[2]   = empfang[5];
94
              abgleichwert[2] = empfang[6];
95
              adckorrektur[2] = empfang[7];
96
              faktor[2]    = empfang[8];
97
98
              messbereich[3]   = empfang[9];
99
              abgleichwert[3] = empfang[10];
100
              adckorrektur[3] = empfang[11];
101
              faktor[3]    = empfang[12];
102
103
              messbereich[4]   = empfang[13];
104
              abgleichwert[4] = empfang[14];
105
              adckorrektur[4] = empfang[15];
106
              faktor[4]    = empfang[16];
107
108
              messbereich[5]   = empfang[17];
109
              abgleichwert[5] = empfang[18];
110
              adckorrektur[5] = empfang[19];
111
              faktor[5]    = empfang[20];
112
113
              messbereich[6]   = empfang[21];
114
              abgleichwert[6] = empfang[22];
115
              adckorrektur[6] = empfang[23];
116
              faktor[6]    = empfang[24];
117
118
              messbereich[7]   = empfang[25];
119
              abgleichwert[7] = empfang[26];
120
              adckorrektur[7] = empfang[27];
121
              faktor[7]    = empfang[28];
122
123
              messbereich[8]   = empfang[29];
124
              abgleichwert[8] = empfang[30];
125
              adckorrektur[8] = empfang[31];
126
              faktor[8]    = empfang[32];
127
128
              test = empfang[1];
129
              testa = empfang[2];
130
              testb = empfang[3];
131
              testc = empfang[4];
132
133
134
            }
135
136
137
138
139
               f=0;
140
               for(g=0;g<20;g++)              //string wird gelöscht
141
             string[g] = 0;    
142
}


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

von Martink11 M. (Firma: google) (martink11) Flattr this


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

von Martink11 M. (Firma: google) (martink11) Flattr this


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

von Thomas K. (tomthegeek)


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

von Klaus W. (mfgkw)


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.

von Martink11 M. (Firma: google) (martink11) Flattr this


Lesenswert?

Wieder einiges klarer!!!
danke euch beiden!!!

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.