Arduino: luz automática con temporizador de apagado

2020-11-29 - Categorías: C/C++

¡Hola de nuevo! Comparto aquí un codekata para construir una luz automática con Arduino. La idea es que se encienda con un sensor, y se mantenga encendida durante 30 segundos. Si mientras está encendida, se producen nuevos movimientos, entonces resetea la cuenta atrás a 30 segundos de nuevo para que se mantenga la luz encendida. A los 30 segundos de no haber movimiento se apagará.

Como único input tiene un sensor PIR, el clásico sensor de movimiento basado en infrarojos. Como output usa 3 pines, dos son simplemente leds para ver que está activo o no, y un tercer output que es un relay para encender y apagar luces usando voltajes y amperajes más altos como lámparas a 220v, por ejemplo.

Al grano, el código fuente


unsigned long stopMs = 0; // Timestamp to stop..
int secsWait = 30;
bool debug = true;

// Inputs..
int pirSensor = 9;

// Outputs..
int internalLed = 13;
int externalLed = 5;
int relay = 7;

// Current status
int currentStatusSensor = LOW;
int currentStatusLedsRelay = LOW;

void setup() {
  pinMode(internalLed, OUTPUT); 
  pinMode(externalLed, OUTPUT);
  pinMode(relay, OUTPUT);
  pinMode(pirSensor, INPUT);

  Serial.begin(9600);
}

void loop() {
  currentStatusSensor = digitalRead(pirSensor);

  if(debug) {
    String sms = "CurrentMillis: " + (String) millis() + " => StopMillis: " + (String) stopMs
      + " Sensor: " + (String) currentStatusSensor 
      + " Leds+relay: " + currentStatusLedsRelay;
    Serial.println(sms);
  }

  if(stopMs > millis()) {
    if (currentStatusSensor == HIGH) {
      stopMs = millis() + secsWait * 1000;
    }
  } else {
    // Switch on/off lights if counter is zero..
    if (currentStatusSensor == HIGH) {
      stopMs = millis() + secsWait * 1000;
      
      digitalWrite(internalLed, HIGH);
      digitalWrite(externalLed, HIGH);
      digitalWrite(relay, HIGH);
      currentStatusLedsRelay = HIGH;
    } else {
      digitalWrite(internalLed, LOW);
      digitalWrite(externalLed, LOW);
      digitalWrite(relay, LOW);
      currentStatusLedsRelay = LOW;
    }

    stopMs = 0;
  }

  // Reset because of the loop of millis..
  if(stopMs > millis() && (stopMs - millis()) > 2 * (secsWait * 1000)) {
    stopMs = secsWait * 1000;
  }
}

En la parte final del reset, hay que tener en cuenta la vuelta a cero de millis(). Sino se puede quedar la luz encendida si se activó el PIR justo antes de la puesta a cero de millis(). Según la documentación oficial este contador se resetea cada 50 días:

https://www.arduino.cc/reference/es/language/functions/time/millis/

Depurando con el monitor del puerto serie

En Arduino IDE podemos depurar el proceso abriendo la sección Herramientas > Monitor Serie, y veremos una pantalla como la siguiente si todo ha ido bien:

Arduino log depurando con el monitor serie

