domingo, 19 de junio de 2011

Entrada Analógica (Analog Input)

Hoy nos dedicaremos a interactuar con una entrada analógica, la cual a diferencia de una entrada digital (entrega anterior) permite leer un rango de valores. Estos valores representan voltaje, pero dentro del microcontrolador pueden ser representados por un rango de valores enteros, los cuales pueden ir de 0 a 255 o de 0 a 1024, etc., esto depende del tipo de procesador que estemos utilizando... por eso es muy útil obtener las especificaciones del micro y las funciones asociadas (en el lenguaje que escogiéramos) a la lectura de un puerto analógico.

La idea de un puerto analógico es leer de un puerto diferentes valores, lo cual permite tomar decisiones más amplias o interactuar con rangos que permiten realizar tareas diferentes.

En lo personal, cuando pienso en una entrada digital pienso en un switch on/off, y cuando pienso en una entrada analógica pienso en un potenciómetro, o cualquier dispositivo cuya salida oscile entre 0V y 5V.

Estos dispositivos (ejemplo un lm35 - termómetro digital) alimentándolos con 5V, pueden entregar al puerto en donde se conecten un rango de valores de acuerdo a las características con las cuales el dispositivo está diseñado.

Por ejemplo, un potenciómetro permite entregar al micro un rango de voltaje que depende del voltaje con el cual esté alimentado. Un termómetro digital, entregará un voltaje de acuerdo a la alimentación del mismo y a las condiciones de temperatura a la cual esté expuesto. En cualquier caso, siempre se obtiene un voltaje asociado a la lectura del dispositivo, y a través de este voltaje podemos tomar decisiones y ejecutar tareas.

El siguiente circuito conecta 8 leds a la plataforma de prototipado pinguino en los pines 0-7, que son puertos digitales. Un potenciómetro es conectado a los puertos GND,VCC del micro y su salida la enviamos al puerto 13, el cual es analógico.


El código que utilizaremos permite utilizar los 8 leds como una barra de indicación. Cuando el potenciómetro está en el tope izquierdo, este entrega al puerto 13 cero voltios. Cuando el potenciómetro está en el tope derecho le entrega al puerto 5V.

El micro traduce este voltaje en un número entero que oscilará entre 0 y 1024, dependiendo del voltaje, el cual estará en un rango de oV a 5V.

Nuestra intención es que a medida que vamos rotando el potenciómetro a la derecha (0->5)V la barra de 8 leds debe ir iluminándose a la derecha hasta llegar a encender los 8 leds, justamente cuando el potenciómetro esté en el tope derecho. En la rotación contraria (5->0)V, los leds deben irse apagando uno a uno de derecha a izquierda hasta quedar todos apagados.

A continuación el codigo

// Ejemplo de utilización de lectura de potenciometro y encendido de leds
#include "ADlib/__map.c"

const int potPin=13;

void setup()
{
byte i;
for (i=0; i < 8; i++)
pinMode(i,OUTPUT);
pinMode(potPin,INPUT);
}

void apagarLeds()
{
byte i;
for (i=0; i<8; i++)
digitalWrite(i,LOW);
}

void encenderLeds(int count)
{
byte i;
for (i=0; i<count; i++)
digitalWrite(i,HIGH);
}

void loop()
{
apagarLeds();
encenderLeds(map(analogRead(potPin),0,1024,0,8));
delay(50);
}

Veamos como funciona esto. En primer lugar tenemos la declaración de una constante (potPin) que nos indica cual es el puerto que utilizaremos para leer el voltaje que nos entrega el potenciómetro.

Luego tenemos la función setup() para definir la modalidad de los puertos. Los puertos de entrada(0,7) los definimos como salidas en el ciclo for. Asimismo, el puerto 13 lo definimos como entrada con la función pinMode.

Hemos creado 2 funciones. apagarLeds() nos permite apagar todos los leds al tiempo utilizando un ciclo for con el siguiente rango (0<=i<8). Luego definimos una función que nos permite encender hasta el led definido por el parámetro count.

