Electrónica y programación para Microcontroladores.

Libros técnicos para electrónica programable.

Email
Contactanos en:

consultas@firtec.com.ar

Arduino

Las palomas si bien son aves simpáticas pueden dejar de serlo cuando deciden de manera insistente construir su nido en el compresor del sistema de aire acondicionado.
Esto ademas de ser molesto por la cantidad de basura que generan al construir su nido resulta peligroso para las propias palomas y  para el equipo de aire acondicionado .
Como la idea es tratar de convencer a las palomas de que se busquen otro lugar sin hacerles daño se me ocurrió construir este pequeño dispositivo usando el sensor ultrasónico HC-SR04 un Arduino Nano y algunos componentes extras como un potenciómetro de 10K, dos display cátodo común  y dos transistores BC337.

El objetivo es usar el sensor para detectar palomas en donde no deben estar y activar una señal sonora que las espante cada vez que se acerquen a la zona de cobertura. El sistema cuenta con un potenciómetro que ajusta el rango de alcance donde se debe  activar el sistema "espanta palomas", este rango se visualiza en dos dígitos.
El rango se puede cambiar actuando sobre el botón de programación y moviendo el potenciómetro, el nuevo valor se almacena en memoria EEPROM por lo tanto el sistema siempre "recuerda" el valor fijado aunque su alimentación se pierda.
El siguiente es el código completo del trabajo propuesto.

/******************************************************************************
** Detector de proximidad por ulatrasonido con Arduino y sensor SRF-04.
** El ejemplo incluye un ajuste de rango que va desde 1 cmts. a 50 cmts. 
** mediante un potenciómetro y la posibilidad de ver el rango en dos dígitos
** con multiplexor de dos transistores BC337 y un decodificador BCD CD4511.
**
** Target: Arduino nano
** Ide para Arduino v.1.8.19 con Linux Debian.
** 
********************************************************************************/
/* NOTA: Para la conexion de los segmentos del display (cátodo común) al CD4511 
 *       ver la hoja de datos del BCD.
********************************************************************************/
#include <EEPROM.h>
#define prog 4  // Boton para programar nuevo rango
#define led 15  // Pin para controlar la sirena, led o un relevador.
 
#define A 8   // Pin A entrada BCD del CD4511 (pin 7)
#define B 9   // Pin B entrada BCD del CD4511 (PIN 1)
#define C 10  // Pin C entrada BCD del CD4511 (Pin 2)
#define D 11  // Pin D entrada BCD del CD4511 (Pin 6)
#define T1 2  // Pin control de la base del transistor BC337 (Unidad)
#define T2 3  // Pin control de la base del transistor BC337 (Decena)
 
const unsigned char EchoPin = 5;    // Pin para el ultrasonido
const unsigned char TriggerPin = 6; // Pin para el ultrasonido
unsigned int conversion =0;
unsigned char muestras =0, rango = 0, unidad = 0, decena = 0, marca = 1;
unsigned int M0=0;
 
void setup() {
  pinMode(led, OUTPUT); // Para controlar un led, sirena o un relay
  pinMode(A, OUTPUT);  // Pines para pasar al BCD los valores binarios
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(T1, OUTPUT); // Pin para la base de transistor unidad
  pinMode(T2, OUTPUT); // pin para la base del transistor decena
  pinMode(prog,INPUT_PULLUP); // Botón para programar el rango
  digitalWrite(led,LOW );
  Serial.begin(9600);
  pinMode(TriggerPin, OUTPUT);
  pinMode(EchoPin, INPUT);
  
  if(EEPROM.read(0) > 50){  // Recupera de memoria el último rango válido
    rango = 30;  // Si no es válido asigna uno por defecto.
  }
  else
    rango = EEPROM.read(0);   // Recupera el rango guardado en memoria
  decena = (rango / 10) % 10; // y ajusta la unidad y decena para ver
  unidad = rango % 10;        // el dato del rango en el display.
    
  //---------- Congigura el Timer 1 ----------------
  noInterrupts();           // No interupciones
  TCNT1 = 65000;            // Ajusta modulo a ~6 Milisegundos
  TCCR1B |= (1 << CS10);    // Sin prescalador 
  TIMSK1 |= (1 << TOIE1);   // Habilita la mascara de interrupción
  interrupts();             // Habilita las interrupciones generales
}
 
