Go Down

Topic: Switch Case - in Funktion gefangen (Read 697 times) previous topic - next topic

Ratpack

Hallo Zusammen,

ich habe eine Problem bei einem Switch Case Programm.
Per Serial Read lese ich einen Wert ein, der mit den Case vorgibt. Beispielsweise 48,49,50,51.

Die Cases einrehen und rausdrehen habe ich der übersichtshalber weggelassen.

Mein Problem ist, dass ich nicht mehr in die Loop zurückkomme nachdem mein Case erst einmal ausgewählt ist. Ich verharre in der entsprechenden Funktion. Wenn ich im Seriellen Monitior erneut einen Case auswähle, wechselt dieser trotzdem nicht.

Ist das Problem dies, dass meine Funktionen nicht in der Loop sind?

Beste Grüße
Tim


Code: [Select]


void setup() {

  // Kommunikationsrate
  Serial.begin(9600);

}

void loop()
{
  char input;
  // Case Bedingung
  if (Serial.available() > 0) {
    input = Serial.read();
    Serial.println(input);
  }

  // Case Auswahl
  switch (input) {
    case 48: ruhemodus(); break;
    case 49: rausdrehen(); break;
    case 50: reindrehen(); break;
    case 51: messen();     break;

  }

}

void ruhemodus() {
  Serial.println("warten");
}

void messen() {
  Serial.println("messen aktiviert");

  int A0 = analogRead(A0);
  String messwerte[250];
  if ((A0 > 10) && (A0 < 1020))
    for (unsigned int i = 0; i < 250; i++) {
      messwerte[i] = analogRead(A0);
      delay(1000);
    }
}


Serenifly

#1
Sep 23, 2019, 07:06 pm Last Edit: Sep 23, 2019, 07:10 pm by Serenifly
Code: [Select]

for (unsigned int i = 0; i < 250; i++)
      delay(1000);

Du wartest auch 250 mal 1 Sekunde. Da brauchst du dich nicht zu wundern dass nichts mehr reagiert.

Und ein Array aus 250 String Objekten anzulegen um Messwerte zu speichern ist höchstgradiger Unsinn. Auf einem kleinen Prozessor belegst du leicht den kompletten Arbeitsspeicher. And auch auf den größeren 32 Bittern ist das einfach nur unnötig. Wenn überhaupt Speichern dann als Zahl. Oder besser direkt ausgeben wenn du zwischen den Messungen sowieso so lange wartest. Erst wenn man schneller als die Datenübertragung misst muss man wirklich zwischenspeichern

noiasca

#2
Sep 23, 2019, 07:09 pm Last Edit: Sep 23, 2019, 07:11 pm by noiasca
alllein dein "messen()" kann bis zu 4 Minuten dauern.
Daher --> poste einen vollständigen Sketch und schreibe bei welchem Input du das Verhalten feststellst, und dazu die vollständige Ausgabe deines Serial Monitors.

(schon wieder zu spät ...)
how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

postmaster-ino

Hi

Wie immer in so Fällen: stopfe den Sketch mit Serial.print("12"); voll (die Zahl sollte dabei überall anders sein ...).
So SIEHST Du, wo der Käfer rum rennt.

In Deinem Fall ist's zwar klar - 250 delay(1000) am Stück sind 250 Sekunden Zwangspause, in Denen Du NICHTS ANDERES machen kannst - sonderlich clever ist Das nicht - soll heißen: Da gibt's elegantere Möglichkeiten - Suchwort State-Maschine, Blink_without_delay, Nachtwächtererklärung

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

HotSystems

#4
Sep 24, 2019, 01:48 pm Last Edit: Sep 24, 2019, 01:49 pm by HotSystems
Ist das Problem dies, dass meine Funktionen nicht in der Loop sind?
Eine Funktion ist ein Teil deines Programms, ebenso wie die loop, die auch eine Funktion ist.
Also ist es kein Problem wenn diese Funktion nicht in der loop steht und darf es auch nicht.
Jede Funktion ist ein eigenständiger Bereich deines Programms.

