Forum: Mikrocontroller und Digitale Elektronik char[x]-Wert in Switch Anweisung nicht möglich?


von M.B. (Gast)


Lesenswert?

Hallo, ich programmiere einen ATmega in der AVR GCC Umgebung.

Ich empfange über UART Zeichen und Strings, die ich auswerten möchte:
z.B. 'Run', Stop', 'An', 'Aus'

Dies Sind in meiner Variablen gespeichert und wollen nun ausgewertet 
werden. Meine Idee war mit switch - aber leider bekomme ich das nicht 
hin. Hier ein Ausschnitt von meinem Code:
1
char Data[10];
2
[...]
3
4
  switch (Data)
5
  {
6
    case '1':
7
             USART_Tx_s("Es wurde die Taste 1 gedrueckt");
8
             _Enter;
9
             break;
10
    case 'a':
11
             USART_Tx_s("Das war ein 'a'");
12
             _Enter;
13
             break;
14
    case 'hallo':
15
             USART_Tx_s("Herzlich Willkommen");
16
             _Enter;
17
             break;
18
    default:
19
             USART_Tx_s("Leider nicht im Programm.\n\r Versuchen Sie es noch einmal...");
20
             _Enter;
21
             break;
22
  }

Die Daten werden über UART empfangen. Ich sende sie als Echo zurück. Das 
funktioniert alles. Aber wie kann ich sie nun auswerten?

von Mark B. (markbrandis)


Lesenswert?

switch akzeptiert als Parameter int oder char, kein Array von chars. 
Möglich wäre z.B.
1
switch (Data[0])

Bzw. Du kannst dann nicht auf 'hallo' prüfen, sondern nur auf 'h'.

von Jürgen S. (Gast)


Lesenswert?

Data ist ja nur die Adresse auf das Array...

von Mark B. (markbrandis)


Lesenswert?

Äh, ja. Ich vergaß.
Was man manchen könnte, wenn man es mit switch machen will: Auf das 
erste Zeichen prüfen. Im case-Block dann die weiteren Zeichen checken, 
z.B. mit strcmp()?

von M.B. (Gast)


Lesenswert?

M..., so was blödes. Gibts eine andere Möglichkeit?
Trotzdem vielen Dank für die schnellen antworten.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Nimm Dir eine verkettete Liste, in der Du an jeder Listenposition einen 
Zeiger auf einen String sowie einen Zeiger auf eine Abarbeitungsroutine 
speicherst. Diese Strings sind Deine Befehlsworte.
Wenn Du einen Befehl bekommen hast, musst Du diese Liste durchsuchen und 
bei einem Treffer die Abarbeitungsroutine anspringen.

Oder sowas (in etwa):
1
if      (strcmp("1", Data)) {...}
2
else if (strcmp("hallo", Data)) {...}
3
else {...}

Data muss hier natürlich Nullterminiert sein.

von Karl H. (kbuchegg)


Lesenswert?

M.B. schrieb:
> M..., so was blödes. Gibts eine andere Möglichkeit?

es gibt 2 Möglichkeiten:
Entweder du beschränkst dich in deiner Übertragung und damit in den 
Kommandos, die du übertragen kannst, auf 1-buchstabige (dann kannst du 
switch nehmen) oder du überträgst ganze Strings, dann ist eine if - 
elseif Kette mit lauter strcmp oder strncmp angebracht.
1
  ...
2
3
  if( !strncmp( Data, "Run", 3 ) )
4
     // Bearbeite Run-Kommando
5
6
  else if( !strncmp( Data, "Stop", 4 ) )
7
     // Bearbeite Stop-Kommando
8
9
  else if( !strncmp( Data, "An", 2 ) )
10
     // Bearbeite An-Kommando
11
12
  else if( !strncmp( Data, "Aus", 3 ) )
13
     // Bearbeite Aus Kommando
14
15
  else
16
    // Bearbeite ungültiges Kommando

(und immer schön auf den Unterschied 'einzelner char' und 'String' 
achten. Strings werden mit " geschrieben!)

von Mark B. (markbrandis)


Lesenswert?

Hm, was sind die Trennzeichen zwischen den zu empfangenden Wörtern? Man 
könnte den Empfangsstring mit strtok() aufdröseln und dann in einer 
Schleife mit strcmp() weitermachen.

von Simon K. (simon) Benutzerseite


Lesenswert?

Christian H. schrieb:
> Nimm Dir eine verkettete Liste, in der Du an jeder Listenposition einen
> Zeiger auf einen String sowie einen Zeiger auf eine Abarbeitungsroutine
> speicherst. Diese Strings sind Deine Befehlsworte.
> Wenn Du einen Befehl bekommen hast, musst Du diese Liste durchsuchen und
> bei einem Treffer die Abarbeitungsroutine anspringen.

Ein Array tut es auch ;)

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Simon K. schrieb:
> Christian H. schrieb:
>> Nimm Dir eine verkettete Liste, in der Du an jeder Listenposition einen
>> Zeiger auf einen String sowie einen Zeiger auf eine Abarbeitungsroutine
>> speicherst. Diese Strings sind Deine Befehlsworte.
>> Wenn Du einen Befehl bekommen hast, musst Du diese Liste durchsuchen und
>> bei einem Treffer die Abarbeitungsroutine anspringen.
>
> Ein Array tut es auch ;)

Ja, meinte ich eigentlich auch. Wieso ich "verkettete Liste" geschrieben 
habe, weiß ich auch nicht. Irgenwie war ich mit den Gedanken woanders 
8-|

Also vergesst "verkettete Liste" und denkt euch an der Stelle "Array".

von Sven P. (Gast)


Lesenswert?

Christian H. schrieb:
>
1
> if      (strcmp("1", Data)) {...}
2
> else if (strcmp("hallo", Data)) {...}
3
> else {...}
4
>

Schreib lieber noch '==0' dahinter oder '!' davor :->

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Stimmt, der strcmp vergleicht ja auch auf "kleiner" bzw "größer". Nur 
bei "gleich" ist das Ergebnis 0.

von M.B. (Gast)


Lesenswert?

Ok, vielen Dank für eure vielen Tipps und Kommentare.
Ich werde dann mein Programm so aufbauen, das ich mit "Einzelbuchstaben" 
auskomme.
Ist zwar schade, aber einfacher. Trotzdem vielen Dank für die 
hilfreichen Tipps, die nicht nur mir helfen werden.
Da bin ich mir sicher.

von Karl H. (kbuchegg)


Lesenswert?

M.B. schrieb:
> Ich werde dann mein Programm so aufbauen, das ich mit "Einzelbuchstaben"
> auskomme.
> Ist zwar schade, aber einfacher.

:-)
Im Long-Run ist es auch nicht einfacher.
Warte ab, bis du das erste mal einem Kommando einen Parameter mitgibst. 
Dann kommst du um Stringbearbeitung nicht mehr sinnvoll rum.

Das bischen switch versus strcmp Unterschied macht das Kraut auch nicht 
fett. Zumal es, wie Christian H. schon angedeutet hat, eine sehr schöne 
und praktikable Lösung gibt, eine zur Compilezeit gut konfigurierbare 
Kommandostruktur über ein Array von Strukturen und Funktionspointer zu 
schaffen. Und dann spielt der Unterschied Einzelbuchstabe versus 
Kommandostring praktisch so gut wie keine Rolle mehr (ausser höchstens 
durch den Speicherverbauch)


Fazit:
Es bringt nichts, sich vor Stringverarbeitung zu drücken. Irgendwann 
holt sie dich trotzdem ein :-)

von vlad (Gast)


Lesenswert?

kannst das ganze ja auch succsessive überprüfen und die switch 
cases-cascadieren
wenn du zb die befehle an, aus, hoch runter hast:
1
char* text = inputStr;
2
switch(text[0])
3
{
4
  case 'a': 
5
    switch(text[1]){
6
      case 'n':
7
        doAnStuff();
8
        break;
9
      case 'u':
10
        doAusStuff();
11
        break;
12
      default:
13
        error();
14
    }  
15
    break;
16
  case 'h':
17
    doHochStuff();
18
    break;
19
  case 'r':
20
    doRunterStuff();
21
    break;
22
  default:
23
    error();
24
}
25
26
{/c]
27
28
29
bei wenigen befehlen mag das gehen.
30
Bei längeren Befehlslisten, würd ich das verallgemeinern:
31
alle befehle in ein Array aus struct mit text und funktionspointer packen (ascibetisch sortiert).
32
33
[c]
34
  typedef struct UartCommand{
35
     const char* cmd;
36
     uint8_t     Len;  // um nicht jedes mal nach der länge fragen zu müssen
37
     UCCallback  actionRoutine;
38
  }UartCommand;
39
40
#define COMMAND_COUNT 4
41
static const UartCommand myCommands[COMMAND_COUNT] = 
42
{ 
43
  {.cmd = "an",       .len=2, .actionRoutine = &doAnStuff()},
44
  {.cmd = "arbeiten", .len=8, .actionRoutine = &doArbeitenStuff()},
45
  {.cmd = "aus",      .len=3, .actionRoutine = &doAusStuff()},
46
  {.cmd = "runter",   .len=6, .actionRoutine = &doRunterStuff()},
47
}
48
49
parseInput( const char* input)
50
{
51
  uint8_t anfang = 0;
52
  uint8_t ende   = COMMAND_COUNT;
53
  do{
54
    // zeichenweise durch die Liste gehen und schauen, welche infrage kommen
55
    // anfangs- und endeposition merken, bei 'a' also 0 2
56
    // immer auf länge der zechenketten achten!
57
    // nun wieder von vorn anfangen und liste von 0-2 durchsuche nach 2. Zeichen schauen
58
  while( anfang!=ende )
59
60
  myCommands[anfang].actionRoutine( input+myCommands[anfang].len );
61
62
}
Is natürlich nicht komplett, aber das Prinzip sollte klar sein.

Damit könnte man sogar eine autocompletion bauen, Dh der Benutzer tippt 
ein Zeichen und der µC bietet mögliche Kommandos an.

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.