Go Down

Topic: [Projekt] Multitasking (Read 8809 times) previous topic - next topic

Doc_Arduino

#45
Oct 14, 2019, 08:22 am Last Edit: Oct 14, 2019, 04:28 pm by Doc_Arduino
Hallo,

Edit:  Bevor ich Ärger bekomme, gelöscht. In deinem eigenen Thread sehen wir uns vielleicht wieder.
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

combie

#46
Oct 14, 2019, 09:36 am Last Edit: Oct 14, 2019, 05:40 pm by combie
Schau doch mal bitte....
Schade, dass die Kommunikation zwischen uns beiden nicht so richtig funktioniert.

Ein paar Probleme gibt es hier:
Du kaperst meinen Taskmakro Vorstellungsthread, anstatt einen eigenen aufzumachen.
Die Salamitaktik, die geht mir quer. (erst kein Code, dann eine unformatierte Wurst, dann 3 Züge)
Sagst mir, meine Makros funktionieren nicht. Bist aber nicht bereit dich den Bedingungen zu stellen (Endlosschleife einzubauen)
Und dann die dreiste Aufforderung: Mach du mal für mich....

Sorry, dass ich das etwas grob formuliert habe, aber, du siehst die Diskrepanz, zwischen deiner und meiner Erwartungshaltung, oder?

---

Meine Makros können dir den Bau von endlichen Automaten, Schrittketten und Ablaufsteuerungen vereinfachen.
Aber sie können nicht dein Denken ändern.
Das kannst nur du.

Geht ja auch alles wie gewünscht, nur das Warten an den Bahnhöfen nicht. Wie kann ich das Lösn?
Denke in Nebenläufigkeiten.

Und wenn es um 3 Züge geht, welche sich gleich verhalten sollen, dann wären eher die Taskobjekte für das Problem geeignet, als dieser eher primitive Vorläufer davon.
Auch ist da die Endlosschleife schon fest eingebaut.
Da gibts dann kein Weg drumrum.

Tipp:
Male Ablaufdiagramme, so wie es dir auf der Wikipedia Seite zu endlichen Automaten vorgemacht wird
Vielleicht verstehe ich dich ja dann.....
Heute war Gestern Morgen.
Heute ist Morgen Gestern.
Morgen ist Heute Gestern.
Gestern war Heute Morgen

epunkt

Servus, ich noch mal kurz.....

Keinesfalls wollte ich sagen, das die Makros nicht funktionieren.
Ich schrieb, das ich irgendwas nicht gerafft habe, weil taskWaitFor(condition) nur bei mir nur einmal
greift, und dann nie wieder.

Ist es so, das eine einmal gestartete Task eigentlich immer aktiv ist und nie endet?

Ich bin Deinem Rat gefolgt und hab mal überlegt wie Züge in der Wirklichkeit fahren (sollten :))
Da gibt es einen Fahrplan mit Abfahrtszeiten an den Bahnhöfen. Ab der Erkenntnis war alles ganz einfach, ein Array mit Abfahrtsminuten, also:
Code: [Select]

int BlinksAbfahrt[] = {2, 7, 12, 21, 26, 32, 36, 45, 49, 54, 58};
int BrechtsAbfahrt[] = {5, 10, 15, 24, 29, 34, 39, 48, 51, 56};
int BmitteAbfahrt[] = {3, 6, 8, 11, 13, 16, 22, 25, 27, 30, 33, 35, 37, 40, 46, 49, 50, 52, 55, 57, 59};

hat das Ganze einfach und flexibel gelöst. Läuft so natürlich auch für beliebig viele Züge, so sie unterschiedliche Gleise und Stromkreise haben und sieht auf der Platte ausreichend echt aus:)

die Makros für das beschleunigen und abbremsen sind nach wie vor drin und tun genau was sie sollen, nämlich das wenn grade gebremst wird bekommt der Prozessor trotzdem sofort mit wenn ein anderer Zug den Streckenabschnitt wechselt, was bei delay() definitiv nicht der Fall wäre.

