Mostrando entradas con la etiqueta ejemplo. Mostrar todas las entradas
Mostrando entradas con la etiqueta ejemplo. Mostrar todas las entradas

lunes, 29 de junio de 2015

Arduino , Ethernet Shield y algo de HTML

Repasando la entrada anterior, me gustaría comentar algunos puntos que no se tocaron y que pueden resultar de interés.
El primero tiene que ver con el hardware del ejemplo. Hay mucha variedad de Ethernet Shields en el mercado. Os recomendé un par que son compatibles con el Arduino, hay muchas más, pero debéis fijaros que el CHIP que use sea el W5100 Ethernet controller IC , para evitar problemas de compatibilidad.

 El siguiente punto, también de hardware tiene que ver con el consumo de ese chip. Puede llegar a ser muy alto, y además de calentarse, y de qué manera, es necesario alimentar el ejemplo con una fuente de alimentación externa, pues vuestra conexión USB no dispone de la potencia necesaria. Si aún no lo habíais hecho, es un buen momento para hacerse con una fuente externa de 9 V para alimentar vuestro Arduino.
El último punto relacionado con el hardware,  tiene que ver con los pins 10,11,12 y 13 del Arduino. Estos pins se usan para la comunicación con la Ethenet shield, por lo que no podrán ser usados para otro fin cuando se use con esta ampliación.
El resto de puntos que me gustaría tratar, están relacionados con el código del sketch de ejemplo. Al final lo que conseguimos es convertir nuestro Arduino en un servidor web.  La página mostrada es de una sencillez máxima,(es un ejemplo “demo”)  y tampoco veréis grandes florituras en los ejemplos míos  que vendrán, pues mis conocimientos de HTML son básicos.
Pero me gustaría desarrollar un poco las líneas más básicas de código HTML para mostrar la información de una manera mínimamente inteligible.
Hasta ahora, en algún ejemplo como este, habíamos usado la instrucción serial.print(); para mostrar la información que queríamos en el Monitor Serial.
Sin embargo en este ejemplo usamos la instrucción :

client.println();

Entre los parantésis podemos escribir desde un texto entre comillas:

            client.print("analog input ");


O el valor de una variable cualquiera:

            client.print(sensorReading);


Salto de línea, mostrará el siguiente valor o texto en otra línea:

            client.println("<br />");      


Y dos líneas imprescindibles que marcan el inicio y el final de un código en HTML:

            client.println("<html>");


Y
          client.println("</html>");


Otra instrucción también interesante, es la que controla el tiempo de refresco de la página. En el ejemplo del día anterior era cada 5 segundos:

client.println("Refresh: 5"); // refresh the page automatically every 5 sec

Eso es todo de momento. Espero hayáis podido configurar vuestra Ethernet Shield y el router sin problemas, pues seguiremos avanzando en las próximas entradas en estos temas.

viernes, 22 de mayo de 2015

Termómetro diario ( II )

Sigamos con el ejemplo del día anterior. Después de completar en casa el ejemplo, el código tenía una complejidad considerable. Bueno, para ser más exactos, más que complejo empezaba a tener unas dimensiones considerables, y la programación tal y como la hemos visto hasta ahora, hacía muy complicado e ininteligible el código del programa.

Por lo que he decido hacer un bloque principal para el cuerpo del programa, y diferentes "subprogramas" que realizarán los cálculos necesarios , o las acciones complementarias que iremos describiendo.

Estos "subprogramas" reciben el nombre de funciones.

Uso de funciones con Arduino

Aunque pueda parecer algo nuevo, ya hemos usado funciones en nuestros sketches de Arduino, son las funciones void setup y void loop, que además son de uso obligatorio.

Las funciones personalizadas se han de declarar siempre después del void loop. A partir de aquí existen diferentes formas de trabajar según si la función debe devolver valores ( el resultado de una operación), o simplemente ejecutar una parte del código.

Mejor un ejemplo:


void setup() {
  Serial.begin(9600);
}

void loop()
{
  int a = 2;
  int b = 3;
  int c;

  c = FuncionMultiplicarNumeros(a, b); // C vale 6
  Serial.println(c);
  delay(500);
}

int FuncionMultiplicarNumeros(int x, int y) 
{
  int resultado;
  resultado = x * y;
  return resultado;
}







En este ejemplo, declaramos una función del tipo integer. Le pasamos dos valores a y b  , que queremos que multiplique. Para ello, dentro de la función definimos dos variables más, las variables x  e Y, que usaremos para realizar los cálculos, y que solo serán validos dentro de la función de multiplicar.
Una vez realizada la operación devolvemos el resultado con la función return

¿ Se entiende? No verdad, yo tampoco lo entendí a la primera, por lo que a veces es mejor coger lápiz y papel y dibujar el baile de variables. 

