char[x]-Wert in Switch Anweisung nicht möglich?

Gast #1310564
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?
Persönliche Seite #1310587
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.
#1310588
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!)
Persönliche Seite #1310660
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 ;)
Persönliche Seite #1310693
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".
Gast #1310866
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.
#1310877
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 :-)
Gast #1311232
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren