Forum: Mikrocontroller und Digitale Elektronik switch Anweisung default Zweig (Kompilerfehler?)


von Matthias R. (matsch)


Lesenswert?

Hallo Forum,
ich habe ein Problem mit folgender switch-case Anweisung:
1
switch (Befehl){
2
 case 'D' :                      
3
   uart_puts("ein D\r");
4
   break;
5
 case 'R' :                      
6
   uart_puts("ein R\r");
7
   break;
8
 case 'W' :
9
   uart_puts("ein W\r");
10
   break;
11
 case 'P' :                      
12
   uart_puts("ein P\r");
13
   break;
14
 default:
15
   uart_puts("nop\r");
16
   break;
17
}
In 'Befehl' steht ein Zeichen, welches ich über RS232 mit meinem 
ATMega88 empfange. Je nach empfangenem Zeichen wird eine Antwort über 
RS232 an den PC gesendet (mit der UART library von P. Fleury).
Das ganze funktioniert auch sehr gut.

Nun habe ich neu den default-Zweig eingefügt. Wenn jetzt ein ungueltiges 
Zeiche empfangen wird, soll ein 'nop' gesendet werden - funktioniert 
auch.

ABER: Wenn ein gültiges Zeichen empfangen wird (D, R, W oder P) wird 
neben dem zugehörigen Text auch immer noch das 'nop' aus dem default 
Zweig gesendet.
Nach meinem Verständnis soll der default Zweig aber nur durchlaufen 
werden, wenn keine andere Bedingung erfüllt ist, und nicht bei jeder 
richtigen UND falschen Bedingung.

Ist das ein Kompilerfehler oder habe ich einen Fehler zwischen den 
Ohren?
Wie erreiche ich, dass der default Zweig NUR bei ungültigen Zeichen 
durchlaufen wird?

P.S.
Ich verwende avr-gcc (WinAVR 20080610) 4.3.0

von Sven (Gast)


Lesenswert?

Das sieht eher nach einem Problem in der Datenübertragung aus. Z.b. 
verwendet dein Terminal 9 Bit, statt 8. o.ä. so dass dein µC denkt, es 
würde 2 Zeichen empfangen. setze mal dort an...

Zum debuggen: Einfach mal vor das Switch ein:
1
char str[8];
2
sprintf(str, "RX: %02X\n\r", Befehl);
3
printf(str);

von Sven P. (Gast)


Lesenswert?

Wie sendest du denn die Zeichen an den Controller? Am Terminal das 
Zeichen eigeben und Enter drücken..? --> Zwei Zeichen!

von Karl H. (kbuchegg)


Lesenswert?

Jede Wette du empfängst in Wirklichkeit nicht 1 Zeichen sondern 2. Zb 
ein abschliessendes Return nach dem Buchstaben.

Lass dir doch einfach mal den 'Befehlsbuchstaben' zurückgeben (als 
Zeichen und zusätzlich den ASCII Code in Zahlenform) dann siehst du was 
dein Programm wirklich zu Gesicht bekommt.

von Klaus (Gast)


Lesenswert?

Ich bin immer wieder erstaunt, das fast alle Kompilerfehler von 
Anfängern gefunden werden...

Oder ist es vielleicht doch einfach nur die Selbstüberschätzung der 
Anfänger, die immer zuerst dem Kompiler die Schuld geben?

von Karl H. (kbuchegg)


Lesenswert?

Klaus schrieb:
> Oder ist es vielleicht doch einfach nur die Selbstüberschätzung der
> Anfänger, die immer zuerst dem Kompiler die Schuld geben?

Ich unterstelle niemandem in dem Bereich eine böse Absicht.
Es ist einfach der Lernprozess, dass unser vermeintlich gut 
funktionierendes Gehirn ganz schnell den Überblick über vermeintlich 
einfache Abläufe verliert.

von (nein) (ich) (bin) (kein) (Gast)


Lesenswert?

versuche es mit einem lokalen funktionsblock, also {} nach jedem case


quasi case 'a': {//weil hier mehr als ein Befehl kommt}

von (nein) (ich) (bin) (kein) (Gast)


Lesenswert?

wenn du ein oszi hast, siehst du, ob zwei zeichen gesendet werden...
ist noch viel wahrscheinlicher, als dass du {} verwenden musst.

von Matthias R. (matsch)


Lesenswert?

> Ich bin immer wieder erstaunt, das fast alle Kompilerfehler von
> Anfängern gefunden werden...
@Klaus
OK, ich bin nicht der Profi, und habe auch nicht wirklich an einen 
Kompilierfehler geglaubt. Die echten Fehler des Kompilers sind bestimmt 
nicht von so einfacher Natur. Darum auch das '?'. Dafür kann ich besser 
Minigolf ;-)