void loop() {
rango = EEPROM.read(0); 
if (digitalRead(prog) == LOW){ // Boton de programa activado?
  Leer_Conversor();            // OK, entonces leer el conversor.
  EEPROM.write(0, conversion); // Almacena el nuevo rango
  delay(500);
}
  int dist = ping(TriggerPin, EchoPin); 
  if(dist <= rango)              // Distancia es menor al rango??
    digitalWrite(led,HIGH );     // Sirena o led activado
  if(dist >= rango || dist == 0) // Distancia > 31  o 0 ?? 
     digitalWrite(led,LOW );  // Entonces apagar sirena!!!
  Serial.println(dist);
  delay(500);
  
}
/****************************************************************
* Función para medir la distancia a que se encuentra el intruso
*****************************************************************/
int ping(int TriggerPin, int EchoPin) {
  long tiempo, distancia;
  digitalWrite(TriggerPin, LOW);  // Genera un pulso limpio de 4us
  delayMicroseconds(4);
  digitalWrite(TriggerPin, HIGH);  // Genera disparo de 10us
  delayMicroseconds(10);
  digitalWrite(TriggerPin, LOW);
  tiempo = pulseIn(EchoPin, HIGH);  // Mide el tiempo entre pulsos
  distancia = tiempo * 10 / 292/ 2; // Convierte la distancia, en cm 
  return distancia;
} 
/****************************************************************
*  Lee el canal A0 donde se ha colocado un potenciómetro de 10K
*  para leer un voltaje entre 0 y 5V que se escalara a un valor
*  entre 0 y 50 para ajustar nuevos rangos.

*****************************************************************/
void Leer_Conversor(void){      
do{
  M0 += analogRead(A0);    // Lee el A/D y acumula el dato en M0
  muestras++;         // Incrementa el contador de muestras
}while(muestras <=49);    // Se tomaron  muestras ??
  conversion = M0/50;    // Se busca el promedio de las 50 muestras
  conversion = map(conversion, 0, 1023, 0, 50);
  decena = (conversion / 10) % 10;
  unidad = conversion % 10;
  M0 =0;
  muestras =0;
 }
/************************************************************************
  Muestra el rango ajustado o extraído de la memoria
**************************************************************************/
void Multiplexador(){
  switch(marca){   // El valor de marca determina que transistor se activa.
    case 1:{
      PORTB = unidad;   // Pasa al BCD CD4511 el valor de la Unidad
      digitalWrite(T1, HIGH); // Activar el display de la unidad
      break;
     }
    case 2:{
      digitalWrite(T1, LOW);  // Apagar el display de la unidad
      PORTB = decena;         // Pasa al BCD CD4511 el valor de la Decena
      if(decena > 0)          // Si la decena es 0 apagar el dígito
         digitalWrite(T2, HIGH); // Activar el display de la decena
       break;
    }
    case 3:{
      digitalWrite(T2, LOW);  // Apagar el display de la decena
      marca =0;
      break;
    }
  }
} 
 
 
/* ******** ISR del Timer 1 por desborde **************
  *  Determina la velocidad a la cual se mostrará el 
  *  valor de la unidad y la decena.
 ******************************************************/
