Ausgang Schalten nach Signal

Hallo, ich bin neu hier und habe dazu noch nichts brauchbares gefunden. Folgendes Problem: Ich möchte mit meinem Arduino gerne 2 Ausgänge steuern. Der erste Ausgang soll für 1500ms schalten. Wenn der „Master“ ein Signal abgibt.
Der „Master“ bleibt jedoch eine länger Zeit aktiv. Erst wenn der Master wieder Ausgeht soll der zweite Ausgang Aktiv werden für 1500ms. Dies funktioniert im Moment relativ Semi-Optimal. Bei Ausgänge schalten ab und zu.

Ich stell euch mal meinen Code zur Verfügung. Vllt kann mir ja jemand neue Denkansätze liefern.

int Master = 5;
int Auf = 9;
int Zu = 8;

int merker = 0;

void setup(){

pinMode(Master, INPUT);
pinMode(Auf, OUTPUT);
pinMode(Zu, OUTPUT);

}

void loop(){

if(digitalRead(Master)==1 && merker==0){

merker++;

digitalWrite(Auf, 1);
delay(1500);
digitalWrite(Auf, 0);
}else if(digitalRead(Master)==0 && merker==1){

merker—;

digitalWrite(Zu, 1);
delay(1500);
digitalWrite(Zu, 0);
}

#undef MyHW
#ifdef MyHW
const int pinSig    = A1;
const int pinAuf    = 10;
const int pinZu     = 11;

#else
const int pinSig = 5;
const int pinAuf    = 9;
const int pinZu     = 8;
#endif

unsigned long msecAuf;
unsigned long msecZu;

enum { OutOff = HIGH, OutOn = LOW };
enum { SigOff = HIGH, SigOn = LOW };

byte sigLst;

#define AufOn   1500
#define ZuOn    1500

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();

    byte sig = digitalRead (pinSig);

    if (sigLst != sig)  {
        sigLst = sig;
        delay (20);         // debounce

        if (SigOn == sig)  {
            digitalWrite (pinAuf, OutOn);
            msecAuf = msec;
        }

        if (SigOff == sig)  {
            digitalWrite (pinZu,  OutOn);
            msecZu  = msec;
        }
    }

    if (OutOn == digitalRead (pinAuf) && (msec - msecAuf) > AufOn)
        digitalWrite (pinAuf,  OutOff);

    if (OutOn == digitalRead (pinZu) && (msec - msecZu) > ZuOn)
        digitalWrite (pinZu,  OutOff);
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    pinMode (pinSig, INPUT);
    sigLst = digitalRead (pinSig);

    digitalWrite (pinAuf, OutOff);
    pinMode (pinAuf, OUTPUT);
    digitalWrite (pinZu,  OutOff);
    pinMode (pinZu,  OUTPUT);
}

Hallo
Ich denke der Sketch benötigt drei Timer.
Einen zum Scannen des Masters und und die anderen zum Schalten der zwei LEDs.

Das hängt davon ab, was im nicht beschriebenen Fall passieren soll:
Wenn das Master-Signal vor Ablauf der 1,5 s seinen Zustand wechselt.

Angenommen, es soll nichts passieren, die geschaltete LED bleibt auf jeden Fall an.
Wenn erst nach Ablauf der LED-Zeit wieder das Master-Signal überwacht wird, passiert dann entweder erstmal nichts, oder die andere LED startet sofort ihre 1,5 s Phase.

In diesem Fall braucht man gar keine Timer, sondern kann mit delay und einem Merker arbeiten.
Und hat auch keine Sorgen mit prellendem Taster.

Mit den richtigen Datentypen ist diese Aufgabenstellung sehr einfach:

const byte Master = 5;  // Eingangssignal-Pin
const byte Auf = 9;   // Led an, wenn Master 0->1
const byte Zu = 8;   // Led an, wenn Master 1->0

bool merker = false;  // gemerkter Zustand von Master 

void setup() {
   pinMode(Master, INPUT);
   pinMode(Auf, OUTPUT);
   pinMode(Zu, OUTPUT);
}

void loop() {
    if(digitalRead(Master) != merker) {  // Änderung
       if ( ! merker) {
          // 0 -> 1
          merker=true;
          digitalWrite(Auf, 1);
          delay(1500);
          digitalWrite(Auf, 0);
       } else {
          // 1 -> 0
          merker=false;
          digitalWrite(Zu, 1);
          delay(1500);
          digitalWrite(Zu, 0);
       }
   }  // End if Änderung
}  // End loop