--
     Cool .signatures are so 90s...

combie

#48
Oct 15, 2019, 02:28 pm Last Edit: Oct 15, 2019, 02:29 pm by combie
Erstmal: Schön, dass es funktioniert.

Quote
Ist es so, das eine einmal gestartete Task eigentlich immer aktiv ist und nie endet?
Wenn sie die Gelegenheit bekommt, dann ja.


Code: [Select]


// leicht witzig, aber recht realistisch.


   const bool stromausfall = false;


   while(not stromausfall)
   {
     taskA();
     taskB();
   }



Hier Lesestoff wird das Prinzip beschreiben. Natürlich kann ein kleiner AVR das nicht alles, darum auch meine gnadenlos abgespeckte Version.
Heute war Gestern Morgen.
Heute ist Morgen Gestern.
Morgen ist Heute Gestern.
Gestern war Heute Morgen

heweb

Schon vor Jahren habe ich mit dieser Konstruktion experimentiert.
Hier mein Link zu meinem Tutorial in 8 Lektionen mit 60 Seiten Dokumentation dazu und Sourcecn.
Vom einfachsten Multitasking bis zum Scheduler, Taskstart in Interrupts etc.
Für alle Prozessoren geeignet. In Deutsch.

https://github.com/MacLeod-D/CoopOS-Kurs-Deutsch

combie

@heweb
Schämst du dich gar nicht?
Heute war Gestern Morgen.
Heute ist Morgen Gestern.
Morgen ist Heute Gestern.
Gestern war Heute Morgen

DrDiettrich