ISR(TIMER1_OVF_vect){
  TCNT1 = 65000;    // 5,7 Milisegundos
  marca++;          // Apuntador para activar los transistores  
  Multiplexador();  // LLama a la función para mostrar los datos
}
 
 
/************************************************************************
  Escala el valor del conversor a un valor entre 0 y 50
**************************************************************************/
 long map(long x, long in_min, long in_max, long out_min, long out_max){
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

También podemos eliminar el CD4511 y manejar todo el display directamente con Arduino, para esto tendríamos que modificar el circuito electrónico y adecuarlo a este nuevo código que es el que actualmente esta funcionando en terreno.

/********************************************************************************* 
* Los segmentos están conectados de la siguiente forma:
* Pin 2 segmento a           * Pin 3 segmento b          * Pin 4 segmento c          * Pin 5 segmento d          * Pin 6 segmento e * Pin 7 segmento f * Pin 8 segmento g        ***********************************************************************************/ #include <EEPROM.h> #define prog 15  // Botón para programar nuevo rango #define led 16  // Pin para controlar la sirena, led o un relevador. #define T1 17  // Pin control de la base del transistor BC337 (Unidad) #define T2 18  // Pin control de la base del transistor BC337 (Decena)   //----- Codifica los números y segmentos --------------- const unsigned char num_array[10][7]PROGMEM =    {{ 1,1,1,1,1,1,0 },   // 0   { 0,1,1,0,0,0,0 },    // 1   { 1,1,0,1,1,0,1 },    // 2   { 1,1,1,1,0,0,1 },    // 3   { 0,1,1,0,0,1,1 },    // 4   { 1,0,1,1,0,1,1 },    // 5   { 1,0,1,1,1,1,1 },    // 6   { 1,1,1,0,0,0,0 },    // 7   { 1,1,1,1,1,1,1 },    // 8   { 1,1,1,0,0,1,1 }};   // 9      const unsigned char EchoPin = 11;    // Pin para el ultrasonido const unsigned char TriggerPin = 12; // Pin para el ultrasonido unsigned int conversion =0; unsigned char muestras =0, rango = 0, unidad = 0, decena = 0, marca = 1; unsigned int M0=0;   boolean debug = false; // falso o true ahorra memoria y código mas ágil   void setup() {   pinMode(led, OUTPUT); // Para controlar un led, sirena o un relay   pinMode(T1, OUTPUT); // Pin para la base de transistor unidad   pinMode(T2, OUTPUT); // pin para la base del transistor decena   pinMode(prog,INPUT_PULLUP); // Botón para programar el rango   // -- Configuración de los pines de los segmentos     pinMode(2, OUTPUT);   pinMode(3, OUTPUT);   pinMode(4, OUTPUT);   pinMode(5, OUTPUT);   pinMode(6, OUTPUT);   pinMode(7, OUTPUT);   pinMode(8, OUTPUT);   digitalWrite(led,LOW );       if (debug)       Serial.begin(9600);      pinMode(TriggerPin, OUTPUT);   pinMode(EchoPin, INPUT);      if(EEPROM.read(0) > 50){  // Recupera de memoria el último rango válido     rango = 30;  // Si no es válido asigna uno por defecto.   }   else     rango = EEPROM.read(0);   // Recupera el rango guardado en memoria   decena = (rango / 10) % 10; // y ajusta la unidad y decena para ver   unidad = rango % 10;        // el dato del rango en el display.        //---------- Congigura el Timer 1 ----------------   noInterrupts();           // No interrupciones   TCNT1 = 65000;            // Ajusta modulo a ~6 Milisegundos   TCCR1B |= (1 << CS10);    // Sin prescalador    TIMSK1 |= (1 << TOIE1);   // Habilita la mascara de interrupción   interrupts();             // Habilita las interrupciones generales }   void loop() { rango = EEPROM.read(0);  if (digitalRead(prog) == LOW){ // Boton de programa activado?   Leer_Conversor();            // OK, entonces leer el conversor.   EEPROM.write(0, conversion); // Almacena el nuevo rango   delay(500); } // NOTA: // La sirena suena mientras el intruso este dentro del rango.   int dist = ping(TriggerPin, EchoPin);    if(dist <= rango -1)           // Distancia es menor al rango offset??     digitalWrite(led,HIGH );     // Sirena o led activado   if(dist >= rango +1 || dist == 0) // Distancia > al offset  o 0 ??       digitalWrite(led,LOW );  // Entonces apagar sirena (o lo que sea)!!!      if (debug) {      Serial.println(dist);      }        delay(500);    } /**************************************************************** * Función para medir la distancia a que se encuentra el intruso *****************************************************************/ int ping(int TriggerPin, int EchoPin) {   long tiempo, distancia;   digitalWrite(TriggerPin, LOW);  // Genera un pulso de 4us   delayMicroseconds(4);   digitalWrite(TriggerPin, HIGH);  // Genera disparo de 10us   delayMicroseconds(10);   digitalWrite(TriggerPin, LOW);   tiempo = pulseIn(EchoPin, HIGH);  // Mide el tiempo entre pulsos y   distancia = tiempo * 10 / 292/ 2; // lo convierte a distancia en cm    return distancia; }  /**************************************************************** *  Lee el canal A0 donde se ha colocado un potenciometro de 10K *  para leer un voltaje entre 0 y 5V que se escalara a un valor *  entre 0 y 50 para ajustar nuevos rangos. *****************************************************************/ void Leer_Conversor(void){       do{     M0 += analogRead(A0);    // Lee el A/D y acumula el dato en M0   muestras++;         // Incrementa el contador de muestras }while(muestras <=29);    // Se tomaron  muestras ??   conversion = M0/30;    // Se busca el promedio de las 30 muestras   conversion = map(conversion, 0, 1023, 0, 50);   decena = (conversion / 10) % 10;   unidad = conversion % 10;   M0 =0;   muestras =0;  } /************************************************************************   Muestra el rango ajustado o extraído de la memoria **************************************************************************/ void Multiplexador(){   switch(marca){   // El valor de marca determina que transistor se activa.     case 1:{       Muestra_Dato(unidad);   // Muestra el valor de la unidad       digitalWrite(T1, HIGH); // Activar el display de la unidad       break;      }     case 2:{       digitalWrite(T1, LOW);  // Apagar el display de la unidad       Muestra_Dato(decena);   // Muestra el valor de la decena       if(decena > 0)          // Si la decena es 0 apagar el dígito          digitalWrite(T2, HIGH); // Activar el display de la decena        break;     }     case 3:{       digitalWrite(T2, LOW);  // Apagar el display de la decena       marca =0;       break;     }   } }    /************************************************************************   Matriz bidimensional para activar los segmentos del display **************************************************************************/ void Muestra_Dato(unsigned char number){   unsigned char pin = 2;   for (unsigned char j=0; j < 7; j++) {    digitalWrite(pin, pgm_read_byte(&num_array[number][j]));    pin++;   } }     /* ******** ISR del Timer 1 por desborde **************   *  Determina la velocidad a la cual se mostrará el    *  valor de la unidad y la decena.  ******************************************************/ ISR(TIMER1_OVF_vect){   TCNT1 = 65000;    // 5,7 Milisegundos   marca++;          // Apuntador para activar los transistores     Multiplexador();  // LLama a la funcion para mostrar los datos }     /************************************************************************   Escala el valor del conversor a un valor entre 0 y 50 **************************************************************************/  long map(long x, long in_min, long in_max, long out_min, long out_max){   return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
 

En los meses que el sistema lleva funcionando los resultados han sido impecables y las palomas finalmente decidieron buscar un lugar mas tranquilo donde construir su nido :)


 

