Go Down

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

DrDiettrich

Ich denke, daß ich das Problem mit der überflüssigen Schleife in taskSwitch() gelöst habe. Wichtig ist alleine der Block, der den Code zusammenhält, die Schleife drumrum ist überflüssig.
Code: [Select]
#define taskSwitch() { mark=__LINE__; return; case __LINE__: ; }
Ohne die Klammern kann es vorkommen, daß nur das erste Statement zu einem vorhergehenden if oder while gehört, der Rest danach aber immer ausgeführt wird.

Jetzt scheint in meiner ALib0 alles zu funktionieren, und ich kann die erste Version nach github hochladen. In dieser Bibliothek liegt neben den Task Makros noch eine AButton Klasse, mit der sich die häufigsten Anfängerprobleme (Debounce, StateChange) einfach erschlagen lassen.

Ich hatte diverse Probleme mit dem Upload, kann jemand die Beispiele testen?

DrDiettrich

Inzwischen ist mir noch ein schnuckeliges Makro für die regelmäßige Ausführung eingefallen. Das soll allerdings in loop() verwendet werden, um beliebige Abläufe in regelmäßigem Abstand auszuführen.
Code: [Select]
//do something at regular intervals. This is designed for use in loop(), not within a task
#define every(ms) for (static millis_t _t=0; millis()-_t>=ms; _t+=ms)

Hier wird for für das Verstecken lokaler Variablen mißbraucht, funktioniert prima :-)

Für das sperrige "unsigned long" bei millis() habe ich dazu noch die Abkürzung millis_t eingeführt.

michael_x

Quote
funktioniert prima :-)
kann man es schachteln ?  ( nicht unbedingt nötig, aber wenn schon, denn schon )

Code: [Select]
#define every(ms) for (static millis_t _t=0; millis()-_t>=ms; _t+=ms)
typedef unsigned long millis_t;
#define LED 13

void setup() {
  Serial.begin(9600);
  pinMode(LED,OUTPUT);
}
void loop() {
 
 static bool status;
 every(500) {
   status = !status;
   digitalWrite(LED, status);
   every (10000) Serial.write('.'); 
 }
}
compiliert auf jeden Fall schonmal

DrDiettrich

Läuft Dein Testprogramm nicht?

Normalerweise schreibt man solche Aktionen hintereinander:
Code: [Select]
every(500) dies;
every(10000) das;
Bei meinem Testprogramm in der ALib0 loggen 3 Tasks etwas parallel, nach verschiedenen Verfahren und mit unterschiedlichen Intervallen.

michael_x

Hab hier grade keinen Arduino zur Hand, kann es daher nur compilieren.
Gefällt mir aber schonmal gut.

Quote
Normalerweise schreibt man solche Aktionen hintereinander
Ja klar.
War nur neugierig, was passiert, wenn man sowas machen würde.

Oder sowas:

Code: [Select]
void loop() {
   every(1000) sekundenZyklus();
}

void sekundenZyklus() {
   every(60000UL) minutenZyklus();
}

void minutenZyklus() {}


Das geht "noch sicherer", da sich die Variablen erst recht nicht ins Gehege kommen können.
Auch wenn es -normalerweise- nicht so nicht nötig wäre.

combie

#35
Apr 14, 2017, 12:01 pm Last Edit: Jun 29, 2017, 10:04 am by combie
Hi!

Bin gerade dabei die TaskMakros zu überarbeiten.

Hier möchte ich euch schon mal ein Halbzeug vorstellen.
Ein einfacher Scheduler.

Als Vorlage habe ich das original Blink Beispiel verwendet.
Die delay() sind erhalten geblieben.

Nur den Scheduler und 2 UserTasks hinzugefügt.
Um ein wenig Demo Kram da rein zu bekommen.


In Tasks sind delay() weiterhin blockierend. Wirken sich aber nicht fatal aus, denn
in yield() wird eine Rekursion erkannt und verhindert.

Code: [Select]
#include <TaskMacro.h>
// siehe: https://forum.arduino.cc/index.php?topic=415229.0

unsigned long loopcount  = 0;
unsigned long yieldcount = 0;