Algunas de las FAQ's que comúnmente surgen tras el ejemplo es, ¿para qué tantas variables para multiplicar dos números? Bien, si solo tengo que multiplicar dos números, hasta el uso de funciones es un poco exagerado, pero definir las variables dentro de la función me permite "mandarle" cualquier pareja de valores en cualquier punto del programa.
En codigos más complejos también sirve para tener un programa más estructurado y nos permite ir programando bloques. Incluso, si trabajaremos en equipo para miembro podría hacerse cargo de programar una función concreta.

Un uso más sencillo, usar las variables definidas en el cuerpo del programa

Algo así:







void setup() {
  Serial.begin(9600);
}

void loop()
{
  int a = 2;
  int b = 3;
  int c;

  c = FuncionMultiplicarNumeros(); // C vale 6
  Serial.println(c);
  delay(500);
}

int FuncionMultiplicarNumeros() 
{
 c = a * b;;
}


Obtendría el mismo resultado, pues usaría las variables que se han declarado de manera global, pero solo me permitiría multiplicar los valores a y b. De la primera manera, insisto me permitirá obtener el resultado de diferentes valores.

Aprovechad, para tomar un respiro, ir al baño o beber algo de líquido antes de seguir.

De vuelta ya, os voy a colocar el código completo del ejercicio. Tomaros un tiempo en ver que hace cada función y entender porque se llaman en cada momento.

También se podría hacer una función para leer las pulsaciones de los botones, pero eso lo dejo en vuestras manos.

Para que en cualquier momento me pueda ofrecer una temperatura media, mínima o máxima coherente, antes de nada, en el void setup, inicializo TODOS los valores de la matriz con la primera muestra de temperatura. Es sólo un criterio, y cualquier otro podría ser válido. No olvides cambiar en el bucle milllis el 1000 por 360000 para obtener las muestras cada hora.




#include <LiquidCrystal.h>

LiquidCrystal lcd(4, 5, 6, 7, 8, 9);

float tempactual = 0; //mostrara la temperatura actual
float tempmin = 0; // VAlor minimo obtenido
float tempmax = 0; // el maximo
float tempmedia = 0; // y el minimo
float sensor = 0; 
float voltaje = 0;

int boton1 = 2; // Pulsador de Reset en el pin 2
int boton2 = 3; // El de set o show en el pin 3
int pulsacion = 0; // Necesaria para ller estado del pulsador
int accion = 0; // Truco para mantenerme en el bucle de la pulsacion
int posicion = 0; // Indicador o puntero de la matriz de Temperatura
float temperatura; // Para almacenar temperatura
float tempdata [24]; //Array para almacenar las muestras
unsigned long tiempoentremuestras = 0; // necesarias para los intervalos de
unsigned long tiempomuestraanterior = 0;// tiempo

void setup() {

  Serial.begin(9600);
  lcd.begin(16, 2); // Dimensiones de la pantalla
  lcd.setCursor(0, 0);
  lcd.print("    Arduino    ");//Para mi autoestima
  lcd.setCursor(0, 1);
  lcd.print("*   Practico   *"); // Pero lo puedes cambiar ;)
  delay(3000);
  lcd.clear();
  pinMode (boton1, INPUT);
  pinMode (boton2, INPUT);
  Calculo_temperatura(); // Medimos la temperatura
  Reset_Temp(); // E iniciamos las variables con la primera muestra
  
}

void loop()

{

  tiempomuestraanterior = millis();
// PAra muestras horarias sustituir el 1000 por 360000

// Cogemos muestras y vamos rellenado el array con los valores

  if ( tiempomuestraanterior - tiempoentremuestras > 1000)
  {

    Calculo_temperatura ();
    tempdata[posicion] = temperatura;
    posicion = posicion + 1;
    tiempoentremuestras = tiempomuestraanterior;

  }

  if (posicion > 23)
  {
    posicion = 0;
  }
  
  // Mostramos en pantalla la temperatura actual
  
  show_temperatura();

  // Empezamos el bloque para leer los pulsadores
  
  pulsacion = digitalRead(boton2);

// SI pulsamos mostramos las ultimas 24 muestras
// y los valores calculados

  if ( pulsacion == HIGH)

  {
    pulsacion = 0;
    Calculo_Tmax_Tmin_Tmedia();// llamada a la funcion de calculos
    lcd.clear(); // clear LCD screen
    lcd.setCursor(0, 0);
    lcd.print("Las ultimas 24");
    lcd.setCursor(0, 1);
    lcd.print("muestras son:");
    delay(1000);
    for (int j = 0; j <= 23; j++)
    {
      lcd.clear(); //
      lcd.setCursor(0, 0);
      lcd.print("Muestra: ");
      lcd.print(j + 1);
      lcd.print("/24  ");
      lcd.setCursor(0, 1);
      lcd.print(tempdata[j], 2);
      lcd.print(" grados C");
      delay(500);
    }
    lcd.clear(); // clear LCD screen
    lcd.setCursor(0, 0);
    lcd.print("Tmin  Tmed  TMax");
    lcd.setCursor(0,1);
    lcd.print(tempmin,1);
    lcd.setCursor(6, 1);
    lcd.print(tempmedia,1);
    lcd.setCursor(12, 1);
    lcd.print(tempmax,1);
    delay (3000);
    lcd.clear();
  }

// Lectura del pulsador de Reset

  pulsacion = digitalRead(boton1);
  if (pulsacion == HIGH)
  {
    pulsacion = 0;
    accion = 0;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Reset min/max?");
    lcd.setCursor(0,1);
    lcd.print("1 = Yes, 2 = No");
    delay(500); // Tiempo para evitar rebotes
    while (accion == 0) // Aun no ha pasado nada
    {
      if (digitalRead(boton1)==HIGH)  // Ha pulsado si?
      {
        Reset_Temp();
        accion = 1;// Ha pasado algo y por tanto puedo salir del loop
        delay(500); // Tiempo para evitar rebotes
      }
      if (digitalRead(boton2)==HIGH) // Ha pulsado no?
      {
        accion = 1; // Ha pasado algo y por tanto puedo salir del loop
        delay(500); // Tiempo para evitar rebotes
      }

    } 
    lcd.clear();
  }




}