Und jetzt freuen wir uns auf dein Ergebnis bzw. deine Rückmeldung.
Gruß Dieter

I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

Ratpack

Moin,

vielen Dank für eure Rückmeldungen.
Ich hab leider nicht an die lange Wartezeit beim testen gedacht. Das war auch der Grund warum ich nicht wieder raus kam.

Das mit den 250 Einträgen als war eine erste herangehensweise um analoge Messwerte seriell weiterzugeben. Ich habe mich an dieser Stelle noch für keine Sinnvolle Funktion entschieden, bin mir aber bewusst dass es so schwachsinn ist. Ich möchte jede Millisekunde einen Wert Speichern, dass ganze eben für 250 ms. Die 1 sec delay in meinem Programm war dahingehend auch falsch.

Ich habe jetzt, um meine case Funkion auszutesten die Programme dahingehend vereinfacht, dass ich nur eine Notiz im Plotter bekomme sobald diese aktiviert ist.
Was ich jetzt noch machen muss, ist eine Abbruchbedingung mit einbauen, also dass meine Funktion exakt 1x ausgeführt wird und dann case 0 (warten) aktiviert wird. Aber das versuche ich erst einmal selber herauszufinden :)

Vielen Dank für eure Hilfe
Tim


Code: [Select]


void setup() {

  // Kommunikationsrate
  Serial.begin(9600);

}

void loop()
{
  char input;
  // Case Bedingung
  if (Serial.available() > 0) {
    input = Serial.read();
    Serial.println(input);
  }

  // Case Auswahl
  switch (input) {
    case 48: ruhemodus(); break;
    case 49: rausdrehen(); break;
    case 50: reindrehen(); break;
    case 51: messen();     break;

  }

}

void ruhemodus() {
  Serial.println("warten");
}

void rausdrehen() {
  Serial.println("rausdrehen");
}

void reindrehen() {
  Serial.println("reindrehen");
}

void messen() {
  Serial.println("messen aktiviert");

    }
}


Ratpack

Hallo Nochmal,

ich habe jetzt versucht meine Loop mit einer Flag zu versehen um das Programm nur ein mal auszuführen. Das klappt zwar, in dem es nach ausführen des gewählten case aufhört, aber die Loop wird nicht weiter durchlaufen.
Code: [Select]
void loop()
{
  char input;
  // Case Auswahl
  if (Serial.available() > 0) {
    input = Serial.read();
    Serial.println(input);
  }

 static boolean Flag = true;
if (Flag) {
  switch (input) {
    case 48: ruhemodus(); Flag = false; break;
    case 49: rausdrehen(); Flag = false; break;
    case 50: reindrehen(); Flag = false; break;
    case 51: messen();      Flag = false; break;
  }
  }

  }


Auch ein rausziehen von Flag = false für nur dazu, dass erst gar keine Eingabe mehr erkannt wird.
Was mache ich falsch? In den Einzelnen Case Funktionen ist nur ein Println drin.

Serenifly

#7
Sep 25, 2019, 01:24 pm Last Edit: Sep 25, 2019, 01:25 pm by Serenifly
Du willst einen Zustandsautomaten / endlichen Automaten. Dann merke dir auch in welchem Zustand du bist und nicht einfach nur mit einem bool der nur zwei Werte annehmen kann. Dazu gibt es in diesem Forum unendlich oft Beispiele. Und auch im Netz gibt es sehr viel dazu.
switch/case ist schon ok, aber man verwenden im einfachsten Fall ein enum um den Zustand zu speichern.

Verzögerungen macht man mit millis() nach dem BlinkWithoutDelay Prinzip. Dann kannst du zwischen den Messungen Daten versenden wenn die Zeit reicht.

