Forum: Compiler & IDEs probleme bei Portierung von einem Konsolen Programm auf den AVR


von Björn C. (bjoernc) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo ich habe da ein kleines Problem bei einem programm von mir.
Das Problem ist folgendes: Ich bin gerade dabei, eine Art Konsole für 
den AVR zu schreiben. Dafür wollte ich ein paar String Manipulatoren 
schreiben sprich einer der mir in einem String bei entsprechenden 
Trennzeichen zB. bei set_date 05.09.09 dann in drei unsigned char Werte 
umwandelt so das ich mit dem zB. 0x05 usw. weiter rechnen kann. 
Ausserdem gibt es eine Funktion, die dann die ersten chars im String 
untersucht so das ich dann weiß um welchen Befehl es sich handelt in 
diesem Fall um set_date.
So ich habe angefangen zu schreiben und habe dieses dann direkt auf dem 
PC getestet. Dieses Funktionen funktionieren auf dem PC wunderbar ohne 
Probleme. Nur auf dem ATMega 32 nicht.
Folgende Dinge habe versucht um das Problem besser eingrenzen zu können:

* den test String direkt als konstante im prog. Speicher zu speichern um 
zu schauen, ob die FUnktion den Befehl erkennt
* per USART den String übertragen und auch den String selbst über UART 
zurück übertragen lassen um evtl. Verbindungsprobleme erkennen zu 
können.

Der string den ich ausgeben lasse ist immer richtig (laut terminal 
programm kommen auch keine versteckten Zeichen wie zB. Steuerbefehle wie 
\n oä an) nur das Ergebnis in den betreffenden Funktionen ist Falsch 
obwohl auch in den Funktionen der String per USART richtig übertragen 
wird.
Daher ist meine Frage, hat evtl. jemand eine Idee an was das liegen 
könnte?
(die betreffende Funktionen findet ihr im Anhang)
Die Aufrufe waren im AVR wie folgt:
1
//per USART empfangen: (fragmentfree)
2
 if(read_usart_stream(inc_buffer,Buffersize-offset, &recieved_bytes, offset)==0){
3
     if(recieved_bytes>=11){              //11 für 11 Bytes die benötigt werden
4
  get_instruction(inc_buffer, offset+recieved_bytes);
5
    offset=recieved_bytes;
6
     }
7
  else{
8
    offset=0;
9
  } 
10
//... empfangenen stream ausgeben usw. usw.
11
}
12
//per konstante:
13
char tst_val[]="set_time 18:03:06";
14
get_instruction(tst_val,11);
zugehörige Funktionen:
1
void change_char(char *string, char comp_val, char ref_val){
2
  for(unsigned char i=0; i<255 && string[i]; i++){
3
    if(string[i]==comp_val) string[i]=ref_val;
4
  }
5
}
6
7
unsigned char comp_string( char * comp_string, char * ref_string){
8
  for(unsigned char i =0; i<0xFF && ref_string[i];i++)
9
    if(comp_string[i]!=ref_string[i]) return 0xff;
10
11
  return 0x00;
12
13
}
14
15
unsigned char str_to_int (char * ref_string, unsigned char position, unsigned char  values){
16
  unsigned char buffer[3]={0,0,0};  //max 3 stellen sind erlaubt...
17
  unsigned char value=0;
18
  for(unsigned char pos_tmp=(position+1); pos_tmp<=(position+values); pos_tmp++){
19
    buffer[pos_tmp-position-1]=ref_string[pos_tmp]-'0';
20
  }
21
  for(unsigned char i=1; i<=values; i++){
22
    value+=buffer[i-1];
23
    if(i!=values)value*=10;
24
  }
25
  return value;
26
}
27
28
unsigned char get_information(char * string,char f_sep,char n_sep, unsigned char values,unsigned char length, unsigned char * res_vect){
29
  unsigned char result=0, v_counter=0;
30
  for(unsigned char i=0; i<0xFF && string[i];i++){
31
    if(v_counter==0 && string[i]==f_sep){
32
      res_vect[v_counter]=str_to_int(string, i, length);
33
      v_counter++;
34
    }
35
    if(v_counter!=0 && string[i]==n_sep){
36
      res_vect[v_counter]=str_to_int(string, i, length);
37
      v_counter++;
38
    }
39
    if(v_counter>=values)  return 0x00;
40
  }
41
  return 0xFF;
42
}

von Karl H. (kbuchegg)


Lesenswert?

Björn Cassens schrieb:
>
1
> //per USART empfangen: (fragmentfree)
2
>  if(read_usart_stream(inc_buffer,Buffersize-offset, &recieved_bytes,
3
> offset)==0){
4
>      if(recieved_bytes>=11){              //11 für 11 Bytes die benötigt
5
> werden
6
>   get_instruction(inc_buffer, offset+recieved_bytes);
7
>     offset=recieved_bytes;
8
>      }
9
>   else{
10
>     offset=0;
11
>   }
12
> //... empfangenen stream ausgeben usw. usw.
13
> }
14
> //per konstante:
15
> char tst_val[]="set_time 18:03:06";
16
> get_instruction(tst_val,11);
17
>

Wieso 11?
Ich kann in deinem Code bzw in den Testdaten keine Begründung für 11 
finden.

>
1
> void change_char(char *string, char comp_val, char ref_val){
2
>   for(unsigned char i=0; i<255 && string[i]; i++){
3
>     if(string[i]==comp_val) string[i]=ref_val;
4
>   }
5
> }
6
>

Verzichte darauf, mittels Index-Variablen durch einen String 
durchzulaufen. Du brauchst sie nicht und es gibt keinen Grund da jetzt 
eine künstliche Beschränkung auf 255 Zeichen maximal einzuführen
1
void change_char(char *string, char comp_val, char ref_val){
2
  while( *string ) {
3
    if( *string == comp_val )
4
      *string = ref_val;
5
    string++;
6
  }
7
}

> unsigned char comp_string( char * comp_string, char * ref_string){
>   for(unsigned char i =0; i<0xFF && ref_string[i];i++)
>     if(comp_string[i]!=ref_string[i]) return 0xff;
>
>   return 0x00;
>
> }

Warum erfindest du hier das Rad neu?
Die Standardfunktion dafür heisst strcmp() und ist in string.h enthalten

http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F

> unsigned char str_to_int (char * ref_string, unsigned char position,
> unsigned char  values){
>   unsigned char buffer[3]={0,0,0};  //max 3 stellen sind erlaubt...
>   unsigned char value=0;
>   for(unsigned char pos_tmp=(position+1); pos_tmp<=(position+values);
> pos_tmp++){
>     buffer[pos_tmp-position-1]=ref_string[pos_tmp]-'0';
>   }
>   for(unsigned char i=1; i<=values; i++){
>     value+=buffer[i-1];
>     if(i!=values)value*=10;
>   }
>   return value;
> }

Ziemlich umständlich. Warum benutzt du nicht atoi?

> unsigned char get_information(char * string,char f_sep,char n_sep,
> unsigned char values,unsigned char length, unsigned char * res_vect){
>   unsigned char result=0, v_counter=0;
>   for(unsigned char i=0; i<0xFF && string[i];i++){
>     if(v_counter==0 && string[i]==f_sep){
>       res_vect[v_counter]=str_to_int(string, i, length);
>       v_counter++;
>     }
>     if(v_counter!=0 && string[i]==n_sep){
>       res_vect[v_counter]=str_to_int(string, i, length);
>       v_counter++;
>     }
>     if(v_counter>=values)  return 0x00;
>   }
>   return 0xFF;
> }

Aus der Funktion werde ich nicht richtig schlau.

In Summe denke ich, dass du das alles viel zu kompliziert angehst.

> Dafür wollte ich ein paar String Manipulatoren
> schreiben sprich einer der mir in einem String bei entsprechenden
> Trennzeichen

