Mostrando entradas con la etiqueta primeros pasos. Mostrar todas las entradas
Mostrando entradas con la etiqueta primeros pasos. Mostrar todas las entradas

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!




sábado, 14 de febrero de 2015

Calculando la temperatura

Calculando la temperatura


Hola de nuevo. Siguiendo la línea de interactuar con nuestro Arduino y el entorno, vamos a hablar de los sensores de temperatura, y de cómo ensamblarlos con nuestro Arduino.

Un sensor de temperatura es un tipo de dispositivo que transforma un cambio de temperatura en un cambio en sus características ( resistencia, caída de voltaje, etc), que podemos medir con un equipo electrónico.
Hay varios tipos de distintos de sensores, en función de si varían su resistencia en función de la temperatura, (PTC, NTC, RTD), o si transforman el calor en diferencias de tensión como el termopar.
Para el ejemplo vamos a usar un económico, y fácil de encontrar TMP-36. Este semiconductor actúa parecido a un diodo Zener. Cuando se le somete a una diferencia de potencial entre dos de sus terminales, varía la caída de tensión en el tercero en función de la temperatura. Y esto será lo que mediremos en el conversor ADC de nuestro Arduino.

Aún hay más…. Entre las bondades del TMP-36 está que es completamente lineal en su rango de trabajo , -40°C a 150°C, y que su salida es en grados Celsius. Pero ,¿cómo haremos para medir la temperatura? Bien, el montaje es muy sencillo, conectaremos el terminal correspondiente a 5V, otro a GND, y el de en medio a una entrada analógica del Arduino. Tal que así:


El montaje en la protoboard  no podría ser más sencillo:




Después, y si nos dirigimos al datasheet del fabricante, encontraremos lo siguiente:


A nosotros nos interesa la curva b, señalada en rojo. Vemos que corta los 0°C en 0.5V, y que gana 10mV por cada incremento de 1°C. Por lo tanto la fórmula matemática que rige el comportamiento de este dispositivo sería:

T = ( V-0.5)*100

Donde :

T : es la temperatura en C, y
V: es la tensión en Volts.

Para este primer ejemplo  con las temperaturas, usaremos para visualizarlas el monitor serie del IDE. 

Con lo que el algoritmo para nuestro ejemplo, sería:

-Abrir la comunicación serie con el Arduino,
- Realizar la lectura del voltaje en el pin del sensor,
- Convertirla en grados Celsius,
- Mostrarla en pantalla.

Mi propuesta para este ejemplo es la siguiente:



/* Lectura de temperatura
Con un TMP-36
 */

// Declaración de constantes
const int sensorPin = A0; // Pin conectado al TMP36
float voltaje; //variable para calcular la tensión 
float temperatura; //variable para almacenar la temperatura;

void setup()
{
  // Empezamos la comunicación con el puerto serie
  // para mostrar los valores en el serial monitor
  Serial.begin(9600);
}


void loop(){
  // Leemos el valor de tensión en el pin
  // donde está conectado el sensor TMP36
  int sensorVal = analogRead(sensorPin);

  // Convertimos el valor de la lectura digital
  // en voltaje
  float voltaje = (sensorVal/1024.0) * 5.0;

  // Mostramos el valor del voltaje en pantalla
  Serial.print(", Volts: ");
  Serial.print(voltaje);
  
  // Convertimos el valor de tensión en temperatura
  // en grados Celsius. Para ello usamos la formula
  // explicada en http://arduinopractico.blospot.com.es
  // restando al voltaje el offset de 0.5V que tiene el sensor
  // e incrementando la temperatura en 1ºC por cada 10 mV
  // T = (V-0.5)*100 , siendo V el voltaje leido
  
  Serial.print(", Temperatura en C: "); 
  float temperatura = (voltaje - .5) * 100;
  Serial.println(temperatura);
  
   delay(1000);
}


Lo podeis descargar desde aquí.

Se trata de un ejemplo muy sencillo, con pocas particularidades. Quizás convenga resaltar, que para ganar precisión hemos usado variables del tipo float para hacer los cálculos, pues del tipo integer no obtendríamos decimales en las operaciones necesarias.


Este caso tan solo tenemos que cargarlo en el IDE, y enviarlo a nuestra placa.

Activar el monitor serie, está dentro de la pestaña herramientas. Aquí obtendremos las temperaturas con la cadencia que hayamos marcado.




