Mehrere Funktionen gleichzeitig ansteuern (Threads)?

Hi,

kann man auch 3 oder 4 Aktionen (Pins) gleichzeitig und unabhängig von einander ansteuern?

Ein Bekannter meinte was von "Threads", aber da diese Frage mit den darauffolgenden Antworten ebenfalls so bezeichnet wird, komme ich mit der Suche nciht weiter... :frowning:

Mikrocontroller (außer sie haben zwei Kerne) arbeiten ihr Programm von oben nach unten ab. Echt paralleles arbeiten ist nur mit FPGAs /CPLDs (werden in VHDL Programmiert / synthetisiert) oder Mehrkernprozessoren möglich.
Das Threading beschreibt ein Verfahren bei dem auch nicht "echt" parallel gearbeitet wird, sondern sehr schnell hintereinander. Wobei die einzelnen Threads über ein Scheduler gesteuert werden.
Im Prinzip wird jeder Funktion / jedem Programm ein Intervall zugewiesen. Vom Scheduler wird dann die Funktion in diesem Intervall aufgerufen, wobei auch überprüft wird ob eine andere Funktion eine wichtigere Priorität hat. Es kommt auch vor, dass die Ausgeführte Funktion unterbrochen wird um eine Wichtigere Funktion auszuführen.

Auf dem Arduino ist dies diese Struktur nur ansatzweise umsetzbar.

Es gibt mittlerweile ein Lib die eine ähnliche Funktionalität umsetzt:

simpleThreads for arduino

Beschreib doch mal, was Du vorhast. Dann kann man ev. Lösungswege vorschlagen.

Mehrere Pins können gleichzeitig angesteuert werden, wenn sie auf dem gleichen PORT liegen und Du den Port direkt ansteuerst (siehe Arduino Playground - PortManipulation ) Damit ändern sie gleichzeitig den Zustand und nicht hintereinander wie wenn Du sie mit zB mit 2 igitalWrite() änderst.Du kannst aber immer nur einen Sketch abarbeiten.
Grüße Uwe

Aquarium:
kann man auch 3 oder 4 Aktionen (Pins) gleichzeitig und unabhängig von einander ansteuern?

Völlig "gleichzeitig" geht nicht, also ein paar millionstel oder tausendstel Sekunden werden zwischen den Aktionen immer liegen. Bei grottenschlechter Programmierung auch Sekunden. Unabhängig voneinander ist allerdings kein Problem.

Das Prinzip ist, für jede der Aktionen in der Loop eine Funktion zu haben:

void loop()
{
unter_loop1();
unter_loop2();
unter_loop3();
unter_loop4();
}

Und jede der unter_loop Funktionen arbeitet für sich selbst hin, und zwar OHNE die Verwendung irgendwelcher delay Funktionen. Stattdessen müssen delays über die Auswertung von Timern oder millis oder Timer-Interrupts realisiert werden.

Bei längerdauernden Aktionen mußt Du mit Statusvariablen arbeiten. Beispiel Blinken: Du schaltest den Blinker an und ermittelst den Zeitpunkt, wann er wieder ausgehen soll. Dann wird die Loopfunktion zum Blinken zwischendurch hunderte, tausende oder millionen mal aufgerufen und nichts passiert, bis die Zeit zum Ausschalten da ist. Dann schaltet die Blinkfunktion aus und setzt wieder die neue Aktionszeit für den Start des nächsten Blinkvorgangs.

Bei anderen "länger dauernden" Aktionen entsprechend.

Funktionen, die "länger dauern" als Du es unter "gleichzeitig" verstehst, sind in dem Programm dann komplett verboten und dürfen nicht verwendet werden.

MaFu:
Beschreib doch mal, was Du vorhast. Dann kann man ev. Lösungswege vorschlagen.

Hi zusammen,

also ich möchte im ersten Schritt ein Aquarium ansteuern, und irgendwann ggf. sogar regeln....

Im ersten Schritt habe ich 2 Leuchtquellen und 4 Pumpen, die ich wie folgt starten will:

von 6.00 Uhr bis 6.30 Uhr läuft Leuchte 1
von 6.30 Uhr bis 18.00 Uhr läuft Leuchte 2
von 7.oo Uhr bis 17.00 Uhr läuft Leuchte 1 (zusätzlich)
von 18.00 Uhr bis 19.00 Uhr läuft Leuchte 1 (nochmal)

Zusätzlich soll im Rhythmus von 5 Stunden eine der 4 Pumpen über einen Zufallsgenerator starten.

Ich glaube, ich könnte auch die Millisekunden "counten" und dann mit "if-else" arbeiten und das permanent durchlaufen lassen...

Muß da wirklich was GLEICHZEITIG gesteuert werden? Genügt da nicht eine Genauigkeit von einigen Sekunden / Minuten?

Zur Steuerung der Lampen/Pumpen:

Nimm eine RTC, wandle die Zeit (stunden, minuten sekunden) in Sekunden und steuere damit das einschalten bzw asschalten der einzenlen Leuchten / Pumpen.

Grüße Uwe

Ach, auf eine Sekunde, oder 2 kommt es nciht an.

Ich dachte, dass ich, wenn ich den ersten Befehl einschalte, warten muss, bis ich wieder ausschalte...

Was ist RTC ?

RTC steht für Real Time Clock.

siehe hier:
http://playground.arduino.cc/Main/DS1302

Grüße,
J3RE

Aquarium:
Ach, auf eine Sekunde, oder 2 kommt es nciht an.

Ich dachte, dass ich, wenn ich den ersten Befehl einschalte, warten muss, bis ich wieder ausschalte...

Was ist RTC ?

Es kann nur eine Funktion in einem bestimmten Zeitpunkt ausgeführt werden, der "Zeitpunkt" ist aber sehr kurz.
zB

loop ()
{
  if (time >lampe1an1 && time < lampe1aus1&&statuslampe1==0;)
   {
   digitalWrite(lampe1,HIGH);
   statuslampe1=1;
   }
  if (time > lampe1aus1&&statuslampe1==1;)
   {
   digitalWrite(lampe1,LOW);
   statuslampe1=0;
   }
...
}

braucht zur Ausführung weniger als 1mS und schaltet die Lampe 1 zur Zeit lampe1an ein und zur Zeit lampe1aus aus. Es können viele solcher if- Bedingungen im loop() stehen.

Grüße Uwe

Hi,

@J3RE

Danke für den Link!

@Uwe,

so in etwa hatte ich das gedacht, mit dem "if"...

Aquarium:
so in etwa hatte ich das gedacht, mit dem "if"...

Ok, dann versuch mal Deinen Sketch zu schreiben. Wir sind bei Problemen hier zu finden. Grüße Uwe

Alles klar, danke.

ich habe gerade mal fix den Code getippt, so wie ich mit den vorstelle.

In das RTC mit den dazugehörigen Variablen und Formaten muss ich mir noch mal ansehen, aber im groben könnte es so aussehen:

//Lampe 1
  int lampe_1 = 13;         //Port im Arduino one
  //int lampe_dimmer_1 = 11;  //Port im Arduino one
  int lampe_an_1 = 0000;    //Startzeit
  int lampe_aus_1 = 0000;   //Endzeit
//Lampe 2
  int lampe_2 = 12;         //Port im Arduino one
  //int lampe_dimmer_2 = 10;  //Port im Arduino one
  int lampe_an_2 = 0000;    //Startzeit
  int lampe_aus_2 = 0000;   //Endzeit
// Motor 1
  int motor_1 = 2;          //Port im Arduino one
  int motor_an_1 = 0000;    //Startzeit
  int motor_aus_1 = 0000;   //Endzeit
// Motor 2
  int motor_2 = 4;          //Port im Arduino one
  int motor_an_2 = 0000;    //Startzeit
  int motor_aus_2 = 0000;   //Endzeit
// Motor 3
  int motor_3 = 7;          //Port im Arduino one
  int motor_an_3 = 0000;    //Startzeit
  int motor_aus_3 = 0000;   //Endzeit
// Motor 4
  int motor_4 = 8;          //Port im Arduino one
  int motor_an_4 = 0000;    //Startzeit
  int motor_aus_4 = 0000;   //Endzeit

//Status
int status_lampe_1 = "0";
int status_lampe_2 = "0";
int status_motor_1 = "0";
int status_motor_2 = "0";
int status_motor_3 = "0";
int status_motor_4 = "0";

void setup(){
  pinMode(lampe_1, OUTPUT); // Digitaler Pin als Ausgang
  pinMode(lampe_2, OUTPUT);
  pinMode(lampe_dimmer_2 , OUTPUT);
  pinMode(lampe_dimmer_2 , OUTPUT);
  pinMode(motor_1 , OUTPUT);
  pinMode(motor_2 , OUTPUT);
  pinMode(motor_3 , OUTPUT);
  pinMode(motor_4 , OUTPUT);
}


loop ()
{
  //Lampe 1
  if (time >lampe_an_1 && time < lampe_aus_1 && status_lampe_1==0;)
  // Wenn die Zeit größer ist, als in "lampe_an_1"
  // und
  // Wenn die Zeit kleiner ist, als in "lampe_aus_1"
  // und
  // Wenn der Status auf "0" (aus) steht
   {
   digitalWrite(lampe_1,HIGH);
   status_lampe_1=1;
   }
  if (time > lampe_aus_1 && status_lampe_1==1;)
   {
   digitalWrite(lampe_1,LOW);
   status_lampe_1=0;
   }
  //Lampe 2
  if (time >lampe_an_2 && time < lampe_aus_2 && status_lampe_2==0;)
   {
   digitalWrite(lampe_1,HIGH);
   status_lampe_2=1;
   }
  if (time > lampe_aus_2 && status_lampe_2==1;)
   {
   digitalWrite(lampe_1,LOW);
   status_lampe_2=0;
   }
   
   
   
  //Motor 0
  if (status_motor_1==0 && status_motor_2==0 && status_motor_3==0 && status_motor_4==0;)
   {
   int motor_0 = random(1, 20);
   // Nur Motor 1 läuft
   if (motor_0==1 || motor_0==2)
    {
    aktuelle_zeit = get(time);
    motor_an_1 = aktuelle_zeit;
    motor_aus_1 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 2 läuft 
   if (motor_0==3 || motor_0==4)
    {
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 3 läuft   
   if (motor_0==5 || motor_0==6)
    {
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 4 Läuft 
   if (motor_0==7 || motor_0==8)
    {
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 1+2 laufen 
   if (motor_0==9)
    {
    aktuelle_zeit = get(time);
    motor_an_1 = aktuelle_zeit;
    motor_aus_1 = aktuelle_zeit + /*5 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 1+3 laufen 
   if (motor_0==10)
    {
    aktuelle_zeit = get(time);
    motor_an_1 = aktuelle_zeit;
    motor_aus_1 = aktuelle_zeit + /*5 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 1+4 laufen 
   if (motor_0==11)
    {
    aktuelle_zeit = get(time);
    motor_an_1 = aktuelle_zeit;
    motor_aus_1 = aktuelle_zeit + /*5 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*5 Stunden*/;
    }    
   // Nur Motor 2+3 laufen 
   if (motor_0==12)
    {
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*5 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 2+4 laufen 
   if (motor_0==13)
    {
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*5 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 3+4 laufen 
   if (motor_0==14)
    {
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*5 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*5 Stunden*/;
    }
   // Nur Motor 1+2+3 laufen 
   if (motor_0==15)
    {
    aktuelle_zeit = get(time);
    motor_an_1 = aktuelle_zeit;
    motor_aus_1 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*2 Stunden*/;
    }
   // Nur Motor 1+2+4 laufen 
   if (motor_0==16)
    {
    aktuelle_zeit = get(time);
    motor_an_1 = aktuelle_zeit;
    motor_aus_1 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*2 Stunden*/;
    }
   // Nur Motor 1+3+4 laufen 
   if (motor_0==17)
    {
    aktuelle_zeit = get(time);
    motor_an_1 = aktuelle_zeit;
    motor_aus_1 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*2 Stunden*/;
    }
   // Nur Motor 2+3+4 laufen 
   if (motor_0==8)
    {
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*2 Stunden*/;
    }
   // Alle Motoren laufen
   if (motor_0==19)
    {
    aktuelle_zeit = get(time);
    motor_an_1 = aktuelle_zeit;
    motor_aus_1 = aktuelle_zeit + /*1 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*1 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*1 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*1 Stunden*/;
    }
   }
   
   
  //Motor 1
  if (time >motor_an_1 && time < motor_aus_1 && status_motor_1==0;)
   {
   digitalWrite(motor_1,HIGH);
   status_motor_1=1;
   }
  if (time > motor_aus_1 && status_motor_1==1;)
   {
   digitalWrite(motor_1,LOW);
   status_motor_2=0;
   }  
  //Motor 2  
  if (time >motor_an_2 && time < motor_aus_2 && status_motor_2==0;)
   {
   digitalWrite(motor_2,HIGH);
   status_motor_2=1;
   }
  if (time > motor_aus_2 && status_motor_2==1;)
   {
   digitalWrite(motor_2,LOW);
   status_motor_2=0;
   }  
  //Motor 3  
  if (time >motor_an_3 && time < motor_aus_3 && status_motor_3==0;)
   {
   digitalWrite(motor_3,HIGH);
   status_motor_3=1;
   }
  if (time > motor_aus_3 && status_motor_3==1;)
   {
   digitalWrite(motor_3,LOW);
   status_motor_3=0;
   }  
  //Motor 4
  if (time >motor_an_4 && time < motor_aus_4 && status_motor_4==0;)
   {
   digitalWrite(motor_4,HIGH);
   status_motor_4=1;
   }
  if (time > motor_aus_4 && status_motor_4==1;)
   {
   digitalWrite(motor_4,LOW);
   status_motor_4=0;
   }    
}

Bei der Variante "Motor 0", in der die Zufallszahlen ermittelt werden habe ich überlegt, ob ich das nach den Antrieben oder nach den Antriebskonstellationen anordne, ich habe mich für letzteres entschieden, da ich so individuell die Dauer beeinflussen kann, wenn mehrere Antriebe geschaltet werden.

Was meint ihr zum Code? :slight_smile:

// Nur Motor 2+3+4 laufen 
   if (motor_0==8)
    {
    aktuelle_zeit = get(time);
    motor_an_2 = aktuelle_zeit;
    motor_aus_2 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_3 = aktuelle_zeit;
    motor_aus_3 = aktuelle_zeit + /*2 Stunden*/;
    aktuelle_zeit = get(time);
    motor_an_4 = aktuelle_zeit;
    motor_aus_4 = aktuelle_zeit + /*2 Stunden*/;
    }

Bei der if-Abfrage hast du dich vertippt, hier sollte 18 statt 8 stehen.
Die aktuelle Zeit brauchst du auch nur einmal pro Programmdurchlauf abfragen, so ein Durchlauf dauert nur einen Bruchteil einer Sekunde.

//Motor 1
  if (time >motor_an_1 && time < motor_aus_1 && status_motor_1==0;)
   {
   digitalWrite(motor_1,HIGH);
   status_motor_1=1;
   }
  if (time > motor_aus_1 && status_motor_1==1;)
   {
   digitalWrite(motor_1,LOW);
   status_motor_2=0;
   }

Hier setzt du den falschen Status zurück, hier sollte status_motor_1 zurückgesetzt werden.

Ansonsten ist mir nichts aufgefallen.

Grüße,
J3RE

Hallo,

das Thema ist schon ein bisschen älter, aber ich hatte damals keine Zeit, es weiter vorran zu treiben. :blush:

Ich hatte mit damals den DS1302 geholt, und das dort angegebene Script ausprobiert. Es scheint soweit zu funktionieren.

In den dortigen void loop integriere ich meine Zeilen, aus meinen void loop, das selbe beim void setup.
Allerdings komme ich nicht an die Uhrzeit ran.

Soweit ich den Code verstehe, definiere ich eine Start-Zeit:

  // Example for april 15, 2013, 10:08, monday is 2nd day of Week.
  // Set your own time and date in these variables.
  seconds    = 0;
  minutes    = 8;
  hours      = 10;
  dayofweek  = 2;  // Day of week, any day can be first, counts 1...7
  dayofmonth = 15; // Day of month, 1...31
  month      = 4;  // month 1...12
  year       = 2013;

Das sollten dann doch auch die Variablen sein, die im im Code abfrage, oder?

Das sind die Variablen, die du nur einmal brauchst um die Uhr erstmalig zu stellen und zu starten.
Danach ( bis du sowohl Arduino aus und Batterie entfernt hast ), kannst du dies überspringen durch Ändern etwas weiter oben:

// Remove the next define, 
// after the right date and time are set.
// #define SET_DATE_TIME_JUST_ONCE
#ifdef SET_DATE_TIME_JUST_ONCE  

// alles folgende wird nicht mitkompiliert bis
// ...
#endif

Was nun genau dein Problem ist, habe ich aber nicht verstanden

...das dort angegebene Script ausprobiert. Es scheint soweit zu funktionieren.

Das heisst, die Uhr läuft jetzt, oder ?

Wenn die Frage nichts mehr mit dem ursprünglichen Thema "Mehrere Funktionen gleichzeitig ansteuern (Threads)?" zu tun hat, kann man auch gern was Neues anfangen :wink:

michael_x:
Was nun genau dein Problem ist, habe ich aber nicht verstanden

...das dort angegebene Script ausprobiert. Es scheint soweit zu funktionieren.

Das heisst, die Uhr läuft jetzt, oder ?

Also das Script scheint zu funktionieren, denn beim compilieren kommt kein Fehler, und das letzte Programm wurde überschrieben.
Ich habe jedoch keine Ausgabe-Möglichkeit. Also kein LCD oder sowas...

Ich wollte in den Standard-Code eigentlich eine If-Abfrage rein haben, zum testen, in etwa so, wenn jetzt September ist, dann soll die LED auf Pin 13 blinken.
in etwas so:

if (month ==4)
   {.....

bloß ich bekommen die Variable "month" nicht.....

Ich habe jedoch keine Ausgabe-Möglichkeit.

Was spricht gegen Serial ???

Im Playground - Beispiel ist z.B. in loop()

void loop()
{
   ds1302_struct rtc;
   char buffer[80];     // the code uses 70 characters.

   // Read all clock data at once (burst mode).
   DS1302_clock_burst_read( (uint8_t *) &rtc);

   sprintf( buffer, "Time = %02d:%02d:%02d, ", \
     bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
     bcd2bin( rtc.Minutes10, rtc.Minutes), \
     bcd2bin( rtc.Seconds10, rtc.Seconds));
   Serial.print(buffer);
...
delay (5000);
}

Also sollte alle 5 Sek eine Ausgabe der aktuellen Uhrzeit zu sehen sein.
Und deinen Monat kriegst du so

int month = bcd2bin( rtc.Month10, rtc.Month);
Serial.print("Monat = "); Serial.println(month);

Gegen seriell spricht, dass der alles resettet.

klemme ich die Arduino ab, und stecke ihn wieder dran, fängt der von neuem an zu zählen. Selbst mit einem externen Netzteil, was sogar meine Relais weiter laufen lässt, fängt der beim anklemmen neu an. Ich kann so gar nicht überprüfen, ob die Batterie funktioniert. :~

Gegen seriell spricht, dass der alles resettet.

Das lässt sich vermeiden.
In der Arduino IDE ist es halt wichtiger, dass der Upload eines neuen Sketch super easy geht.

Aber "Bitte kein Reset beim Start des SerialMonitor" ist ein schon oft gelöstes Problem.