mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Zahl im String finden


Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo an alle!

Hab da ein Problem und ich komm nicht drauf, wieso das nicht 
funktioniert:

Und zwar will ich aus einem String eine Zahl herausfiltern.

Der String sieht z.B. so aus:

> char string[]="PARAM#123";

nun will ich die Zahl 123 herausfiltern. Ich habe es bisher so probiert:

> volatile int stringPosition=0;

> while(string[stringPosition]!='#')
> {
>   stringPosition++;
> }
> for(i=stringPosition, j=0; i<(stringPosition+3); i++, j++)
> {
>   zeitString[j]=string[i+1];
> }
> zeit1=atoi(zeitString);

wenn der String jetzt z.B. "PARAM#001" ist, ist zeit1=1, aber wenn im 
String jetzt "PARAM#010" steht, dann ist zeit1=0

Wieso liest er das nicht alle drei Stellen ein???

Bitte um Hilfe!

lg Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zeit1 = atoi( strchr(string, '#') + 1);


Peter

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ peter

kannst du mir erklären, was das genau macht?

Autor: Bartholomäus Steinmayr (sam_vdp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du deinen zeitString richtig initialisiert (z.B. char 
zeitString[4]) und terminiert (mit einem 0-Byte, z.B. so: 
zeitString[4]=0).
 Könnte sein, dass atoi da drüber stolpert.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Bartholomäus Steinmayr

jep,

> xdata volatile char zeitString[4];

dürfte normal passen, oder muss ich

> xdata volatile char zeitString[4]=0; schreiben?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter H. wrote:
> @ peter
>
> kannst du mir erklären, was das genau macht?

strchr sucht ein Zeichen im String und gibt den Zeiger darauf zurück.

Deine Zahl beginnt dahinter, also "+1".

Und dann noch den Zeiger an atoi übergeben.


Peter

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ peter

danke, d.h ich brauch die ganzen schleifen gar nicht und brauch nur

> zeit1 = atoi( strchr(string, '#') + 1);

zu schreiben?

Wenn ja, was ist, wenn der String so aussieht: "PARAM#123#456"

werden in zeit1 dann nur die zeichen bis zum nächsten # gespeichert, 
oder muss ich das dann anders machen?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das '#' ist keine gültige Ziffer und daher bricht atoi dort ab.

Der korrekte Weg ist allerdings, erstmal nachzusehen, ob überhaupt ein 
'#' im String ist, z.B.:
if( strchr(string, '#') ){
// ...  # gefunden
}else{
// ... # nicht gefunden
}


Peter

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@peter

Ok, danke. Ich bin mir sicher, dass ein '#' im String ist, von dem her 
ist das dann kein Problem. Danke nochmal!

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ja, was ist, wenn der String so aussieht: "PARAM#123#456"

Peters Ansatz für eine beliebige Anzahl (auch 0) von Nummern:
#include <stdio.h>
#include <string.h>

char str[] = "PARAM#1#22#333#4444 blabla #55555 ende";

int main() {
  char *p;
  p = str;
  while(p=strchr(p, '#'))
    printf("%d\n", atoi(++p));
  return 0;
}

Die Zeile mit dem printf kannst du natürlich durch etwas anderes 
ersetzen, bspw.
array[n++] = atoi(++p);

wenn du die gefundenen Zahlen in ein Array schreiben möchtest.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo noch einmal an alle!

Hab jetzt mein Programm mit folgender Variante die letzte Zeit laufen 
gehabt:

Also der String sieht so aus:

>"PARAM#123*456+789:"

Und so lese ich das ein:

>zahl1=atoi(strchr(string,'#')+1);
>zahl2=atoi(strchr(string,'*')+1);
>zahl3=(atoi(strchr(string,'+')+1));

Nach längerem Testen stellte sich nun heraus, dass diese Art nicht immer 
zuverlässig ist. D.h. manchmal steht in den Variablen eine andere Zahl 
als im String und manchmal gar nichts.

Vielleicht sollte ich noch erwähnen, dass ich den String über die 
serielle Schnittstelle einlese, aber das Einlesen funktioniert.

Hat vielleicht einer eine Idee oder eine andere sichere Variante?

Bin für jeden Tip dankbar!

lg Peter

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ja alles ziemlich vage. Ich würde drauf tippen, daß da 
irgendwelcher Schrott eingelesen wird, der Deinen Parser aus dem Gleis 
haut.

Nur ohne gesichertes Wissen über die Eingangsdaten kommst Du nicht 
weiter... interessant ist nicht, was die Gegenseite der seriellen 
Leitung abgeschickt hat, sondern was tatsächlich angekommen ist.

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

Bewertung
0 lesenswert
nicht lesenswert
Peter H. wrote:
> Hallo noch einmal an alle!
>
> Hab jetzt mein Programm mit folgender Variante die letzte Zeit laufen
> gehabt:
>
> Also der String sieht so aus:
>
>>"PARAM#123*456+789:"
>
> Und so lese ich das ein:
>
>>zahl1=atoi(strchr(string,'#')+1);
>>zahl2=atoi(strchr(string,'*')+1);
>>zahl3=(atoi(strchr(string,'+')+1));
>
> Nach längerem Testen stellte sich nun heraus, dass diese Art nicht immer
> zuverlässig ist. D.h. manchmal steht in den Variablen eine andere Zahl
> als im String

Beispiel?

> und manchmal gar nichts.
Gar nichts kann nicht sein. Ein int hat immer einen Wert

>
> Hat vielleicht einer eine Idee

Übernimm nie das Ergebnis eines strchr ungeprüft.
wenn der NULL zurückliefert weiss niemand was der
atoi für ein Ergebnis liefern wird.

Dann bleieben noch die üblichen Verdächtigen:
Fehler sonstwo, Array Überlauf, String zu klein dimensioniert, ...
Dinge in der Art

> oder eine andere sichere Variante?

Das grundsätzliche Vorgehen ist ok.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger

Hallo! Danke erstmal für die schnelle Antwort.

Also wie schon gesagt schicke ich den String über die serielle 
Schnittstelle und der passt so, dass ist sicher.

Woran ich merke, dass da was ab und zu nicht stimmt?

Wenn ich bestimmte Werte per serieller Schnittstelle schicke, dann setze 
ich Leds um zu überprüfen, ob sie richtig eingelesen wurden. Es 
funktioniert ja auch an und ab, aber wie gesagt nicht immer. Und dass 
ist das, was ich überhaupt nicht verstehe, wieso das manchmal geht und 
wieso nicht.

Der Einlese-String ist auch groß genug, von da her dürfte auch nichts 
sein. Wo könnte dann der Fehler sein?

Wo ist ein Fehler, wenn es manchmal geht und dann wieder nicht?

Hoffe auf weitere Antworten wie auch auf etwaige andere 
Lösungsvorschläge.

lg Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Peter H. wrote:
> @Karl heinz Buchegger
>
> Hallo! Danke erstmal für die schnelle Antwort.
>
> Also wie schon gesagt schicke ich den String über die serielle
> Schnittstelle und der passt so, dass ist sicher.
>
> Woran ich merke, dass da was ab und zu nicht stimmt?
>
> Wenn ich bestimmte Werte per serieller Schnittstelle schicke, dann setze
> ich Leds um zu überprüfen, ob sie richtig eingelesen wurden. Es
> funktioniert ja auch an und ab, aber wie gesagt nicht immer. Und dass
> ist das, was ich überhaupt nicht verstehe, wieso das manchmal geht und
> wieso nicht.
>
> Der Einlese-String ist auch groß genug, von da her dürfte auch nichts
> sein. Wo könnte dann der Fehler sein?
>
> Wo ist ein Fehler, wenn es manchmal geht und dann wieder nicht?

Das ist sehr, sehr schwer zu sagen ohne Source Code.
Selbst mit Source Code ist es schwer :-)