Auch angenommen, vor dem Start wird von Master == 0 ausgegangen.
Nach Ablauf der 1,5 s wird sofort auf einen eventuellen Wechsel des Eingangssignals reagiert.

In dem von mir geposteten Code reagieren die LEDs einfach auf das Master-Signal. Wenn das Signal schnell pulsiert, leuchten beide LEDs gleichzeitig

Der compiliert nicht.
Und nein es liegt nicht an der fehlenden Klammer am Ende.

Wozu?
Der Sketch braucht nur eine StateMachine.

Das Ding ist wohl ein Aktor. Der soll für genau 1500ms arbeiten - so zumindest habe ich das rausgelesen. Egal wie lange das "Startsignal" anliegt. Und wenn das Signal weg ist, soll nach frühestens 1500ms der andere Pin auslösen.

Eine schöne Schrittkette.

Ungetestet - und nur so reingeschrieben. kompiliert aber.

const unsigned int Master = 5;
const unsigned int Auf = 9;
const unsigned int Zu = 8;

unsigned int schritt = 0;
unsigned long lastmillis = 0;
bool merker=false;
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(Master, INPUT);
  pinMode(Auf, OUTPUT);
  pinMode(Zu, OUTPUT);
}

void loop()
{
  switch (schritt)
  {
    case 0:
      if (digitalRead(Master))
      {
        Serial.println(F("Mache auf!"));
        merker = true;
        lastmillis = millis();
        digitalWrite(Auf, true);
        schritt++;
      }
      break;
    case 1:
      if (millis() - lastmillis > 1500)
      {
        Serial.println(F("Zeit abgelaufen - mache zu!"));
        digitalWrite(Auf, 0);
        schritt++;
      }
      break;
    case 2:
      if (!merker)
      {
        Serial.println(F("Mache zu!"));
        lastmillis = millis();
        digitalWrite(Zu, 1);
        schritt++;
      }
      break;
    case 3:
      if (millis() - lastmillis > 1500)
      {
        Serial.println(F("Ende Zu machen - Ende Statemachine"));
        digitalWrite(Zu, 0);
        schritt = 0;
      }
      break;
  }
  if (merker && !digitalRead(Master))
  {
    Serial.println(F("Master ist abgeschaltet"));
    merker = false;
  }
}

Hallo
Ich füge dem Zoo von Lösungen auch die Lösung mit drei Timern hinzu. So kann der Fragesteller sich die beste und passende Lösung für sein Projekt aussuchen. :nerd_face:

//BLOCK COMMENT
// https://forum.arduino.cc/t/ausgang-schalten-nach-signal/899726
#define ProjectName "Ausgang Schalten nach Signal"
// CONSTANT DEFINITION
// you may need to change these constants to your hardware
const byte Input_[] {A0};
const byte Output_[] {2, 3};
// VARIABLE DECLARATION
enum {Master};
enum {Auf,Zu};
struct MASTER {
  byte pin;
  bool state;
} master {Input_[Master], 0};
struct AUSGANG {
  byte pin;
} ausgang[] {
  {Output_[Auf]},
  {Output_[Zu]},
};
struct TIMER {
  unsigned long stamp;
  unsigned long duration;
};
TIMER scan {0, 20};
TIMER auf {0, 1500};
TIMER zu {0, 1500};

// FUNCTIONS

void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);
  for (auto Input : Input_) pinMode(Input, INPUT_PULLUP);
  for (auto Output : Output_) pinMode(Output, OUTPUT);
  // check outputs
  for (auto Output : Output_) digitalWrite(Output, HIGH);
  delay(1000);
  for (auto Output : Output_) digitalWrite(Output, LOW);
}
void loop () {
  unsigned long currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  if (currentTime - scan.stamp >= scan.duration) {
    scan.stamp = currentTime;
    bool stateNew = !digitalRead(master.pin);
    if (master.state != stateNew) {
      master.state = stateNew;
      switch (stateNew) {
        case Auf:
          auf.stamp = currentTime;
          digitalWrite(ausgang[Auf].pin, HIGH);
          break;
        case Zu:
          zu.stamp = currentTime;
          digitalWrite(ausgang[Zu].pin, HIGH);
          break;
      }
    }
  }
  if (currentTime - auf.stamp >= auf.duration && digitalRead(ausgang[Auf].pin)) digitalWrite(ausgang[Auf].pin, LOW);
  if (currentTime - zu.stamp >= zu.duration && digitalRead(ausgang[Zu].pin)) digitalWrite(ausgang[Zu].pin, LOW);
}