Auch solltest du die Baudrate weit, weit höher setzen. Bei 9600 Baud braucht ein einzelnes Zeichen schon ca. 1ms (1 / Baudrate * 10 Sekunden).
Da die Übertragungzeit und die Zeit für die A/D-Wandlung bekannt sind, kann man so auch leicht sehen ob die Zeit für die Übertragung der Messwerte reicht und ob man überhaupt etwas zwischenspeichern muss

Doc_Arduino

Hallo,

erstmal muss dein serielles einlesen funktionieren. Du möchtest Werte wie 48 oder 50 eingeben. Okay. Aber das sind beim einlesen 2 getrennte Ziffern. 48 wird als 4 und 8 eingelesen und 50 als 5 und 0. Schau dir atoi() an.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Serenifly

#9
Sep 25, 2019, 02:00 pm Last Edit: Sep 25, 2019, 02:01 pm by Serenifly
erstmal muss dein serielles einlesen funktionieren. Du möchtest Werte wie 48 oder 50 eingeben. Okay. Aber das sind beim einlesen 2 getrennte Ziffern. 48 wird als 4 und 8 eingelesen und 50 als 5 und 0. Schau dir atoi() an.
Es werden schon einzelne Zeichen eingelesen. Und das ist sicherlich auch so gewollt. Es ist halt blöd geschrieben. So sieht sofort man was eigentlich gemeint ist und muss nicht rätseln oder die ASCII Tabelle auswendig können:
Code: [Select]

  case '0':
  case '1':
  case '2':
  case '3':


Wenn man ganze Strings einlesen will, muss man weiter ausholen. Also in Array einlesen, Endzeichen, Null-Terminator, etc. atoi() kommt erst am Ende. Das ist hier aber erst mal unnötig. Es gibt genug einzelne Zeichen um Kommandos darzustellen

Doc_Arduino

Hallo,

ich dachte weil der TO Eingangs zweistellige Werte verwendet. Wenn er mit Einstelligen auch zufrieden ist, okay.
Habe mal ein Grundgerüst erstellt.

Code: [Select]

enum class Job : byte {ruhe, raus, rein, messen};
Job job = Job::ruhe;

void setup()  {

  Serial.begin(9600);

}


void loop(void) {

  readSerial();

  makeYourJob(1000);
}

/* --------------------------------------------------------------- */

void makeYourJob (unsigned int interval)
{
  static unsigned long last_ms = 0;
  unsigned long ms = millis();

  if (ms - last_ms >= interval) {
    last_ms = ms;
    switch (job) {
      case Job::ruhe:   Serial.println(F("ich bin in ruhe")); break;
      case Job::raus:   Serial.println(F("ich bin raus")); break;
      case Job::rein:   Serial.println(F("ich bin drin")); break;
      case Job::messen: Serial.println(F("ich messe")); break;
    }
  }
}


void readSerial()
{
  if (Serial.available() > 0)  {
    char c = Serial.read();

    switch (c) {
      case '1': job = Job::ruhe;   break;
      case '2': job = Job::raus;   break;
      case '3': job = Job::rein;   break;
      case '4': job = Job::messen; break;
      default: break;
    }
  }
}


Wenn man im Messmodus ist und der ist fertig, dann setzt man job einfach mit job = Job::ruhe in den Ruhemodus. Dort dreht er dann Däumchen bis du wieder mit einer Zifferneingabe einen anderen Modus auswählst.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

michael_x

#11
Sep 25, 2019, 03:20 pm Last Edit: Sep 25, 2019, 03:20 pm by michael_x
Quote
ich habe jetzt versucht meine Loop mit einer Flag zu versehen um das Programm nur ein mal auszuführen. Das klappt zwar, in dem es nach ausführen des gewählten case aufhört, aber die Loop wird nicht weiter durchlaufen.
Du verwirrst dich selber mit dieser Interpretation zu deiner Version in #6. Natürlich wird loop weiter durchlaufen.
Allerdings wird dein static boolean Flag nie wieder auf true gesetzt.

Das Problem (schon in deinem ersten Versuch) ist eher, dass input immer den Wert des letzten empfangenen Zeichens behält.
Entweder
-- dein switch-Block kommt in den  Zweig
  if (Serial.available()) {} 