void Calculo_temperatura()

{

  sensor = analogRead(2);       // TMP36 sensor  pin 0
  voltaje = (sensor * 5000) / 1024;
  voltaje = voltaje - 500;
  temperatura = voltaje / 10;

}

void Calculo_Tmax_Tmin_Tmedia()
{
  for (int j = 0; j <= 23; j++)
  {
    if (tempdata[j] < tempmin)
    {
      tempmin = tempdata[j];
    }
    else if (tempdata[j] > tempmax)
    {
      tempmax = tempdata[j];
    }
  }
  tempmedia=0;
  for (int j = 0; j <= 23; j++)
  {
    tempmedia=tempmedia+tempdata[j];
  }
  tempmedia=tempmedia/24;
    
}


void show_temperatura()
{

  lcd.setCursor(0, 0);
  lcd.print("Temp actual");
  lcd.setCursor(0, 1);
  lcd.print(temperatura);
  lcd.print(" grados C");
  delay(1000);
}

void Reset_Temp() // Restablecemos todos los valores con el ultimo valor
{  
  tempmin = temperatura;
  tempmax = temperatura;
  for (int j = 0; j <= 23; j++)
  {
    tempdata[j] = temperatura;
  }
}


Si os resulta más cómodo lo podéis descargar desde aquí.

Os dejo un video con el funcionamiento del proyecto. Nos vemos!!







viernes, 8 de mayo de 2015

Termometro diario ( I )

Recuperamos el hilo donde lo dejamos hace ya unos días. Espero que las circunstancias personales me permitan continuar con el ritmo anterior.
Recordemos el último post, donde realizábamos un termómetro con una pantalla LCD de 16x2, que nos mostraba la temperatura.
Vamos a ir un poco más allá, y empezaremos a realizar proyectos que nos permitan interactuar con la información que nos presentan, y a procesar la información según nos convenga.
La propuesta, que atenderemos en varias entradas, es confeccionar un termómetro que guarde un registro de 24 muestras diarias a intervalos de una hora, y que las muestre a voluntad del usuario. Informando también de la temperatura media, mínima y máxima. También debe permitir resetear los valores tomados.

Casi nada.

El interfaz de usuario lo haremos con una pantalla LCD de 16X2 y dos pulsadores. Uno servirá para mostrar la información y además confirmar el borrado de datos. El otro pulsador lanzará el menú de reseteo de muestras, y desestimará la opción de borrar los datos.
La temperatura la calcularemos con nuestro ya conocido TMP-36.

El hardware es bien sencillo, pero para resolver posibles dudas y aclarar el tema de las entradas usadas , mi propuesta es esta.


Una de las primeras dificultades que nos encontramos es donde almacenar las 24 muestras que iremos tomando a lo largo del tiempo. Mi propuesta para resolverlo es a través de una matriz o ARRAY, vamos a ello.

Arrays[]

Un array, o matriz, es un conjunto de valores a los cuales se puede acceder a través de un índice. El primer valor de una matriz está indicado con el numero 0.

Hay varias formas de declarar una matriz. Veamos unos ejemplos:


int array1[5];

int array2[] = {1,3,5,7,9}

int array3[5] = {1,3,5,7,9}




En el caso del array1, declaramos un array de 5 elementos tipo integer (se puede escoger cualquier tipo de variable flor, double,string) , pero no asignamos valores, ya lo haremos más adelante, en cualquier punto del sketch.



El array2, declaramos un array, sin especificar la dimensión, pero sí que les asignamos unos valores. Por tanto a la hora de compilar, leerá el número  de valores y creará un array de dimensión igual al número de valores.



En el ejemplo del array3, declaramos la dimensión del array, y los valores que le asignaremos.

Como ya he comentado el primer índice de una matriz es el 0, por tanto :




int array3[5] = {1,3,5,7,9}