En el ciclo Loop(), vemos como apagamos los leds para luego encender hasta el led que nos devuelve la función map.

La función map es una función que nos permite convertir un rangoA en un rangoB. Esta función es estándar en arduino, pero no en pinguino, por lo que está programada y agregada al directorio de librerías de pinguino, y es por esta razón que la segunda línea existe.

#include "ADlib/__map.c"

En nuestro caso, la función mapea el rango (0,1024) al rango (0,8) utilizando como entrada lo que devuelve analogRead(potPin). Esta conversión es muy conveniente ya que directamente le pasamos un valor entre 0 y 8 a la función encenderLeds(). Este ciclo se repite infinitamente cada 50 milisegundos debido la función delay(50) que hemos colocado al final del loop.

// map function
// Alejandro-Dirgan 2011

#ifndef __MAP__
#define __MAP__

#define MAP 1

float map(int value, int fLow, int fHigh, int tLow, int tHigh)
{
return ((float )tHigh*(float )(value-fLow)+(float )tLow*(fHigh-value))/(float )(fHigh-fLow);
}

#endif

Veamos como funciona en la práctica.


Con las entradas analógicas se pueden hacer infinidad de cosas, solo la imaginación y los requerimientos lo dirán.

En la próxima entrega veremos las salidas analógicas.


Read More......

jueves, 16 de junio de 2011

Entrada Digital (Digital Input)

En el artículo anterior vimos como utilizar las salidas del microcontrolador para encender y apagar leds, utilizando valores lógicos altos y bajos (0,5V):(LOW;HIGH) con la función digitalWrite(). En este artículo utilizaremos los puertos para obtener información del entorno.

Generalmente cuando pensamos en una entrada digital, inmediatamente evocamos un switch ON/OFF. Cuando el swith está en off, no hay paso de energía y nuestro puerto, al cual está conectado el switch, se encontrará en un nivel bajo (LOW, 0v). Por el contrario, si el switch está en ON, el mismo permitirá el paso de energía y el puerto destino obtendrá un valor alto (HIGH, 5v). Esta lógica esta perfecta, pero veamos como podemos implementarla adecuadamente y veremos las variantes correspondientes.

Lo primero que debemos entender es como mantenemos un valor estable en un puerto de entrada. Como estamos hablando de una entrada digital, nuestra intención es determinar cuando la misma tiene un valor alto o bajo, y luego tomar una decisión al respecto, para por ejemplo encender un led, iniciar una secuencia de comandos, para activar un parámetro, etc.

En general, si no definimos una voltaje en una entrada digital esta podrá tener un valor flotante, lo cual debemos evitar. Requerimos tener un valor alto o un valor bajo, y esto se logra a través de las resistencias pull-up o pull-down.


En la figura de la derecha vemos como el terminal 1 del circuito lógico puede ser alimentado con un valor bajo (LOW, 0V) en el momento que el switch S1 es presionado.

Esto efectivamente sucede cuando el switch S1 se presiona, ya que hay un camino directo desde tierra a este terminal. Pero que pasa cuando S1 esta abierto?. El problema es que no podemos garantizar que valor lee el terminal 1 cuando esta condición prevalece.

En toda entrada lógica digital siempre debemos garantizar los dos valores a leer (alto y bajo), de forma que no haya ambigüedad.

Para ello existen dos modalidades, utilizando conceptos básicos de circuitos digitales: las resistencias pull-up y pull-down.

Veamos la siguiente figura:


En el circuito de la izquierda podemos observar que el terminal 1 esta conectado a través de una resistencia pull-up a Vcc (HIGH, 5V), cuando S1 está abierto. En este estado estamos garantizando un valor Alto cuando S1 no está presionado. Cuando S1 se presiona, el terminal 1 quedará conectado directamente a tierra, obteniendo un valor bajo (LOW, 0V). El valor de la resistencia puede conseguirse persiguiendo un valor bajo de corriente a circular entre VCC y Masa, utilizando V=I*R. La idea es dejar pasar menos de 1 mA para no dañar ni el circuito ni el cableado (en general el valor de esta resistencia está entre 10K y 47K).

