Forum: Mikrocontroller und Digitale Elektronik Stringauswertung Problem


von Stefan (Gast)


Lesenswert?

Hallo,

ich habe ein kleines Problem beim Auswerten eines Strings.
Der String sieht folgendermaßen aus: 1.f.0.0.0.1.$

Diesen String möchte ich gern mit folgendem Code auswerten und die 
einzelnen Zahlenwerte in ein Array schreiben:
1
long eingang[10];
2
char *ptr;
3
char delimiter[] = ".";
4
5
ptr = strtok(empfang,delimiter);
6
for(x=0;x<=6;x++){
7
eingang[x] = strtol(ptr, NULL, 16);
8
ptr = strtok(NULL, delimiter);
9
}

Die einzelnen Teilstücke die durch strtok erzeugt werden funktionieren 
soweit einwandfrei, doch die Umwandlung mit strtol funktioniert leider 
nicht und ich weiß nicht warum. Kann mir jemand von euch vielleicht 
weiterhelfen?

von Thomas K. (tomthegeek)


Lesenswert?

Hi

warum machst du das nicht wie in dem Beispiel hier:

http://www.cplusplus.com/reference/clibrary/cstdlib/strtol/

Du kannst dir dann das strtok() sparen. Eventuell noch pEnd++ um den "." 
zu überspringen.
Ansonstn kann ich noch die Funktion atol() empfehlen, die erstellt dir 
auch einen long aus einem String.

Thomas

von Stefan (Gast)


Lesenswert?

Danke für die schnelle Antwort ich habe es gleich mal ausprobiert doch 
leider ist eingang immer 0.
Hier mal mein geänderter Code:
1
eingang[0] = strtol (empfang,&pEnd,16);
2
for(x=1;x<=6;x++){
3
  eingang[x] = strtol (pEnd,&pEnd,16);
4
  pEnd++;
5
  PRINT("Zahl%d:  %ld\r\n",x,eingang[x]);
6
}

von Karl H. (kbuchegg)


Lesenswert?

Stefan schrieb:
> Danke für die schnelle Antwort ich habe es gleich mal ausprobiert doch
> leider ist eingang immer 0.
> Hier mal mein geänderter Code:
>
>
1
> eingang[0] = strtol (empfang,&pEnd,16);
2
>

hier fehlt das anschliessende pEnd++ um den darauffolgenden '.' zu 
überspringen. Die nachfolgenden strtol verweigern daher alle, weil sie 
mit einem '.' nichts anfangen können.