// array3[0] Contiene el valor 1
// array3[4] Conetiene el valor 9
// array3[5] No existe y producir´a un error


Una de las dificultades de los array, es que indexar en lenguaje C un valor "imposible" como el del ejemplo no genera un error, y puede ser un fallo complicado de detectar.

Para asignar un valor a un array, se debe indicar la posición y el valor que queremos guardar. Hay que tener cuidado con asignar valores del mismo tipo del que se ha creado el array, y tener en cuenta que machacaremos el valor que hubiese.




Así cambiar el valor 5 por un 4 tendría la siguiente sintaxis:



    
array3[2] = 4;



Es decir, el numero cinco , que ocupa la posición 2 ( recordad que se empieza contando desde 0), le asignamos el número 4.


Otra utilidad es asignar a una variable el valor de una posición en concreto. ¿Cómo? Pues si queremos asignar a la variable dato el valor de la posición 3:

        dato = array3[3]; // array3[3] Contiene el valor 7



Para el ejemplo que nos ocupa, usaremos el array como si se tratara de una variable circular. Este es uno de los usos más comunes que se le da a este tipo de variable. 

Definiremos un bucle que va rellenando la matriz con los valores captados, y cuando llega al último empieza desde el principio. Si queremos tomar muestras de temperaturas máxima , mínima y media de un día, lo haremos con un array de 24 posiciones.


Esta parte del cuerpo del programa podría quedar algo parecido a esto:



...
...
...


float tempdata [24];//array de tipo float para 24 muestras hora
...
...
...
for (int i=0; i<=23; i++)//Bucle que nos permite tomar 24 muestras
  {
  sensor = analogRead(0); //Sensor TMP36 en pin analogico 0 
  voltaje = (sensor*5000)/1024; //operaciones necesarias
  voltaje = voltaje-500;        // para calculo de temperatura
  tempactual = voltaje/10;  
  tempdata[i]=tempactual;// Grabamos en la posición iesima  del array
                          // la temperatura calculada
  delay (360000); retardo de 1 hora entre muestras
}
...
...
...







Obviando la parte del programa que realiza el cálculo, que ya está explicada aquí, vemos como declaramos una variable array para 24 valores float.

Luego definimos un bucle de 0 a 23, para grabar en cada posición el valor de temperatura obtenido. 

Establecemos un delay de una hora con el fin de conseguir una muestra horaria que es lo que estamos buscando. 

Pero....


¿Que sucederá si aplicamos un delay de una hora? Pues eso, que durante una hora nuestro arduino no atenderá ninguna de sus entradas-salidas, porque estará esperando. Vamos que así no nos sirve.

Sí que hay una manera de interrumpirlo, y es usar uno de los pies de entrada (depende del modelo de Arduino usado), como una interrupción, que saque del delay al equipo. De todas maneras es un método que no me gusta para este ejemplo por lo que lo resolveremos de otra manera.

¿Cómo?

Pues con el uso de la función milis(). Ya la explicamos brevemente en su día en esta entrada

Un breve repaso, esta función cuenta el tiempo que ha pasado desde que se puso en marcha nuestro Arduino. Podemos contar en cada bucle el tiempo pasado y tomar muestras si es mayor de una hora respecto la muestra anterior. Esto nos permitirá con el código necesario, atender también los pulsadores del interfaz de usuario. 

Esta modificación también repercute en el bucle que recorre el array para grabar las muestras. Ahora será necesario crear un "puntero" que indique la posición del array que queremos grabar. Es importante que se mueve solo ente las posiciones 0-23, de lo contrario el comportamiento sería inesperado. 

¿Cómo quedaría el bloque anterior con la modificación?

...
...
...
unsigned long tiempoentremuestras=0; // reseteamos contadores de tiempo
unsigned long tiempomuestraanterior=0;// Este tambien
int posicion=0;//indice o puntero que recorrera el array
...
...


void loop() 

{
  ...
  ...

 tiempomuestraanterior=millis();// leemos el tiempo trasncurrido
 if( tiempomuestraanterior-tiempoentremuestras>360000)//Una hora

 {
  sensor = analogRead(2);       // TMP36 sensor  pin 0
  voltaje = (sensor*5000)/1024; // Calculos necesarios para tempertura
  voltaje = voltaje-500;   // Calculos necesarios para tempertura    
  tempactual = voltaje/10;    // Calculos necesarios para tempertura
  ...
  tempdata[posicion]=tempactual;// Grabamos en el array el dato
  posicion=posicion+1;// Incremetamos el puntero para la siguiente posici´n
  tiempoentremuestras=tiempomuestraanterior;// Resetamos el "cronometro"
  }
  
  if (posicion > 23)
   {posicion=0;} // Volvemos el puntero a 0 cuando pase de la posicion 23
   
...
...
}


¿Alguna duda este bloque? Los nombres de las variables son un tanto extensos, pero nos ayudará a entender mejor el funcionamiento del programa.