En el circuito de la derecha estamos implementando una resistencia pull-Down a Tierra (LOW, 0V), garantizando 0V cuando S1 está abierto y 5V cuando S1 esta cerrado. De esta forma estamos garantizando en cualquier caso un valor predicho que podemos leer desde nuestro microcontrolador.

Como podemos observar, dependiendo que variante hayamos escogido, S1 puede representar un valor alto o bajo cuando está presionado, y viceversa. Depende de nuestra lógica y de como deseemos programar nuestro la escogencia de alguna de las modalidades descritas anteriormente.

OK. ya sabemos entonces como colocar un valor predecible en una entrada, ahora veamos como leerla y utilizarla para nuestros fines.

La figura muestra la conexión hecha para que el sketch que mostramos funcione adecuadamente.


El siguiente programa muestra

const int potPin=14, ledPin=12;

void setup()
{
pinMode(potPin,INPUT);
pinMode(ledPin,OUTPUT);
}

void loop()
{
if (analogRead(potPin))
digitalWrite(ledPin,LOW);
else
digitalWrite(ledPin,HIGH);

delay(50);
}

Objetivo:

Demostrar como leer una entrada digital y tomar una decisión de acuerdo a lo leído, para la ejecución de una acción.

Descripción:

(1) const int potPin=14, ledPin=12;

Definen constantes asociadas a el pin de entrada (14) y el pin de salida (12).

(2) Procedimiento setup()
{
pinMode(potPin,INPUT);
pinMode(ledPin,OUTPUT);
}

Definimos los pines como de entrada y salida en el procedimiento de setup.

(3) procedimiento loop()
{
if (analogRead(potPin))
digitalWrite(ledPin,LOW);
else
digitalWrite(ledPin,HIGH);

delay(50);
}

En el loop del programa, vemos una estructura de toma de decisiones.

if (analogRead(potPin))

analogRead es una función que permite obtener una lectura del pin potPin (14). En la estructura if lo único que requerimos es saber si esta lectura es mayor que cero (0), para apagar el led, o si la lectura es cero (0) (cuando se evalúa el else), para en encender el led.

Esta lógica aplica porque el circuito que montamos está basado en una resistencia pull-up.

Este ciclo se repite cada 50 milisegundos. Si el switch está abierto el if (analogRead(potPin)) nos retornará true, y apagaremos el led con digitalWrite(ledPin,LOW).

Por el contrario, si el switch está cerrado el potPin estará conectado directamente a tierra y se leerá un valor bajo (oV), lo que hace que en el ciclo del programa la instrucción asociada al else se ejecute: digitalWrite(ledPin,HIGH).

Es muy sencilla su programación. Luego compilamos el programa buscando que todo esté OK y reprogramamos el microcontrolador (en mi caso el pinguino) y dejamos que ejecute el programa.

En el video se puede observar que he agregado un display lcd 16x2 para mostrar si el valor de potPin es alto o bajo y para indicar que estamos ejecutando de acuerdo a estos valores.


Read More......

lunes, 6 de junio de 2011

Playing with LEDS

En la entrega anterior vimos como utilizar las salidas digitales. En este artículo solo quiero mostrar que lo que se puede hacer con las salidas digitales es directamente proporcional a lo que podemos hacer programando.

La inteligencia de estos dispositivos electrónicos es solo cuestión de imaginación y capacidad de programación.

En esta entrega quiero mostrarles como hacer un divertimento de iluminación de leds.

EL ESQUEMA

7 LEDs conectados a las salidas 0-6 del pinguino 2550.



EL CODIGO

Un simple programa que permite iluminar 7 leds. El código está definido con 6 procedimientos:

- ledOff(): Pone las salidas 0-6 en LOW
- secuencia1(): hace una secuencia del pin 0 al 6 con 10 ms de retardo
- secuencia2(): hace una secuencia del pin 6 al 0 con 10 ms de retardo
- secuencia3(): enciende los leds impares y hace flash en los pares
- secuencia4(): enciende los leds pares y hace flash en los impares
- secuencia5(): hace flash alternativo entre los leds pares e impares

//Playing with leds
byte const pines[]={0,1,2,3,4,5,6};
byte pausa1, pausa2;

void ledOff()
{
byte i;
for (i=1;i<7;i++)
digitalWrite(pines[i-1],LOW);

}

void setup()
{
byte i;
for (i=0;i<7;i++)
pinMode(pines[i],OUTPUT);
pausa1=10;
pausa2=50;
ledOff();
}

void secuencia1()
{
byte i;
ledOff();
for (i=1;i<7;i++)
{
digitalWrite(pines[i-1],HIGH);
delay(pausa1);
digitalWrite(pines[i-1],LOW);
delay(pausa1);
}
}

void secuencia2()
{
byte i;
ledOff();
for (i=7;i>=1;i--)
{
digitalWrite(pines[i-1],HIGH);
delay(pausa1);
digitalWrite(pines[i-1],LOW);
delay(pausa1);
}
}

void secuencia5()
{
byte i;
ledOff();
for (i=0;i<7;i++)
{
digitalWrite(pines[0],HIGH);
digitalWrite(pines[2],HIGH);
digitalWrite(pines[4],HIGH);
digitalWrite(pines[6],HIGH);
delay(pausa2);
digitalWrite(pines[0],LOW);
digitalWrite(pines[2],LOW);
digitalWrite(pines[4],LOW);
digitalWrite(pines[6],LOW);
delay(pausa2);
digitalWrite(pines[1],HIGH);
digitalWrite(pines[3],HIGH);
digitalWrite(pines[5],HIGH);
delay(pausa2);
digitalWrite(pines[1],LOW);
digitalWrite(pines[3],LOW);
digitalWrite(pines[5],LOW);
delay(pausa2);
}
}

void secuencia3()
{
byte i;
ledOff();
digitalWrite(pines[0],HIGH);
digitalWrite(pines[2],HIGH);
digitalWrite(pines[4],HIGH);
digitalWrite(pines[6],HIGH);
for (i=0;i<7;i++)
{
digitalWrite(pines[1],HIGH);
digitalWrite(pines[3],HIGH);
digitalWrite(pines[5],HIGH);
delay(pausa2);
digitalWrite(pines[1],LOW);
digitalWrite(pines[3],LOW);
digitalWrite(pines[5],LOW);
delay(pausa2);
}
digitalWrite(pines[0],LOW);
digitalWrite(pines[2],LOW);
digitalWrite(pines[4],LOW);
digitalWrite(pines[6],LOW);
}

void secuencia4()
{
byte i;
ledOff();
digitalWrite(pines[1],HIGH);
digitalWrite(pines[3],HIGH);
digitalWrite(pines[5],HIGH);
for (i=0;i<7;i++)
{
digitalWrite(pines[0],HIGH);
digitalWrite(pines[2],HIGH);
digitalWrite(pines[4],HIGH);
digitalWrite(pines[6],HIGH);
delay(pausa2);
digitalWrite(pines[0],LOW);
digitalWrite(pines[2],LOW);
digitalWrite(pines[4],LOW);
digitalWrite(pines[6],LOW);
delay(pausa2);
}
digitalWrite(pines[1],LOW);
digitalWrite(pines[3],LOW);
digitalWrite(pines[5],LOW);
}

void loop()
{
byte j;
for (j=0;j<7;j++)
secuencia1();
for (j=0;j<7;j++)
secuencia2();
secuencia3();
secuencia4();
secuencia5();
}

EL RESULTADO

El siguiente video muestra el resultado de cargar este programa en el pinguino y ejecutarlo conectado al breadboard con los 7 leds.



Read More......