Normalerweise sind solch sporadische Dinge auf
Array Overflows, Stack Overflows oder sonstige Schweinereien
zurückzuführen.

Was ich tun würde:
Ich würde auf jeden Fall mal die Return Werte der strchr
anschauen. Wahrscheinlich würde ich mir auch an dieser
Stelle eine Debug-Strecke über die Serielle zurück aufbauen
um zu sehen:
* Welcher String kommt den da (du bist nicht der erste der
  schwört, dass die Eingangswerte in Ordnung sind und wenn man
  dann genauer hinschaut, stellt man fest, dass dem nicht so ist :-)
* Welche Teilstrings wurden mit dem strchr identifiziert
* Was ist das Ergebnis vom atoi()
Ohne solche Debug-Mittel ist das ziemlich schwer zu finden.

Ich weiss schon, du willst wahrscheinlich hören, dass strchr oder
atoi manchmal Fehler machen. Schmink dir das gleich wieder ab.
Der Fehler liegt mit 99.9% Sicherheit in deinem Code.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger

>Ich weiss schon, du willst wahrscheinlich hören, dass strchr oder
>atoi manchmal Fehler machen. Schmink dir das gleich wieder ab.
>Der Fehler liegt mit 99.9% Sicherheit in deinem Code.

Du kennst mich ja gut. ;-)

