Programación del Arduino

PROGRAMACIÓN

Muy bien, ahora vamos a empezar con la programación de nuestro Arduino.
Para empezar vamos a realizar un montaje básico que nos permitirá poner en marcha nuestro proyecto sin demasiadas complicaciones. Yo os recomiendo que montéis los componentes sobre una "protboard", ya que así podréis probar los circuitos sin necesidad de soldar nada, de esta manera ajustaréis la barrera de IR, y probaréis que todo funciona antes del montaje definitivo.

El programa que os pongo a continuación está pensado para hacer las primeras pruebas. Funciona ejecutando una secuencia de llamadas a las distintas funciones que necesitamos, y esta secuencia la podéis ver dentro del "void loop()", donde se llamará a las funciones y se enviará al "monitor serial" unos mensajes que nos permitirán observar el avance del programa función a función. El "monitor serial" está en la pestaña "herramientas" de la consola de programación del Arduino, y debéis abrirla antes de pulsar el botón de Inicio.


La primera llamada es a "esperaPulsacion()", aquí el programa se detendrá esperando a que pulsemos el botón, cuando hayamos pulsado retornará el control a "void loop()"donde se enviará al "monitor serial" el mensaje "pulsado".

La segunda llamada es a "DisparadorCamara()", aquí se activa el disparador de la cámara. Si aún no hemos hecho el cable no pasará nada, solo que debemos disparar manualmente. (si utilizamos este cable y la electroválvula basta un tiempo de exposición de 1 seg. o algo menos, mientras que si lo hacemos todo manual podemos necesitar un tiempo de exposición de 3 o 4 seg.). En cualquier caso la función devolverá el control a "void loop()", y se enviará el mensaje "disparada cámara".

La tercera llamada es a "activaValvula()", aquí se suelta una gota de agua. Si no tenemos la electroválvula no ocurrirá nada, solo que deberemos soltar la gota manualmente. De momento solo se suelta una gota, cuando tengamos el programa completado se podrán soltar mas de una. En cualquier caso la función devolverá el control a "void loop()", y se enviará el mensaje "soltada gota".

La cuarta llamada es a "controlaInfrarrojos()", aquí el programa se detendrá hasta que algo corte la Barrera de Infrarrojos. Entonces se devolverá el control a "void loop()", y se enviará el mensaje "soltada gota".

La quinta y última llamada es a "Dispara_Flash()", aquí se activará el circuito de disparo del flash, con un tiempo de retardo dependiente del "potenciómetro de reatardo". Si no hemos puesto el potenciómetro, esperará unos 400 mseg (valor que mide el Pin A3 cuando no tiene nada conectado dividido por 2).
He utilizado para esta función el pin digital 13 porque tiene un led incorporado en la placa Arduino. De esta manera podemos saber si Arduino ha disparado el flash con solo observar dicho led, aunque no tengamos flash conectado.

Resumiendo, para empezar solo necesitamos los componentes para la Barrera de Infrarrojos, y un pulsador de Inicio. Cuando carguemos el programa, abriremos el "monitor serial", y veremos que Arduino quedará a la espera de que pulsemos el botón de Inicio. Una vez pulsado nos aparecerán los mensajes de "pulsado", "disparada cámara", y "soltada gota" (aunque no haya nada conectado), y pasará a vigilar la Barrera IR. 

No necesitamos tener construido el circuito del flash para estas pruebas, ya que se puede monitorizar el disparo del flash por la luz del led incorporado en la placa junto al Pin 13.
Los led deben estar metidos en unos tubitos negros para que no les entre luz del exterior, solo debe llegarle al receptor la señal del emisor.

Y ahora a cargar el programa y a jugar.

// PRIMEROS_PASOS_V2

//DECLARACION DE VARIABLES GENERAL
int retardo=100;                            // Tiempo entre corte IR y disparo flash

//PINES ANALOGICOS
const int analogPinRetardo = A3;    // Potenciómetro de retardo de Flash

//PINES DIGITALES
const int inPinBotonInicio = 10;     // pin Botón Inicio proceso
const int pinAlimentaEmisor=12;    // pin alimentación Emisor
const int pinReceptorIR = 2;          // pin receptor Infrarrojos
const int pinDisparaValvula=11;      //pin activación de electroválvula
const int pinDisparoFlash = 13;      // pin de Disparo del Flash 
const int pinDisparadorCamara = 9;// pin disparador cámara

void setup()
{
  Serial.begin(9600);
  pinMode(inPinBotonInicio, INPUT);
  pinMode(pinAlimentaEmisor,OUTPUT);
  pinMode(pinDisparaValvula,OUTPUT);
  pinMode(pinDisparoFlash, OUTPUT);
  pinMode(pinDisparadorCamara,OUTPUT);
  pinMode(pinReceptorIR, INPUT);
  digitalWrite(pinDisparoFlash,LOW);
}
  
void loop()
{  
  EsperaPulsacion();                         //llamada a función
    Serial.println("pulsado");
  DisparadorCamara();                     //llamada a función
     Serial.println("disparada cámara");
  ActivaValvula();                            //llamada a función
    Serial.println("soltada gota");
  ControlaInfrarrojos();                    //llamada a función
    Serial.println("cortada barrera");
  Dispara_Flash();                           //llamada a función
    Serial.println("flash disparado");
    Serial.print("retardo= ");
    Serial.println(retardo);
  }

void EsperaPulsacion(){                // ESPERA A QUE SE PULSE EL BOTON DE INICIO //
  int botonpulsado=0;

  while (botonpulsado==LOW){
      botonpulsado=digitalRead(inPinBotonInicio);
      }

     retardo = analogRead(analogPinRetardo);
     digitalWrite(pinAlimentaEmisor, HIGH);     

void DisparadorCamara(){           // ACTÚA EL DISPARADOR DE LA CAMARA //

  digitalWrite(pinDisparadorCamara, HIGH); //si no hay cable, esto lo haremos manualmente
  delay(100);
  digitalWrite(pinDisparadorCamara, LOW);
}

void ActivaValvula(){                  // ACTIVA VÁLVULA PARA SOLTAR GOTA //

digitalWrite(pinDisparaValvula, HIGH);  //si no hay válvula la soltaremos manualmente
delay(20);
digitalWrite(pinDisparaValvula, LOW);
}

void ControlaInfrarrojos(){           // CONTROLA LA BARRERA DE INFRARROJOS//

   while (digitalRead(pinReceptorIR)==LOW){      
      }
   digitalWrite(pinAlimentaEmisor, LOW);
}

void Dispara_Flash(){                  // DISPARA EL FLASH //  
  delay(retardo/2);
  digitalWrite(pinDisparoFlash, HIGH);
  delay(10);
  digitalWrite(pinDisparoFlash,LOW);
  }

Para comprobar el funcionamiento he realizado el montaje en "protboard" con el Arduino, la Barrera de infrarrojos, el Botón de Inicio, y el Potenciometro de Retardo. He pegado este código en la consola de programación  v1.0.1 de mi Arduino y he comprobado que todo está correcto.

Si queréis anular el Botón de Inicio, bien porque no lo tengáis, o bien porque preferís no tener que pulsarlo cada vez para activar la barrera, podéis modificar estas tres lineas de la función "void esperaPulsacion()":

while (botonpulsado==LOW){
botonpulsado=digitalRead(inPinBotonInicio);
}

Les añadís delante //, dejándolas de esta manera:

//while (botonpulsado==LOW){
//botonpulsado=digitalRead(inPinBotonInicio);
//}

Así el programa no se detendrá esperando que pulséis el botón, y cada vez que se corte la barrera se disparará el Flash.

Si habéis llegado hasta aquí, ya estáis preparados para afrontar el montaje completo.


Y AHORA VAMOS CON EL PROGRAMA DEFINITIVO

Yo según mi experiencia os propongo un montaje final en el que dispondremos de una pantalla LCD (1 x IIC I2C 2004 204 20 x 4 Character LCD Display Module Yellow Green (SKU107152)  que cuesta unos 6 Euros en Banggood. La colocaremos en la parte superior de la caja.
Podéis ver el esquema de conexión en la página principal de este blog.

Pondremos 3 pulsadores (microinterruptores) también en la parte superior de la caja. Uno será el botón de Inicio, otro para cambiar el cursor de línea en la pantalla, y otro servirá de embrague para los potenciómetros (luego lo explico). El esquema de conexión es idéntico para los 3 pulsadores (excepto el pin digital al que van unidos).

Y finalmente 2 potenciómetros  en el frontal de la caja con los que ajustaremos las variables cuando estemos trabajando. Estos potenciómetros también se conectan con el mismo esquema pero a distinto pin analógico.

La pantalla estará dividida en dos partes (dcha. e Izda.). Las variables de la Izda. se cambiarán girando el pot. de la Izda, y las de la Dcha. se cambiarán girando el pot de la Dcha. Así solo tenemos que seleccionar una línea y podremos acceder a las dos variables de ella con los potenciómetros.


Cuando el cursor esté en la primera línea, moviendo el pot. de la Izda. se podrá cambiar el número de gotas (1 ó 2). Cuando el cursor está en la segunda línea, podremos variar el tamaño de las gotas con los potenciómetros. En la tercera línea vemos el Retardo del flash (ajustable con el pot.Izdo.), y el tiempo entre gotas (ajustable con el pot. Dcho.) . En la cuarta línea irán saliendo indicaciones sobre el estado del proceso.

El botón de embrague nos permitirá reposicionar los potenciómetros cuando nos llegan a tope y no podemos girar mas.

Este es el montaje que yo he elegido según mi experiencia de muchas horas haciendo fotos de gotas, el cursor se posicionará por defecto en la tercera línea y nos permitirá ir cambiando las dos variables mas utilizadas para conseguir los choques de gotas.

Cuando apretamos el botón de Inicio se apaga la luz de la pantalla para no afectar a la fotografía, después de disparar el flash se volverá a encender para que podamos seguir con los ajustes. 

------------------------------------------------------------------------------

PROGRAMA DEFINITIVO

El programa que os pongo a continuación está hecho para los circuitos que se han publicado en la página principal del blog y que podeis ver resumidos en la página "Esquema General".

// Arduino_Gotas_V190915

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// la dirección 0x3F puede cambiar en vuestra pantalla. Si no va probad con 0x27 //

//DECLARACION DE VARIABLES GENERAL
int retardoFlash=100;     
int entregotas=100;
unsigned long momentoCorte=0;
int PosCol=0;
int PosFila=2;
int tamgota1=20;
int tamgota2=20;
int numdegotas=2;

//PINES ANALOGICOS
const int analogPinPotDcha = A3;    // Potenciómetro izquierda
const int analogPinPotIzda = A2;    // Potenciómetro derecha

//PINES DIGITALES
const int inPinBotonInicio = 10;        // pin Botón1 Inicio proceso
const int inPinBotonSaltoLinea = 8;     // pin Botón2 cambio linea pantalla
const int inPinBotonEmbrague = 7;   // pin Botón3 para embragar potenciómetros
const int pinAlimentaEmisor=12;    // pin alimentación Emisor
const int pinReceptorIR = 2;          // pin receptor Infrarrojos
const int pinDisparaValvula=11;      //pin de activación válvula
const int pinDisparoFlash = 13;      // pin de Disparo del Flash
const int pinDisparadorCamara = 9;   // pin disparador cámara
const int pinPilotoFlash = 6;        // para poner un piloto del flash en la caja
void setup()
{
  Serial.begin(9600);
  pinMode(inPinBotonInicio, INPUT);
  pinMode(inPinBotonSaltoLinea, INPUT);
  pinMode(inPinBotonEmbrague, INPUT);
  pinMode(pinAlimentaEmisor,OUTPUT);
  pinMode(pinDisparaValvula,OUTPUT);
  pinMode(pinDisparoFlash, OUTPUT);
  pinMode(pinDisparadorCamara,OUTPUT);
  pinMode(pinReceptorIR, INPUT);
  digitalWrite(pinDisparoFlash,LOW);
  digitalWrite(pinAlimentaEmisor, HIGH);
  attachInterrupt(0,CorteBarrera,FALLING);
 
  lcd.begin(20,4);                      // initializa el lcd
  lcd.backlight();
  lcd.setBacklight(HIGH); 
 
  lcd.clear();
  Serial.println("Hola");
  lcd.print("Version...V190915");    //++++++++++++++++++
  espera(2000);
  lcd.clear(); 
}
 
void loop()
{
  EsperaPulsacion();                         //llamada a función
    Serial.println("pulsado");
  DisparadorCamara();                     //llamada a función
     Serial.println("disparada cámara");
  ActivaValvula();                            //llamada a función
    Serial.println("soltada gota");
  ControlaInfrarrojos();                    //llamada a función
    //Serial.println("cortada barrera");
  Dispara_Flash();                           //llamada a función
    Serial.println("flash disparado");
    Serial.print("retardo= ");
    Serial.println(retardoFlash);
   
  }
void EsperaPulsacion(){        // ESPERA A QUE SE PULSE EL BOTON DE INICIO //
  lcd.setCursor(0,4);
  lcd.print("                    "); 
  momentoCorte=0;
  escribe_valor();
  digitalWrite(pinAlimentaEmisor, HIGH);
  espera(1000);
  }
void DisparadorCamara(){           // ACTÚA EL DISPARADOR DE LA CAMARA //
  lcd.setBacklight(LOW);
  digitalWrite(pinDisparadorCamara, HIGH); //si no hay cable, esto lo haremos manualmente
  espera(100);
  digitalWrite(pinDisparadorCamara, LOW);
  lcd.setCursor(0,4);
  lcd.print("Disp ");
}
void ActivaValvula(){                  // ACTIVA VÁLVULA PARA SOLTAR GOTA //
digitalWrite(pinDisparaValvula, HIGH);  //si no hay válvula la soltaremos manualmente
espera(tamgota1);
digitalWrite(pinDisparaValvula, LOW);
if (numdegotas==2) {
espera(entregotas);
digitalWrite(pinDisparaValvula, HIGH);  //si no hay válvula la soltaremos manualmente
espera(tamgota2);
digitalWrite(pinDisparaValvula, LOW);
}
  lcd.print("Gota ");
}
void ControlaInfrarrojos(){           // CONTROLA LA BARRERA DE INFRARROJOS//
  while(momentoCorte==0){
    espera(1); 
  }
   lcd.print("Cor ");
}
void Dispara_Flash(){                  // DISPARA EL FLASH  
  int diferencia;
  long tiempo;
  tiempo=millis();
  diferencia=tiempo-momentoCorte;
  int tiempoquefalta=retardoFlash-diferencia;
  if (tiempoquefalta<1){
    tiempoquefalta=0;
  }
  espera(tiempoquefalta);
  digitalWrite(pinDisparoFlash, HIGH);
  espera(10);
  digitalWrite(pinDisparoFlash,LOW);
  digitalWrite(pinPilotoFlash, HIGH);
  espera(10);
  digitalWrite(pinPilotoFlash,LOW);
  espera(1000);
  lcd.print("Fl");
    lcd.setBacklight(HIGH);
    espera(1000);   
  }
 
void CorteBarrera(){           // ESTABLECE EL MOMENTO DE CORTE
if (momentoCorte==0){
  momentoCorte=millis(); 
  }
}
int espera(int tiempoEspera){          //  FUNCION ESPERA
  long tiempoInicio;
  tiempoInicio=millis();
  while (millis()<tiempoInicio+tiempoEspera){   
      }
  }
void escribe_valor(){              // ACTUALIZA VARIABLES Y PANTALLA
int embragado;
int LecturaIzda;
int LecturaDcha;
int antLecturaIzda;
int antLecturaDcha;
int iniciopulsado;
int Dif_tamgota1;
int Dif_tamgota2;
int Dif_entregotas;
int Dif_retardoFlash;
lcd.blink();
lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("NumGotas ");
  lcd.print(numdegotas);
  lcd.setCursor(0,1);
  lcd.print("Gota1 ");
  lcd.print(tamgota1);
  lcd.setCursor(10,1);
  lcd.print("Gota2  ");
  lcd.print(tamgota2);
  lcd.setCursor(0,2);
  lcd.print("Rflas ");
  lcd.print(retardoFlash);
  lcd.setCursor(10,2);
  lcd.print("Entreg ");
  lcd.print(entregotas);
  PosCol=0;
  PosFila=2;
  lcd.setCursor(PosCol,PosFila);
  espera(1000);
 iniciopulsado=digitalRead(inPinBotonInicio);
  while (iniciopulsado==LOW){
  
  antLecturaIzda=analogRead(analogPinPotIzda)/5;
  antLecturaDcha=analogRead(analogPinPotDcha)/5;
  espera (100);
    if (PosFila==0){
      LecturaIzda=analogRead(analogPinPotIzda)/5;
      if(LecturaIzda>antLecturaIzda+5){
        numdegotas=2;
     }
      if(LecturaIzda<antLecturaIzda-5){
        numdegotas=1;
    }
      lcd.setCursor(9,0);
      lcd.print("   ");
      lcd.setCursor(9,0);
      lcd.print(numdegotas);
      lcd.setCursor(0,0);
      espera(30);
  } 
   
    if (PosFila==1){
      LecturaIzda=analogRead(analogPinPotIzda)/5;
      if(LecturaIzda>antLecturaIzda){
        Dif_tamgota1=LecturaIzda-antLecturaIzda;
        tamgota1=tamgota1 + Dif_tamgota1;
      }
      if(LecturaIzda<antLecturaIzda){
        Dif_tamgota1=antLecturaIzda-LecturaIzda;
        tamgota1=tamgota1 - Dif_tamgota1;
    if(tamgota1<1) tamgota1=1; 
    }
      lcd.setCursor(6,1);
      lcd.print("   ");
      lcd.setCursor(6,1);
      lcd.print(tamgota1);
      lcd.setCursor(0,1);
      espera(30);
     
      LecturaDcha=analogRead(analogPinPotDcha)/5;
      if(LecturaDcha>antLecturaDcha){
        Dif_tamgota2=LecturaDcha-antLecturaDcha;
        tamgota2=tamgota2 + Dif_tamgota2;
      }
      if(LecturaDcha<antLecturaDcha){
        Dif_tamgota2=antLecturaDcha-LecturaDcha;
        tamgota2=tamgota2 - Dif_tamgota2;
        if(tamgota2<1) tamgota2=1;
      }
      lcd.setCursor(16,1);
      lcd.print("    ");
      lcd.setCursor(17,1); 
      lcd.print(tamgota2);
      lcd.setCursor(0,1);
      espera(30);     
    }     
      if (PosFila==2){       
      LecturaIzda=analogRead(analogPinPotIzda)/5;
       if(LecturaIzda>antLecturaIzda){
        Dif_retardoFlash=LecturaIzda-antLecturaIzda;
        retardoFlash=retardoFlash + Dif_retardoFlash;
      }
      if(LecturaIzda<antLecturaIzda){
        Dif_retardoFlash=antLecturaIzda-LecturaIzda;
        retardoFlash=retardoFlash - Dif_retardoFlash;
    if(retardoFlash<0) retardoFlash=0; 
    }
      lcd.setCursor(6,2);
      lcd.print("   ");
      lcd.setCursor(6,2);
      lcd.print(retardoFlash);
      lcd.setCursor(0,2);
      espera(30);     
      LecturaDcha=analogRead(analogPinPotDcha)/5;
      if(LecturaDcha>antLecturaDcha){
        Dif_entregotas=LecturaDcha-antLecturaDcha;
        entregotas=entregotas + Dif_entregotas;
      }
      if(LecturaDcha<antLecturaDcha){
        Dif_entregotas=antLecturaDcha-LecturaDcha;
        entregotas=entregotas - Dif_entregotas;
    if(entregotas<0) entregotas=0; 
    }
      lcd.setCursor(16,2);
      lcd.print("    ");
      lcd.setCursor(17,2); 
      lcd.print(entregotas);
      //lcd.print(33);
      lcd.setCursor(0,2);
      espera(30);
    }
     embragado=digitalRead(inPinBotonEmbrague);
    while (embragado==HIGH) {    
      antLecturaIzda=analogRead(analogPinPotIzda)/5;
      antLecturaDcha=analogRead(analogPinPotDcha)/5;
      embragado=digitalRead(inPinBotonEmbrague);
    }
  
if (digitalRead(inPinBotonSaltoLinea)==HIGH) {
  PosFila=PosFila+1;
  if (PosFila>3){
    PosFila=0; }
    lcd.setCursor(PosCol,PosFila);
    espera(300);
}
 iniciopulsado=digitalRead(inPinBotonInicio);   
}
}

Como habréis observado he cambiado algunas cosas respecto al programa anterior. en primer lugar ahora vamos a emplear una Interrupción Externa (AttachInterrupt) para determinar el momento de corte de la Barrera de Infrarrojos, esto lo hago porque si soltamos 2 gotas podría coincidir el Corte de Barrera durante la emisión de la segunda gota, y  utilizando AttachInterrupt siempre captaremos el momento de corte.

Otro cambio que he realizado es el uso de una función "espera()" para sustituir a los "delay()". Esto es para evitar los tiempos en los que el microprocesador se detiene, con la función "espera()" realizamos las pausas que deseamos pero sin detener el trabajo del micro.






2 comentarios:

  1. Tengo un problema no me funciona el programa por que dice qe le falta #include he mirado por todas partes y no encuentro ninguna solucion, me podeis hechar una mano

    ResponderEliminar
  2. Creo que te pude faltar alguna de las tres librerías de las tres primeras líneas del programa.
    Yo no se programación pero a mi me funciona perfectamente. Copié el programa e incluso modifiqué alguna línea. De todas formas, el autor del blog Juan Carlos Bravo creo que no tendrá ningún problema en ayudarte. Conmigo lo ha echo varias veces.

    Saludos José Santiago

    ResponderEliminar