Ich richte ein PIR-aktiviertes Relais (mit einigen Lichtern verbunden) mit einem Arduino Nano ein.
Ich habe den PIR-Code funktioniert (erhalten von einer Drittanbieter-Website), aber ich hätte gerne die Option, den PIR-Eingang basierend auf einem Eingang von einem Druckknopfschalter zu überschreiben. Um noch mehr Komplexität hinzuzufügen, möchte ich eine LED aufleuchten lassen, um mich darüber zu informieren, wenn die PIR manuell außer Kraft gesetzt wird (Relais immer eingeschaltet).
Der Knopf ist ein einfacher Druckknopf.
Standardmäßig möchte ich, dass sich das Gerät im PIR-Modus befindet. Das Relais wird aktiviert, wenn eine Bewegung erkannt wird, und schaltet dann nach X Sekunden ab. Wenn ich die Taste einmal drücke, wird sie manuell übersteuert und das Relais wird (dauerhaft) eingeschaltet und die blaue LED wird aktiviert, um mich darüber zu informieren, dass das Gerät ständig eingeschaltet ist. Wird die Taste erneut gedrückt, schaltet das Gerät wieder in den PIR-Modus.
Hier ist der Code, den ich bisher habe - aber die LED und das Relais scheinen ständig aktiv zu sein. Der PIR liest immer noch (laut seriellem Monitor).
/*
* PIR sensor tester
*/
int PIR_override = 3; // the number of the switch pin
int overridestatus = 12; // the number of the led pin
int relaypin = 13; // choose the pin for the LED
int inputPin = 2; // choose the input pin (for PIR sensor)
int pirState = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int DELVAR = 3000; // Delay in milliseconds
int override_state = LOW; // the current state of the output pin
// set states for PIR override switch
int state = LOW; // the current state of the output pin
int reading; // the current reading from the input pin
int previous = HIGH; // the previous reading from the input pin
///////////////////////////////////////////////////////
void setup() {
pinMode(relaypin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input
Serial.begin(9600);
}
void loop()
{
digitalRead(PIR_override); // read input value of PIR override switch
if (val == LOW)
{ // check if the input is LOW
val = digitalRead(inputPin); // read input value
if (val == HIGH)
{ // check if the input is HIGH
digitalWrite(relaypin, HIGH); // turn LED ON
if (pirState == LOW)
{
// we have just turned on
Serial.println("Motion detected!");
// We only want to print on the output change, not state
pirState = HIGH;
delay(DELVAR); // maximum delay is 32776 millisecons,
// delay(DELVAR); // so add multiple delays together to get
// delay(DELVAR); // so add multiple delays together to get
}
}
else
{
digitalWrite(relaypin, LOW); // turn LED OFF
if (pirState == HIGH)
{
// we have just turned of
Serial.println("Motion ended!");
// We only want to print on the output change, not state
pirState = LOW;
}
else
{
digitalWrite(overridestatus, HIGH); // turn override status LED ON
digitalWrite(relaypin, HIGH); // turn relay ON
}
}
}
}
Hier ist der Code, den ich bisher habe - aber die LED und das Relais scheinen ständig aktiv zu sein. Der PIR liest immer noch (laut seriellem Monitor).
Mit meiner if-else-Schleife stimmt eindeutig etwas nicht, aber ich bin mir nicht ganz sicher, wo ich anfangen muss zu suchen.
Ich füge auch ein einfaches Steckbrettbild der Schaltung bei (es ist mein erster Fritz, also seien Sie vorsichtig!) Außerdem ignorieren Sie bitte den Pin auf der Relaisplatine. Ich verwende ein SRD-05VDC-SL-C, aber es befindet sich auf einer etwas anderen Platine mit nur 3 Pins (IN, VCC, GND).
Ich denke, Ihr Hauptproblem besteht darin, dass Sie keine Variable zuweisen oder eine if
Anweisung mit Ihrem verwenden digitalRead(PIR_override);
, aber selbst damit können Sie den Tastendruck in der Schleife verpassen. Wenn es sich um einen momentanen Schalter handelt, geht er nur für die Zeit hoch / niedrig, in der er gedrückt wird, sodass der Prozessor dies zum richtigen Zeitpunkt in der While-Schleife sehen müsste. Sie können die Taste einfach etwa eine Sekunde lang gedrückt halten oder die Taste an Pin 2 oder 3 anschließen und einen Interrupt verwenden, bei dem es so aussieht, als wäre Ihre Taste gemäß Ihrem Code mit Pin 3 verbunden. Ich denke, das ist eine bessere Lösung. In der eingebetteten Welt sind Interrupts Ihr Freund.
Laut Dokumentation ( https://www.arduino.cc/en/Reference/AttachInterrupt ) könnten Sie also so etwas tun:
const byte PIR_override = 3; // the number of the switch pin
volatile boolean override = false; // Use this to know if your currently in override mode or not when looking at the button press
Innen Setup()
hinzufügen:
pinMode(PIR_override, INPUT);
attachInterrupt(digitalPinToInterrupt(PIR_override), motionOverride, LOW); // the sense may need to be changed - from your image it looks like the button goes low when pressed
So motionOverride
wird jetzt aufgerufen, wenn die Taste gedrückt wird. Geben Sie einfach in diese Funktion ein, was passieren soll. Etwas wie das:
void motionOverride()
{
if(override) // overriding motion and the button has been pressed - got to PIR mode
{
digitalWrite(overridestatus, LOW); // turn override status LED OFF
digitalWrite(relaypin, LOW); // turn relay OFF - you may not want to do this... depends on what you want
override = false; // set the override flag
}
else // not overriding motion and the button has been pressed - go to override mode
{
digitalWrite(overridestatus, HIGH); // turn override status LED ON
digitalWrite(relaypin, HIGH); // turn relay ON
override = true; // set the override flag
}
// I guess Arduino takes care of clearing the interrupt for you
}
Dann schauen Sie sich in Ihrem Hauptfenster loop()
einfach das Override-Flag an (Hinweis: Ich habe keine Ihrer PIR-Bewegungserkennungslogik überprüft und hoffentlich habe ich Ihre Klammern dort nicht durcheinander gebracht):
void loop()
{
if(!override)
{
val = digitalRead(inputPin); // read PIR input value
if (val == HIGH) // check if the input is HIGH
{
digitalWrite(relaypin, HIGH); // turn LED ON
if (pirState == LOW)
{
// we have just turned on
Serial.println("Motion detected!");
// We only want to print on the output change, not state
pirState = HIGH;
delay(DELVAR); // maximum delay is 32776 millisecons,
// delay(DELVAR); // so add multiple delays together to get
// delay(DELVAR); // so add multiple delays together to get
}
}
else
{
digitalWrite(relaypin, LOW); // turn LED OFF
if (pirState == HIGH)
{
// we have just turned of
Serial.println("Motion ended!");
// We only want to print on the output change, not state
pirState = LOW;
}
}
}
}
Probieren Sie das aus, wenn Sie möchten. Wenn es einen Fehler gibt, werde ich versuchen, damit zu helfen.
Ich habe eine Bearbeitung Ihres Codes vorgeschlagen; Einzüge waren nicht vorhanden, also habe ich sie hinzugefügt, um verschachtelte if-else-Anweisungen klarer zu machen.
Ich möchte einige Probleme ansprechen, die ich habe; Bitte ändern Sie Ihre PIN-Definitionen:
int PIR_override = 3; // the number of the switch pin
int overridestatus = 12; // the number of the led pin
int relaypin = 13; // choose the pin for the LED
int inputPin = 2; // choose the input pin (for PIR sensor)
zu etwas wie:
#define PIR_override 3 // the number of the switch pin
#define overridestatus 12 // the number of the led pin
#define relaypin 13 // choose the pin for the LED
#define inputPin 2 // choose the input pin (for PIR sensor)
Bei Ihrer derzeitigen Verwendung von Integer-Variablen ist es möglich, dass sich deren Wert ändert, was Sie sicherlich nicht möchten. Die Verwendung von Ganzzahlen für Pin-Definitionen verbraucht auch Platz auf Ihrem Stack. Dies ist vielleicht nie ein echtes Problem, aber es ist etwas, das man in Betracht ziehen sollte.
Ausführlichere Informationen zu Präprozessordirektiven finden Sie an anderer Stelle.
Wenn Sie Ihren PIR_override-Pin lesen:
digitalRead(PIR_override); // read input value of PIR override switch
Der Wert wird nicht verwendet. Diese müssen Sie einer Variablen zuweisen.
Ich sehe auch ein paar Probleme mit Ihrer if-else-Logik. Nehmen Sie zum Beispiel diesen Code:
if (val == LOW)
{ // check if the input is LOW
val = digitalRead(inputPin); // read input value
Anfänglich ist val auf niedrig gesetzt. Das ist in Ordnung. Die if-Anweisung ist wahr und val wird neu zugewiesen. Aber was ist, wenn val neu zugewiesen wird, um HIGH zu sein? Sobald das Ende der Schleife erreicht und neu gestartet wurde, gibt es keine else-Anweisung, um val == HIGH zu behandeln!
Es scheint mir, dass das, was Sie mit Ihrer verschachtelten if-else-Logik zu tun versuchen, einer Zustandsmaschine nahe kommt. Wenn Sie sich noch nicht damit befasst haben, würde ich vorschlagen, nach „if-else-Zustandsmaschinen“ oder „Switch-Case-Zustandsmaschinen“ zu suchen.
Andernfalls, wenn Sie mit dem Code fortfahren möchten, den Sie jetzt haben, würde ich erwägen, die Startvariablenwerte zu schreiben und Ihren Code manuell "durchzulaufen".
Huskie69
DigitalNinja
DigitalNinja
delayMicroseconds()
da es selbst keine Interrupts verwendet. Wenn Sie die Hardwarelösung nicht durchführen können und die Verzögerung am Ende der ISR nicht funktioniert, denke ich, dass ich eine Problemumgehung habe, die funktioniert. Lassen Sie mich wissen, wie es geht.Huskie69
DigitalNinja
Huskie69
Huskie69
DigitalNinja
motionOverride
Funktion. Ich bin mir nur nicht ganz sicher, wie es sich auf der Arduino-Plattform verhalten wird, deshalb habe ich die Hardwarelösung vorgeschlagen.