En la siguiente entrada trabajaremos con otras alternativas para visualizar valores.

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! 

sábado, 10 de enero de 2015

Interruptor crepuscular con LDR y Arduino

Hola a todos. Espero que hayáis tenido una buena entrada de año. Una vez pasadas las fiestas retomamos el hilo de este blog.

Esta vez nuestra propuesta es construir un interruptor que active nuestro led en función de la luz ambiental. Un proyecto sencillo pero que nos sirve para empezar a trabajar con sensores.
Hasta ahora hemos dado siempre a nuestro Arduino las órdenes de forma manual, ya sea a través de pulsadores, interruptores o potenciómetros.

Ahora nuestro circuito será capaz de decidir "solito" en función de una variable ambiental. Así que paso a describir del componente que nos hará posible realizar el proyecto.

Fotorresistor o LDR ("ligth-dependent resistor")


El fotorresistor es un componente electrónico, del tipo semiconductor, cuya resistencia varía en función de la luz que recibe.
Los valores resistivos que alcanza van de los 100Ω a los 10kΩ bajo una luz brillante, hasta valores en la oscuridad que típicamente están entre los 500kΩ y los 10MΩ .
Para nuestro ejemplo usaremos el  VT90N2. Aquí lo tenéis junto a una tarjeta SD para comparar el tamaño.



Este modelo en concreto se encuentra en muchos kits de Arduino, tiene una resistencia en la oscuridad de 0,5MΩ y unos 100Ω, bajo luz intensa.
Para usarla en este montaje necesita una resistencia convencional para montar un divisor de tensión a modo de resistencia pull-down. El esquema del circuito que utilizaremos es el siguiente:



Mi propuesta para el montaje en la protoboard es esta:



Es totalmente necesario el uso de la resistencia pull para poder tener variación de tensión en la entrada analógica del Arduino, pues si conectaremos la resistencia directamente a la entrada analógica, entre VCC y masa, tendríamos variación en la intensidad que fluye a través de la resistencia, pero no variaciones de tensión que es lo que podemos analizar con el conversor AD.

El algoritmo del sketch sería muy sencillo, pues tan solo queremos que lea el valor de la resistencia, lo compare con un valor de consigna, y decida si debe apagar o encender el led.

Os invito a intentar encontrar la solución antes de continuar leyendo... tic tac tic tac.

De acuerdo pues aquí os dejo el sketch. Y podéis descargarlo desde aquí.

/* Ejemplo !_), recreamos un interruptor
crepuscular que actua en funcion del valor leido
por una LDR. Ver el video para ver como ajustar
en http://arduinopractico.blogspot.com.es */

int LDR_Pin = 0;  //pin conectado al fotoresistor LDR
int ledPin=9;     //pin conectado al led
int luminosidad;  // variable para registrar la lectura del LDR
int umbral=330;   // valor umbral de luminosidad
void setup()
{
    Serial.begin(9600);  //Begin serial communcation
    pinMode( ledPin, OUTPUT );//  Lo usaremos para ver la lectura real
    digitalWrite(ledPin,LOW);// y ajustar si necesario
}

void loop()
{
   
    luminosidad= analogRead(LDR_Pin); 
    Serial.println(analogRead(luminosidad)); //Escribimos el valor en monitor serie
    //monitorizando este valor podemos  ajustar el umbral para encender el led
    //en funci´n de la luminosidad
    if (luminosidad > umbral)// valor experimental
    {
      digitalWrite(ledPin,LOW);// si la luminosidad es mayor apagamos el led
    }    
    else
    {
      digitalWrite(ledPin,HIGH);// en caso contrario encendemos el led
    }
      
   delay(10); // A mayor valor mas lenta sera la respuesta a los cambios de luminosidad
}





Si os fijais, he incluido una línea para poder monitorizar el valor que obtenemos, ( entre 0 y 1023) de la resistencia LDR en el pin A0 del micro. Para activarlo debereis ir al monitor serial desde el IDE de Arduino.

Serial.println(analogRead(luminosidad));


La explicación del funcionamiento es muy sencilla, primero declaramos las cuatro variables que intervienen en el ejemplo:

int LDR_Pin = 0;  //pin conectado al fotoresistor LDR
int ledPin=9;     //pin conectado al led
int luminosidad;  // variable para registrar la lectura del LDR
int umbral=330;   // valor umbral de luminosidad

