Forum: Mikrocontroller und Digitale Elektronik strcmp() gibt immer "true" zurück


von Peter C. G. (ilem0n)


Lesenswert?

Hallo Leute, folgendes Problem.

Ich nutze einen ATMega8 welchen ich via USART einen Befehl sende.
Naheliegend ist also eine IF Anweisung in Verbindung mit strcmp() 
nachdem der Befehl komplett empfangen wurde.

Interessanterweise scheint strcmp() immer true auszuspucken.

Bei folgendem CodeBeispiel werden beide Ausgänge (OUT_OPEN, OUT_CLOSE) 
angesteuert egal welchen String ich ihm schicke.

Kann mir das jmd erklären ?
1
#define uart_buffer_size 32
2
volatile uint8_t usart_RX_Complete = 0;            // Flag, String komplett empfangen
3
volatile uint8_t usart_TX_Complete = 1;            // Flag, String komplett gesendet
4
char usart_RX_buffer[USART_BUFFER_SIZE];      // Empfangspuffer
5
char usart_TX_buffer[USART_BUFFER_SIZE];      // Sendepuffer
6
7
//Hilfsmethoden
8
void initUSART();
9
void sendString(char* string);
10
11
//Hauptmethode
12
int main(void)
13
{
14
  //I/O-Ebene Konfigurieren
15
  DDRB &= ~((1<<IN_CLOSED) | (1<<IN_OPENED));
16
  PORTB |= (1<<IN_CLOSED) | (1<<IN_OPENED);
17
   
18
  DDRC |= (1<<OUT_STATUS_LED) | (1<<OUT_OPEN) | (1<<OUT_CLOSE);
19
  
20
  
21
  initUSART();  //USART initalisieren
22
  sei();      //Globale Interrupts zulassen
23
24
  //Hauptschleife  
25
  while(1){
26
    //PORTC &= ~((1<<OUT_CLOSE) | (1<<OUT_OPEN));
27
    PORTC |= (1<<OUT_STATUS_LED);
28
    _delay_ms(1000);
29
    PORTC &= ~(1<<OUT_STATUS_LED);
30
    _delay_ms(1000);
31
    
32
    if (usart_RX_Complete == 1){
33
/* Hier werden beide IF-Anweisungen ausgeführt, egal was im usart_RX_buffer steht */
34
      if (strcmp(usart_RX_buffer, "Test")){
35
        PORTC |= (1<<OUT_OPEN);
36
      }
37
      if (strcmp(usart_RX_buffer, "Error")){
38
        PORTC |= (1<<OUT_CLOSE);
39
      }
40
      usart_RX_Complete = 0;
41
    }

von Walter T. (nicolas)


Lesenswert?

Wieviele Zeichen passen den in den USART-buffer? Und was passiert, wenn 
der Buffer gelesen wird?

von foo (Gast)


Lesenswert?

strcmp() gibt 0 zurück wenn die Strings gleich sind, einen Wert größer 0 
wenn das erste nicht-gleiche Zeichen im ersten String einen höheren Wert 
hat und einen Wert kleiner eins im umgekehrten Fall.

von Εrnst B. (ernst)


Lesenswert?

dir ist klar, das strcmp zwei Strings auf "Größer/Kleiner" vergleichen 
soll, und entsprechend >0 / <0 zurückgibt?

Nur wenn die Strings gleich sind, kommt 0 raus. d.h.
1
if (strcmp(usart_RX_buffer, "Test")==0){ ...

von Peter C. G. (ilem0n)


Lesenswert?

foo schrieb:
> strcmp() gibt 0 zurück wenn die Strings gleich sind, einen Wert größer 0
> wenn das erste nicht-gleiche Zeichen im ersten String einen höheren Wert
> hat und einen Wert kleiner eins im umgekehrten Fall.

Upps ja stimmt ^^das erklärte dann wohl ^^ haha ;) So simpel kanns sein 
^^

Vielen dank


Manchmal sieht man den Wald vor lauter Bäumen nicht ^^

von foo (Gast)


Lesenswert?

foo schrieb:
> wenn das erste nicht-gleiche Zeichen im ersten String einen höheren Wert
> hat und einen Wert kleiner eins im umgekehrten Fall.

Korrekterweise muss es "einen Wert kleiner 0 im umgekehrten Fall" heißen

von Peter C. G. (ilem0n)


Lesenswert?

Wobei jetzt eher interessant wäre wieso ich nicht auf 0 komme.

Ich sende ihm Exakt den passenden String und trotzdem gibt strcmp() 
nicht 0 raus.
Fällt jmd etwas auf ?

Hier mal der ganze code:
1
/*
2
 * FerRemote.c
3
 *
4
 * Version: 0.1 
5
 *
6
 * Created: 25.07.2013 01:37:51
7
 *  Author: iLem0n
8
 */ 
9
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
#include <util/delay.h>
13
#include <string.h>
14
15
#define USART_BUFFER_SIZE 32
16
#define BAUD 9600UL
17
18
//Baudrate und Taktfrequenz prüfen
19
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
20
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))
21
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)
22
23
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
24
#error Systematischer Fehler der Baudrate größer 1% und damit zu hoch!
25
#endif
26
27
//Ein-/Ausgänge
28
#define IN_OPENED PB0
29
#define IN_CLOSED PB1
30
31
#define OUT_OPEN PC0
32
#define OUT_CLOSE PC1
33
#define OUT_STATUS_LED PC2
34
35
//Globale Variablen
36
#define uart_buffer_size 32
37
volatile uint8_t usart_RX_Complete = 0;            // Flag, String komplett empfangen
38
volatile uint8_t usart_TX_Complete = 1;            // Flag, String komplett gesendet
39
char usart_RX_buffer[USART_BUFFER_SIZE];      // Empfangspuffer
40
char usart_TX_buffer[USART_BUFFER_SIZE];      // Sendepuffer
41
42
//Hilfsmethoden
43
void initUSART();
44
void sendString(char* string);
45
46
//Hauptmethode
47
int main(void)
48
{
49
  //I/O-Ebene Konfigurieren
50
  DDRB &= ~((1<<IN_CLOSED) | (1<<IN_OPENED));
51
  PORTB |= (1<<IN_CLOSED) | (1<<IN_OPENED);
52
   
53
  DDRC |= (1<<OUT_STATUS_LED) | (1<<OUT_OPEN) | (1<<OUT_CLOSE);
54
  
55
  
56
  initUSART();  //USART initalisieren
57
  sei();      //Globale Interrupts zulassen
58
59
  //Hauptschleife  
60
  while(1){
61
    /*
62
    PORTC &= ~((1<<OUT_CLOSE) | (1<<OUT_OPEN));
63
    PORTC |= (1<<OUT_STATUS_LED);
64
    _delay_ms(1000);
65
    PORTC &= ~(1<<OUT_STATUS_LED);
66
    _delay_ms(1000);
67
    */
68
    
69
    if (usart_RX_Complete == 1){
70
      sendString(usart_RX_buffer);
71
      
72
      if (strcmp(usart_RX_buffer, "Test\r") == 0){
73
        PORTC |= (1<<OUT_STATUS_LED);
74
      }
75
      if (strcmp(usart_RX_buffer, "Test\0") == 0){
76
        PORTC |= (1<<OUT_OPEN);
77
      }
78
      if (strcmp(usart_RX_buffer, "Test\n") == 0){
79
        PORTC |= (1<<OUT_CLOSE);
80
      }
81
      
82
     
83
      /*
84
      sendString(usart_RX_buffer);
85
      if (strcmp(usart_RX_buffer,"OpenCage")){
86
        while ( PINB & (1<<IN_OPENED)){
87
          PORTC |= (1<<OUT_OPEN);
88
        }
89
        PORTC &= ~(1<<OUT_OPEN);
90
        sendString("Cage_Opened"); 
91
      }
92
      
93
      if (strcmp(usart_RX_buffer, "CloseCage")){
94
        while ( PINB & (1<<IN_CLOSED)){
95
          PORTC &= ~(1<<OUT_OPEN);
96
          PORTC |= (1<<OUT_CLOSE);
97
        }
98
        PORTC &= ~(1<<OUT_CLOSE);
99
        sendString("Cage_Closed");
100
      }
101
      */
102
      usart_RX_Complete = 0;
103
    }
104
  }
105
}
106
107
//###### USART #####
108
void initUSART(){
109
  UBRRH = (unsigned char)(UBRR_VAL>>8);
110
  UBRRL = (unsigned char) UBRR_VAL;
111
  
112
  UCSRB = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE);    //RXEN(Empfang), TXEN(Senden), RXCIE(Empfang komplett Interrupt),