void printCount()  // User Task
{
  taskBegin();
  while(1)
  {
    taskPause(1000); // jede Sekunde 
    Serial.print("Loop: ");   
    Serial.print(loopcount);   
    Serial.print("    Yield: ");   
    Serial.print(yieldcount);   
    Serial.println();
  } 
  taskEnd();
}

void printA() // User Task
{
  taskBegin();
  while(1)
  {
    taskPause(5000); // alle 5 Sekunden   
    Serial.println("A");
  } 
  taskEnd();
}



// hier alle Tasks, gefolgt von einem taskSwitch() eintragen
// alternativ, ein Array verwenden
void scheduler() //  Scheduler
{
  taskBegin();
  while(1)
  {
    printCount();
    taskSwitch();
    printA();
    taskSwitch();
  } 
  taskEnd();
}

void yield() // wird im Delay aufgerufen
{
    static bool reentranceFlag = true;
    yieldcount++;
    if(reentranceFlag) 
    {
      reentranceFlag = false; // zirkulaere Aufrufe unterdruecken
      scheduler();   
      reentranceFlag = true;
    }
}

void setup()
{
  Serial.begin(9600);
  Serial.println();
  Serial.println("Start");
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  loopcount++;
  digitalWrite(LED_BUILTIN, HIGH);   
  delay(1000);                     
  digitalWrite(LED_BUILTIN, LOW);   
  delay(1000);                       
}

 

Unsichtbar wird der Wahnsinn, wenn er genügend große Ausmaße angenommen hat.
(Berthold Brecht)

epunkt

Hi, hoffentlch liest hier noch jemand....

Code schicke ich nach, aber die Frage scheint mir ganz einfach: Bei mir wartet taskWaitFor(condition) bis zum ersten true und dann nicht mehr. Die Task wird ganz normal beendet (wird sie das?) und später wiederholt aufgerufen, aber da wird nicht mehr gewartet, obwohl condition gar nicht true ist. Oder hab ich da wie ich vermute ein Verständnisproblem?

--
Servus, Elmar

combie

Du machst was falsch!
Das kann ich dir so schon sagen.

Ist die Frage damit beantwortet?
Unsichtbar wird der Wahnsinn, wenn er genügend große Ausmaße angenommen hat.
(Berthold Brecht)

epunkt

#38
Oct 13, 2019, 07:43 pm Last Edit: Oct 13, 2019, 07:52 pm by epunkt
Okay, Super das Du hier noch liest :))

Wie füge ich Code ein?

Code: [Select]

#include <TaskMacro.h>
#include <millisDelay.h>

int t1Power = 13;
int t2Power = 2;
int BHR = 3; //Bahnhofsreed
//int GBM1 = 4;  //Gleisbesetztmelder Bahnhof außen
int SignalBahnhof = 10;
int speed = 110;  // Geschwindigkeitsvektor, startet bei Programmstart mit Normalgeschwindigkeit 0-255
int smax = 240;    // Maximalgeschwindigkeit
int norm = speed;   // Normalgeschwindigkeit
int smin = 180;      // Minimalgeschwindigkeit
int t1stop,t1start,t2stop,t2start = 0;
int t1stopzeit,t2stopzeit=4000;
int t1haltezeit,t2haltezeit=15000;
int t1halt,t2halt=0;

int t1speed=0;
int t2speed=0;
int t1norm=220;
int pstart=1;
int t1direction=0; //0-right, 1-left
int W1rechts=8;
int m1=30;
int m2=31;
int mo1=32;
int mo2=33;
long delay1 = 180000;
long delay2 = 60000;
long delay3 = 120000;
long delay0 = 5000;
int GBM1 =7, GBM2=6, GBM3=5, GBM4=4;

unsigned long ankunft = 0;
unsigned long zeit = 0;
const long takt = 12000;

static uint8_t tog,tog1 =0;

// static uint32_t ledtime=millis(),s1=ledtime+66,s2=s1+90,s3=s1+187,s4=s1+231;
static uint32_t s1= millis(),s2=s1+20000,s3=s1+50000,s4=s1;

// the setup routine runs once when you press reset:
void setup() {
  randomSeed(100);
  pinMode(BHR, INPUT);
  pinMode(GBM1, INPUT_PULLUP); //äußeres Gleis links innen
  pinMode(GBM2, INPUT_PULLUP); //äußeres Gleis links außen
  pinMode(GBM3, INPUT_PULLUP); //äußeres Gleis Bahnhof
  pinMode(GBM4, INPUT_PULLUP); //äußeres Gleis rechts
 
  pinMode(t1Power, OUTPUT);
  pinMode(t2Power, OUTPUT);
 
  pinMode(m1,OUTPUT);
  pinMode(m2,OUTPUT);
  pinMode(mo1,OUTPUT);
  pinMode(mo2,OUTPUT);
Serial.begin(9600);

//m1 HIGH, m2 LOW --> Zug nach links
//m1 low  m2 HIGH --> Zug nach rechts
//ELok t1norm guter Speed
          digitalWrite(m1,LOW);
          digitalWrite(m2,HIGH);
  //        analogWrite(t1Power, t1speed);
          analogWrite(t1Power, 220);
          delay(500);
          //digitalWrite(t1Power, 0);
}

void rechts() {
  digitalWrite(m1,LOW);
  digitalWrite(m2,HIGH);
  t1direction=0;
  Serial.println("Rechts-----------------------------");
}
void links() {
  digitalWrite(m2,LOW);
  digitalWrite(m1,HIGH);
  t1direction=1;
  Serial.println("Links-----------------------------");
}



void t1anhalten(){
taskBegin();

while (t1speed>0){
  Serial.println("anhalten-----------------------------");
  t1speed=t1speed-20; analogWrite(t1Power, t1speed);
  taskPause(50);
  ankunft=millis();
if (t1speed<=20) {
  t1speed=0;analogWrite(t1Power, t1speed);

}

}

taskEnd();
t1halt=2;
}

void t1losfahren(){
taskBegin();
taskWaitFor((zeit-ankunft>=takt) && (zeit-ankunft<=200000)); //??????????????????????????????????????????????????

while (t1speed<t1norm){
//taskSwitch();
  Serial.println("beschleunigen-----------------------------");
  t1speed=t1speed+15;analogWrite(t1Power, t1speed);
  taskPause(10);
if (t1speed>155) {
  t1speed=t1norm;analogWrite(t1Power, t1speed);
 
}
}

t1halt=0;
taskEnd();
}

// the loop routine runs over and over again forever:
void loop() {
 
delay(500); 
//analogWrite(t1Power, t1speed);
//taskBegin();   
 
// wenn GBM1 == 0 und m1==HIGH bremsen (while t1speed>0 reduce)
// warten Richtungswechsel (m1 LOW) beschleunigen (while t1speed<t1norm increase)
// wenn GBM4 == 0 und m1=LOW bremsen (while t1speed>0 reduce)
// warten Richtungswechsel (m1 HIGH) beschleunigen (while t1speed<t1norm increase)

if (pstart<10){
  if (digitalRead(GBM1)==0){
    rechts();
    t1losfahren();
  }
  if (digitalRead(GBM4)==0){
    links();
    t1losfahren();
  }
   
  pstart++;
}
//analogWrite(t1Power, t1speed);
//delay(100);
//analogWrite(t1Power, t1speed);
Serial.println("loop-----------------------------");

if (((digitalRead(GBM1)==1)) &&  ((digitalRead(GBM4)==1)))
{
   t1speed=220;analogWrite(t1Power, t1speed); //--------------------------------------------------------------
}

if ((digitalRead(GBM1)==0) && (t1direction==1))
{
 
  t1anhalten();
  //delay(44000);
}

if ((digitalRead(GBM1)==0) && (t1halt==2)) //Bahnhof links

 
  rechts();
  delay(50);
  Serial.println("beschleunigen aufrufen-----------------------------");
  t1losfahren();
 //taskPause(84000);
}


if ((digitalRead(GBM4)==0) && (t1direction==0))
{
  t1anhalten();

  //delay(4000);

if ((digitalRead(GBM4)==0) && (t1halt==2)) {  //Bahnhof rechts
   // taskPause(54000);
    links();
    delay(50);
    Serial.println("beschleunigen aufrufen -----------------------------");
    t1losfahren();
  }

Serial.print(t1direction);
Serial.print("-");
Serial.print(digitalRead(GBM1));
Serial.print("-");
Serial.print(digitalRead(GBM2));   
Serial.print("-");
Serial.print(digitalRead(GBM3));
Serial.print("-");
Serial.print(digitalRead(GBM4));
Serial.print("-");
Serial.print(t1speed);
Serial.print("--");
Serial.print(t1halt);
Serial.print("--");
Serial.print(zeit-ankunft);
Serial.println("");
zeit=millis();
//taskEnd();
}

Tommy56

Setze Deinen Code bitte in Codetags (</>-Button oben links im Forumseditor oder [*code] davor und [*/code] dahinter ohne *).
So ist er auch auf portablen Geräten lesbar. Das kannst Du auch noch nachträglich ändern.

Schön wäre auch, wenn Du unnötige Leerzeilen löschst.

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

epunkt

Okay, hab ich gemacht. Entschuldigung bitte.

combie

Okay, Super das Du hier noch liest :))
Warum auch nicht.....

Mir fehlen die Enlosschleifen in deinen Tasks!
Von daher darfst du dich nicht wundern, dass es nur eine Runde läuft.

Endlosschleifen sind in dem Zusammenhang was ganz normales.
Jede Windows/Linux/FreeRtos usw. tut sowas, oder so ähnlich.
Darum findest du dieses auch in jedem meiner Beispiele.

Ansonsten, keine Ahnung, was dein Programm tun soll.
Und Formatiert ist es auch gruselig.
Ein STRG-T würde schon helfen..



Unsichtbar wird der Wahnsinn, wenn er genügend große Ausmaße angenommen hat.
(Berthold Brecht)

epunkt

Dankeschön für die Antwort. Strg T hab ich grade gemacht.....

Ich bin vielleicht etwas unbeholfen, nur zur Erklärung, nicht Entschuldigung, ich bin 62 und wollte mal etwas neues probieren. Arduino Mega + diese http://wiki.seeedstudio.com/Motor_Shield_V1.0/ H-Brücke  sind die verbauten Komponenten.

Das Programm soll die einfachste Form einer Pendelzugsteuerung sein. Fahre nach rechts, bis der rechte Gleisbesetztmelder (GBM4) belegt meldet (digitalread(GBM4==0)) , dann bremse ab bis null, warte die Zeit die in takt festgelegt ist, beschleunige wieder nach links bis Zug am linken Bahnhof (GBM1) ist, bremse ab, warte die Zeit die in takt festgelegt ist usw.
Der Rest im Programm ist nur, damit der Zug auch losfährt, wenn er bei Programmstart irgendwo, jedenfalls nicht im rechten oder linken Bahnhof auf einem Gleisbesetztmelder steht und schlampige Rudimente aus Versuchen.

Das alles _funktioniert_ bis auf das Warten.

Der Zug bremst, wartet beim _ersten_ Durchlauf den takt ab, beschleunigt, bremst wieder am Gegenbahnhof, wartet dann aber nicht mehr, sondern fängt sofort wieder mit Beschleunigen in die Gegenrichtung an.

Irgendwas mach ich da falsch, und vielleicht kannst Du mir helfen. Das Problem beim Nachstellen ist, das der Code bei Dir sicher compiliert aber für den Ablauf eine fahrende Lok und die Gleisbesetzmelder braucht..

Danke und viele Grüße

Elmar

combie

Dieses Multitasking System ist dafür gedacht, dass mehre Abläufe quasi gleichzeitig ablaufen können.
Wenn du es verwenden möchtest, wirst du dein Programm in Nebenläufigkeiten aufteilen müssen.

Im Moment, sehe ich noch nicht, wie man das tun könnte...

Unsichtbar wird der Wahnsinn, wenn er genügend große Ausmaße angenommen hat.
(Berthold Brecht)

epunkt

Das quasi gleichzeitig wird sofort benötigt wenn die zweite Strecke und der zweite Zug dazukommt. Mit einer Ausweichstelle in der Mitte der Strecke gehen dann sogar 3 Züge gleichzeitig. (Auf der Platte schon vorhanden)

Geht ja auch alles wie gewünscht, nur das Warten an den Bahnhöfen nicht. Wie kann ich das Lösn? Schau doch mal bitte....

--
Elmar

Go Up