[Projekt] Multitasking

skorpi08: Was gefällt euch an Jomelos simpleThread nicht?

Das kannte ich vorher noch nicht.

Auch sind meine taskMacros vermutlich schon einiges älter. Hatte sie nur noch nicht aufs Arduino Umfeld portiert.

Hallo,

genau jetzt gehts in die richtige Richtung. Ich hatte noch keine Zeit mir das näher anzuschauen, habe nur deine Texte hier dazu mehrfach gelesen. Also macht der Task sein Ding und wenn er fertig ist gehts in der loop normal weiter. Und wenn der Task selbst aktuell nichts zu tun hat blockiert er auch nicht sondern gibt sich sofort wieder frei zurück an loop. Okay, dass verstehe ich. Wie dein Intervall nur eben anders verpackt. Sehr schön. :) Werde das sicherlich bald selbst testen.

Was mache ich falsch :confused:

kurze Einleitung:

ich möchte einen Servo ansteuern und nebenbei andere dinge erledigen
doch ich bekomme diese Fehlermeldung und habe keinen schimmer was falsch ist

Bitte um richtigstellung !!

#include <TaskMacro.h>
#include <Servo.h>
Servo servo1;

void setup() {
  
  Serial.begin(38400);     
  delay(500);
  servo1.attach(9);

}

void loop() {

 bewegung();
 
}

void bewegung() {
 
 taskBegin();

  int position;


  for(position = 20; position < 180; position += 2)   
  {
    servo1.write(position);  
    taskPause(20);               
  }

  
  for(position = 180; position >= 20; position -= 2)
  {                                
    servo1.write(position);  
    taskPause(20);     
   
  }
  
}

Fehlermeldung:

 In function 'void bewegung()':

sketch_aug04a:40: error: expected '}' at end of input

 };

  ^

exit status 1
expected '}' at end of input
#include <TaskMacro.h>
#include <Servo.h>
Servo servo1;

void setup() {
  
  Serial.begin(38400);     
  delay(500);
  servo1.attach(9);

}

void loop() {

 bewegung();
 
}

void bewegung() {  
  static int position;
  taskBegin();

  for(position = 20; position < 180; position += 2)   
  {
    servo1.write(position);  
    taskPause(20);               
  }

  
  for(position = 180; position >= 20; position -= 2)
  {                                
    servo1.write(position);  
    taskPause(20);     
   
  }
  taskEnd();
  
}

Die Meldung sagt: taskEnd(); vergessen

int position muss static werden, damit der Wert über mehrere Taskdurchläufe erhalten bleibt.
Die Deklaration sollte vor taskBegin stattfinden.

Evtl fehlt da noch eine Schleife, damit sich das Gezappel wiederholt.

Danke für die Rückmeldung nach deinen Verbesserungen klappte es wie gewollt! Hoffe das es dabei bleibt!!

Hoffe das es dabei bleibt!!

Ach, sicher… ich habe da volles Vertrauen.

Danke für die Rückmeldung

Und, dir Danke für den Test!

was mach ich jetzt falsch :frowning:

#include <TaskMacro.h>
#include <Servo.h>
Servo servo1;

void setup() {
  
  Serial.begin(38400);     
  delay(500);
  servo1.attach(9);

}



void bewegung() {

if(Serial.available())
{
  if(Serial.read() == "1")
  {

 
 taskBegin();

 static int position;

  while(1){
  
  for(position = 20; position < 180; position += 2)   
  {
    servo1.write(position);  
    taskPause(20);               
  }

  
  for(position = 180; position >= 20; position -= 2)
  {                                
    servo1.write(position);  
    taskPause(20);     
   
  }
  }
  }
  taskEnd();
}


void count() {

  taskBegin();

  static int zahl = 0;

  while(1) {

    Serial.println(zahl);
    zahl++;
    taskPause(100);
  }
  taskEnd();
}

void loop() {

 bewegung();
 count();
}

Fehlermeldung:

In function 'void bewegung()':

sketch_aug04a:19: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]

   if(Serial.read() == "1")

                       ^

sketch_aug04a:48: error: a function-definition is not allowed here before '{' token

 void count() {

              ^

sketch_aug04a:67: error: expected '}' at end of input

 }

 ^


exit status 1
ISO C++ forbids comparison between pointer and integer [-fpermissive]

Der Fehler ist genau was da steht. Du kannst C Strings (d.h. Null-terminiere char Arrays) nicht mit == vergleichen. Und C Strings und Integer vergleichen geht erst recht nicht. Wir sind hier nicht in Visual Basic. C++ ist zwar nur schwach typisiert und macht einige implizierte Konvertierungen, aber du musst schon etwas auf die Datentypen achten. Da steht was von Zeigern weil Arrays in Zeiger auf das erste Element zerfallen.

Das willst du allerdings auch nicht. 1 als ein ASCII Zeichen ist '1' (ASCII Code 49 und ein Integer) und nicht "1"

Fehlt da nicht noch eine Klammer beim schließen. Ich zähl 5 die du öffnest, aber nur vier die du schließst.

void bewegung() {

...

Wo wird die While Schleife geschlossen ?

Richtig!

Am Besten ordentlich einrücken, dann sieht man auch was zusammen gehört.
Und nochmal: Statische Variablen gehören an den Anfang der Funktion.(und sei es nur für die Übersichtlichkeit

Und auch das taskEnd(); sollte an die richtige Stelle. Um diese zu finden hilft das Einrücken.

#include <TaskMacro.h>
#include <Servo.h>
Servo servo1;

void setup() {
  
  Serial.begin(38400);     
  delay(500);
  servo1.attach(9);

}



void bewegung() 
{
  static int position;

  if(Serial.available())
  {
    if(Serial.read() == '1')
    {
       taskBegin();
     
        while(1)
        {
        
            for(position = 20; position < 180; position += 2)   
            {
              servo1.write(position);  
              taskPause(20);               
            }
          
            
            for(position = 180; position >= 20; position -= 2)
            {                                
              servo1.write(position);  
              taskPause(20);     
             
            }
        } 
        taskEnd();   
    }
  }
 
}


void count() 
{
  static int zahl = 0;
  taskBegin();


  while(1) 
  {
    Serial.println(zahl);
    zahl++;
    taskPause(100);
  }
  taskEnd();
}

void loop() {

 bewegung();
 count();
}

)

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.

#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?

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.

//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.

funktioniert prima :slight_smile:

kann man es schachteln ? ( nicht unbedingt nötig, aber wenn schon, denn schon )

#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

Läuft Dein Testprogramm nicht?

Normalerweise schreibt man solche Aktionen hintereinander:

every(500) dies;
every(10000) das;

Bei meinem Testprogramm in der ALib0 loggen 3 Tasks etwas parallel, nach verschiedenen Verfahren und mit unterschiedlichen Intervallen.

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

Normalerweise schreibt man solche Aktionen hintereinander

Ja klar. War nur neugierig, was passiert, wenn man sowas machen würde.

Oder sowas:

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.

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.

#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);                       
}

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

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

Ist die Frage damit beantwortet?

Okay, Super das Du hier noch liest :))

Wie füge ich Code ein?

#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();
}

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