Ja, du hast wahrscheinlich recht, also dann werde ich mal überprüfen, 
was strch() genau findet und was atoi() liefert.

Eins wäre vielleicht noch zu sagen:

Die Daten von der seriellen Schnittstelle kommen von einem Java 
Programm.
Wenn ich aber nun das Java-Programm mittels Hyperterminal simuliere. 
Also per Hand eintippe was kommen soll dann funktioniert es immer.

Vielleicht fällt dir dazu noch was ein?

lg Peter



Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich aber nun das Java-Programm mittels Hyperterminal simuliere.
> Also per Hand eintippe was kommen soll dann funktioniert es immer.

Na, wo wird dann wohl der Fehler liegen????

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

Bewertung
0 lesenswert
nicht lesenswert
Peter H. wrote:
> @Karl heinz Buchegger
>
> Eins wäre vielleicht noch zu sagen:
>
> Die Daten von der seriellen Schnittstelle kommen von einem Java
> Programm.
> Wenn ich aber nun das Java-Programm mittels Hyperterminal simuliere.
> Also per Hand eintippe was kommen soll dann funktioniert es immer.

Da klingeln bei mir alle Alarmglocken, dass du dir
auf jeden Fall das was von der Schnittstelle kommt in
irgendeiner Form anschauen sollst.

>
> Vielleicht fällt dir dazu noch was ein?

Da fällt mir zum Beispiel ein, dass das Java Programm
die Daten wesentlich schneller senden kann als du tippen
kannst -> hast du ein Handshake implementiert?

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, hab jetzt mal ausgiegig getestet.

Ich hab mir den ganzen String gespeichert und dann wieder ausgeben.

Bei den werten Zahlen 2, 50 und 100 sollen leds leuchten.
Jetzt hat z.B. nur die led für 2 geleuchtet, aber der String sah 
folgendermaßen aus:

>PARAM#002*050+0100:

D.h. es müsste funktionieren. Also weiter Fehlersuche.


Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>PARAM#002*050+0100:

Woher weiß Du, daß der Sting so ausgesehen hat? Hast Du ihn im µC 
gespeichert und dann im Debugger angesehen?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Führende 0: atoi interpretiert Zahl als oktal

Peter

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Uhu Uhuhu

Ich hab ihn wieder zum hyperterminal geschickt!

@Peter Dannegger

Heißt das, ich muss schauen, dass vor der Zahl keine Nullen kommen? Aber 
im Hyperterminal hat es auch mit Nullen davor geklappt.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach ja, noch was:

Also im String steht:

>PARAM#002*050+0100:

Die leds für zahl1 und zahl2 leuchten, für die zahl3 nicht, obwohl es im 
String steht.
Dann hab ich mir die zahlen noch einmal geschickt
zahl1=2
zahle2=50
zahl3=0

???

also kann es doch am Einlesen liegen, oder?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter H. wrote:

> im Hyperterminal hat es auch mit Nullen davor geklappt.

Dann macht atoi wohl doch kein oktal draus.


Peter

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Führende 0: atoi interpretiert Zahl als oktal

Nein, habe gerade die Definition für atoi bei M$ nachgelesen - hätte 
mich auch schwer verblüfft, wenn Du recht hättest...

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du einen Debugger an Deinen µC hast, dann schreib doch einfach 
hinter den Befehl, der die letzte Zahl einliest, sowas:

   if (zahl3 == 0)
      zahl3 = zahl3;

Auf die bedingt ausgeführte Anweisung - die nichts bewirkt - setzt Du 
einen Debugger-Haltepunkt.

Damit Du die Strings ansehen kannst, machst Du was in der Art:

   char *S1, *S2, S3;

   S1 = strchr(string,'#') + 1;
   zahl1=atoi(S1);
   ...

Dann kannst Du Dir die Strings im Debugger ansehen und mußt nicht 
rätselraten... Achte auch darauf, daß die S*-Pointer auch wirklich in 
Deinen Puffer zeigen!

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Uhu Uhuhu

Ich muss auch nicht rätselraten, ich hab es zwar nicht mit dem Debugger 
gemacht, aber ich weiß, dass im String das Richtige steht.

