Forum: Mikrocontroller und Digitale Elektronik über Seriellen Monitor in switch-case springen


von Franco O. (Gast)


Lesenswert?

Hi,
hoffe Ihr habt alle frohe Festtage !

Ich versuche gerade über den Seriellen Monitor in eine Switch-CASE zu 
springen.
jedoch funktioniert das nicht ganz. Der Compiler meldet folgendes:
1
sketch_dec26a:18:10: error: expected identifier before 'case'
2
3
     goto case 1;
4
5
          ^
6
7
sketch_dec26a:18:10: error: expected ';' before 'case'
8
9
sketch_dec26a:18:10: error: case label '1' not within a switch statement
10
11
sketch_dec26a:18:16: error: expected ':' before ';' token
12
13
     goto case 1;
14
15
                ^

hier mein Code:
1
byte Case = 1;
2
3
unsigned long Millis;
4
5
void setup() {
6
  Serial.begin(115200);
7
  Millis = millis();
8
9
}
10
11
void loop() {
12
13
  if (Serial.available() > 0) {
14
15
    const char a = Serial.read();
16
17
    if (a == '1') {
18
    goto case 1;
19
    }
20
    else if (a == '2') {}
21
    else if (a == '3') {}
22
    else if (a == '4') {}
23
    else if (a == '5') {}
24
    else if (a == '6') {}
25
26
  }
27
}
28
29
if (millis() - Millis >= 10000) {
30
  switch (Case) {
31
32
    case 1:
33
      Serial.println("Case 1");
34
35
      Case = 2;
36
      Millis = millis();
37
38
      break;
39
40
    case 2:
41
      Serial.println("Case 2");
42
43
      Case = 3;
44
      Millis = millis();
45
46
      break;
47
48
    case 3:
49
      Serial.println("Case 3");
50
51
      Case = 4;
52
      Millis = millis();
53
54
      break;
55
56
    case 4:
57
      Serial.println("Case 4");
58
59
      Case = 5;
60
      Millis = millis();
61
62
      break;
63
64
    case 5:
65
      Serial.println("Case 5");
66
67
      Case = 6;
68
      Millis = millis();
69
70
      break;
71
72
    case 6:
73
      Serial.println("Case 6");
74
75
      Case = 1;
76
      Millis = millis();
77
78
      break;
79
  }
80
}
81
}

Was mache ich falsch?

Mfg

von . . (Gast)


Lesenswert?

Franco O. schrieb:

> Was mache ich falsch?

Meherer Sachen.
Aber im Hauptanklagepunkt verwendest Du "goto", und das auch noch 
falsch.

von Rolf M. (rmagnus)


Lesenswert?

Franco O. schrieb:
> Was mache ich falsch?

Das sagt doch der Compiler schon.
1
 goto case 1;

Das ergibt keinen Sinn. hinter goto muss ein Label stehen. case dagegen 
nutzt man innerhalb eines switch-Blocks.

von STK500-Besitzer (Gast)


Lesenswert?

mach daraus:
1
 goto case 1;
1
 Case = 1;

von Taiga Wutzzz (Gast)


Lesenswert?

Hier noch einige Konstrukte die dir bei weiteren "Programmieruebungen"
sicherlich hilfreich sein werden:
1
Conditional Statements
2
3
WHAT IF
4
    Used in simulation languages. Branches before evaluating the test condition.
5
6
OR ELSE
7
    Conditional threat as in: "Add these two numbers OR ELSE"
8
9
WHY NOT
10
    Executes the code that follows in a devil-may-care fashion
11
12
WHO ELSE
13
    Used for polling during I/O operations
14
15
ELSEWHERE
16
    This is where your program really is when you think it's here
17
18
GOING GOING GONE
19
    For writing unstructured programs. Takes a random branch to another part of your program.
20
    Does the work of a hundred GOTOs
21
22
Case Statements
23
24
JUST IN CASE
25
    For handling afterthoughts and fudge factors.
26
    Allows you to multiply by zero to correct for accidently dividing by zero
27
28
BRIEF CASE
29
    To encourage portable software
30
31
OPEN AND SHUT CASE
32
    No proof of correctness is necessary with this one
33
34
IN ANY CASE
35
    This one always works
36
37
HOPELESS CASE
38
    This one never works
39
40
BASKET CASE
41
    A really HOPELESS CASE