Una vez comienza el ejemplo, realizamos la lectura analógica en el pin 0, y lo almacenamos en la la variable luminosidad.

luminosidad= analogRead(LDR_Pin); 

En el siguiente bloque usamos una forma condicional, IT THEN, ( lo podéis repasar aquí), para comparar el valor leído con lo que queremos que sea nuestro umbral de luminosidad.

if (luminosidad > umbral)

Si es mayor, apagaremos el led ( entendemos que hay suficiente luz ambiental).
Por otro lado cuando cae por debajo de nuestra consigna encendemos nuestro led.

if (luminosidad > umbral)// valor experimental
    {
      digitalWrite(ledPin,LOW);// si la luminosidad es mayor apagamos el led
    }    
    else
    {
      digitalWrite(ledPin,HIGH);// en caso contrario encendemos el led
    }
      

El valor que que he usado es experimental. Dependerá del valor que uséis en la resistencia para hacer el PULL, del LDR, de la temperatura, etc.

Por eso es interesante el uso del monitor serial para monitorizar los valores obtenidos y ajustar de forma empírica.

Como procederíamos?

Cargamos el sketch,




y activamos el monitor serial (Heramientas > Monitor serie):


Simulando la luminosidad que queremos obtener y observando el monitor serial tendremos una idea de que valor aproximado podemos usar para nuestro circuito.

Un último consejo, para un ajuste de "campo" más sencillo, en el caso que quisiéramos cambiar este valor de forma más sencilla sin necesidad de conectarnos, sería sustituir la resistencia de 10kΩ por un potenciómetro.

Un video de ejemplo:




domingo, 28 de diciembre de 2014

Dimmer con un potenciometro. analogRead()

Hola a todos.

Vamos explicar en esta entrada como hacer un dimmer más "clásico", esta vez con el uso de un potenciómetro.

Potenciómetro


Un potenciometro no es más que una resistencia cuyo valor es variable. ¿Así de sencillo?

Bueno, más o menos, después se pueden clasificar según su construcción, su aplicación, o su ley de variación. Pero no nos extenderemos aquí. Recomiendo la lectura de algún capítulo de electrónica básica, o la búsqueda en internet. La entrada de wikipedia, es muy generalista pero nos puede dar una idea básica de sus usos.
Para nuestra aplicación usaremos un potenciómetro rotatorio lineal de 10kohms. 

En este supuesto  lo usaremos como un divisor de tensión. Es decir, conectaremos un extremo a 5V (Vcc) y el otro a masa (GND). El cursor lo llevaremos a una entrada analógica del Arduino. 
Con este montaje lo que tendremos en la entrada del Arduino es una tensión que oscilará entre los 0 y los 5V.
Con este voltaje que variaremos a voluntad pilotaremos el led de salida. El esquema del montaje es el siguiente:



analogRead ()


Esta función será la que utilizaremos para hacer funcionar nuestro circuito. Como hemos explicado, hemos realizado un montaje que aplicará un voltaje variable a la entrada del Arduino. Ahora toca leerlo para actuar en consecuencia.
Nuestro Arduino , tiene 6 pins que pueden actuar como un convensor analógico-digital de 10 bits. Son los pins que van del A0..A5. Con una resolución de 10 bits, los valores enteros que obtendremos irán del 0 al 1023. 
La resolución en volts, sera 5V/1024 , o sea de 0,0049V o 4,9mV por unidad.
El Arduino necesita 100us para realizar una lectura , por lo que la frecuencia de muestro que obtendremos como máximo es de 10KHz. 
Existen maneras de configurar de manera diferente estas entradas , pero las veremos más adelante, en otras aplicaciones.
La función solo necesita un parámetro y es el pin de entrada, que en el caso del Arduino UNO, será un número entre 0 y 5.
Un curiosidad es que no hace falta configurar el pin como entrada para realizar lecturas, aunque lo más adecuado y siguiendo con el patrón de programación definido hasta ahora, declararemos siempre los pines en la cabecera del programa.

Si picais este programa, vereis en el IDLE , el valor entero del conversor. Cargar el programa, realizar el montaje expuesto, y dentro de herramientas buscar el monitor serial.

Vereis, como si actuais sobre el potenciometro obtenemos diferentes valores en el monitor serial. Han de estar coprendidos entre 0 y 1023. Es posible que por las tolerancias de los componentes no obtengamos los valores extremos.
El programa lo puedes descargar desde aquí.