Hasta aquí la entrada de hoy. Con esto tenemos resuelto el grabar muestras de temperatura a intervalos de una hora durante un día. Pasadas 24 horas el programa irá machacando la primera muestra, y así sucesivamente, con lo que tendré siempre los datos de las últimas 24 horas.

En la proxima entrada trabajaremos el interfaz de usuario y como conseguir mostrar la información. Gracias por vuestra atención.

Nos vemos!




viernes, 27 de marzo de 2015

Termómetro LCD

Termometro LCD


En esta entrada vamos aprovechar nuestro montaje "estrella" del termómetro con un TMP36, para explicar el uso de una pantalla LCD.

Como podeis apreciar en la fotografia la pantalla consta de 16 pins que explicaremos brevemente a continuación.



El esquema de conexiones:


Siendo los pines en orden del 1 al 16, los siguientes:

  1. VSS, o GND
  2. VCC, 5 Volts, (comprobarlo en el datasheet, pues hay fabricantes que usan 3,3V)
  3. Contraste, (llevarlo al puntero de un potenciómetro de 10K para ajustar) 
  4. RS
  5. RW
  6. Enable,
  7. DB0, (de DB0...DB7), se usan para transmisión de datos
  8. DB1
  9. DB2
  10. DB3
  11. DB4
  12. DB5
  13. DB6
  14. DB7
  15. LED+, alimentación positiva para la retroiluminación.( no para todas las pantallas)
  16. LED-, GND para la retroiluminación. 
La pantalla del ejemplo tiene retroiluminación y funciona a 5V. Por tanto el esquema de conexión será el siguiente:



Estas pantallas pueden funcionar con 4 u 8 líneas de datos. Para la aplicación que nos ocupa, y para la mayoría, con cuatro tendremos suficientes.


Para este ejemplo, y otros que seguirán con este tipo de display, usaremos una pantalla compatible con el chipset de HITACHI HD44780. En este ejemplo, usaremos una pantalla de 16x2, es decir, 2 líneas de 16 caracteres cada una.

El motivo de usar este tipo de  pantalla compatible, es el de usar una librería ya creada para el entorno Arduino, que tendremos que llamar con una línea como ésta al principio de nuestro sketch.


#include <LiquidCrystal.h> //libreria necesaria para el uso del LCD


Esta librería facilita enormemente la gestión de la pantalla, y realizar las operaciones más habituales, con unos sencillos comandos. Una vez incluida la librería, deberemos crear una variable para el LCD, definiendo los pines a los cuales la hemos conectado.
Por orden serán, RS, Enable, D4, D5, D6 y D7.

LiquidCrystal lcd(4,5,6,7,8,9);


Por último, y para terminar de configurar la pantalla deberemos incluir en el void setup{} la siguiente instrucción:

lcd.begin(16,2);

Esta instrucción configura nuestra pantalla LCD de 16 columnas y 2 filas, definida previamente como variable lcd.

Veamos ahora algunas de las instrucciones que usaremos en nuestro ejemplo. 

   lcd.clear();


Con esta instrucción , borramos el contenido de la pantalla.

 
  lcd.setCursor(0,0);


Sirve para posicionar el cursor donde queremos emplazar el texto. Para colocarlo en la primera línea entre paréntesis usaremos los valores (0,0). Para colocarlo en el inicio de la segunda fila, la instrucción debe ser (0,1).


  lcd.print("Temperatura:");


Escribe el texto entre parentesis. Funciona igual que la instrucción print, escribiendo tal cual el texto que se encuentra entre las comillas .


  lcd.print(Temperatura);


Presenta el valor de la variable Temperatura.

Pues estas son las nociones básicas que deberían ser suficientes para completar esta primera parte del ejercicio propuesto. Si recuperamos de esta entrada, y sustituimos las líneas que muestran el resultado  en el serialmonitor, por las LCD , y configuramos la pantalla, deberíamos conseguir finalizar el ejercicio....

Que no lo conseguimos, de acuerdo  pues os muestro mi propuesta, que podéis descargar desde aquí.


/* Ejemplo practico para mostrar la temperatura de un TMP-36
en una pantalla LCD. La explicacion necesaria la encontramos
aqui http://arduinopractico.blogspot.com.es
 */
 
#include <LiquidCrystal.h> //libreria necesaria para el uso del LCD

LiquidCrystal lcd(4,5,6,7,8,9);// definicion de los pins conectados al 
// Arduino, por este orden RS, Enable, D4, D5, D6 y D7.

void setup() 
{
  Serial.begin(9600); // Iniciamos puerto serie, solo necesario si usamos PC 
  lcd.begin(16, 2); // Definimos el tamaño de pantalla que usaremos
  lcd.setCursor(0,0);// Posicionamos el cursor enel punto 0
  lcd.print("Arduino practico"); // Imprimimos nuestro logo...usad el vuestro
  lcd.setCursor(0,1);// vamos a la segunda linea
  lcd.print("*Termometro LCD*"); // Y explicamos que haremos
  delay(3000); //Esperamos 3 segundos para dar tiempo a leerlo
  lcd.clear(); // Y borramos la pantalla
}

