String aufsplitten in 40 Einzelwerte

OP (Firma: google) #1853809
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
Gast #1853817
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
}
Gast #1853820
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
Persönliche Seite #1853831
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?
OP (Firma: google) #1853839
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/]
#1853860
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.
OP (Firma: google) #1853936
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
#1854838
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
OP (Firma: google) #1855099
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!!!!!
OP (Firma: google) #1855109
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!!!!
OP (Firma: google) #1857915
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!!!
#1857921
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
#1857922
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren