Realisierung multithread mit uno

Hallo zusammen,

habe mich soeben neu registriert weil ich sehe das hier nicht nur viele kluge sondern auch motivierte und hilfsbereite Leute sind.
Ich bin grade dabei mich mit so einem funduino Set an microcontroller ranzutasten.

Ich möchte gerne folgendes realisieren:

Ultraschall misst durchgehend Entfernung.
Entfernung <=16 & & >=6cm

bool END = false
LED1 fängt an zu blinken(so lange END ==false)

Entfernung <=6

Piezo speaker piept in kurzen Intervallen. (so lange servomotorEndPosition ==false)
LED2 und LED3 blinken abwechselnd (so lange servomotorEndPosition== false)
Servomotor bewegt sich in bspw. 2er Schritten 90° (servomotorEndPosition
wird dann =true)

Entfernung >16 && END==false

Piezo speaker piept in kurzen Intervallen. (so lange END ==false)
LED2 und LED3 blinken abwechselnd (so lange End== false)
Servomotor bewegt sich in bspw. 2er Schritten 90° zurück (servomotorEndPosition
wird dann =false)
Wenn Servomotor wieder auf 0° -> END=true.

Entschuldigt bitte diesen amateur-pseudocode und dass ich zum Teil Bedingungen doppelt geschrieben habe, es soll primär nur dazu dienen zu verstehen was mein Vorhaben ist.
Das Problem ist dass ein paralleles ansteuern der Pins nicht möglich ist.
Meine Frage ist also, ob es eine Möglichkeit gibt, es wenigstens so zu programmieren, dass ich nicht jede einzelne Aktivität des Controllers einzeln schreiben muss, damit es wenigstens so aussieht als würde es parallel laufen.

Ich habe mir praktisches und theoretisches Grundlagen wissen anhand c++ angeeignet, habt dennoch bitte Geduld und Verständnis wenn ich für euch selbsterklärende Sachen auf Anhieb nicht verstehe.

Besten Dank im Voraus!

vereinfacht gesagt, gibt es im Uno kein "Parallel".
Nur "so schnell hintereinander", dass es dir so fast so erscheint, dass es "fast" gleichzeitig ist.

Zerlege dein Programm in kleine Funktionen, alle OHNE Delay ("nicht blockierend"), alles nach Muster "BlinkWithoutDelay" dann kannst du nach und nach dein Programm zusammenfügen.

Warum multithreading when multitasking auch reicht?

Schau mal nach Combie's TaskMakros, wie man so quasi-parallele Abläufe ganz einfach implementieren kann.

Das Problem ist dass ein paralleles ansteuern der Pins nicht möglich ist.

Falsch. Das ist kein Problem. Erstens wäre es theoretisch möglich, zweitens ist das überhaupt nicht erforderlich.
Multithreading wäre eventuell sinnvoll, wenn ein Prozessor viele voneinander unabhängige Sachen gleichzeitig erledigen soll, und du die Aufgaben auf mehrere Programmierer verteilen willst, die nichts miteinander zu tun haben wollen.

Eventuell kannst du TaskMakros einsetzen, das schon. Vermutlich wird dir das aber nicht viel helfen, da doch (nach meinem groben Überfliegen deiner Aufgabenbeschreibung) vieles miteinander verknüpft ist.
Mach dir lieber Gedanken über Zustandsvariable, die dir helfen, die Abhängigkeiten einfach zu halten.

Damit du eine LED blinken siehst, muss ein Microcontroller sehr viel Zeit vertrödeln, in der alles mögliche gleichzeitig gemacht werden kann. Auch wenn ein Servo sich langsam bewegen soll, bedeutet das, dass der Microcontroller sehr viel Langeweile hat und gleichzeitig vieles andere erledigen kann.

Das kritischste wäre ein Piezo, der Töne dadurch erzeugt, dass er z.B. tausendmal pro Sekunde ein und wieder ausgeschaltet werden muss, um einen 1000 Hz Ton zu erzeugen. Wenn du einen Piepser im Sinn hast, der beim Einschalten seinen einen Ton von sich gibt, ist auch diese (lösbare) Herausforderung entfallen.

Vermutlich kannst du sogar die Aufgabe "Ultraschall misst durchgehend Entfernung" auf primitive Weise erledigen (beim Warten auf das Echo macht dann der Arduino tatsächlich nichts anderes gleichzeitig). Das Wort "durchgehend" ist natürlich realistisch zu interpretieren, egal wie viele Threads du erfinden willst. ( Wie schnell ändert sich denn diese Entfernung ? )

Wenn loop() nicht "den Programmablauf" beschreibt, sondern nur für jeden Moment feststellt, ob überhaupt etwas zu tun ist und dafür (fast) keine Zeit braucht, ist deine Grundforderung nach multithreading (oder auch multitasking) trivial: Schreib alles was gleichzeitig geprüft und gemacht werden soll, in beliebiger Reihenfolge auf. (Die Reihenfolge dient nur der Übersichtlichkeit)

Was bisher eigentlich fehlt in deiner Beschreibung, ist der Grundzustand (END = true) :
Bedingungen:
Entfernung > 16 cm
Servo in Stellung 0
-> Piepser AUS, alle LED AUS
(richtig?)

Ob noch andere Zustände möglich sind, die nicht beschrieben sind, wäre zu prüfen.

Das Problem ist dass ein paralleles ansteuern der Pins nicht möglich ist.

Ich sehe nicht, dass das bei dir nötig ist.

Ablaufsteuerung
Meine Standardantwort zu Ablaufsteuerungen:

Eine Stichworte Sammlung für Google Suchen:
Endlicher Automat,
ProtoThreads,
State Machine,
Multitasking,
Coroutinen,
Ablaufsteuerung,
Schrittkette,
BlinkWithoutDelay,

Automat (Informatik)
Blink Without Delay
Die Nachtwächter Erklärung

MicroBahner/MobaTools
Intervall Macro
Multitasking Macros
INTERVAL Ersatzstoff
CooperativeTask

hab jetzt keinen Ultraschall-Sensor hier, aber es kompiliert

/*
  by noiasca
  https://forum.arduino.cc/index.php?topic=696079.msg4679349#new
*/

#include <NewPing.h>
const byte triggerPin = 12;    // Arduino pin tied to trigger pin on the ultrasonic sensor.
const byte echoPin = 11;       // Arduino pin tied to echo pin on the ultrasonic sensor.
const byte maxDistance = 50 ;  // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(triggerPin, echoPin, maxDistance); // NewPing setup of pins and maximum distance.

#include <Servo.h>
Servo myservo;  // create servo object to control a servo
const byte servoPin = 9;

class BlinkLed {
  protected:
    uint16_t on = 500;                 // Intervall to blink the led
    const byte ledAPin;                // a GPIO for the LED
    unsigned long previousMillis;      // last blink timestamp
    bool ledState = LOW;
    bool state = false;                // on/off
  public:
    BlinkLed(byte ledAPin):
      ledAPin(ledAPin)
    {}

    void begin() {
      pinMode(ledAPin, OUTPUT);         // as we have to set the pinMode for, we will call this method once in setup() section
    }
    void setOn()
    {
      state = true;
    }
    void setOff()
    {
      state = false;
      digitalWrite(ledAPin, LOW);
    }

    void tick() {
      uint32_t currentMillis = millis();
      if (state && currentMillis - previousMillis >= on) {
        // save the last time you blinked the LED
        previousMillis = currentMillis;
        ledState = !ledState;
        digitalWrite(ledAPin, ledState);
      }
    }
};
BlinkLed blinkLed(4);

class BlinkDouble: public BlinkLed {   // inherited class
  protected:
    const byte ledBPin;                // a second GPIO for the second LED

  public:
    BlinkDouble(byte ledAPin, byte ledBPin):
      BlinkLed(ledAPin),
      ledBPin(ledBPin)
    {
      on = 300;
    }

    void begin() {
      pinMode(ledAPin, OUTPUT);         // as we have to set the pinMode for, we will call this method once in setup() section
      pinMode(ledBPin, OUTPUT);
    }
    void setOff()
    {
      state = false;
      digitalWrite(ledAPin, LOW);
      digitalWrite(ledBPin, LOW);
    }

    void tick() {
      uint32_t currentMillis = millis();
      if (state && currentMillis - previousMillis >= on) {
        // save the last time you blinked the LED
        previousMillis = currentMillis;
        ledState = !ledState;
        digitalWrite(ledAPin, ledState);
        digitalWrite(ledBPin, !ledState);
      }
    }
};

BlinkDouble blinkDouble(2, 3);

void setup() {
  Serial.begin(115200);
  blinkLed.begin();
  blinkDouble.begin();
  myservo.attach(servoPin);

  //blinkLed.setOn();    // only to test the hardware
  //blinkDouble.setOn();
}

void loop() {
  // Abstand messen
  byte distance = sonar.ping_cm();
  Serial.print(distance);
  Serial.println(F("cm"));

  // act according distance:
  switch (distance)
  {
    case 0 :                 // keine gültige Messung
      break;
    case 1 ... 5:
      blinkLed.setOff();
      blinkDouble.setOn();
      myservo.write(90);
      break;
    case 6 ... 16:
      blinkLed.setOn();
      blinkDouble.setOff();
      myservo.write(0);
      break;
    default:                 // größer 16
      blinkLed.setOff();
      blinkDouble.setOff();
      myservo.write(0);
  }
  // give each object some time
  blinkLed.tick();
  blinkDouble.tick();
}

Die Servos sind noch hart 90/0 aber das kann man ja auch in ein entsprechendes Objekt packen in dem man ein Ziel vorgibt und dann den Servo halt "langsam" sein Ding machen lässt. Vermutlich gibts das in den Mobatools eh auch schon fertig.

Sollte ja nur in etwa eine Idee geben, wie man Sachen/Geblinke so nebenbei laufenlassen kann.

gogly:
Meine Frage ist also, ob es eine Möglichkeit gibt, es wenigstens so zu programmieren, dass ich nicht jede einzelne Aktivität des Controllers einzeln schreiben muss, damit es wenigstens so aussieht als würde es parallel laufen.

Ja, das kann man. Das Stichwort lautet „Endlicher Automat“. Guck hier im Forum nach der Nachtwächter-Erklärung oder auch hier.

Gruß

Gregor

(deleted)