www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Stringauswertung Problem


Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
long eingang[10];
char *ptr;
char delimiter[] = ".";

ptr = strtok(empfang,delimiter);
for(x=0;x<=6;x++){
eingang[x] = strtol(ptr, NULL, 16);
ptr = strtok(NULL, delimiter);
}

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?

Autor: Thomas K. (tomthegeek)
Datum:

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

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
eingang[0] = strtol (empfang,&pEnd,16);
for(x=1;x<=6;x++){
  eingang[x] = strtol (pEnd,&pEnd,16);
  pEnd++;
  PRINT("Zahl%d:  %ld\r\n",x,eingang[x]);
}

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

Bewertung
0 lesenswert
nicht 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:
>
>
> eingang[0] = strtol (empfang,&pEnd,16);
> 

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

>
> for(x=1;x<=6;x++){
> 
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.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
eingang[0] = strtol (empfang,&pEnd,16);
pEnd++;
for(x=1;x<=5;x++){
  eingang[x] = strtol (pEnd,&pEnd,16);
  pEnd++;
  PRINT("Zahl%d:  %ld\r\n",x,eingang[x]);
}

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

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

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
empfang[count]=data;
count++;
if (data=='$'){
 empfang[count]='\0';
 count=0;
 new_ms=1;
}

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.

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

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

Autor: holger (Gast)
Datum:

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

Autor: sebastians (Gast)
Datum:

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

Autor: Stefan (Gast)
Datum:

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

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

Und hier mal meine komplette Main.c:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include <util/delay.h>
#include <stdio.h>
#include <inttypes.h>

#include "uart.h"
#include "global.h"
#include "defaults.h"
#include "pwm.h"
// ----------------------------------------------------------------------------

#define  PRINT(string, ...)    printf_P(PSTR(string), ##__VA_ARGS__)

static int putchar__(char c, FILE *stream) {
  uart_putc(c);
  return 0;
}

static FILE mystdout = FDEV_SETUP_STREAM(putchar__, 0, _FDEV_SETUP_WRITE);

// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// Hauptprogram

int main(void)
{
 id_set=0x01;
 DDRC=0xBF;
 DDRB=0xC3;
 DDRD=0xF4;
  // Initialisiere die UART Schnittstelle
  uart_init(UART_BAUD_SELECT(9600UL, F_CPU));
  // Umleiten der Standardausgabe => ab jetzt koennen wir printf() verwenden
  stdout = &mystdout;
    // Timer 1 OCRA1, als variablen Timer nutzen
  OCR1A = 255;
  TIMSK = (1 << OCIE1A) | (1 << OCIE1B);
  TCCR1B = (1 << WGM12) | 4;
  
  // Aktiviere Interrupts
  sei();

  for(uint8_t i=0; i<CHANNELS; i++){
    pwm_queue[i] = i;
  }
  for (uint8_t i = 0; i <= 15; i++) {
    PWM[i]=0;
  }
  pwm_update();

  int x, id, dimmwert[10], channel, action;
  long eingang[10];
  char *ptr;
  while (1) {
     if (new_ms){
      new_ms=0;
            empfang[count+1]='\0';
      count=0;
      PRINT("Eingang: %s\r\n", empfang);
      eingang[0] = strtol (empfang,&pEnd,16);
      pEnd++;
      for(x=1;x<6;x++){
        eingang[x] = strtol (pEnd,&pEnd,16);
        PRINT("Zahl%d:  %ld\r\n",x,eingang[x]);
        pEnd++;
      }
      id=eingang[0];
      if (id==id_set){
        channel=eingang[1];
        action=eingang[2];
        if (action==0){
          PWM[channel-15]=eingang[3];
          PWM[channel-14]=eingang[4];
          PWM[channel-13]=eingang[5];
        }
        if (action==1){
          for (uint8_t i=0; i<15; i=i+3){  
            PWM[i]=inhalt[2];
            PWM[i+1]=inhalt[3];
            PWM[i+2]=inhalt[4];
          }
        }
        pwm_update();
      }
    }  
  }
return 0;
}

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

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

Autor: Stefan (Gast)
Datum:

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

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

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

 while (1) {
     if (new_ms){
      new_ms=0;
            empfang[count+1]='\0';
      count=0;

      strcpy( empfang, "1.f.0.0.0.1.$" );

      PRINT("Eingang: %s\r\n", empfang);
      eingang[0] = strtol (empfang,&pEnd,16);
      pEnd++;
      for(x=1;x<6;x++){
        eingang[x] = strtol (pEnd,&pEnd,16);
        PRINT("Zahl%d:  %ld\r\n",x,eingang[x]);
        pEnd++;
      }

....


Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
SIGNAL(UART0_RECEIVE_INTERRUPT)
/*************************************************************************
Function: UART Receive Complete interrupt
Purpose:  called when the UART has received a character
**************************************************************************/
{
  unsigned char tmphead;
  unsigned char data;
  unsigned char usr;
  unsigned char lastRxError;


  /* read UART status register and UART data register */ 
  usr  = UART0_STATUS;
  data = UART0_DATA;
  empfang[count]=data;
  count++;
  if (data=='$'){
    new_ms=1;
  }
  /* */
#if defined( AT90_UART )
  lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#elif defined( ATMEGA_USART )
  lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#elif defined( ATMEGA_USART0 )
  lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );
#elif defined ( ATMEGA_UART )
  lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#endif
    
  /* calculate buffer index */ 
  tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
  
  if ( tmphead == UART_RxTail ) {
    /* error: receive buffer overflow */
    lastRxError = UART_BUFFER_OVERFLOW >> 8;
  }else{
    /* store new index */
    UART_RxHead = tmphead;
    /* store received data in buffer */
    UART_RxBuf[tmphead] = data;
  }
  UART_LastRxError = lastRxError;   
}

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.