Ich wünsche einen geschmeidigen Abend und viel Spass beim Programmieren.

"Niiemand hat die Absicht einen Timer zu errichten."
oder doch?

weil ich heute grad an einem gebastelt hab, etwas vergenusswurzelt...

/*
  Timer with limit

  A timer can have a limit, to stop the timer after n iterations
  and you can assign callback function for the start and for the end

  by noiasca
*/

class LittleTimer {
  protected:
    byte state = 0;                // 0 off; 1 on; 2 paused (rfu)
    uint32_t previousMillis = 0;
    using CallBack = void (*)(void);
    CallBack cbOnStart, cbOnInterval, cbOnStop;
    uint32_t interval = 1000;      // interval in ms
    uint32_t limit = 0;            // 0 = infinte (no limit)
    uint32_t iteration = 0;        // counts the current loops

  public:
    LittleTimer(CallBack cbOnInterval, uint32_t interval, uint32_t limit = 0) :
      cbOnInterval (cbOnInterval), interval {interval}, limit{limit}
    {}

    byte getState() {
      return state;
    }
    
    void start() {
      if (state != 1)
      {
        state = 1;
        previousMillis = millis();
        if (cbOnStart) cbOnStart();
      }
    }

    void stop() {     
      if (state != 0) 
      {
        state = 0;
        if (cbOnStop) cbOnStop();
      }
    }
    
    void attachOnStart(const CallBack cbOnStart)
    {
      (*this).cbOnStart = cbOnStart;
    }

    void attachOnStop(const CallBack cbOnStop)
    {
      (*this).cbOnStop = cbOnStop;
    }

    void setLimit(uint32_t newLimit)
    {
      limit = newLimit;
    }

    void setIteration(uint32_t newIteration)
    {
      iteration = newIteration;
    }

    uint32_t getIteration()
    {
      return iteration;
    }

    void update() {
      if (state)
      {
        uint32_t currentMillis = millis();
        if (currentMillis - previousMillis >= interval)
        {
          iteration++;
          previousMillis = currentMillis; 
          if (limit == 0 || (limit > 0 && limit > iteration))  // running endless or limit not reached
          {
            if (cbOnInterval) cbOnInterval();
          }
          else                                                  // if there is a defined CB for the end, call it otherwise call the cb for interval the last time
          {
            if (cbOnStop) cbOnStop(); else if (cbOnInterval) cbOnInterval();
            state = 0;      // stop the FSM 
            iteration = 0;  // reset iteration for next run
          }
        }
      }
    }
};

const byte inputPin = A0;    // 5 Eingangssignal-Pin  5
const byte openPin = 9;      // 9 Led an, wenn Master 0->1
const byte closePin = 8;     // 8 Led an, wenn Master 1->0

void cbOpenOn() {
  Serial.println(F("open on"));
  digitalWrite(openPin, HIGH);
  digitalWrite(closePin, LOW);
}

void cbOpenOff() {
  Serial.println(F("open off"));
  digitalWrite(openPin, LOW);
}

void cbCloseOn() {
  Serial.println(F("close on"));
  digitalWrite(openPin, LOW);
  digitalWrite(closePin, HIGH);
}

void cbCloseOff() {
  Serial.println(F("close off"));
  digitalWrite(closePin, LOW);
}

//                    callback  interval  limit
LittleTimer openTimer {cbOpenOff,  1500,   1};
LittleTimer closeTimer{cbCloseOff, 1500,   1};

void cbReadButton()
{
  static byte previousState = 0;
  byte currentState = digitalRead(inputPin);
  if (currentState != previousState)
  {
    Serial.println(F("state change"));
    if (currentState == HIGH)
      openTimer.start();
    else
      closeTimer.start();
    previousState = currentState;
  }
}
LittleTimer inputTimer{cbReadButton, 20}; // for debounce


void setup() {
  Serial.begin(115200);
  Serial.println(F("\nStart"));
  pinMode(inputPin, INPUT);      // getestet mit INPUT_PULLUP
  pinMode(openPin, OUTPUT);
  pinMode(closePin, OUTPUT);
  openTimer.attachOnStart(cbOpenOn);
  closeTimer.attachOnStart(cbCloseOn);
  inputTimer.start();
}

void loop() {
  // you must call the update() method for each object:
  openTimer.update();
  closeTimer.update();
  inputTimer.update();
}

(edit: das debounce auch noch vertimert...)

1 Like