Funktion über Serielle Schnittstelle aufrufen

Hallo Zusammen,
ich frage aktuell meine Serielle Schnittstelle wie folgt ab:

void ReadSerialCommands() {

  String Command;
  
  while (Serial.available() > 0) {
    Command += (char) Serial.read();
    delay(5); 

  if (Command == "Schlüsselwort") {
   //Aktion
  }

Je nach Schlüsselwort führe ich unterschiedliche Funktionen (voids) aus. Ist es möglich eine Funktion durch eingeben des Funktionsnamen auszuführen? Würde beuteten ich hätte z.B. folgende Funktion:

void TEST2345() {

  Serial.println("Es funktioniert!!");

}

...und gebe in den Seriellen Monitor folgendes ein: TEST2345

Die Funktion müsste dann irgendwie so aussehen:

void ReadSerialCommands() {

  String Command;
  
  while (Serial.available() > 0) {
    Command += (char) Serial.read();
    delay(5); 
  }
  
  Call Command; //???????

Schließe Deine Eingabe mit '\n' (Zeilenvorschub) ab, dann weißt Du, wann sie zu Ende ist. Bis dahin liest Du die Zeichen ein.
Du schreibst nicht, was Du für einen Arduino benutzt. Wenn der nicht sehr viel RAM hat, dann lass die Finger von den Strings und benutze Char-Arrays. Infos dazu gibt es z.B. hier.

Routinen, wie Du das einliest gibt es hier im Forum genügend.

Gruß Tommy

Vielleicht meinst Du sowas.. Das wäre annähernd in die Richtung.

Funktionszeiger_in_C

Wobei du ja nur Funktionen aufrufen kannst die du deklariert hast..

Somit wäre switch-case zb als Umleitung einfacher switch(command) case "meinefunktion" meinefunction();

magie004:
Hallo Zusammen,
ich frage aktuell meine Serielle Schnittstelle wie folgt ab:

void ReadSerialCommands() {

String Command;
 
 while (Serial.available() > 0) {
   Command += (char) Serial.read();
   delay(5);

if (Command == "Schlüsselwort") {
  //Aktion
 }




Je nach Schlüsselwort führe ich unterschiedliche Funktionen (voids) aus. Ist es möglich eine Funktion durch eingeben des Funktionsnamen auszuführen?

Nein, die Funktionsnamen stehen zur Laufzeit des Programms nicht mehr zur Verfügung.
Allerdings kannst Du Funktionen über die Funktionsadressen im Programm aufrufen (Funktionszeiger).

Du kannst daher folgendes machen und zwei Arrays mit Konstanten definieren:

  • ein Array mit den ganzen Schlüsselwörtern, die Du als Kommandos verwenden möchtest
    -ein Array mit Funktionszeigern auf die Funktionen, die bei Eingabe eines Schlüsselworts ausgeführt werden sollen

  • Zur Laufzeit könntest Du dann nach eingegebenen Schlüsselwörtern Ausschau halten und jeweils die einem Schlüsselwort zugeordnete Funktion aufrufen.

Das ist kein Problem, wenn man mit Funktionszeigern umgehen kann und erfordert eine einzige for-Schleife.

Das wäre für mich kein Problem.

Wenn Du möchtest, kann ich mir ein kleines Beispielprogramm einfallen lassen und Dir hier als Anschauungsobjekt posten.

jurs:
... kann ich mir ein kleines Beispielprogramm einfallen lassen und Dir hier als Anschauungsobjekt posten.

Ich bin auf jeden Fall an einem kurzen Beispiel interessiert. Mich betrifft das Problem aktuell zwar nicht, aber es ist interessant und ein Thread mit Beispiel würde sofort in meiner Linksammlung landen.

Gruß

Gregor

Dem kann ich mich nur voll inhaltlich anschließen!

Bitte jurs, mach ein Beispielsprogramm mit Funktionszeigern für uns!

const char x1[] PROGMEM = "liste";
const char x2[] PROGMEM = "dump";
const char x3[] PROGMEM = "sprich";
const char x4[] PROGMEM = "lies";

const char * const sTable[] PROGMEM = { x1, x2, x3, x4 };

void liste();
void dump();
void sprich();
void lies();

typedef void (*pvfu)();

const pvfu fTable[] PROGMEM = { liste, dump, sprich, lies };

void setup() {
  Serial.begin(250000);
  Serial.print(F("Ich kenne folgende Kommandos:"));
  for (byte i = 0; i < sizeof(sTable) / sizeof(sTable[0]); i++) {
    Serial.write(' ');
    Serial.print((__FlashStringHelper*)pgm_read_word(sTable + i));
  }
  Serial.println();
}

void loop() {
  serialHandler();
}

void processCmd(const char* buf)
{
  Serial.println(buf);
  for (byte i = 0; i < sizeof(sTable) / sizeof(sTable[0]); i++) {
    const char* sadr = pgm_read_word(sTable + i);
    if (!strncmp_P(buf, sadr, strlen_P(sadr))) {
      (*((pvfu)pgm_read_word(fTable + i)))();
      return;
    }
  }
  Serial.write('\'');
  Serial.print(buf);
  Serial.println(F("' nicht erkannt"));
}

void liste() {
  Serial.println(F("exec liste()"));
}
void dump() {
  Serial.println(F("exec dump()"));
}
void sprich() {
  Serial.println(F("exec sprich()"));
}
void lies() {
  Serial.println(F("exec lies()"));
}

void serialHandler()
{
  const byte sCBMax = 30;
  static char sCBuffer[sCBMax];
  static byte buffIndex = 0;

  byte inChar;
  bool doCheck = false;

  while (Serial.available()) {
    inChar = Serial.read();
    if (inChar == 13) {
      doCheck = true;
    } else if (inChar != 10) {
      if ((buffIndex == 0) && isWhitespace(inChar)) {
        continue;
      }
      sCBuffer[buffIndex++] = inChar;
      doCheck = (buffIndex == (sCBMax - 1));
    }
    if (doCheck) {
      sCBuffer[buffIndex] = 0;
      doCheck = false;
      if (buffIndex != 0) {
        processCmd(sCBuffer);
        buffIndex = 0;
      } else {
        Serial.println();
      }
    }
  }
}
Ich kenne folgende Kommandos: liste dump sprich lies
liste
exec liste()
dump
exec dump()
sprich
exec sprich()
lies
exec lies()
mach was
'mach was' nicht erkannt

Whandall:
...

Vielen Dank für die Erleuchtung!

Gruß

Gregor

gregorss:
Vielen Dank für die Erleuchtung!

Schönes Beispielprogramm!
Aber aufpassen, dass im seriellen Monitor das richtige Zeilenende-Zeichen gesetzt ist, weil in Whandalls Code am Ende des Kommandos auf Carriage Return (ASCI-13)geprüft wird:
inChar = Serial.read();
if (inChar == 13) {

Falls auf der PC-Seite nicht der serielle Monitor läuft, sondern ein serielles Terminalemulationsprogramm zur Eingabe von Kommandos verwendet wird,, dann am Ende des Kommandos einfach die Return- oder Enter-Taste drücken, das funktioniert auch mit jedem Terminalprogramm.

Vielen Dank!!!