Cuando se programa la placa Raspberry Pi Pico con Micropython el proceso de actualizar el código en memoria Flash  resulta muy cómodo, como el interprete ya esta cargado en memoria solo conectamos el cable USB y se actualiza el nuevo programa tantas veces como sea necesario o actualizaciones tengamos del código.

Sin embargo cuando trabajamos en C/C++ la mecánica para actualizar los programas en Flash es un poco diferente teniendo que desconectar el cable USB, presionar el boton BOOTSEL y en simultaneo conectar nuevamente el cable USB.
El tema de tener que conectar/desconectar el cable USB me parecía molesto y me puse a investigar la forma de eliminar la necesidad de tener que conectar y desconectar el cable USB en cada re-programación de la Flash. En mi caso tengo montada la placa en un proto-board con alimentación de 5 voltios, esta placa es donde ensamblo los prototipos que luego son programados en la placa definitiva esto es importante porque la placa no debe recibir alimentación por el cable USB, solo el cable GND deberá estar conectado entre la computadora y la placa pico.
Para no tener que desconectar el cable USB del computador he construido el siguiente circuito electrónico que toma señal del punto marcado como TP6 en la placa Pico, cuando se oprime el botón BOOTSEL se dispara un temporizador que corta la energía de la placa durante un par de segundos, la computadora entonces  "entiende" que se desconecto el cable USB y se volvió a conectar luego de unos segundos y la placa pasa a modo programación.

Es decir que solo con actuar sobre el botón BOOTSEL ya es suficiente y no es necesario remover el cable USB en cada actualización de Flash.