113
  UCSRC = (1<<URSEL) | (3<<UCSZ0);  //1 Stop Bit(s), 8-bit
114
}
115
116
//##### Senden #####
117
void sendString(char* string){
118
  if (usart_TX_Complete == 1){
119
    strcpy(usart_TX_buffer, string);  //String in Sendebuffer laden 
120
    usart_TX_Complete = 0;        //Flag zurücksetzen 
121
    UCSRB |= (1<<UDRIE);        //Senden Interrupt erlauben
122
  }
123
}
124
125
//###### Interrupts #####
126
ISR(USART_RXC_vect) {
127
  //Init
128
  static uint8_t usart_RX_cnt; 
129
  char data;
130
  
131
  data = UDR;                        //Zeichen aus Empfangsregister laden
132
  
133
  if (!usart_RX_Complete) {                //Wenn Empfangen nicht abgeschlossen
134
    if (data=='\r') {                  //Wenn CarriageReturn
135
      usart_RX_buffer[usart_RX_cnt]="\0";        //String terminieren
136
      usart_RX_Complete=1;              //"Empfang komplett"-Flag setzten  
137
      usart_RX_cnt=0;                  //Empfangszähler rücksetzen 
138
    }else if (usart_RX_cnt<(USART_BUFFER_SIZE-1)) {    //Bufferüberlauf verhindern
139
      usart_RX_buffer[usart_RX_cnt]=data;        //Zeichen in Empfangsbuffer schreiben
140
      usart_RX_cnt++;                  //hochzählen
141
    }
142
  }
143
}
144
145
ISR(USART_UDRE_vect) {
146
  //Init
147
  static char* usart_TX_pointer = usart_TX_buffer;  //Pointer auf Sendebuffer
148
  char data;
149
150
  data = *usart_TX_pointer++;              //Zähler im Sendebuffer um 1+ verschieben 
151
  
152
  if (data=="\0") {                  //Wenn terminiert,
153
    UCSRB &= ~(1<<UDRIE);              //Interrupt verbieten
154
    usart_TX_pointer = usart_TX_buffer;        //Pointer zurücksetzen
155
    usart_TX_Complete = 1;              //"Senden komplett"-Flag setzen 
156
  }else UDR = data;                  //Wenn nicht termniniert Zeichen senden
157
}