float temperatura = 0; // Variable para leer la temperatura

void loop()
{
  
  delay(200);
    temperatura = analogRead(0);           // Lectura del TMP36 en pin0
    temperatura = (temperatura*5000)/1024; // Convertimos el valor en milivolts
    temperatura = temperatura-500;         // Restamos el offset de 0.5V
    temperatura = temperatura/10;          // Convertimos los milivolts en º Celsius
    lcd.clear();              // Borramos pantalla
    lcd.setCursor(0,0);       // vamos al inicio de la primera linea
    lcd.print("Temperatura"); // Mostramos el texto temperatura
    lcd.setCursor(0,1);       // Saltamos a la segunda linea
    lcd.print(temperatura,2); // mostramos la  temperatura con 2 digitos decimales
    lcd.print("C");           // la unidad de medida, grados Celsius
    delay(1000);              //
}


Os dejo con unas imágenes del montaje, y del resultado en pantalla que obtendréis.


Y funcionando:



Nos vemos.



miércoles, 4 de febrero de 2015

Calibración de sensores (II) Uso de un pulsador

Calibración de sensores (II) .

En esta entrada vamos a explicar varios conceptos que serán de gran utilidad a la hora de realizar proyectos de mayor envergadura.

En concreto y siguiendo con nuestro montaje con el sensor LDR, queremos calibrar nuestro sensor cuando pulsemos un interruptor. De esta manera no interferimos en el resto de procesos que pudiera estar realizando nuestro montaje.

Para ello volveremos a hacer uso de la instrucción While, y haremos uso por primera vez de los procedimientos.


Podríamos modificar nuestro ejemplo anterior y hacerlo por tiempo en el void setup, pero lo que queremos es iniciar el proceso de calibración con la pulsación del pulsador-interruptor. Como siempre , antes de seguir con el programa mostramos el circuito del montaje.



A continuación vamos a definir el algoritmo de nuestro programa:
  • Leemos el valor del LDR
  • Mapeamos la lectura y mandamos la señal PWM equivalente al led de salida
  • Leemos el estado del pulsador, si esta pulsado salvamos los valores máximos y mínimos leídos, de lo contrario, reiniciamos el bucle.
Con la máxima de usar un bucle del tipo While para resolver el ejemplo el sketch podría quedar de la siguiente manera:

/* Ejemplo para calibrar un LDR con un pulsador 
  haciendo uso de la instruccion While
  El circuito analiza el valor en el LDR, y mapea la 
 salida en funcinn de la lectura obtenida.
 Este ejemplo se basa en un adaptacion del que podeis encontrar en

 http://arduino.cc/en/Tutorial/WhileLoop
 
 Mas informacion en castellano en :
 http://arduinopractico.blogspot.com.es
 
 */

// Definicion de constantes
const int ldrPin = A0;       // pin conectado al LDR
const int ledPin = 9;           // pin conectado al LED
const int calibracionLedPin = 13; // Led para indicar el proceso de calibracion
const int pulsador = 2;        // pin concectado al pulsador


// Definicion de Variables
int sensorMin = 1023;  // Valor minimo del sensor
int sensorMax = 0;     // Valor maximo del Sensor
int sensorValor = 0;   // VAlor leido por el sensor

void setup() {
  // set the LED pins as outputs and the switch pin as input:
  pinMode(calibracionLedPin, OUTPUT);//o usaremos para indicar cuando esta calibrando
  pinMode (ledPin, OUTPUT);
  pinMode (pulsador, INPUT);
}

void loop() {
  // Leemos el pulsador y pasamos a calibrar si pulsado
  while (digitalRead(pulsador) == HIGH) {
    calibrado(); 
  }
  // Apgamos led13 cuando acaba el calibrado
  digitalWrite(calibracionLedPin, LOW);  

  // Leemos el sensor
  sensorValor = analogRead(ldrPin);

  // MApeamos el valor del sensor, con los valores
  // obtenidos de la calibracion
  sensorValor = map(sensorValor, sensorMin, sensorMax, 0, 255);

  // Descartamos los valores fuera del rango obtenido en la calibracion
  //restringiendo a la horquilla que heos medido
  sensorValor = constrain(sensorValor, 0, 255);

  // 
  analogWrite(ledPin, sensorValor);
}

void calibrado() 
{
  // Encendemos led 13, para indicar que estamos calibrando
  digitalWrite(calibracionLedPin, HIGH);
  //Leemos el valor del LDR
  sensorValor = analogRead(ldrPin);

  // Grabamos el valor maximo obtenido
  // si supera el que habia grabado
  if (sensorValor > sensorMax) {
    sensorMax = sensorValor;
  }

  // Grabamos el valor minimo obtenido
  //si es inferior al que habia grabado
  if (sensorValor < sensorMin) {
    sensorMin = sensorValor;
  }
}