Das hab ich jetzt ausgiebig getestet.

Und ich weiß jetzt auch immer, was in den Zahlen steht.

Wenn die entsprechende Led nicht leuchtet, dann steht in der Zahl auch 
nicht das Richtige.

Ich habe die Zahlen öfter überprüft, nicht nur mit den Leds. Ich hab sie 
auch so anggesehen.

Somit muss wohl der Fehler beim Einlesen sein, oder?

Also bei:

>zahl1=atoi(strchr(string,'#')+1);
>zahl2=atoi(strchr(string,'*')+1);
>zahl3=(atoi(strchr(string,'+')+1));

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Glaubst Du wirklich, daß Du auf Anhieb in den Routinen, die vor Dir 
tausende von Programmierern erfolgreich benutzt haben und deren korrekte 
Implementierung seit 30 Jahren bekannt ist, einen Fehler findest?

Eher fällt der erste Mai auf einen Freitag den 13...

Checks nochmal so nach, wie ich es vorhin beschrieben habe.

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Somit muss wohl der Fehler beim Einlesen sein, oder?

Stimmt.

Du machst keine Fehler. Nur die anderen.

Autor: Lukas D. (ltd)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hab mir den thread gerade durchgelesen und da stellt sich mir doch eine 
frage:

@ Peter H.: Wieso bist du dir so sicher das der string, den du von der 
seriellen schnittstelle bekommst tatsächlich dem string entspricht, den 
du erwartest?

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Lukas D.

Hallo!

Ich habe das Programm sozusagen angehalten, den String abgespeichtert 
und dann wieder über die serielle Schnittstelle zum Hyperterminal 
gesendet. D.h. ich habe das Java-Programm geschlossen und dann den 
String zum Hyperterminal gesendet. Und der String passt, nur in den 
Zahlen steht manchmal das Richtige drinnen und manchmal nicht.

Ich bin immer noch nicht dahinter gekommen wieso.

@all

Mir ist schon klar, dass ich da wo einen Fehler habe. Is ja klar, wer 
sonst? Und dass die Funktionen funktionieren will ich auch nicht 
anzweifeln, sondern ich denke mir nur, dass ich sie eventuell falsch 
verwende.

lg Peter

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmal: Machs, wie ich am 04.05.2007 20:07 geschrieben habe. Du mußt 
wirklich in die Variablen im µC gucken, alles andere ist 
Kaffeesatzleserei.

Es ist z.B. denkbar, daß es sich um ein dynamisches Problem handelt, das 
erst dann entsteht, wenn Du den empfangenen String schon zurückgeschickt 
hast - z.B. daß während der Verarbeitung des Pufferinhaltes von der 
Gegenstelle schon wieder was neues in den Puffer geschrieben wird - 
Fachausdruck Racecondition.

Solche Dinger kriegt man am besten mit der Haltepunktfalle, die ich oben 
skizziert habe.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Uhu Uhuhu

Hallo!

Es könnte tatsächlich sein, dass sich da auch noch andere Zeichen in den 
String schmuggeln. Weil es werden kurz danach, auch noch andere Zeichen 
vom Java aus gesendet (vl ja zeitgleich???). Ich verstehe nur nicht, 
wieso dann der String im Hyperterminal passt. Aber ich glaube schon, 
dass du recht hast, dass ich nur im µC schauen kann, was wirklich 
drinnen steht.

Das Problem ist leider nur, dass ich vom debuggen nicht viel Ahnung habe 
und es deswegen damit noch nicht probiert habe.

Also kann es sein, dass obwohl der String im Hyperterminal richtig 
steht, er im µC anders gespeichert ist?


Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Also kann es sein, dass obwohl der String im Hyperterminal richtig
>steht, er im µC anders gespeichert ist?

Ja: Wenn er kurz nach dem Absenden an das HT im µC zerdroschen wurde - 
z.B. von der Interrupt-Routine, die für das Datenempfangen auf der 
Leitung verantwortlich ist.

Benutzt Du nur einen einzigen Empfangspuffer?

> Das Problem ist leider nur, dass ich vom debuggen nicht viel Ahnung habe
> und es deswegen damit noch nicht probiert habe.

Dann ist das die Gelegenheit, es zu lernen...

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, ich habe nur einen Empfangsbuffer.

Aber den String schicke ich erst, nachdem ich die Zahlen eingelesen 
habe. Und siehe da, in den Zahlen steht nicht das Richtige, aber dann im 
Hyperterminal steht der String richtig.

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Poste mal Deinen Code.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, das sind jetzt nur ein paar Auszüge:

die Variablen sind global und volatile
void main (void)
{
  init();
  led1=0;
    
  while(1)
  {
    getParam();

    //Hier arbeite ich mit den Zahlen dann weiter

  }    
    
}

void serISR (void) interrupt 4
{
  if(RI)
  {
    RI=0;
    rec=SBUF;

    if((rec=='\r')||(rec=='\n'))
    {  
      serflag=1;
    }

    else
    {
      receive[cnt]=rec;
      cnt++;
    }
  }
}

void getParam (void)  
{  
  if(serflag==1)
  { 
    serflag=0;
          
    if(strstr(receive, "PARAM"))
    {                
      zahl1=0;
      zahl2=0;
      zahl3=0;
      zahl1=atoi(strchr(receive,'#')+1);
      zahl2=atoi(strchr(receive,'*')+1);
      zahl3=(atoi(strchr(receive,'+')+1))*10;

      //Leds zum Testen
      if(zeit==2)
        led2=0;
        
      if(kP==50)
        led3=0;
        
      if(maxPegelstand==1000)
        led4=0;  
    }
    clearString();
    cnt=0;
  }
}

void clearString (void)
{
  int i;

  for(i=0; i<200; i++)
  {
    receive[i]=0;
  }
}

  

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Überleg Dir mal, was passiert, wenn in receive gerade "PAR" steht, wenn 
getParam aufgerufen wird...

Ich sehe gerade, daß das nicht vorkommen sollte...

Aber was passiert, wenn Zeichen kommen, bevor getParam cnt = 0 
ausgeführt hat?

Ich würde sagen, dann zerklopft die ISR Dir den Speicher...

Wenn das nicht zum Absturz führt, können natürlich trotzdem Daten 
überschrieben werden. Das Mindeste ist jedoch, daß der betreffende 
Datensatz verloren geht.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie gesagt, es handelt sich um Codeauszüge.

Hätte ich aber dazuposten können, mein Fehler:

Also, main noch einmal:
void main (void)
{
  init();
  led1=0;
    
  while(1)
  {

    if((serflag==1))  
    {
      serflag=0;
      if(strstr(receive,"ready"))
      {
        getParam();
      }
    }

    //Hier arbeite ich mit den Zahlen dann weiter

  }    
    
}

Aber außerdem wird serflag=1 erst gesetzt, wenn '\n' oder '\r' kommt und 
'\n' oder '\r' kommen erst am Ende des Strings, also muss der String 
schon komplett sein.

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sieh nochmal meinen vorigen Beitrag an - ich hatte daran noch 
rumgebastelt...

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist sogar der Fall, dass bevor cnt=0 gesetzt wird, noch Zeichen 
kommen.
Werden die dann nicht einfach hinten drangehängt und somit kann ich den 
String ja trotzdem auslesen, oder?

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du nullst den Puffer aus und dann finden die str*-Routinen den hinten 
angepappten Datensatz nicht, weil sie vorher auf ein NUL-Zeigen gestoßen 
sind.

Wahrscheinlich bekommst Du es folgendermaßen hin:

Wenn die ISR einen vollständigen Satz empfangen hat, kopiert sie ihn in 
einen separaten Puffer, der von getParam gelesen wird, setzt cnt selbst 
zurück und ist dann sofort wieder Empfangsbereit.

GetParam nullt nur seinen eigenen Puffer aus, wenn sie fertig ist.

Die ISR kopiert keine Daten in den Ausgabepuffer, wenn dessen erstes 
Byte != 0 ist und setzt stattdessen ein Overrun-Flag. Dabei geht ein 
Satz verloren.

Übrigens: Keiner der beiden Puffer muß volatile sein - überleg Dir 
warum...

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, hab ich das richtig verstanden?
void main (void)
{
  init();
  led1=0;
    
  while(1)
  {

    if((serflag==1))  
    {
      serflag=0;
      if(strstr(receive2,"ready"))
      {
        getParam();
      }
    }

    //Hier arbeite ich mit den Zahlen dann weiter

  }    
    
}

void serISR (void) interrupt 4
{
  if(RI)
  {
    RI=0;
    rec=SBUF;

    if((rec=='\r')||(rec=='\n'))
    {  
      serflag=1;
      strcpy(receive2, receive);
      cnt=0;
      clearString();
    }

    else
    {
      receive[cnt]=rec;
      cnt++;
    }
  }
}