Wer sich McLeod nennt, der glaubt wohl auch an seine Einzigartigkeit :-(

Ich habe mir sein Tutorial nicht angeschaut - lohnt sich das denn?

TomLA

#52
Jan 18, 2020, 07:51 pm Last Edit: Jan 18, 2020, 08:49 pm by TomLA
Hallo, ich bin neu in diesem Forum und hoffe, das hier in diesen Threat noch jemand mitliest.
Ich benutze die Taskmacros von Combie. Die funktionieren soweit auch recht gut. Nun habe ich aber ein Problem, bei dem ich denke, das ich ohne eure Hilfe nicht mehr weiterkomme.
Das Problem ist folgendes:
Ich bzw. der Arduino arbeitet gerade in einem Task, aus dem ruft er eine andere Funktion auf. Nach Beendigung der anderen Funktion soll aber der ursprünglich Task nicht mehr weiter aufgerufen bzw. ausgeführt werden. Ich vermute, es liegt an der darin vorkommenden taskPause() oder er akzeptiert das return (um den Task zu verlassen) nicht und arbeitet stur nach dem Rücksprung in die Task die nächste Zeile (nach dem return) weiter.
Vielleicht kann mir da jemand auf die Sprünge helfen ??
Falls der Code (ewig lang und etwas unschön, weil ich ein alter Spagetti-Code-Programmierer bin) oder andere Angaben benötigt werden, kann ich das gerne machen, aber ich denke ihr stellt die Fragen, und ich liefere was nötig ist.
Vielen Dank im Voraus
Tom

michael_x

Quote
Ich bzw. der Arduino arbeitet gerade in einem Task, aus dem ruft er eine andere Funktion auf. Nach Beendigung der anderen Funktion soll aber der ursprünglich Task nicht mehr weiter aufgerufen bzw. ausgeführt werden.
Könnte sein, dass das Konzept "Task" gar nicht passt, und du eher eine "State Machine" beschreibst.
?

combie

#54
Jan 19, 2020, 03:14 pm Last Edit: Jan 19, 2020, 03:15 pm by combie
Ich verstehe dein Problem auch nicht.

Das Konzept "Task anhalten", von Außen, ist bei den TaskMacros nicht vorgesehen.
Kooperation, ist das primäre Verhaltensmuster.

Möglichkeiten:
  • taskWaitFor() lässt die Task ruhen, bis die Bedingung wahr wird.
  • Task gar nicht erst aufrufen



Heute war Gestern Morgen.
Heute ist Morgen Gestern.
Morgen ist Heute Gestern.
Gestern war Heute Morgen

TomLA

Hallo erstmal, vielen Dank, dass ihr euch mein Problem mal angesehen habt.
Zur Erklärung bzw. Verdeutlichung, warum ich glaube, einen Task zu benötigen:
Eigentlich war die ursprüngliche Funktion kein Task. In der Funktion wurde, je nach Zustand der (Alarm-)Anlage, eine Taste auf einem TFT angezeigt. Das hat auch sehr gut funktioniert. Dann kam mir die Idee, die angezeigte Taste (rot) könnte nach Betätigung einen Countdown von 15 sekunden anzeigen. Während dieses Countdowns muss vom Benutzer eine Chipcard vor die Anlage gehalten werden. Wenn er das macht, springt die Taste wieder auf ihren Normalzustand um (grün).
Das hat aber nur mit einem Task funktioniert (zumindest ist mir keine andere Lösung eingefallen, um den Countdown darzustellen, ohne delay zu benutzen).
MIt dem Task läuft es auch so wie ich es mir vorstellte, aber sobald die ChipKarte an die Anlage gehalten wird, spring der Arduino von der Funktion (Alarm aus) wieder in den Task (Alarm an mit Countdown der Taste) und startet den Countdown neu.
Mein serieller Monitor zeigt mir das auch so an, das der Zustand von dem Task wieder geändert wird.
Ich weiss, das ist für Aussenstehende schwer zu verstehen, bzw. ich weiss nicht, wie ich es erklären soll.
Ich stelle mal einen Code-Abschnitt und einen Teil der Ausgabe am seriellen Monitor (mit jeweils ein paar Kommentaren meinerseits) zum hoffentlich besseren Verständnis mit ein.

Der Ausschnitt aus dem Programmcode

Code: [Select]

void alarm_an(unsigned char zimmer)
{
  Serial.println("*** alarm_an ***");
  /*
    Serial.print("alarm_zimmer_1: ");
    Serial.println(alarm_zimmer_1);
    Serial.print("alarm_zimmer_2: ");
    Serial.println(alarm_zimmer_2);
  */
  if (zimmer == Zimmer_1)
  {
    //    zimmer_1_btn.initButton(&tft, 175, 70, 300, 40, WHITE, RED, WHITE, "Alarm 1 aus", 2);
    //    zimmer_1_btn.drawButton(false);
    alarm_zimmer_1 = ON;
    alarm_tft_anzeige(Zimmer_1, "alarm1");
  }
  else if (zimmer == Zimmer_2)
  {
    zimmer_2_btn.initButton(&tft, 175, 130, 300, 40, WHITE, RED, WHITE, "Alarm 2 aus", 2);
    zimmer_2_btn.drawButton(false);
    alarm_zimmer_2 = ON;
  }
  alarm_status = 1;
  Wire.beginTransmission(8);
  Wire.write(alarm_status);
  Wire.endTransmission();
  relay_SetStatus(zimmer, ON);         // Relais für alarmauslösendes Zimmer an
}

Task alarm_tft_anzeige(unsigned char zimmer, char alarm_taste_status[])
{
  Serial.println("*** alarm_tft_anzeige ***");
  Serial.print ("zimmer: ");
  Serial.println (zimmer);
  Serial.print ("alarm_taste_status: ");
  Serial.println (alarm_taste_status);
  Serial.print ("alarm_taste_tft_has_to_be_changed: ");
  Serial.println (alarm_taste_tft_has_to_be_changed);
  Serial.print ("countdown: ");
  Serial.println (countdown);
  taskBegin();
  while (1)
  {
    if (zimmer == Zimmer_1)
    {
      if (alarm_taste_status == "ok")
      {
        if (alarm_taste_tft_has_to_be_changed == true)
        {
          zimmer_1_btn.initButton(&tft, 175, 70, 300, 40, WHITE, GREEN, BLACK, "Zimmer 1 OK", 2);
          zimmer_1_btn.drawButton(false);
          alarm_taste_tft_has_to_be_changed = false;
          return;
        }
      }
      else if (alarm_taste_status == "alarm1")
      {
        if (alarm_taste_tft_has_to_be_changed == true)
        {
          zimmer_1_btn.initButton(&tft, 175, 70, 300, 40, WHITE, RED, WHITE, "Alarm 1 aus", 2);
          zimmer_1_btn.drawButton(false);
          alarm_taste_tft_has_to_be_changed = false;
          return;
        }
      }
      else if (alarm_taste_status == "alarm2")
      {
        if (alarm_taste_tft_has_to_be_changed == true)
        {
          zimmer_1_btn.initButton(&tft, 175, 70, 300, 40, WHITE, RED, WHITE, "Alarm 1", 2);
          zimmer_1_btn.drawButton(false);
          alarm_taste_tft_has_to_be_changed = false;
          return;
        }
      }
      else if (alarm_taste_status == "warten")
      {
        if (countdown > 14)
        {
          alarm_taste_tft_has_to_be_changed = true;
          // alarm_taste_status = "alarm2";
          alarm_tft_anzeige(Zimmer_1, "alarm2");
          return;
        }
        if (keycard_status == true)
        {
          keycard_check = false;
          alarm_aus(Zimmer_1);                              //<-- hier springt er zu der Funktion, welche ich im ersten Posting gemeint habe
          /*          alarm_taste_status = "ok";
                    alarm_taste_tft_has_to_be_changed = true;
                    alarm_tft_anzeige(Zimmer_1, "ok");*/
          return;                                                  //<-- hier sollte er den Task dann verlassen und gut is, aber er überspringt diese Anweisung bzw. er sollte nie hier landen, da der alarm_taste_status eigentlich "ok" sein sollte
        }
        zimmer_1_btn.initButton(&tft, 175, 70, 300, 40, WHITE, RED, BLACK, text[countdown], 2);
        zimmer_1_btn.drawButton(true);

        countdown++;
        taskPause(1000);
      }
      else
      {
        zimmer_1_btn.initButton(&tft, 175, 70, 300, 40, WHITE, RED, WHITE, "ERROR", 2);
        zimmer_1_btn.drawButton(false);
      }
    }
    else if (zimmer == Zimmer_2)
    {
      zimmer_2_btn.initButton(&tft, 175, 130, 300, 40, WHITE, RED, WHITE, "Alarm 2 aus", 2);
      zimmer_2_btn.drawButton(false);
      alarm_zimmer_2 = ON;
    }
  }
  taskEnd();
}

void alarm_aus(unsigned char zimmer)
{
  Serial.println("*** alarm_aus ***");
  Serial.print("alarm_zimmer_1: ");
  Serial.println(alarm_zimmer_1);
  Serial.print("alarm_zimmer_2: ");
  Serial.println(alarm_zimmer_2);
  if (zimmer == Zimmer_1)
  {
    if (alarm_zimmer_1 == ON)
    {
      alarm_zimmer_1 = OFF;
      if (menue_flag == true)
      {
        menue_flag = false;
        display_change = true;
      }
      else
      {
        alarm_taste_tft_has_to_be_changed = true;
        alarm_tft_anzeige(Zimmer_1, "ok");
        //        zimmer_1_btn.initButton(&tft, 175, 70, 300, 40, WHITE, GREEN, BLACK, "Zimmer 1 OK", 2);
        //        zimmer_1_btn.drawButton(false);
        display_change = false;
        //      alarm_taste_tft_has_to_be_changed=true;
      }
    }
  }
  else if (zimmer == Zimmer_2)
  {
    if (alarm_zimmer_2 == ON)
    {
      alarm_zimmer_2 = OFF;
      if (menue_flag == true)
      {
        menue_flag = false;
        display_change = true;
      }
      else
      {
        zimmer_2_btn.initButton(&tft, 175, 130, 300, 40, WHITE, GREEN, BLACK, "Zimmer 2 OK", 2);
        zimmer_2_btn.drawButton(false);
        display_change = false;
      }
    }
  }
  Serial.print("display_change: ");
  Serial.println(display_change);
  if (alarm_zimmer_1 == OFF && alarm_zimmer_2 == OFF)
  {
    alarm_status = 2;
    keycard_check = 0;
    Wire.beginTransmission(8);
    Wire.write(alarm_status);
    Wire.endTransmission();
    countdown = 0;
  }
  relay_SetStatus(zimmer, OFF);        // Relais für alarmauslösendes Zimmer aus
}



Und hier der Ausschnitt aus dem seriellen Monitor

Code: [Select]

*** alarm_tft_anzeige ***
zimmer: 24
alarm_taste_status: warten
alarm_taste_tft_has_to_be_changed: 1
countdown: 2
*** keycard_access ***
Authorize with access card or Chip
Authorized access chip
keycard_status: 1
keycard_card: 0
keycard_chip: 1
menue_flag: 0
alarm_status: 1
keycard_check: 0
 
*** keycard_alarm_aus ***
*** alarm_aus ***
alarm_zimmer_1: 1
alarm_zimmer_2: 0
*** alarm_tft_anzeige ***
zimmer: 24
alarm_taste_status: ok                           //<-- an der Stelle ist alles ok
alarm_taste_tft_has_to_be_changed: 1
countdown: 3
display_change: 0
*** alarm_aus ***
alarm_zimmer_1: 0
alarm_zimmer_2: 0
display_change: 0
*** alarm_tft_anzeige ***                    //<-- hier sieht man, das er in den Task zurückkehrt, also auch noch ok
zimmer: 24
alarm_taste_status: warten                   //<-- hier setzt er eigenwillig seinen alten Zustand (vor Verlassen des Task) wieder ein (So ein pösser Pursche ;-))
alarm_taste_tft_has_to_be_changed: 1
countdown: 0
*** keycard_access ***
Authorize with access card or Chip
*** alarm_tft_anzeige ***
zimmer: 24
alarm_taste_status: warten
alarm_taste_tft_has_to_be_changed: 1
countdown: 0



Hoffentlich habe ich jetzt endgültig alle Klarheiten beseitigt ;-)
Tom