>
1
> for(x=1;x<=6;x++){
2
>
Wenn ich ein <= in der Abbruchbedingung einer for-Schleife sehe, 
klingeln bei mir alle Alarmglocken.

Diese Schleife wird 7 mal durchlaufen. Du hast aber in deinem String nur 
6 Zahlen. Der letzte Bestandteil deines Strings "1.f.0.0.0.1.$" ist ein 
$ und das ist keine Zahl mehr.

von Stefan (Gast)


Lesenswert?

Ich hab den Code auf deine Einwände geändert doch leider funktioniert er 
immer noch nicht, ich weiß nicht woran es noch liegen kann. Hier nochmal 
der aktuelle Code:
1
eingang[0] = strtol (empfang,&pEnd,16);
2
pEnd++;
3
for(x=1;x<=5;x++){
4
  eingang[x] = strtol (pEnd,&pEnd,16);
5
  pEnd++;
6
  PRINT("Zahl%d:  %ld\r\n",x,eingang[x]);
7
}

von Karl H. (kbuchegg)


Lesenswert?

Stefan schrieb:
> Ich hab den Code auf deine Einwände geändert doch leider funktioniert er
> immer noch nicht, ich weiß nicht woran es noch liegen kann.

Hast du dein PRINT kontrolliert?

Du musst das 'funktioniert nicht' an anderer Stelle suchen, der 
Codeausschnitt an sich ist jetzt ok.

(Auch wenn du das for falsch rum geändert hast. Schreibs als x < 6 und 
nicht als x <= 5. Kommt hier aufs selbe raus, d.h. das ist jetzt nicht 
das Problem)

Übrigens: Dein Originalcode war ebenfalls ok.

Wo kommt "empfang" her?

von Stefan (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Hast du dein PRINT kontrolliert?

Ich weiß nicht wo da der Fehler liegen sollte.

Karl heinz Buchegger schrieb:
> Wo kommt "empfang" her?

empfang kommt aus der Interruptroutine vom UART
Hier der Code dazu:
1
empfang[count]=data;
2
count++;
3
if (data=='$'){
4
 empfang[count]='\0';
5
 count=0;
6
 new_ms=1;
7
}

Wenn ich mir in der Schleife die Einzelnen Teile von pEnd ausgeben 
lassen sehe ich auch das dies alles wunderbar funktioniert doch in der 
eingang-variable ist leider nur 0.

von Karl H. (kbuchegg)


Lesenswert?

Datentypen.
Zeig doch endlich mal ein wenig mehr!

Wenn ich mir deine Codeschnipsel in ein Testprogramm meiner Wahl 
vervollständige, funktioniert alles so wie es soll.

von holger (Gast)


Lesenswert?

>Zeig doch endlich mal ein wenig mehr!

Machen wir es doch mal auf die altbewährte Tour:

@Stefan

Zeig deinen kompletten Code oder mach dich vom Acker!
Die Hellseher sind im Urlaub.

von sebastians (Gast)


Lesenswert?

> Diese Schleife wird 7 mal durchlaufen.
Stimmt nicht. sie geht von 1 bis 6, nicht von 0 bis 6. Also wird sie 6 
mal durchlaufen.

von Stefan (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Datentypen.
> Zeig doch endlich mal ein wenig mehr!

Kein Problem hier sind die verwendeten Datentypen:
1
int x;
2
long eingang[10];
3
char *pEnd;
4
volatile uint8_t new_ms, count;
5
volatile char empfang[30];

Und hier mal meine komplette Main.c:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/pgmspace.h>
4
5
#include <util/delay.h>
6
#include <stdio.h>
7
#include <inttypes.h>
8
9
#include "uart.h"
10
#include "global.h"
11
#include "defaults.h"
12
#include "pwm.h"
13
// ----------------------------------------------------------------------------
14
15
#define  PRINT(string, ...)    printf_P(PSTR(string), ##__VA_ARGS__)
16
17
static int putchar__(char c, FILE *stream) {
18
  uart_putc(c);
19
  return 0;
20
}
21
22
static FILE mystdout = FDEV_SETUP_STREAM(putchar__, 0, _FDEV_SETUP_WRITE);
23
24
// ----------------------------------------------------------------------------
25
26
// ----------------------------------------------------------------------------
27
// Hauptprogram
28
29
int main(void)
30
{
31
 id_set=0x01;
32
 DDRC=0xBF;
33
 DDRB=0xC3;
34
 DDRD=0xF4;
35
  // Initialisiere die UART Schnittstelle
36
  uart_init(UART_BAUD_SELECT(9600UL, F_CPU));
37
  // Umleiten der Standardausgabe => ab jetzt koennen wir printf() verwenden
38
  stdout = &mystdout;
39
    // Timer 1 OCRA1, als variablen Timer nutzen
40
  OCR1A = 255;
41
  TIMSK = (1 << OCIE1A) | (1 << OCIE1B);
42
  TCCR1B = (1 << WGM12) | 4;
43
  
44
  // Aktiviere Interrupts
45
  sei();
46
47
  for(uint8_t i=0; i<CHANNELS; i++){
48
    pwm_queue[i] = i;
49
  }
50
  for (uint8_t i = 0; i <= 15; i++) {
51
    PWM[i]=0;
52
  }
53
  pwm_update();
54
55
  int x, id, dimmwert[10], channel, action;
56
  long eingang[10];
57
  char *ptr;
58
  while (1) {
59
     if (new_ms){
60
      new_ms=0;
61
            empfang[count+1]='\0';
62
      count=0;
63
      PRINT("Eingang: %s\r\n", empfang);
64
      eingang[0] = strtol (empfang,&pEnd,16);
65
      pEnd++;
66
      for(x=1;x<6;x++){
67
        eingang[x] = strtol (pEnd,&pEnd,16);
68
        PRINT("Zahl%d:  %ld\r\n",x,eingang[x]);
69
        pEnd++;
70
      }
71
      id=eingang[0];
72
      if (id==id_set){
73
        channel=eingang[1];
74
        action=eingang[2];
75
        if (action==0){
76
          PWM[channel-15]=eingang[3];
77
          PWM[channel-14]=eingang[4];
78
          PWM[channel-13]=eingang[5];
79
        }
80
        if (action==1){
81
          for (uint8_t i=0; i<15; i=i+3){  
82
            PWM[i]=inhalt[2];
83
            PWM[i+1]=inhalt[3];
84
            PWM[i+2]=inhalt[4];
85
          }
86
        }
87
        pwm_update();
88
      }
89
    }  
90
  }
91
return 0;
92
}

von Karl H. (kbuchegg)


Lesenswert?

sebastians schrieb:
>> Diese Schleife wird 7 mal durchlaufen.
> Stimmt nicht. sie geht von 1 bis 6, nicht von 0 bis 6. Also wird sie 6
> mal durchlaufen.

Richtig
Und zusammen mit dem ersten Extrahieren ausserhalb der Schleife sind es 
7 Aufrufe von strtol, was trotzdem immer noch falsch ist.

von Stefan (Gast)


Lesenswert?

Da hast du natürlich recht das die Schleife einmal zu oft durchlaufen 
wird, dies habe ich geändert doch mein Problem das nur 0 in der variable 
eingang ist, bleibt weiterhin bestehen und ich weiß nicht warum.

von Karl H. (kbuchegg)


Lesenswert?

Stefan schrieb:
> Da hast du natürlich recht das die Schleife einmal zu oft durchlaufen
> wird, dies habe ich geändert doch mein Problem das nur 0 in der variable
> eingang ist, bleibt weiterhin bestehen und ich weiß nicht warum.

Mach mal deinen String konstant.
Du ´zeigst nicht, wo der String herkommt, auch da könnte noch was sein. 
Wenn im String noch irgendwelche Leerzeichen oder so rumlungern, dann 
sieht man die manchmal bei Kontrollausdrucken nur schwer.

1
 while (1) {
2
     if (new_ms){
3
      new_ms=0;
4
            empfang[count+1]='\0';
5
      count=0;
6
7
      strcpy( empfang, "1.f.0.0.0.1.$" );
8
9
      PRINT("Eingang: %s\r\n", empfang);
10
      eingang[0] = strtol (empfang,&pEnd,16);
11
      pEnd++;
12
      for(x=1;x<6;x++){
13
        eingang[x] = strtol (pEnd,&pEnd,16);
14
        PRINT("Zahl%d:  %ld\r\n",x,eingang[x]);
15
        pEnd++;
16
      }
17
18
....

von Stefan (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Mach mal deinen String konstant.

Hab ich gemacht leider gleiches Ergebniss wie vorher. Im Array sind 
leider nach wievor nur Nullen.

Karl heinz Buchegger schrieb:
> Du ´zeigst nicht, wo der String herkommt, auch da könnte noch was sein.

Hier mal der Code vom UART-Interrupt wo der String gebildet wird:
1
SIGNAL(UART0_RECEIVE_INTERRUPT)
2
/*************************************************************************
3
Function: UART Receive Complete interrupt
4
Purpose:  called when the UART has received a character
5
**************************************************************************/
6
{
7
  unsigned char tmphead;
8
  unsigned char data;
9
  unsigned char usr;
10
  unsigned char lastRxError;
11
12
13
  /* read UART status register and UART data register */ 
14
  usr  = UART0_STATUS;
15
  data = UART0_DATA;
16
  empfang[count]=data;
17
  count++;
18
  if (data=='$'){
19
    new_ms=1;
20
  }
21
  /* */
22
#if defined( AT90_UART )
23
  lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
24
#elif defined( ATMEGA_USART )
25
  lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
26
#elif defined( ATMEGA_USART0 )
27
  lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );
28
#elif defined ( ATMEGA_UART )
29
  lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
30
#endif
31
    
32
  /* calculate buffer index */ 
33
  tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
34
  
35
  if ( tmphead == UART_RxTail ) {
36
    /* error: receive buffer overflow */
37
    lastRxError = UART_BUFFER_OVERFLOW >> 8;
38
  }else{
39
    /* store new index */
40
    UART_RxHead = tmphead;
41
    /* store received data in buffer */
42
    UART_RxBuf[tmphead] = data;
43
  }
44
  UART_LastRxError = lastRxError;   
45
}

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.