Lo podeis descargar de aquí.

Las diferencias con ejemplos anteriores las tenemos en la siguiente parte:

// Leemos el pulsador y pasamos a calibrar si pulsado
  while (digitalRead(pulsador) == HIGH) {
    calibrado();


Antes de comenzar el bucle leemos el pulsador, y si está presionado llamamos al procediemiento        "calibrado". Cada vez que comience el bucle y el pulsador continue pulsado ejecutará la rutina de calibrado.
La rutina de calibrado, es exactamente igual a las realizadas hasta ahora. Leemos el valor del sensor, y grabamos los valores máximo y mínimo en las variables sensorMax y sensorMin. Respectivamente.

Ejemplo con dos LEDs fade-in y fade-out


Por último y para acabar de momento con el LDR, propongo otro ejemplo, esta vez con dos LEDs,    comportándose de forma antagónica. Es decir, si bien hasta ahora el LED era proporcional a los          valores de luz leídos, a mayor luz incidente en el LDR, mayor luminosidad del LED, ahora queremos
que uno de los actué de manera inversamente proporcional a la luz incidente.

El montaje consiste en añadir un led más:



Mi propuesta es muy sencilla. Es esta:

/* Ejemplo para calibrar un LDR con un pulsador 
  haciendo uso de la instruccion While
  El circuito analiza el valor en el LDR, y mapea la 
 salida en funcinn de la lectura obtenida.
 Un led sera proporcial (a mas luz mas brillo) y el 
 otro inversamente proporcional, a mayor luz, menor
 brillo.
 Mas informacion en castellano en :
 http://arduinopractico.blogspot.com.es
 
 */

// Definicion de constantes
const int ldrPin = A0;       // pin conectado al LDR
const int ledPin = 9;           // pin conectado al LED
const int led2Pin = 10;           // pin conectado al segundo LED
const int calibracionLedPin = 13; // Led para indicar el proceso de calibracion
const int pulsador = 2;        // pin concectado al pulsador


// Definicion de Variables
int sensorMin = 1023;  // Valor minimo del sensor
int sensorMax = 0;     // Valor maximo del Sensor
int sensorValor = 0;   // VAlor leido por el sensor
int sensorValor2 = 0;  // VAlor para el 2 LED

void setup() {
  // set the LED pins as outputs and the switch pin as input:
  pinMode(calibracionLedPin, OUTPUT);//o usaremos para indicar cuando esta calibrando
  pinMode (ledPin, OUTPUT);
  pinMode (led2Pin, OUTPUT);
  pinMode (pulsador, INPUT);
}

void loop() {
  // Leemos el pulsador y pasamos a calibrar si pulsado
  while (digitalRead(pulsador) == HIGH) {
    calibrado(); 
  }
  // Apgamos led13 cuando acaba el calibrado
  digitalWrite(calibracionLedPin, LOW);  

  // Leemos el sensor
  sensorValor = analogRead(ldrPin);

  // MApeamos el valor del sensor, con los valores
  // obtenidos de la calibracion
  sensorValor = map(sensorValor, sensorMin, sensorMax, 0, 255);

  // Descartamos los valores fuera del rango obtenido en la calibracion
  //restringiendo a la horquilla que heos medido
  sensorValor = constrain(sensorValor, 0, 255);
  sensorValor2 = 255 - sensorValor; // Una vez adaptado el valor,
  //lo invertimos con este truco
  // 
  analogWrite(ledPin, sensorValor);
  analogWrite(led2Pin, sensorValor2);

}

void calibrado() {
  // Encendemos led 13, para indicar que estamos calibrando
  digitalWrite(calibracionLedPin, HIGH);
  //Leemos el valor del LDR
  sensorValor = analogRead(ldrPin);

  // Grabamos el valor maximo obtenido
  // si supera el que habia grabado
  if (sensorValor > sensorMax) {
    sensorMax = sensorValor;
  }

  // Grabamos el valor minimo obtenido
  //si es inferior al que habia grabado
  if (sensorValor < sensorMin) {
    sensorMin = sensorValor;
  }
}



La diferencia, a parte de definir los nuevos elementos que intervienen, es la invertir, uno vez rescalado el valor que daremos al Led 2 con este sencillo truco:

sensorValor2 = 255 - sensorValor; // Una vez adaptado el valor,
  //lo invertimos con este truco


Por cierto podeis obtener este último ejemplo desde aquí.
Un video con el funcionamiento de este último. No olvidéis calibrarlo primero pulsando el interruptor y sometiéndolo a los valores de luz máximo y mínimo.



Nos vemos.

sábado, 24 de enero de 2015

Calibración de sensores (I). Uso de While

Calibración de sensores (I). Uso de While

En la entrada anterior vimos como ajustar un sensor para que actuase en un rango de funcionamiento determinado. El método era muy sencillo y sobretodo visual, lo que nos enseñaba a entender el procedimiento.
Por otro lado, tenía el inconveniente de que necesitas del portátil para calibrarlo, con lo que pierde practicidad e impide que la calibración la pueda realizar cualquiera, y en cualquier caso la complica un poco.
Veamos en esta entrada otro método más autónomo para calibrar sensores, pero primero explicaremos la instrucción que nos ayudará a realizarlo.

While 

La instrucción while, ejecuta una serie de instrucciones, hasta que la condición a testear sea cierta. Este bucle se repetiría indefinidamente hasta que se cumpla, por lo que hay que incluir una condición que pueda variar para que en algún momento se cumpla, de no ser así, entraríamos en bucle infinito, y sería un error de programación.
Esta condición, que debe estar dentro del bucle, puede ser el incremento de una variable o el chequeo de un sensor o entrada del Arduino.
La sintaxis de la instrucción es:

While (expresión){
Acciones en el bucle
}

Un ejemplo , sacado de la web arduino.cc, sería el siguiente:

var = 0;
while(var < 200){
  
// do something repetitive 200 times
  var++;
}

En este ejemplo, se usa la variable while para realizar un bucle que repetirá una acción 200 veces antes de salir del bucle.

Ejemplo calibración


Para nuestro caso concreto, lo que queremos realizar es la calibración de un sensor LDR durante los primeros segundos de puesta en marcha, para luego modular la luminosidad de un LED en función de la luz incidente.
El algoritmo para nuestro montaje sería algo parecido a esto:

  • Crear un bucle de un tiempo definido desde la puerta en marcha
  • Comprobar en este tiempo los valores ofrecidos por el sensor almacenando los valores máximos y mínimos
  • Fuera del bucle, escalar nuestros valores de salida (mapear)en función de los resultados obtenidos y generar la señal de salida correspondiente.

El montaje será idéntico a la entrada anterior, pero refresquémoslo:



El sketch propuesto para resolverlo es el siguiente:


/* Ejercicio Calibracion I. Procedemos a establecer los valores maximos
y mínimos durante los primeros segundos de ejecución del programa
 */

const int ldrPin = A0;    // pin conectado al LDR
const int ledPin = 9;     // pin conectado al LED
const int settime= 5000;  // Tiempo dedicado al ajuste desde
                          // el inicio del programa 
int ValorLDR = 0;         // Valor lectura LDR
int MinLDR = 1023;        // Valor mínimo de la LDR
int MaxLDR = 0;           // Valor máximo de la LDR

void setup() {
  // Encendemos ell LED del Arduino durante la calibración
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

  //Iniciamos la calibración
  while (millis() < settime) {//Definido en principio para 10 segundos
    ValorLDR = analogRead(ldrPin); // Leemos el valor del sensor

    // Grabamos el valor máximo si es mayor que el guardado
    if (ValorLDR > MaxLDR) {
      MaxLDR = ValorLDR;
    }

    // Grabamos el valor mínimo si es menor que el guardado
    if (ValorLDR < MinLDR) {
      MinLDR = ValorLDR;
    }
  }

  // Apagamos el led 13 pasados los 5 segundos para indicar que 
  // la calibracion ha finalizado
  digitalWrite(13, LOW);
}

void loop() {
  // read the sensor:
  ValorLDR = analogRead(ldrPin);
  
  //Restringimos los valores a los obtenidos durante el calibrado
  ValorLDR = constrain(ValorLDR, MinLDR,MaxLDR);
  
  // Escalamos los valores en la horquilla obtenida en calibracion
  ValorLDR = map(ValorLDR, MinLDR, MaxLDR, 0, 255);

  // Encendemos el LED al valor obtenido con la salida PWM
  analogWrite(ledPin, ValorLDR);
}

El sketch o podeis descargar de aquí.

Esta vez para calibrar el sensor, a diferencia de la entrada anterior bastará con cargar el sketch y durante los primeros segundos ( hemos definido 5s), iluminar y oscurecer el sensor con los valores de trabajo. Transcurrido este tiempo los valores máximo y mínimo quedarán grabados.

Os dejo un video con el procedimiento.



Ya trabajamos con la función milis, en una entrada anterior, pero para refrescar, esta función cuenta el tiempo transcurrido desde la puerta en marcha.

En nuestro bucle While, vamos comprobando los sensores  hasta que transcurra el tiempo previsto.

Otro punto interesante del sketch, es que esta calibración no la realizamos en el cuerpo del programa , void loop, sino en el void setup, por lo que tan solo se realizará en una ocasión durante el arranque del Arduino. Para volver a calibrar el sensor habría que reiniciar el Arduino, con lo que bastaría con pulsar el reset de la placa.

Esta solución, si bien es sencilla, pierde practicidad si se han de calibrar varios sensores, y además implica interrumpir el programa en caso de querer recalibrarlo.

En la siguiente entrada desarrollaremos una versión mejorada, y que serviría para la mayor parte de los montajes.

Nos vemos!