StateChangeDetection und weitere Knöpfe

Hallo zusammen

Ich habe vor eine Steuerung mit einem Klatschschalter und weiteren Knöpfen zu realisieren. Nun stehe ich vor der Herausforderung das Klatschschalter Skript mit einem Button Switch Skript zu kombinieren.

Also konkret möchte ich einen Knopf haben mit welchem ich das Licht ein und ausschalten kann. Ebenfalls möchte ich das Licht per Klatschschalter ein und ausschalten können. Diese beiden Funktionen als einzelnes funktionieren sehr gut. Die Kombination stellt mich vor eine Hürde.

Wie kann ich die Klatschschalter Abfrage mit einem "normalen" Button Skript kombinieren dass wenn der Knopf gedrückt wird oder (zweimal) geklatscht wird das Licht an- respektive aus geht?

Für den Klatschschalter verwende ich das folgende Skript:

int soundSensor = 3;
int relay = 4;
int claps = 0;
long detectionSpanInitial = 0;
long detectionSpan = 0;
boolean lightState = false;
 
void setup() {
  pinMode(soundSensor, INPUT);
  pinMode(relay, OUTPUT);
}
 
void loop() {
 
  int sensorState = digitalRead(soundSensor);
 
  if (sensorState == 0)
  {
    if (claps == 0)
    {
      detectionSpanInitial = detectionSpan = millis();
      claps++;
    }
    else if (claps > 0 && millis()-detectionSpan >= 50)
    {
      detectionSpan = millis();
      claps++;
    }
  }
 
  if (millis()-detectionSpanInitial >= 400)
  {
    if (claps == 2)
    {
      if (!lightState)
        {
          lightState = true;
          digitalWrite(relay, HIGH);
        }
        else if (lightState)
        {
          lightState = false;
          digitalWrite(relay, LOW);
        }
    }
    claps = 0;
  }
}

Für den Button ist es ein einfaches digitalRead(buttonPin):

void loop() {
   // read the state of the pushbutton value:
   buttonState = digitalRead(buttonPin);

   // check if the pushbutton is pressed.
   // if it is, the buttonState is HIGH:
   if (buttonState == HIGH) {
     // turn LED on:
     digitalWrite(ledPin, HIGH);
   } else {
     // turn LED off:
     digitalWrite(ledPin, LOW);
   }
}

Vielen Dank für eure Hilfe

Da hast Du mehrere Varianten. Die Einfachste dürfte sein, Du nimmst aus deinen beiden loop() alle digitalWrite raus und nennst die eine in klatsch() und die andere in schalter() um.

Damit hast Du 2 Funktionen, die Du in einem neuen loop mit der Lichtsteuerung zusammen fasst.
z.B. so (ungetestet):

void loop() {
  klatsch();
  schalter();
  if (lightState) digitalWrite(ledPin, HIGH);
  else digitalWrite(ledPin, LOW);
}

Gruß Tommy

[code]
int soundSensor = 3;
int relay = 4;
int claps = 0;
long detectionSpanInitial = 0;
long detectionSpan = 0;
boolean lightState = false;
 
void setup() {
  pinMode(soundSensor, INPUT);
  pinMode(relay, OUTPUT);
}
 
void loop() {
 
  int sensorState = digitalRead(soundSensor);
      buttonState = digitalRead(buttonPin);
      
  if (sensorState == 0)
  {
    if (claps == 0)
    {
      detectionSpanInitial = detectionSpan = millis();
      claps++;
    }
    else if (claps > 0 && millis()-detectionSpan >= 50)
    {
      detectionSpan = millis();
      claps++;
    }
  }
 
  if (millis()-detectionSpanInitial >= 400)
  {
    if (claps == 2)
    {
      if (!lightState) || (buttonState == HIGH)
        {
          lightState = true;
          digitalWrite(relay, HIGH);
        }
        else 
          lightState = false;
          digitalWrite(relay, LOW);
    
    }
    claps = 0;
  }
}

[/code]

if (lightState) digitalWrite(ledPin, HIGH);
~~ else digitalWrite(ledPin, LOW);~~

 digitalWrite(ledPin,lightState);

Also boolean true / false wird problemlos in HIGH / LOW gewandelt? Wußte ich noch nicht, da bei boolean ja nur 0 ist false definiert ist.

Wieder was gelernt.

Gruß Tommy

hi,

da ist die frage, was man als "definiert" sieht.

es ist schon richtig, daß alles außer 0 als true erkannt wird. andererseits kann der arduino, wenn er eine boolean-variable auf true setzen will, ja nicht "alles außer 0" in dieses byte schreiben. er schreibt das rein, als das diese konstante true definiert ist, und das ist eben 1. genauso wie die konstante HIGH als 1 definiert ist.

finde jetzt die datei nicht, in der diese konstanten definiert sind. vielleicht weiß es ja jemand...

gruß stefan

Also boolean true / false wird problemlos in HIGH / LOW gewandelt?

Das implizite Casting funktioniert ganz gut.
Man kann eigentlich alle Datentypen verwenden.
Alles von Null, oder 0, verschiedene wird zu HIGH, bzw. true