-- oder du löschst input nach dem Abarbeiten einfach wieder
-- oder du setzt Flag wieder auf true, wenn ein neuer Befehl über Serial reinkommt.

Serenifly

ich dachte weil der TO Eingangs zweistellige Werte verwendet.
Es sind aber keine zweistelligen Werte. 50 ist was anderes als "50". 50 ist einfach die Integer Darstellung eines ASCII Zeichens

Rentner

Hallo

mir ist ja noch nicht ganz klar was Du vorhast, spielt aber erst mal keine Rolle.

Du willst analoge Messwerte  in einem Array ablegen und in festen Zeitabständen messen. Gesteuert werden soll das mit dem Monitor mit der Eingabe 0-3. Für die Zeitabstände kann man am einfachsten millis() verwenden. Jetzt bleibt da noch die Frage soll während einer Messperiode eine andere Funktion ausgeführt werden können , oder soll die Eingabe gesperrt sein. Ansonsten könnte es sein das die Zeit zwischen zwei Messungen nicht konstant ist. Wenn Du aber wie geschrieben jede ms einen Wert messen willst dann sollte man das besser sperren. Dazu dürfte dann eine neue Eingabe nur möglich sein wenn der Status nicht 3 ist.


Ich hab das jetzt auf die Schnelle mal nur mit zwei Blöcken hinbekommen.
1 Abfrage der Eingabe als char dabei geht so nur 1 Zeichen  und damit einen byte Status setzen 0-3
2.Status auswerten

ob man das jetzt mit if , select oder enum macht ist Geschmackssache.

Hier mal ein Vorschlag damit Du da weiterkommst.

Heinz


Code: [Select]

const byte messpin = A0;
unsigned long altzeit;
char inchar;
int messwert[250];
const unsigned long messzyklus = 1;
byte i = 0; // Arrayindex
byte status = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

  if (Serial.available() > 0) {
    char inchar = Serial.read();
    //Serial.println(inchar);
    switch (inchar) {
      case '0': status = 0; break;
      case '1': status = 1; break;
      case '2': status = 2; break;
      case '3': status = 3; break;
    }
  }
// status auswerten
  if (status == 0) ruhemodus();
  if (status == 1) rausdrehen();
  if (status == 2) reindrehen();
  if (status == 3) messen();
}


void ruhemodus() {
  //Serial.println("ruhe");
  status = 0;
}

void rausdrehen() {
  Serial.println("rausdrehen");
  status = 0;
}

void reindrehen() {
  Serial.println("reindrehen");
  status = 0;
}

void messen() {
  if (i < 250) { // Array füllen
    if (millis() - altzeit >= messzyklus) {
      altzeit = millis();
      if (i == 0) Serial.println("messen aktiv");
      messwert[i] = analogRead(messpin);
      i++;
    }
  }
  else {  // Ausgabe der Werte
    Serial.println("messen fertig");
    for (i = 0; i < 250; i++) {
      Serial.print(i); Serial.print("\t");
      Serial.println(messwert[i]);
    }
    status = 0; // status rücksetzen
  }
}




Doc_Arduino

Es sind aber keine zweistelligen Werte. 50 ist was anderes als "50". 50 ist einfach die Integer Darstellung eines ASCII Zeichens
Wenn ich im seriellen Monitor 50 eingebe und Enter drücke, dann liest er eine 5 und eine 0 getrennt ein. Diese landen im Bufferarray auf Index 0 und 1. Um wieder die gewünschte 50 zu erhalten muss man die doch erst mittels atoi zusammensetzen? ASCII Code 48 bis 57 stellt doch nur eine einzelne Ziffer 0...9 dar. Oder wir reden aneinander vorbei?
Vielleicht wäre es eine wichtige Frage an den TO wo die Werte herstammen? Per Eingabe oder wird von irgendwoher ein Byte übertragen?
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Go Up