Kennst du die Funktion strtok()? Ich denke, dass strtok schon 70% dessen 
erledigt, was du da so mühsam zusammenschreibst.
Mittels strtok den kompletten String an den Leerzeichen in Einzelteile 
aufsplitten. Damit hast du dann Pointer auf die Einzelteile
      set_time
und   18:03:06

set_time ist das Kommando bei dessen Erkennung wird der erste 
Argumentstring an den : in 3 Einzelteile aufgesplittet (zb wieder mit 
strtok()) und jeder Einzelteil mittels atoi in eine Zahl umgewandelt. 
Fertig.

von Björn C. (bjoernc) Benutzerseite


Lesenswert?

hmm naja ich dachte das ich mit meinem Code ein wenig kleiner werde... 
und naja ich dachte darüberhinaus, dass gerade die Funktionen, die in 
string.h wären dann dohc ein bissl groß wären für ein uC.
Aber alles in allem habe ich grad mal meinen Code ein wenig aufgeräumt 
und naja ich habe einige potenzielle Fehlerquellen gefunden. Das werde 
ich gleich mal ausprobieren. Aber du hast recht mit den Funktionen die 
du mir genannt hast, ist es wahrscheinlich leichter naja - gut dann halt 
ein paar Stunden Arbeit (Fehlersuche) für die Tonne und um ein paar 
Erfahrungen und Überlegungen reicher.
Danke für deine Ausführliche Antwort.

von Karl H. (kbuchegg)


Lesenswert?

Björn Cassens schrieb:
> hmm naja ich dachte das ich mit meinem Code ein wenig kleiner werde...

Solange du Stringverarbeitung darauf aufbaust, mit einer Indexvariable 
alle Zeichen durchzugehen und nicht mit Pointer arbeitest, wird es 
ziemlich schwierig sein, etwas noch langsameres und größeres als deinen 
jetzigen Code zu schreiben.

> und naja ich dachte darüberhinaus, dass gerade die Funktionen, die in
> string.h wären dann dohc ein bissl groß wären für ein uC.

Ähm. Die meisten Funktionen in string.h sind in C-Quellcode 
ausgeschrieben einfache 3-Zeiler. strtok ist eine der Ausnahmen, das ist 
in der Tat etwas umfangreicher. So in der Gegend von 15 Zeilen.

Was ich damit sagen will:
Es ist sinnlos Dinge wie Stringverarbeitungsfunktionen in C selbst zu 
schreiben. Es sei denn, du benötigst Funktionalität, die du so nicht in 
string.h vorhanden hast bzw. nicht einfach daraus zusammensetzen kannst. 
Manchmal kann man auch die Funktionalität 2-er string Funktionen in eine 
einzige Schleife zusammenfassen, dann bringt das ein bischen was.
Aber gerade am Anfang ist das Wichtigste was du in C lernen kannst: 
welche Funktionen habe ich in der Standard-Library zu meiner Verfügung 
und wie kann ich sie benutzen bzw. wie kann ich aus diesen Funktionen 
komlpexere Funktionalität zusammensetzen. Dazu muss man aber den 
Funktionsvorrat kennen.

Nimm zb deine Funktion comp_string
1
unsigned char comp_string( char * comp_string, char * ref_string){
2
  for(unsigned char i =0; i<0xFF && ref_string[i];i++)
3
    if(comp_string[i]!=ref_string[i]) return 0xff;
4
5
  return 0x00;
6
7
}

und dagegen eine Standardimplementierung von strcmp
1
int strcmp( const char * str1, const char * str2 )
2
{
3
  while( *str1 && *str1 == *str2 ) {
4
    str1++;
5
    str2++;
6
  }
7
  return *str2 - *str1;
8
}

Nicht nur ist der Returnwert universeller (er verrät mir neben 
Ungleichheit auch noch welcher String den der Größere war) sondern er 
hat auch keine Längenbeschränkung auf 255 Zeichen.
Ob hingegen deine Version schneller oder kleiner ist, wage ich mal zu 
bezweifeln.

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.