Tommy56

Dein Problem ist delay(), ohne brauchst Du keinen Tasks.

Schau Dir BlinkWithoutDelay in den Beispielen der IDE an und verstehe es.
Dabei kann Dir z.B. die Nachtwächtererklärung helfen.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

combie

#57
Jan 19, 2020, 07:31 pm Last Edit: Jan 19, 2020, 07:31 pm by combie
Quote
if (alarm_taste_status == "alarm1")
So vergleicht man keine Zeichenketten, sondern Zeiger.
Und das willst du sicherlich nicht.
Heute war Gestern Morgen.
Heute ist Morgen Gestern.
Morgen ist Heute Gestern.
Gestern war Heute Morgen

TomLA

@Tommy56
OK - Ich verstehe BlinkWithoutDelay und meine ich hätte das auch schon mal versucht. Aber ich werde es nochmal versuchen, es in meinen Fall einzubauen. Ich melde mich dann wieder, wenn ich ein Ergebnis habe (hoffentlich ein positives).

@combie
Sorry für die doofe Gegenfrage - wie würde es denn richtig gehen? Mit strcmp?

Danke schon mal im Voraus
Tom

TomLA

Juhu - es funktioniert. War total easy.
Manchmal braucht es eben doch den berühmten Schlag aud den Hinterkopf ;-)

Vielen, vielen Dank an Tommy56

Go Up