@Sven, K-H.
Richtig, ich sende nicht nur ein Zeichen sondern eine Zeichenkette mit 
abschießendem 'CR' (ist die Ende Kennung). Zusammen bis zu 4 Zeichen 
(das CR mitgezählt.
Die Routine wird eigentlich aber erst aufgerufen, wenn die Ende Kennung 
gefunden wurde (so hofft der Anfänger).
Ich werde eure Tipps mal verfolgen. Danke schon mal. Ist echt gut, dass 
einige von euch hier auf andere Bäume hinweisen, wenn mann den Wald 
nicht mehr sieht.... Wobei ich auch immer für eine spitzfindige 
Bemerkung offen bin.

MfG
Matthias

von Matthias R. (matsch)


Lesenswert?

Karl heinz Buchegger schrieb:
> Jede Wette du empfängst in Wirklichkeit nicht 1 Zeichen sondern 2. Zb
> ein abschliessendes Return nach dem Buchstaben.

Vor der Switch Anweisung kopiere ich mir das erste Zeichen des Strings 
in die Variable 'Befehl':
1
Befehl  = String[0]; // erstet Zeichen aus dem String holen
2
Parameter1 = String[1]; // zweites Zeichen aus dem String holen
3
4
switch (Befehl){
5
... siehe oben ...
6
}

der default Zweig wird aber wie beschrieben durchlaufen.

matsch

von Karl H. (kbuchegg)


Lesenswert?

Matthias R. schrieb:

> Ich werde eure Tipps mal verfolgen.

Der Haupttip ist immer:
Spick dein Programm mit Ausgaben. Wenn du nicht weißt, warum eine 
bestimmte Aktion ausgelöst wird, dann mach vor den entscheidenden if 
(oder in deinem Fall switch) eine Ausgabe rein, die dir den 
'Entscheidungsträger' anzeigt.

In deinem Fall hätte sich auch angeboten ...
1
 default:
2
   uart_putc("->'");
3
   uart_putc(Befehl);
4
   uart_putc("'"); 
5
   uart_puts("nop\r");
6
   break;

... damit du nicht nur siehst, dass etwas nicht verarbeitbares in den 
Verteiler gekommen ist, sondern auch noch siehst was das den war.
Bei einer 'Fehlermeldung' ist es immer gut, den Auslöser auch mit 
auszugeben. Die Anzahl der von Micorosoft mit der simplen Fehlermeldung 
in die Verzweiflung getriebenen Programmierer "Eine DLL konnte nicht 
gefunden werden" ist legendär  .... Verdammt - WELCHE?

von Karl H. (kbuchegg)


Lesenswert?

Matthias R. schrieb:

> der default Zweig wird aber wie beschrieben durchlaufen.

Der ganze switch-case wird dann aber wahrscheinlich in einer 
übergeordneten Schleifenstruktur ein zweites mal aufgerufen.

Mach mal folgendes:
1
switch (Befehl){
2
 case 'D' :                      
3
   uart_puts("ein D\r");
4
   break;
5
 case 'R' :                      
6
   uart_puts("ein R\r");
7
   break;
8
 case 'W' :
9
   uart_puts("ein W\r");
10
   break;
11
 case 'P' :                      
12
   uart_puts("ein P\r");
13
   break;
14
 default:
15
   uart_puts("nop\r");
16
   break;
17
}
18
19
uart_puts( "Fertig\r" );   // <-

von Matthias R. (matsch)


Lesenswert?

Karl heinz Buchegger schrieb:
> ... sondern auch noch siehst was das den war.
Danke für den Tipp, den Fehler mit auszugeben.

Die Funktion wurde tatsächlich immer zwei mal aufgerufen. Fehler 
erkannt, gefunden, behoben ... und der Anfänger hat sogar das 'warum' 
verstanden.

Danke
Matsch

von Simon K. (simon) Benutzerseite


Lesenswert?

(nein) (ich) (bin) (kein) schrieb:
> versuche es mit einem lokalen funktionsblock, also {} nach jedem case
>
>
> quasi case 'a': {//weil hier mehr als ein Befehl kommt}

So ein Quatsch!

von Εrnst B. (ernst)


Lesenswert?

das mit dem "Kompilerfehler" im Betreff ist schon richtig...

Auf keine andere Weise kriegt man im GCC-Forum so schnell gute und 
fundierte Antworten.
Mit dem Betreff "Wie funktioniert default: in switch" wären nur 
haufenweise Antworten wie "Kauf dir ein C-Buch" gekommen

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.