von Εrnst B. (ernst)


Lesenswert?

Peter C. Glade schrieb:
> Wobei jetzt eher interessant wäre wieso ich nicht auf 0 komme.

Vermutung: Dein Terminal-Programm sendet CRLF, da wird keiner deiner 
Tests glücklich.

evtl. str*n*cmp mit Länge 4 verwenden?

Oder gleich richtig parsen, strtok &co...


Edith:
Hab grad erst deine RXC-ISR gesehen.
das \r filterst du da ja schon raus... Aber:


Test\r\n kommt an.
bei \r setzt du usart_RX_cnt auf 0.
\n kommt aber trotzdem hinterher.
Buffer enthält dann also
"\nest\0"


Edith2: das sollte eigentlich dein "complete"-Flag verhindern...

von Basti (Gast)


Lesenswert?

versuch halt mit strstr(...

von Karl H. (kbuchegg)


Lesenswert?

Ein kleiner Tip, um solchen Dingen auf die Spur zu kommen.

Das hier
1
    if (usart_RX_Complete == 1){
2
      sendString(usart_RX_buffer);

ist schon gut. Den String zurückschicken ist ok.
Aber: Es gibt auch Zeichen im String, wie die berühmten \r oder \n, die 
sieht man dann im Terminal nicht oder nur sehr schwer. Genausowenig wie 
man Leerzeichen (als schlampiger) Mensch nicht sieht.

D.h. es ist eine gute Idee, sich vor dem STring und hinter dem String 
Terminierungszeichen auszugeben!
1
    if (usart_RX_Complete == 1){
2
      sendString("#");
3
      sendString(usart_RX_buffer);
4
      sendString("#");

tippst du jetzt zb
1
Test
im Terminal, dann muss das Echo so aussehen:
1
#Test#

Sieht es so aus
1
#
2
Test#
dann hast du einen Zeilenumbruch am Anfang des Srings. Sieht es so aus
1
#Test
2
#
dann hast du einen Zeilenumbruch am Ende des Strings. Achte auch auf 
eventuelle Leerzeichen. kriegst du als Echo
1
#Test #
dann hat sich ganz offensichtlich ein Leerzeichen an das Ende des 
Strings gemogelt.

Zur Kontrolle ist es auch immer gut, wenn man sich zusätzlich noch die 
Stringlänge mit ausgeben lässt.
1
    if (usart_RX_Complete == 1){
2
      sendInt( strlen(usart_RX_buffer) );
3
      sendString("#");
4
      sendString(usart_RX_buffer);
5
      sendString("#");
denn dann bleiben auch ansonsten komplett 'unsichtbare' Zeichen nicht 
unentdeckt. Steht dann im Terminal
1
5#Test#
dann ist irgendwo ein nicht darstellbares Zeichen im String versteckt.

Hint2: für eine derartige Debug-Ausgabe lohnt es sich, eine eigene 
Funktion zu machen.

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.