Como se ve en el diagrama de la placa Pico, el botón BOOTSEL cambia el estado del pin CS de la memoria Flash en el mismo momento que el cable USB es removido y vuelto a conectar al computador conectando y desconectado la alimentación de la placa Pico y dejando la memoria lista para recibir el nuevo programa Flash.
Obviamente que para que esto funcione la placa Pico no debe recibir alimentación por el USB desde el computador pero si compartir el GND. En mi caso y como ya lo tenía utilicé un pequeño relay de 5 voltios para desconectar/conectar la alimentación de la placa Pico y para eliminar la alimentación por el cable USB, prolijamente abrí un cable USB y corte el cable que trae los 5 voltios.
El sistema funciona perfecto y ya no tengo que conectar y desconectar el cable USB cada vez que actualizo el código en C++ en la memoria Flash de Pico.


 

Medición de Temperatura y Humedad con Arduino.

 Uno de mis pasatiempos es el cultivo de plantas tropicales, hortalizas y hongos en ambientes controlados y conocer los valores de temperatura y humedad ambientales resultan indispensables para conocer las condiciones en que los cultivos se están desarrollando. 
Fue entonces que construí este simple medidor basado en un DHT22 conectado a un Arduino Nano. Para mejorar la visualización utilicé una pantalla gráfica JL12864G como se aprecia en la siguiente imagen.

El desarrollo original no pretendía construir un dispositivo elegante si mas bien funcional y práctico que pudiera mover a cualquier parte del vivero o al espacio de cultivo con bancales o cajones de madera.
El código para Arduino es muy simple, el sensor DHT22 conectado al INT0 de la placa Arduino Nano y la pantalla a los pines 8,9,10,18 y 19.

/****************************************************************
* Programa ejemplo para el control de una pantalla JLX12864G.
* Mide temperatura y humedad con sensor DHT22.

* Placa Arduino: ARDUINO NANO
* Arduino IDE con Linux Ubuntu
*
* Por: Daniel Schmidt.
* ***************************************************************/
#include "U8glib.h"
#include <DHT.h>
#include <DHT_U.h>
#include <avr/wdt.h>
 
U8GLIB_NHD_C12864 u8g(19, 18, 8, 10, 9);// Arduino NANO PB0, PB1, PB2, A5 (SCL) A4 (SDA)
 
/*---------------------------------------------------------------------------
 | JLX12864G-086 (Graphic LCD 128x64)                                        |
 |---------------------------------------------------------------------------|
 | Pin Connect :                                                             |
 |          CS : 8         VDD : 3v3                                         |
 |         RST : 9         VSS : GND                                         |
 |          RS : 10       LEDA : 5v                                          |
 | SPI:    SDA : 11                                                          |
 | SPI:    SCK : 13                                                          |
  ---------------------------------------------------------------------------*/
#define DHTTYPE DHT22      // Tipo de sensor
const int DHTPin = 2;       // Pin del sensor (PD2_INT0)
DHT dht(DHTPin, DHTTYPE);   // Instancia del sensor
// Variables del programa
static char Temperatura[5]="";
static char Humedad[5]="";
 
void Mostrar(void) {
  wdt_reset(); // Borra el contador del perro guardián
  u8g.setFont(u8g_font_10x20r);
  u8g.drawStr( 7, 15, "Temperatura");
  u8g.setFont(u8g_font_8x13r);
  u8g.drawStr( 16, 58, "Humedad ");
  u8g.drawHLine(0,0, 128);    // Linea horizontal superior
  u8g.drawHLine(0,63, 128);   // Linea horizontal inferior
  u8g.drawVLine(0, 1, 64);    // Linea vertical izquierda
  u8g.drawVLine(127, 1, 64);  // Linea vertical derecha
  u8g.setFont(u8g_font_osb21);
  u8g.drawStr( 40, 43, Temperatura);
  u8g.setFont(u8g_font_8x13r);
  u8g.drawStr( 75, 58, Humedad);
  u8g.setFont(u8g_font_8x13r);
  u8g.drawStr( 110, 58, "%");
}
 
void setup(void) {
  u8g.setContrast(0); // Configura el contraste
  u8g.setRot180();    // Rota la pantalla (si fuera necesario)
  dht.begin();	      // Inicia la Electrónica del sensor
  wdt_disable();      
  wdt_enable(WDTO_8S);// Ajusta el perro guardián a 8 segundos
}
 
void loop(void) {
  u8g.firstPage();  // Muestra la pagina principal
  do {
    Mostrar();
  } 
 while( u8g.nextPage() );
  Medir();       // Obtiene datos del sensor
  delay(3000);
  wdt_reset(); // Borra el contador del WD
}
void Medir(){
 wdt_reset(); // Borra el contador del WD
 float t = dht.readTemperature(); // Lee sensor temperatura
 float h = dht.readHumidity();  // Lee sensor humedad
 
  if (isnan(h) || isnan(t)) { // Verifica si error de lectura
              Serial.println("ERROR!"); 
              }
            else{ // No hay error, procesa los datos
              
   dtostrf(t, 4, 1, Temperatura); // Procesa la temperatura 
   dtostrf(h, 4, 1, Humedad);     // Procesa la humedad
   }
}

 

 

El verano está próximo y con los calores llegan los problemas con la presión en la red de agua y ya sea que tengamos una cisterna a nivel del suelo o elevada sobre el techo de la vivienda siempre es útil saber cuanta agua tiene el depósito.
El ejemplo propuesto mide la cantidad de agua disponible y envía un mensaje al móvil mediante una aplicación escrita para el sistema Android.

El sistema es muy sencillo de construir como se puede ver en el diagrama electrónico. Usando como base un procesador Arduino, un Bluetooth HC-06 y un circuito integrado SN7404N. 
El gran problema que presentan los sistema en base a electrodos es la descomposición de los mismos por efectos de la electrolisis. El trabajo propuesto corrige esto energizando el electrodo que lleva el potencial a los electrodos sensores durante unos mili-segundos por lo tanto los electrodos están todo el tiempo sin potencial. 

El SN7404N oficia como interfaz para llevar la señal eléctrica al Arduino, una señal que se envía por el pin 19 de Arduino cada vez que se piden datos se encarga de enviar potencial en un conductor común que energiza el sensor.
El funcionamiento es muy simple, se envía un potencial de +12 voltios por un conductor común y según en que pin del sensor se recoja señal será la cantidad de agua disponible en la cisterna.
Para el sensor de medición se utilizó un trozo de caño de plástico rectangular, en el interior corre el común con la señal que sale del pin 19 y en unos orificios se se colocan los cables sensores de tal forma que queden próximos al cable común pero sin posibilidad de tocarse entre si y como está sumergido el contacto lo hace el agua.

En la imagen anterior se puede ver el proceso de armado del sensor que finalmente fue pintado para darle seguridad de que nada se desprenda en el tanque.
Lo ideal sería ensamblar el sensor usando varas de acero inoxidable de 3 mm que tienen un costo razonable, en la siguiente imagen se puede ver el sensor ensamblado con acero inoxidable.

El largo del tubo con los sensores dependerá de la profundidad del tanque, en el ejemplo que se encuentra funcionando el tanque tiene capacidad para 1000 litros de agua y el tubo con los sensores tiene 1,20 mts, pero esto depende de la geometría del tanque.
Otro detalle interesante que se puede ver en el código es que el Arduino permanece en reposo en modo bajo consumo incluso con su CPU dormida.
Esto si bien tiene como resultado un consumo muy bajo para alimentar el sistema con baterías, genera un problema puesto que en ese nivel de inactividad y con la CPU dormida la única forma de activar el sistema es con una interrupción, para esto se programa una interrupción por flanco de bajada en el pin 2 y se conecta este pin con el pin de recepción de tal forma que cuando llega un dato desde el Bluetooth este pin es puesto a nivel bajo el tiempo del bit de inicio de la trama serial. El sistema se despierta, toma la lectura del nivel, envía el dato y retorna al modo bajo consumo. También se podría usar solo la interrupción del puerto UART sin embargo de la forma propuesta se asegura la correcta recepción de los datos. 
El siguiente es el código completo del ejemplo.

/*************************************************************
 Monitor de nivel de cisterna de agua por medio de Bluetooth
 La sonda detectora trabaja con 12 voltios por lo que se usa
 un SN7404N como interfaz acoplada a un divisor resistivo para
 adecuar los niveles lógicos que se presentan al Arduino.
 
 Autor: Daniel Schmidt
          Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.

 
**************************************************************/
#include <avr/sleep.h>
#include <SoftwareSerial.h>
 
