relé PIR de Arduino con interruptor de anulación manual

1

Estoy configurando un relé activado por PIR (conectado a algunas luces) usando un Arduino Nano.

Tengo el código PIR funcionando (obtenido de un sitio de terceros) pero me gustaría tener la opción de anular la entrada PIR en función de la entrada de un interruptor de botón pulsador. Para agregar aún más complejidad, me gustaría tener un LED encendido para avisarme cuando el PIR se está anulando manualmente (relé siempre encendido).

El botón es un simple botón pulsador.

Por defecto, quiero que la unidad esté en modo PIR. El relé se activa si se detecta movimiento, y luego de X segundos se apaga. Si presiono el botón una vez, se anula manualmente y el relé se enciende (constantemente) y se enciende el LED azul para informarme que la unidad está encendida constantemente. Si se presiona nuevamente el botón, la unidad regresa al modo PIR.

Aquí está el código que tengo hasta ahora, pero el LED y el relé parecen estar constantemente activos. El PIR sigue leyendo (según el monitor de serie).

/*
 * 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
            }
        }
    }
}

Aquí está el código que tengo hasta ahora, pero el LED y el relé parecen estar constantemente activos. El PIR sigue leyendo (según el monitor de serie).

Es evidente que hay algo mal con mi bucle if-else, pero no estoy del todo seguro de dónde debo empezar a buscar.

También estoy incluyendo una imagen básica del circuito (¡es mi primer Fritz, así que sé amable!) Además, ignora el pin en el tablero de relés. Estoy usando un SRD-05VDC-SL-C pero está en una placa ligeramente diferente con solo 3 pines (IN, VCC, GND).

    
pregunta Huskie69

2 respuestas

1

Creo que su principal problema es que no está asignando una variable o utilizando una declaración if con su digitalRead(PIR_override); , pero incluso con eso puede perderse la pulsación del botón en el bucle. Si se trata de un interruptor momentáneo, se activa / desactiva solo durante el tiempo que se pulsa, por lo que el procesador tendría que verlo en el momento correcto en el bucle while. Puede simplemente mantener presionado el botón durante aproximadamente un segundo o puede conectar el botón al pin 2 o 3 y usar una interrupción, que parece que su botón está conectado al pin 3 según su código. Creo que esta es una mejor solución. En el mundo incrustado las interrupciones son tus amigos.

Entonces, de acuerdo con la documentación ( enlace ), puedes hacer algo como esto:

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

Dentro de Setup() add:

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

Así que ahora se llamará a motionOverride cuando se presione el botón. Solo pon lo que quieras que pase dentro de esta función. Algo como esto:

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
}

Luego, dentro de su principal loop() solo mire la marca de anulación (Nota: no comprobé ninguna de su lógica de detección de movimiento PIR, y espero que no arruinara sus soportes allí):

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;
            } 
        }
     }
}

Prueba eso si quieres. Si hay un error, intentaré ayudarlo.

    
respondido por el DigitalNinja
1

He sugerido una edición de tu código; Las sangrías no estaban presentes, así que las agregué para que las declaraciones anidadas if-else sean más claras.

Me gustaría abordar algunos problemas que tengo; Por favor cambia tus definiciones de pin:

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)

a algo como:

#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)

Con su uso actual de variables enteras, es posible que su valor cambie, lo que seguramente no desea hacer. El uso de enteros para las definiciones de pines también consume espacio en tu pila. Es posible que esto nunca sea un problema real, pero es algo a tener en cuenta.

Puede encontrar más información detallada sobre las directivas de preprocesador en otra parte.

Cuando lees tu pin PIR_override:

digitalRead(PIR_override);  // read input value of PIR override switch

El valor no se está utilizando. Debes asignarlo a una variable.

También veo algunos problemas con su lógica if-else. Toma este código por ejemplo:

if (val == LOW)
{            // check if the input is LOW
    val = digitalRead(inputPin);  // read input value

Inicialmente, val se establece en bajo. Esta bien. La sentencia if será verdadera, y val será reasignada. Pero, ¿qué pasa si val se reasigna a ALTO? Una vez que se llega al final del bucle y se reinicia, no hay otra declaración para manejar val == HIGH!

Me parece que lo que estás tratando de hacer con tu lógica anidada if-else está cerca de una máquina de estados. Si aún no lo ha consultado, sugeriría buscar 'máquinas de estado if-else' o 'máquinas de estado de conmutación'.

De lo contrario, si desea continuar con el código que tiene ahora, consideraría la posibilidad de escribir los valores de las variables de inicio y 'revisar' su código manualmente.

    
respondido por el Daniel

Lea otras preguntas en las etiquetas