void getParam (void)  
{  
  if(serflag==1)
  { 
    serflag=0;
          
    if(strstr(receive2, "PARAM"))
    {                
      zahl1=0;
      zahl2=0;
      zahl3=0;
      zahl1=atoi(strchr(receive2,'#')+1);
      zahl2=atoi(strchr(receive2,'*')+1);
      zahl3=(atoi(strchr(receive2,'+')+1))*10;

      //Leds zum Testen
      if(zahl1==2)
        led2=0;
        
      if(zahl2==50)
        led3=0;
        
      if(zahl3==1000)
        led4=0;  
    }
    clearString2();
  }
}

void clearString (void)
{
  int i;

  for(i=0; i<200; i++)
  {
    receive[i]=0;
  }
}

void clearString2 (void)
{
  int i;

  for(i=0; i<200; i++)
  {
    receive2[i]=0;
  }
}

Meiner Meinung nach müssen receive und receive2 schon volatile sein, 
sonst steht ja nicht immer der aktuelle Wert drinnen, oder? Und 
übergeben tu ich die Strings ja nie.

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, das kommt dem sehr nahe...

Ein paar kleine Optimierungen:

Sieh mal nach, ob Dein Compiler eine Funktion memset, oder setmem kennt 
- dann brauchst Du das Rad nicht nochmal zu erfinden.

Aber generell brauchst Du den zweiten Puffer garnicht auszunullen, denn 
die ISR benutzt strcpy und die kopiert die abschließende 0 mit.

Das clearString() in der ISR kannst Du Dir auch sparen, wenn Du im Block

    if((rec=='\r')||(rec=='\n')) {
       receive[cnt]= 0;
       ...
    }

den ersten Puffer ordentlich terminierst.

Zum Thema 'volatile':
Der Puffer, der nur von der ISR zugegriffen wird, muß nicht volatile 
sein - es gibt keine konkurrierenden Zugriffe.

Statt den zweiten Puffer volatile zu machen, reicht es aus, serflag 
volatile zu definieren; wenn die von der ISR gesetzt ist, greift die ja 
nicht mehr darauf zu.

Ein weiteres mögliches Problem: 'if((rec=='\r')||(rec=='\n'))'.

Was wenn die Gegenstelle - wie das unter Windows üblich ist - eine Zeile 
mit \r\n abzuschließt?

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, stimmt, danke!

Ich werde dann das mal alles programmieren und testen und schauen, ob es 
funktioniert.

Vielen Dank für deine Hilfe.

lg Peter

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit '\n' und '\r' hast du wahrscheinlich recht.

Ich hab mir nun folgendes überlegt:

In meinem Programm kommen öfter solche Abfragen vor und es funktioniert 
immer, bis auf das eine mal, also könnte ich es doch einfach so machen:
void getParam (void)  
{  
  if(serflag==1)
  { 
    serflag=0;
          
    if(strstr(receive2, "PARAM"))
    {  
      strcpy(receive2,receive);              
      zahl1=0;
      zahl2=0;
      zahl3=0;
      zahl1=atoi(strchr(receive2,'#')+1);
      zahl2=atoi(strchr(receive2,'*')+1);
      zahl3=(atoi(strchr(receive2,'+')+1))*10;

      //Leds zum Testen
      if(zeit==2)
        led2=0;
        
      if(kP==50)
        led3=0;
        
      if(maxPegelstand==1000)
        led4=0;  
    }
  }
}

Also nur bei dieser Abfrage mit receive2 arbeiten, dann kann mir ja auch 
nichts mehr reinpfuschen, oder?

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist keine gute Idee, denn die Synchronisation zwischen ISR und 
Vordergrund wird dadurch gelockert. Das Umkopieren sollte die ISR 
machen.

Wenn sich Deine ISR merkt, daß sie gerade den Puffer umkopiert hat, 
reicht es, alle Zeichen kleiner ' ' einfach wegzuschmeißen, bis
was >= ' ' kommt und dann wieder in den ersten Puffer kopieren.

Der Vorteil ist, daß Du unabhängig von Betriebssystemgebräuchen 
bezüglich Zeilenende wirst - solange \r und/oder \n benutzt werden.

Autor: Peter H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da hast du wieder Recht, ich werd das dann mal so probieren.

Danke noch einmal für die vielen Tips und Hilfestellungen!

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na wenigstens ist der erste Mai gerettet...

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.