//Conversor AD, lee la lectura de un potenciometro
// en el pin A0 y nos estrega la lectura
// En el serial monitor
int POT = 0;   //Cursor potenciometro en pin 0.  
int valor = 0; // variable que almacenara el valor

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

void loop()
{
  valor = analogRead(POT);  // leemos el potenciometro
  Serial.println(valor);    // lo visualizamos en el monitor serial
}

Muy bien, pero nuestro led no se enciende. Esto no debería ser una sorpresa, no hemos definido ningún puerto de salida, ni actuado sobre ningún pin.

Ahora que hemos visto como actua el  conversor AD y hemos obtenido el valor de la señal de entrada, hay que trasladarlo a nuestra salida, el led.

Aquí nos surge otra dificultad. Si recordáis la entrada donde explicábamos el funcionamiento de la modulación por ancho de pulsos ( PWM aquí). La función analogWrite, esperaba un valor entre 0 y 255. 
Resumiendo, tenemos un convensor AD en la entrada de 10bits, y en la salida de tan solo 8 bits, es decir, solo acepta valores entre 0 y 255. No podemos decir que la salida es "igual " a la entrada, hay que escalarla primero. 
Una de las soluciones más extendidas cuando queremos hacer que la salida sea proporcional a la entrada, como en este caso, es dividir la entrada entre 4 antes de la función analogWrite().

Muy bien, ahora con todo este rollo post-turrones y cava, como quedará el programa. Primero el algoritmo de lo que deseamos:


  1. Capturar la entrada analógica con el conversor AD de 10 bits,
  2. Escalarla dividiendo la entrada entre 4, para preparar la señal para el conversor de 8 bits,
  3. Generar la señal de salida, proporcional a la entrada
  4. Cambiar la salida cada vez que lo haga la entrada, indefinidamente.
Ahora sí, mi propuesta para realizar el ejercicio sería la siguiente:


// Ejemplo Dimmer con un potenciometro
// Conectamos el cursor de un potenciometro
// al pin A0, y sus extremos uno a VCC
// y el otro a GND o masa
// EL led de salida al pin 9 a traves de una
// resistencia de 220 ohmioa

const int LED = 9; // pin para el LED
const int POT = 0; // pin para el pulsador
int brillo = 0;
void setup() 
{
pinMode(LED, OUTPUT); // LED es una salida
pinMode(POT, INPUT); // Entrada analogica
}
void loop() {
 brillo =  analogRead(POT); // leemos la caida de tension en el pot
 brillo = brillo/4; // lo escalamos para el conversor DA
 analogWrite (LED,brillo); // escribimos la salida del PWM
}

Lo puedes descargar desde aquí.
En este ejemplo tenemos mayor control sobre la luminosidad del led que con el pulsador, sin embargo  
siempre existirá un consumo de corriente en el potenciómetro por lo que no es el más eficiente energéticamente.
Esta entrada es  más potente de lo que parece, porque ahora podemos leer cualquier entrada analógica, por tanto todo tipo de sensores que den una respuesta analógica, temperatura, humedad, luminosidad, etc, usan este tipo de procedimiento para leer sus señales. En las siguientes entradas experimentaremos con algunos de ellos.

Os dejo un vídeo con el montaje. Casi se me olvidada mis mejores deseos para el 2015.
¡Feliz año nuevo!



sábado, 13 de diciembre de 2014

Otro ejemplo con PWM. Fade-in y fade-out en un led.

Veamos otro ejemplo con el uso de PWM.

El enunciado del ejemplo sería programar un bucle que encienda un led de manera progresiva hasta su máxima luminosidad y lo apague de la misma manera. Pretendemos simular algo parecido al comportamiento de un led en standby de un portátil.
Para ello, utilizaremos el bucle for que ya vimos en pasadas entradas y la función analogWrite().
Usaremos el mismo montaje de la entrada anterior.

El algoritmo del programa  sería algo como esto:
  • Inicializar entradas y salidas.
  • Hacer un bucle ascendente de 0 a 255 (valor máximo y mínimo) que incremente la salida analógica.
  • Hacer un bucle descendente que de 255 a 0 que vaya apagando el led.
  • Repetir indefinidamente...
El programa, perdón el sketch, quedaría:

//Ejemplo 1_5. Encendido y apagado progresivo de un led
// Modificaremos su luminosidad actuando sobre el ciclo de carga
// de la seña de salida

const int LED = 9; // Pin conectado al LED
int i = 0; // Variable que usaremos para el bucle for

void setup() 
{
  pinMode(LED, OUTPUT); // Configuramos el pin como salida
}
void loop()
{
  for (i = 0; i < 255; i++) // bucle de 0 a 254 (fade in).Vamos
                            // incrementando el ciclo de trabajo
  {                         //de 0 a 255     
  analogWrite(LED, i); // esta línea configura el brillo del LED
  delay(10); // Colocamos una espera de 10ms para poder apreciar
             // el efecto. De otro modo sería tan inmediato que
             //no lo veríamos
  }//fin del primer for.   
  for (i = 255; i > 0; i--) { // bucle de 255 a 1 (fade out)
  analogWrite(LED, i); // esta línea configura el brillo del LED
  delay(10); // Espera de 10ms
  }
}



Lo podéis encontrar para descargarlo aquí:

El código es bastante sencillo, así que vamos a añadir un mínimo de complejidad. Vamos a modificar el ejemplo para que sea la activación de un pulsador la que inicie el ciclo.

Cómo sería el algoritmo en esta ocasión:


  • Inicializar entradas y salidas.
  • Leer el estado del pulsador e iniciar el ciclo si se pone a “1”, (se pulsa)
  • Hacer un bucle ascendente de 0 a 255 (valor máximo y mínimo) que incremente la salida analógica.
  • Hacer un bucle descendente que de 255 a 0 que vaya apagando el led.
  • Repetir indefinidamente…

Ok, sencillo ¿no? Solo hemos añadido una línea  en el algoritmo, y ¿en el sketch? Dad le una vuelta antes de seguir leyendo…
…Una vuelta más…
… ¿Ya? Bien pues aquí mi propuesta:


//Ejemplo 1_5b. Encendido y apagado progresivo de un led
// modificando su luminosidad actuando sobre el ciclo de carga
// de la seña de salida. El ciclo lo inicia una pulsación

const int LED = 9; // Pin conectado al LED
const int pulsador = 2 ; //Pin conectado al pulsador
int i = 0; // Variable que usaremos para el bucle for

void setup() 
{
  pinMode(LED, OUTPUT); // Configuramos el pin como salida
  pinMode(pulsador, INPUT); //Configuramos el pin como entrada
}
void loop()
{
    digitalWrite (LED, LOW); //Fijamos la condición inicial del LED
if ( digitalRead(pulsador) == HIGH ) 
  {
    for (i = 0; i < 256; i++) // bucle de 0 a 255 (fade in).Vamos
                            // incrementando el ciclo de trabajo
    {                         //de 0 a 255     
    analogWrite(LED, i); // esta línea configura el brillo del LED
    delay(10); // Colocamos una espera de 10ms para poder apreciar
               // el efecto. De otro modo sería tan inmediato que
               //no lo veríamos
     }//fin del primer for.   
     for (i = 255; i > 0; i--) 
     { // bucle de 255 a 1 (fade out)
     analogWrite(LED, i); // esta línea configura el brillo del LED
     delay(10); // Espera de 10ms
     } // fin del segundo for
    }//Fin condición de la pulsación
    digitalWrite (LED, LOW); //Apagamos el LED en espera de otro pulso
}


¿En qué varía el código? Bien de entrada fijamos que cuando se ejecuta el bucle, el LED esté apagado en espera de recibir una pulsación.

       digitalWrite (LED, LOW);

Seguidamente ponemos una condición con un IF, (ya lo trabajamos aquí), para detectar un flanco positivo en la entrada, (vamos una pulsación):

        if ( digitalRead (pulsador == HIGH ))

Y pasamos a copiar el código anterior. Tan solo debemos recordar salir del bucle volviendo a apagar el LED en espera de otra pulsación.

         digitalWrite (LED, LOW);

El sketch para descarga lo puedes encontrar aquí.

Este montaje tiene muchas posibilidades. Podríamos intentar por que tras la pulsación repita el ciclo n número de veces y se apague.

Otra aún más interesante, que una pulsación comience el ciclo y otra lo apague (con un solo pulsador).  Os dejo con el vídeo del funcionamiento de los dos ejemplos, y en la próxima entrada la solución a estas dos propuestas. Nos vemos.