42
43
Loop Statements
44
45
DON'T DO WHILE NOT
46
    The loop is not executed if the test condition is not false (or it's Friday afternoon)
47
48
DIDN'T DO
49
    The loop executes once and hides all traces
50
51
WON'T DO
52
    The program stops because it doesn't like the code inside the loop.
53
    Execution can be resumed by typing "MAY I" at the command line
54
55
MIGHT DO
56
    Depends on how the program is feeling.
57
    Executed if the CPU is "up", not executed if the CPU is "down" or if its feelings have been hurt
58
59
DO UNTO OTHERS
60
    Used to write the main loop for operating systems to antagonize all programs in a uniform manner
61
62
DO WAH
63
    Used to write loops for computer generated music (e.g. Rag Timing)

Guten Ausrutsch!

von kenny (Gast)


Lesenswert?

if (Serial.available() > 0) {

    const char a = Serial.read();
}

if (millis() - Millis >= 10000) {
  switch (a) {
    case 1:
      Serial.println("Case 1");
      a = 2;
      Millis = millis();
      break;
 }

So wird da eher ein Schuh draus. Keine goto's nötig da switch case über 
den Inhalt des Identifier a gesteuert wird.

Man ist gut beraten goto's nicht zu nutzen.

von Einer K. (Gast)


Lesenswert?

kenny schrieb:
> Man ist gut beraten goto's nicht zu nutzen.

Zumindest sollte man etwas Disziplin dabei wahren.

Was hier nicht geht, ist das Springen mitten in eine Funktion hinein.

@  Franco O.
Leider kann ich nicht erkennen, WAS gebaut werden soll, nur, dass du 
einen falschen Weg gewählt hast.

von Franco O. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> kenny schrieb:
>> Man ist gut beraten goto's nicht zu nutzen.
>
> Zumindest sollte man etwas Disziplin dabei wahren.

Das habe ich aber auch oft gelesen dass man davon die finger lassen 
sollte.

> Was hier nicht geht, ist das Springen mitten in eine Funktion hinein.
>
> @  Franco O.
> Leider kann ich nicht erkennen, WAS gebaut werden soll, nur, dass du
> einen falschen Weg gewählt hast.

Was genau ist der falsche weg?

also Der plan ist dass der die das Switch-Case normal laufen soll mit 
dem Zusatz dass ich einen Bestimmten Case aufrufen kann er dann diesen 
case ausführt und normal über die Millis weiter läuft

von PittyJ (Gast)


Lesenswert?

Ca alle halbe Jahr bau ich irgendwo ein goto ein.
Nicht, weil es nicht ohne goto gehen würde, sondern weil ich es kann.

von Einer K. (Gast)


Lesenswert?

Du möchtest eine Ablaufsteuerung bauen?
Einen auf switch/case basierenden endlichen Automaten?

Dann musst du nicht springen!

Es reicht einfach:

STK500-Besitzer schrieb:
> mach daraus: goto case 1;
>  Case = 1;

Wenn der Automat das nächste mal dran kommt, macht er mit 1 weiter.

von Oliver S. (oliverso)


Lesenswert?

So ginge es:
1
//...
2
3
goto label1;
4
//....
5
6
switch (Case) {
7
8
    case 1:
9
    label1:
10
      Serial.println("Case 1");
11
12
      break;
13
}

Aber wie schon geschrieben wurde, willst du das nicht wollen.

Oliver

von STK500-Besitzer (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Wenn der Automat das nächste mal dran kommt, macht er mit 1 weiter.

Da da sowieso eine "}"-Klammer zu viel ist, macht er gar nichts weiter 
(der Compiler wird weter rummeckern).
Ich habe die if-Else-If-Orgie so verstanden, dass bei Eingabe einer 
Ziffer über die serielle Schnittstelle ein neuer Automatenzustand 
gewählt werden soll.
Die Stelle wird ja auch nur angesprungen, wenn '1' auf der Schnittstelle 
empfangen wurde.

Ich kann natrlich auch mal wieder komplett daneben liegen...

von Einer K. (Gast)


Lesenswert?

STK500-Besitzer schrieb:
> Ich habe die if-Else-If-Orgie so verstanden, dass bei Eingabe einer
> Ziffer über die serielle Schnittstelle ein neuer Automatenzustand
> gewählt werden soll.

Kann ja sein!

Case = geleseneZahl - '0';

von Franco O. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Du möchtest eine Ablaufsteuerung bauen?
> Einen auf switch/case basierenden endlichen Automaten?
> Wenn der Automat das nächste mal dran kommt, macht er mit 1 weiter.

nene Das habe ich ja schon. Er starte bei 1 nach jedem ablauf

Franco O. schrieb:
> case 1:
>       Serial.println("Case 1");
>
>       Case = 2; <-- Nach jedem Case setzt er ihn auf den nächsten
>       Millis = millis();

so wird alle 10 Sekunden der nächste Case ausgeführt was auch so sein 
soll

Jetzt möchte ich aber Case 2 aufrufen. So sind wir bei dem Geschreibsel 
gelandet. Meine Idee war per Seriellen Monitor den Case einzugeben und 
dann direkt dort hinzuspringen.

von STK500-Besitzer (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Kann ja sein!
>
> Case = geleseneZahl - '0';

Vielleicht möchte er aber auch "Something completely different" in den 
anderen Abfragen machen.
Die Abfragen kann man natürlich auch in einer Switch-Case-Abfrage 
verarbeiten.

Man kann auch die Millis-Neuberechnungsgeschichten zusammenfassen und 
vor der zweiten Switch-Case einfügen, sofern nicht vielleicht doch ein 
Fall dabei ist, bei dem die Rechnung nicht durchgeführt werden soll.

Beitrag #6086362 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

Franco O. schrieb:
> Meine Idee war per Seriellen Monitor den Case einzugeben und
> dann direkt dort hinzuspringen.
Ja dann....

von Franco O. (Gast)


Lesenswert?

Oliver S. schrieb:
> So ginge es:
> //...
>
> goto label1;
> //....
>
> switch (Case) {
>
>     case 1:
>     label1:
>       Serial.println("Case 1");
>
>       break;
> }

Würde er diesen Case dann Trotzdem selber ausführen wie bei mir oder nur 
wenn ich label1 aufrufe ?

von Lurchi (Gast)


Lesenswert?

Einfach die Bedingung schaffen, dass er direkt nach Empfang eines 
Characters das "switch" Statement ausführt, also:

if (Serial.available() > 0) {

  const char a = Serial.read();

  if (a == '1') {
    Millis = millis() - 10000;
    Case = 1;
  }
...

if (millis() - Millis >= 10000) {
  switch (Case) {
...

von Dirk B. (dirkb2)


Lesenswert?

Du kannst auch ein Flag (Variable) setzen.
1
sofort = 0;
2
if (Serial.available() > 0) {
3
4
  const char a = Serial.read();
5
6
  if (a == '1') {
7
    sofort = 1;
8
    Case = 1;
9
  }
10
...
11
12
if ((millis() - Millis >= 10000) || sofort) {
13
  switch (Case) {
14
...

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

kenny schrieb:
1
> if (Serial.available() > 0) {
2
> 
3
>     const char a = Serial.read();
4
> }
5
> 
6
> if (millis() - Millis >= 10000) {
7
>   switch (a) {
8
>     case 1:
9
>       Serial.println("Case 1");
10
>       a = 2;
11
>       Millis = millis();
12
>       break;
13
>  }

Das ist aber fast schon genauso fehlerhaft wie das von TO

Oliver S. schrieb:
> So ginge es:
1
> //...
2
> 
3
> goto label1;
4
> //....
5
> 
6
> switch (Case) {
7
> 
8
>     case 1:
9
>     label1:
10
>       Serial.println("Case 1");
11
> 
12
>       break;
13
> }

Nö, das ist in den meisten Fällen eher wie mit dem Großkalibergewehr ins 
Knie geschossen.


Kleiner Tipp, mal über den Gültigkeitsbereich von Variablen und über 
wild im Quellcode verstreute "break" nachdenken.

von Franco O. (Gast)


Lesenswert?

Danke für die vielen Vorschläge!

Irgend W. schrieb:
> Nö, das ist in den meisten Fällen eher wie mit dem Großkalibergewehr ins
> Knie geschossen.

So hats bei mir geklappt. Sollte ich das denn lieber nicht so machen?

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Franco O. schrieb:
> So hats bei mir geklappt. Sollte ich das denn lieber nicht so machen?

Nimm lieber die Variante mit der Hilfsvariable so in der Art wie von 
Dirk.B vorgeschlagen. Sowas ist allemal sauberer als mit goto mitten in 
irgendwelche Konstrukte reinzuspringen und dann zu hoffen das sie 
dennoch sauber verlassen werden.

---
Das mit dem goto|switch|case|label|break habe ich gerade mal mit clang 
rumexperimentiert.
Interessanter weise tut der break genauso als wäre switch|case 
ausgeführt worden und springt an die gleiche Stelle.
Erweckt bei mir jetzt eher den Eindruck dass das c-goto 1:1 in einen 
ASM-Jump umgesetzt wird ohne darauf zu achten das dadurch das 
eigentliche C-Konstrukt etwas ausgehebelt wird.
goto|irgendwas|label|break oder goto|for|switch|case|label|break frist 
der Compiler dagegen nicht ohne heftig zu meckern.
Mich würde jetzt mal interessieren ob diese "als ob" verhalten bei einem 
goto mitten in eine switch irgendwo im Standard definiertes Verhalten 
ist auf das man sich theoretisch verlassen könnte oder eher "Zufall" 
ist. So auf die schnell konnte ich diesbezüglich nichts finden.

PS: ich habe garantiert nicht vor sowas ernsthaft zu verwenden, es 
interessiert mich nur gerade mal wieder was C/C++ so alles an 
"fragwürdigen" Konstrukten zulässt.

von Einer K. (Gast)


Lesenswert?

Irgend W. schrieb:
> Mich würde jetzt mal interessieren ob diese "als ob" verhalten bei einem
> goto mitten in eine switch irgendwo im Standard definiertes Verhalten
> ist auf das man sich theoretisch verlassen könnte oder eher "Zufall"
> ist.

Ist kein Zufall.

Schaue dir dazu mal dem Adam Dunkel seine ProtoThreads an.

Eine Variante arbeitet mit Switch/case, welches auch Case in 
untergerodneten Blöcken "anspringen" kann. Auch mitten in for Schleifen 
rein usw.
Die andere Variante nutzt computed goto für den selben Zweck.

Es gibt viele weitere Implementierungen dieses Prinzips.
z.B.
https://forum.arduino.cc/index.php?action=dlattach;topic=415229.0;attach=176389
https://forum.arduino.cc/index.php?action=dlattach;topic=596279.0;attach=293747

von Rolf M. (rmagnus)


Lesenswert?

Arduino Fanboy D. schrieb:
> Ist kein Zufall.
>
> Schaue dir dazu mal dem Adam Dunkel seine ProtoThreads an.

Oder Duff's Device. Zwar nicht mit goto, aber mit do/while:
https://de.wikipedia.org/wiki/Duff%E2%80%99s_Device
Aber Vorsicht: Davon bekommt man einen Knoten im Hirn ;-)

von Franco O. (Gast)


Lesenswert?

Irgend W. schrieb:
> Nimm lieber die Variante mit der Hilfsvariable so in der Art wie von
> Dirk.B vorgeschlagen. Sowas ist allemal sauberer als mit goto mitten in
> irgendwelche Konstrukte reinzuspringen und dann zu hoffen das sie
> dennoch sauber verlassen werden.

Gut dann nehme ich das Lieber :)

Herzlichen Glückwunsch Dirk du wirst für immer und ewig in meinem Code 
verewigt.

Dankeschön!

von max123 (Gast)


Lesenswert?

Noch eine Beispiellösung:
Einlesen erfolgt im seriellen Interrupt. Gegebenenfalls
könnte man noch einen Puffer zwischen isr und loop einfügen.
1
char help = 0;
2
3
void setup ()
4
{
5
  Serial.begin(9600);
6
  Serial.println("Geben Sie im seriellen Monitor 0 oder 1 ein.");
7
}
8
9
void loop()
10
{   
11
 // Serial.println("232323"); delay(1000);
12
  
13
  if (help != 0)
14
    {
15
      
16
    switch (help)
17
     { 
18
      
19
      case '0' : Serial.println("Anton");
20
                 break;
21
      case '1' :  Serial.println("Berta");        
22
      }                           
23
    }
24
   help = 0;
25
}
26
27
28
29
void serialEvent()
30
{
31
  if (Serial.available())
32
      {
33
        help = (char)Serial.read();
34
      
35
       if(help >= '0'   && help <= '9')
36
            ;     //es beibt alles beim Alten
37
      else
38
      help = 0;
39
      }  
40
}

von Einer K. (Gast)


Lesenswert?

serialEvent() ist keine ISR

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.