Danke Euch beiden für die Erklärung.

Gruß Tommy

Hallo zusammen

Vielen Dank für die Hilfe! Ich werde dies übers Wochenende testen und euch ein update geben ob ich weiter gekommen bin :slight_smile:

Gruess

combie:
Das implizite Casting funktioniert ganz gut.
Man kann eigentlich alle Datentypen verwenden.
Alles von Null, oder 0, verschiedene wird zu HIGH, bzw. true

Nein, das ist falsch.

Erstaunlicherweise ist es anders: es wird nur das unterste Byte des Werts betrachtet.

void setup() {
  unsigned long tVal = 0xFFFFFF00;
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(250000);
  // hier wird implizit auf bool gecastet
  if (tVal) {
    Serial.print(F("if (0x"));
    Serial.print(tVal, HEX);
    Serial.println(F(") true"));
  }
  // hier nicht, die LED bleibt aus, es wird nur das unterste Byte getestet
  digitalWrite(LED_BUILTIN, tVal);
  showLED(F("tVal    "));
  // man benotigt also etwas wie
  digitalWrite(LED_BUILTIN, (bool)tVal);
  showLED(F("(bool)tVal"));
  digitalWrite(LED_BUILTIN, tVal != 0);
  showLED(F("tVal != 0"));
  digitalWrite(LED_BUILTIN, !!tVal);
  showLED(F("!!tVal  "));
}

void showLED(const __FlashStringHelper* was) {
  Serial.print(was);
  Serial.print(F("\tLED ist A"));
  if (digitalRead(LED_BUILTIN)) {
    Serial.println(F("N"));
  } else {
    Serial.println(F("US"));
  }

}
void loop() {}
if (0xFFFFFF00) true
tVal    	LED ist AUS
(bool)tVal	LED ist AN
tVal != 0	LED ist AN
!!tVal  	LED ist AN

Interessant das zu wissen. Das spart böse Überraschungen.
Vielen Dank.

Gruß Tommy

Solange man - wie im OP - mit bools (oder anderen Bytes) arbeitet, geht alles gut, das ist etwas heimtückisch.

Erstaunlicherweise ist es anders: es wird nur das unterste Byte des Werts betrachtet.

Danke, vermutlich wäre ich irgendwann in die Falle gestolpert.

Und Erstaunlich finde ich es jetzt nicht... (nach dem ich mir das mal angesehen habe)
Die Signatur von digitalWrite:

void digitalWrite(uint8_t pin, uint8_t val);

Es findet erst ein impliziter Cast auf uint8_t statt, dieser blendet alle höherwertigen bits aus.

Im Code dann

if (val == LOW)

Eine Änderung der Signatur auf

void digitalWrite(uint8_t pin, bool val);

sollte den Bock beheben.

combie:

 digitalWrite(ledPin,lightState);

Evtl problematisch.

Besser:

 digitalWrite(ledPin,(bool)lightState);
boolean lightState = false;

genügt völlig und ist im Ausgangscode enthalten.

Meine Bemerkung war eher ein Widerspruch auf die globalere Aussage.

combie:
Eine Änderung der Signatur auf

void digitalWrite(uint8_t pin, bool val);

sollte den Bock beheben.

Bock ist vielleicht etwas hart, aber du kannst die Änderung ja mal vorschlagen.
Edit: eine Änderung könnte alten Kode ungültig machen und die Schnittstelle ist sehr tief,
also ist wahrscheinlich viel Kode betroffen, der möglicherweise in Ausnahmefällen nicht mehr funktioniert.
"Never change a winning team" ist dem Arduino Team da vielleicht wichtiger, als die kleine logische Anomalie

Da digitalRead() einen boolean zurückgibt,
würde ich eigentlich auch naiverweise bei digitalWrite annehmen, dass es einen boolean erwartet.

Habe dich schon verstanden, da mach dir mal keine Sorgen.

Danke, vermutlich wäre ich irgendwann in die Falle gestolpert.

Für mich galt es diese Falle zu erkennen und einen Weg zu finden, diese in der Zukunft zu umschiffen.

Nochmals meinen Dank, für die Korrektur.

Da digitalRead() einen boolean zurückgibt,
würde ich eigentlich auch naiverweise bei digitalWrite annehmen, dass es einen boolean erwartet.

Da bist du allerdings im Irrtum :o
Der Bool Wert wird zum 16Bit int aufgeblasen.

Siehe:

int digitalRead(uint8_t pin)

...
Schön, ist das alles nicht
...

Da bekommt man das Gruseln.

Das ist auch etwas unerwarted wenn man digitalRead betrachtet:

	// If the pin that support PWM output, we need to turn it off
	// before getting a digital reading.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

Wenn man den Timer wieder aktivieren würde wäre das ja ok,
aber einfach ein analogWrite hinter den Kulissen in ein digitalWrite zu verwandeln ist unsportlich.

mecker... mecker... mecker...

Wieso tun sich nicht einige schlaue Leute zusammen und basteln an Arduino_2 rum.
Denn davon gibts hier reichlich.

Reichlich Arduino_2? :wink:

Gruß Tommy