// Pines de los sensores de nivel
#define S1 3
#define S2 4
#define S3 5
#define S4 6
#define S5 7
#define led 13
#define comun_5 19  // Pin que corresponde al ADC5
volatile unsigned char bandera =0;
unsigned char control =0;
 
SoftwareSerial mySerial(11, 12); // RX al TX, TX al RX
 
void Medir();
 
void ISR_Despertar(){
  bandera =1;
}
 
void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led,LOW );
  // --- Indicadores de Nivel ------
  pinMode(comun_5, OUTPUT); // Pin que activa los 12 Voltios
  digitalWrite(comun_5,LOW );
  
  //----- Sensores de Entrada --------
  pinMode(S1,INPUT_PULLUP);
  pinMode(S2,INPUT_PULLUP);
  pinMode(S3,INPUT_PULLUP);
  pinMode(S4,INPUT_PULLUP);
  pinMode(S5,INPUT_PULLUP);
  
  Serial.begin(9600);
  mySerial.begin(9600);
  delay(2000); // Esperar electrónica OK
}
 
void loop() {
     sleep_enable();
     attachInterrupt( 0, ISR_Despertar, LOW); 
     set_sleep_mode(SLEEP_MODE_PWR_DOWN);
     sleep_cpu();
 
// Cuando se despierta ejecuta la siguiente linea !!!     
     delay(2000);    
     Medir();
  }
 
/************************************************************************************************
 * Esta es la función lee los sensores y envía la información al Bluetooth
 * 1- Conecta energía para los sensores.
 * 2- Lee el nivel de agua y envía una trama por Bluetooth.
 * 3- Si el sensor no lee ningún nivel envía cartel -TANQUE VACIO-
 ************************************************************************************************/
 
void Medir(){
  
  sleep_disable();
  if(bandera == 1){
  digitalWrite(comun_5,HIGH ); // Envía 12 voltios al al sensor
  delay(2000); // Esperar para estabilizar el sensor con los 12V.
  
// -------------------------------- Evalúa los niveles en los electrodos --------------------------------------
  
  if (digitalRead(S1) == LOW & digitalRead(S2) == LOW & digitalRead(S3) == LOW & digitalRead(S4) == LOW & digitalRead(S5) == LOW) {
    mySerial.print("TANQUE LLENO!!");
    control++;
  }
  if (digitalRead(S1) == HIGH & digitalRead(S2) == LOW & digitalRead(S3) == LOW & digitalRead(S4) == LOW & digitalRead(S5) == LOW) {
    mySerial.print("3/4 TANQUE CON AGUA");
    control++;
  }
  if (digitalRead(S1) == HIGH & digitalRead(S2) == HIGH & digitalRead(S3) == LOW & digitalRead(S4) == LOW & digitalRead(S5) == LOW) {
    mySerial.print("1/2 TANQUE CON AGUA");
    control++;
  }
  if (digitalRead(S1) == HIGH & digitalRead(S2) == HIGH & digitalRead(S3) == HIGH & digitalRead(S4) == LOW & digitalRead(S5) == LOW){
    mySerial.print("1/4 TANQUE CON AGUA");
    control++;
 }
  if (digitalRead(S1) == HIGH & digitalRead(S2) == HIGH & digitalRead(S3) == HIGH & digitalRead(S4) == HIGH & digitalRead(S5) == LOW) {
    mySerial.print("TANQUE VACIO!!");
    control++;
  }
 
//------------------------------------------------------------------------------------------------------------------------- 
 
  if(control == 0){ // Control tiene que se > a 0 si no lo es el sensor tiene un error!!!
     mySerial.print("-SONDA ERROR-");
     control =0;
   }
  
   digitalWrite(comun_5,LOW ); // Asegura que los 12 voltios de los sensores estén apagados
   bandera = 0;                 // Borra la bandera de interrupción
   control =0;
   }
 } // Cuando termina en esta linea regresa al bucle principal y se prepara para pasar a sleep nuevamente

El ejemplo se encuentra en funcionamiento desde hace varios meses y sin presentar problemas.

La aplicación Cisterna.apk para instalar en Android se puede solicitar por correo electrónico a Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo. .

El presente ejemplo ha sido extraído de nuestro libro  "Hágalo Usted Mismo" .