8 respuestas a “Arduino: luz automática con temporizador de apagado”

  1. MarcosProGamer_YT dice:

    Muy buen proyecto

  2. hector dice:

    hola, muchas gracias por el proyecto, es muy util.
    pregunto: se puede hacer lo mismo pero utilizando un pulsador en lugar del sensor PIR ?

    • Jnj dice:

      Hola Hector!
      De nada, gracias por dejar un comentario. También se puede con un pulsador, la señal de activación del pulsador la conectas al pin 9 donde está el input del PIR, y consigues el mismo funcionamiento.

  3. Pedro Garcia dice:

    Hola Jnj
    Yo queria poner el tiempo mas alto a unos 600 segundos y he probado el circuito y a 30 seg funciona
    pero si pongo 60 ya no, es posible poner 600 segundos o mas?
    Gracias

    • Jnj dice:

      Hola Pedro!

      Muchas gracias por dejar un comentario.

      Estoy probando el programa y no logro replicar el error. Es decir, creo que está correcto el programa, para ponerlo a 600 o más sólo tienes que cambiar el código donde pone:
      int secsWait = 30;
      ..cambiándolo por los segundos de espera que quieras:
      int secsWait = 600;

      También es interesante que pongas el debug a true para ver por el puerto serie la lectura del PIR:
      bool debug = true;

      Otra cosa, mira que el PIR puede necesitar ajuste. Suelen tener dos roscas para ajustar con destornillador que ajustan el tiempo que devuelven señal de detección y la distancia de 3 a 7 metros. Este ajuste de la rosca de tiempo, puede afectar al tiempo de apagado porque si el PIR envía durante mucho tiempo la señal de activado, Arduino se pensará durante mucho tiempo que sigue detectando movimientos cuando realmente no es así.

      Saludos.

  4. Pedro dice:

    Hola Jnj
    Si estoy simulando con un pulsador, lo que quiero es como un temporizador de escalera, y cuando pulso el boton a 5 voltios se quede activado todo el rato y cuando lo pongo a masa, que pase el tiempo en segundos que se ha programado y despues de ese tiempo se apague, si no se volvio a pulsar.
    He probado con 30 segundo y funciona bien, pero si pongo 60 o mas ya no funciona, he probado con otros ejemplos y me pasa igual. El debug parece ir bien
    26799=>0 Sensor: 0
    26819=>0 Sensor: 0
    26840=>0 Sensor: 0
    26860=>0 Sensor: 0
    26882=>0 Sensor: 0
    26902=>0 Sensor: 0

    26944=>21408 Sensor: 1
    26969=>21433 Sensor: 1
    26994=>21457 Sensor: 1
    27019=>21483 Sensor: 1
    27043=>21507 Sensor: 1
    27069=>21533 Sensor: 1
    27094=>21558 Sensor: 1

    El ejmplo de usted me gusta mas y es mas completo,
    He probado con este ejemplo y me ocurre lo mismo.
    /*
    * Luz de escalera.
    *
    * Cuando pulsamos el botón la luz se enciende pero permanecerá
    * encendida durante un minuto cuando la soltemos el pulsador. Si volvemos
    * a pulsar volverá a empezar a contar otra vez.
    *
    * Simulamos la luz con el led de la placa.
    */

    unsigned long t; // unsigned long minimo 0 y maximo 4294967295

    //unsigned long stopMs = 0; // Timestamp to stop..
    int secsWait = 60;

    void setup() {
    pinMode(2, INPUT_PULLUP);
    pinMode(13, OUTPUT);
    digitalWrite(13, LOW);
    }

    void loop() {
    // Comprobamos que el botón está pulsado.
    if ( digitalRead(2)==HIGH ) {
    digitalWrite(13,HIGH); // Encendemos la luz.
    t = millis(); // Guardamos CUANDO ha ocurrido.
    }
    // Si el botón NO está pulsado.
    else {
    // Queremos que la luz siga encendida durante un minuto
    // asi que tenemos que comprobar que ha transcurrido ese
    // minuto.
    if ( millis()-t > secsWait * 1000 ) {
    digitalWrite(13,LOW); // Ha pasado el minuto, apagamos la luz.
    }
    }
    }

    • Jnj dice:

      Buenos días Pedro!
      Por lo que comentas parece que el problema está en la lectura del sensor-botón. Añade más log para ver en el Monitor Serial y así lo depuras tu código. Ayer jugando un poco modifiqué el código fuente del post también si quieres pruébalo. Creo que el problema va a estar en la lectura del sensor-botón, puede que esté dando HIGH de vez en cuando con lo que ya no se apaga, sino no le veo sentido a que se comporte como indicas.
      Saludos.

Responder a hector Cancelar la respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

 

© 2024 JnjSite.com - MIT license

Sitio hecho con WordPress, diseño y programación del tema por Jnj.