Electrónica y programación para Microcontroladores.

Libros técnicos para electrónica programable.

Email
Contactanos en:

consultas@firtec.com.ar

Arduino

 Haciendo unas reformas en casa me doy cuenta que la sirena inalámbrica instalada con el sistema de alarma no tiene el alcance con la señal de radio para llegar el sitio donde será instalada.
Viendo que tengo una sirena clásica cableada que nunca instalé por lo incomodo de colocar tantos metros de cable decidí convertirla en inalámbrica mediante dos enlaces de Radio controlados con Arduinos Nano.
En la siguiente imagen se puede ver la sirena con el receptor ya instalado en su interior.

Para activar la sirena remota uso la señal de activación que la propia alarma publica para activar una sirena interna (+12V), esta señal de 12 voltios se conecta a un opto-acoplador PC817 que dispara una interrupción en el Arduino Nano.
Una vez se detecta la interrupción se envía un comando de activación a la sirena remota.
El siguiente es el diagrama electrónico del emisor.

 

El siguiente es el programa para el emisor, se puede ver que en la rutina de interrupción se envía el comando para activar la sirena remota también se puede ver el uso de un delay() en la rutina de la interrupción lo que se puede entender como una interrupción anidada situación prohibida en Arduino sin embargo en este caso y debido a la forma en que el código ha sido diagramado esto es funcional. 
Si se detecta que los 12 voltios de la sirena interna desaparecen se entiende que la alarma se ha desactivado y se envía el comando para apagar la sirena remota y todo el sistema pasa a bajo consumo deteniendo la CPU hasta que una nueva interrupción lo despierte.

/**********************************************************************
** Descripción  : Control de una sirena por enlace de Radio          
**                Envia el 5 veces el comando activación a la sirena.
**               
**  Target       : Arduino NANO
**  ToolChain    : Arduino IDE 1.8.1´9 bajo Linux Debian
**                                          Daniel Schmidt 
**********************************************************************/
#include <avr/sleep.h>
#define alarma   3  // IRQ_1 Detecta el disparo de la alarma
 
volatile unsigned char bandera_1 = 0;
unsigned char control_1 = 0;
unsigned char control_2 = 0;
 
 
void setup() {
  Serial.begin(9600); 
  while (!Serial) {
    ; // Espera que se establezca la conexion
  } 
  pinMode(3,INPUT_PULLUP);  // Pin que detecta el disparo de la alarma 
}
 
void loop() {
  // Si el pin 3 esta a nivel alto enviar comando APAGAR SIRENA
  if (digitalRead(alarma) == HIGH && control_2 <=4){// Envía el comando 5 veces
  do{  
    Serial.write('B'); // Envía el comando stop (Sirena desactivada) 
    control_2++;       // Incrementa el contador de muestras
    control_1 = 0;
    delay(1000);      // Espera un segundo en cada envío de comando
  }while(control_2 <=4);   
 }
  
  sleep_enable(); // Activar el modo sleep
  attachInterrupt( 1, ISR_Alarma_SI, LOW);  // Define que ISR lo despierta
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);      // Modo en que entra al sleep
  sleep_cpu();                              // Detiene la CPU  
} 
 
/*************************************************
  Rutina para detectar el disparo de la alarma
 *************************************************/
void ISR_Alarma_SI(){
  sleep_disable();
  delay(2000); // IMPORTANTE: Tiempo de espera para que toda 
               // la electrónica se active.
                
// Si el pin esta bajo luego de dos segundo enviar comando ACTIVAR SIRENA
if(digitalRead(alarma) == LOW && control_1 <=4){ // Envía el comando 5 veces
  do{  
    Serial.write('A'); // Envía el comando de disparo (Sirena activada) 
    control_1++;  // Incrementa el contador de muestras
    control_2 = 0;
    delay(1000);
  }while(control_1 <=4);
 }
}

 El diagrama electrónico del receptor que controla la sirena remota es el siguiente.

El receptor es quien activa la sirena remota al recibir el comando 'A', en este caso la mantiene activa durante un minuto y pasa en modo bajo consumo al recibir el comando 'B' que indica que la alarma ha sido desactivada.
En este ejemplo se uso un enlace de radio lora simplemente por la distancia a cubrir pero evidentemente cualquier enlace funcionará ya que esto es solo el medio de transporte del protocolo de comunicación que hace que todo funcione.
El siguiente es el código del receptor.

/*************************************************************************************
** Descripción   : Control de una sirena por enlace Lora          
**                 La sirena se activa con el comando A y se desactiva 
**                 con el comando B o transcurridos 1 minuto de estar activada.
**  NOTA         : Recordar que el contador interno de millis es de 32 bits es decir
**                 que va desde 0 a 4294967296 milisegundos.
**  Target       : Arduino NANO
**  ToolChain    : Arduino IDE 1.8.19 bajo Linux Debian
**                                                          Daniel Schmidt
**************************************************************************************/
#include <avr/sleep.h>
#define pin_ISR     2   // Pin IRQ para ATmega 328
#define sirena      9
 
unsigned long milisegundos = 0;
volatile char  dato;
unsigned int segundos = 0;
unsigned char bandera = 0;
unsigned char bandera_timer = 0;
volatile char tmp;
void sleep(void);
 
void ISR_Sirena_SI(){ // Esta ISR se ejecuta primero que la UART (Vector 2)
  sleep_disable();
  dato = '0'; 
 }
 
void setup() {
  Serial.begin(9600); 
  while (!Serial) {
    ; // Espera que se establezca la conexión
    }
  milisegundos = millis();
  pinMode(sirena, OUTPUT);
  digitalWrite(sirena, LOW);   // Sirena en silencio
   sleep_enable();  // Modo sleep habilitado
   attachInterrupt( 0, ISR_Sirena_SI, LOW); // ISR para salir del sleep
   set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Modo del sleep agresivo
   sleep_cpu();    // CPU pasa al modo sleep
}
 
 
void loop() {
  while (Serial.available()>0){  // Usar Inte_Vector 19
      dato = Serial.read();  
}
 
if((dato == 'A') || (dato == 'B')){
  
  if(dato == 'A' && bandera == 0 ){// Control para activar
           digitalWrite(sirena, HIGH);  // Sirena ACTIVADA!! 
           bandera = 1;
           dato = '0'; 
           segundos = 0;      
        } 
   
   if(dato == 'B'){
            digitalWrite(sirena, LOW); // Sirena DESACTIVADA con B!!
            segundos = 0;
            bandera = 0;
            dato = '0';  
            bandera_timer = 0;
            sleep();  // Nuevamente sleep solo si la alarma envía el comando B
        }
 
if(dato == 'A' && bandera_timer == 0 ){
        if ( millis() - milisegundos >= 1000 ) { // Ya pasaron 1000 milisegundos (Un segundo)?
          segundos++;
          milisegundos = millis(); // Actualiza el valor actual de millis 
              if(segundos >= 60){ // Si pasaron 60 segundos desactivar sirena    
                digitalWrite(sirena, LOW); 
                segundos = 0;
                bandera_timer = 1;
       } 
    } 
  } 
}  
   
   // ############ Por si acaso el programa llega hasta este punto pasar a sleep #########
   // ############     (El programa NO debería de llegar hasta este punto)       #########
   
   if(segundos == 120){ // Si pasaron 120 segundos pasar a sleep nuvamente   
              digitalWrite(sirena, LOW);
              segundos = 0;
              bandera = 0;
              bandera_timer = 0;
              sleep();
    }     
}
 
void sleep()          
{
  while (Serial.available()>0)  
  tmp = Serial.read(); // Limpiar buffer de RX
  digitalWrite(sirena, LOW);
  segundos = 0;
  bandera = 0;
  bandera_timer = 0;
  delay(100);
  sleep_enable(); // Activar el modo sleep
  attachInterrupt( 0, ISR_Sirena_SI, LOW);  // ISR que lo hace despertarí
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);      // Modo en que entra al sleep
  sleep_cpu();                              // Detiene la CPU  
}