UN CIRCUITO CON VARIOS LED: ITERACIONES FOR
.
En las sesiones anteriores vimos como gobernar que un diodo LED externo. Si quisiéramos montar un circuito
que tuviera 8 LEDs y en el que la luz se desplazara de uno a otro, una posibilidad sería repetir varias veces las
mismas secuencias de instrucciones que ya conocemos.
Por ejemplo si conectamos distintos LEDs a distintos pines digitales de Arduino, deberíamos declararlo en
nuestra Función de setup() que podría ser:
void setup()
{
// initialize the digital pins as an output
pinMode( 13, OUTPUT) ;
pinMode( 12, OUTPUT) ;
pinMode( 11, OUTPUT) ;
…………………………
pinMode( 6, OUTPUT) ;
}
Y a su vez nuestro loop() debería repetir tantas veces como LEDs tengamos el juego de encender y apagar
cada uno de los LEDs en secuencia desde el pin 13 hasta el 6.
Esta solución es la que podríamos describir como de fuerza bruta, pero no es muy elegante, es trabajosa y
probablemente cometeríamos más de un error al escribirla, porque las personas tendemos a equivocarnos
haciendo tareas repetitivas aburridas (y esta lo es mortalmente, imaginad un circuito de de 16 LEDs).
En cambio los ordenadores no se aburren y además C++ nos ofrece un medio cómodo de indicarle que debe
repetir algo un número definido de veces. Este medio es la instrucción For que podemos usar en combinación
con una variable.
Una variable es un contenedor que puede tomar varios valores, en nuestro caso aceptará todos los valores
entre 6 y 13.
C++ nos exige declarar el tipo de las variables antes de usarlas. En nuestro caso usaremos el tipo entero que
se escribe int para indicar que esta variables es numérica y entera, sin decimales.
Iremos viendo que existen otros tipos de variables. Volveremos sobre este tema en próximas sesiones.
Así por ejemplo, para inicializar en nuestro setup() los pines desde el 13 hasta el 6 como salidas (requerido por
nuestro Arduino) podríamos usar la instrucción for de la siguiente manera:
void setup()
{
int i = 0 ; // Inicializamos la variable i como un entero
for ( i = 6 ; i < 14 ; i++)
pinMode( i , OUTPUT) ;
}
Aunque la sintaxis parece complicada al principio, uno se acostumbra con rapidez. Aquí lo importante es que
for necesita 3 parámetros separados por un carácter de punto y coma.
Estos parámetros son y en éste orden:
Una variable que ira tomando valores según una cierta regla, y a la que asignamos un valor inicial. En este
caso: i = 6 .
El ciclo continúa mientras se cumpla esta condición. En nuestro caso mientras la i sea menor que 14, o sea
hasta el 13: i <14
Como cambia la variable en cada iteración. En nuestro caso i++ que es pedirle a C++ que incremente en uno la
variable i, al final de cada iteración.
Con el mismo criterio podríamos escribir la función loop() así Descargar:
void loop()
{
int i = 0 ; // Inicializamos la variable i como un entero
for ( i = 6 ; i < 14 ; i++)
{
digitalWrite( i , HIGH) ;
delay (500) ;
digitalWrite( i , LOW);
delay (500) ;
}
}
En la sesión 3 el código era muy similar excepto en que escribíamos el valor 13 para el único pin que tenía un
LED conectado. Aquí asignamos el pin con una variable i , que va tomando los valores de 6 hasta el 13 para el
pin.
Nótese que la instrucción for no lleva un punto y coma al final. Esto es porque se aplica al bloque de
instrucciones que le siguen entre llaves, como es el caso del loop() La iteración realiza las cuatro instrucciones
que siguen a la línea del for, porque están dentro de un bloque de instrucciones.
Las instrucciones que se aplican a bloques de código, no llevan punto y coma al final.
En el caso de particular de que el bloque lleve una única línea de código, las llaves pueden ser omitidas, como
en el caso de la instrucción for en la función setup() de arriba.
ESQUEMA ELECTRÓNICO DEL CIRCUITO
.
El esquema del circuito es muy similar al de la sesión 3, salvo por el hecho de que colocamos en la Protoboard
8 LEDs.
La única novedad es que dado que la función de la resistencia es limitar la intensidad de la corriente que circula
por el circuito, y puesto que todos los diodos tienen masa común, basta una única resistencia entre este punto y
Ground.
Cuando nuestro programa levante el pin correspondiente a valor a HIGH, se cerrar el circuito iluminándose el
LED asociado.
Con este circuito, y con el programa 4.1 descrito en las páginas anteriores, tendremos un efecto de luces similar
al del “coche fantástico” (O de los Zylon para los aficionados a la ciencia ficción).
A continuación incluimos un esquema de conexión del circuito en una protoboard.
En general, se considera buena costumbre (la recomendamos), montar los circuitos que veamos a partir del
esquema electrónico del mismo, más que a partir del diagrama de conexiones de la Protoboard.
La razón es que con el esquema, la comprensión del circuito es completa y se evita la tentación de copiar la
práctica sin necesidad de entenderla.
Además, el diagrama electrónico del circuito es su completa descripción y suele resultar más sencillo
comprender la función del mismo. En cambio a medida que los circuitos se hacen más complejos, comprender
su función desde un esquema de Protoboard puede complicarse mucho, y peor aún llevar a una interpretación
errónea.
VARIANTES DEL PROGRAMA CON EL MISMO CIRCUITO
.
Este montaje nos permite jugar con las luces y se presta a varios programas diferentes para conseguir distintos
efectos.
Por ejemplo, con el programa anterior 4.1, el efecto no es exactamente el del coche fantástico porque cuando
acabamos de iterar el for, el programa vuelve a empezar desde el principio, lo que hace que la luz salte desde
el pin 6 hasta la del pin 13.
Así pues ¿ Podríamos hacer que la luz rebotara ? Pensadlo un poco.
Desde luego que sí, bastaría con usar dos ciclos for, similar a lo siguiente:
Contenido solo disponible para suscriptores. ¡Accede al contenido!
El primer ciclo for hace que las luces se encienda en secuencia desde la 6 hasta la 13. El segundo bucle entra a
continuación empezando con la luz 12 (para no repetir la 13) y finalizando con la 7(para no repetir la 6), y vuelta
a empezar.
En el segundo bucle hemos hecho una cuenta atrás diciéndole a la variable i que se decrcmentara en uno en
cada iteración mediante la instrucción i– .
También nos hemos aprovechado de que C++ nos permite definir variables sobre la marcha dentro de la
propia instrucción for, sin necesidad de dedicarle una línea completa a la declaración e inicialización.
Otra variante seria, hacer un efecto de ola en al que las luces subieran dejando encendidos los LEDs previos
hasta alcanzar el máximo y ahora descender apagando los LEDs superiores. Os recomendamos intentar
resolver el problema como desafío, antes de buscar una solución.
Programar es en parte aprender las instrucciones de un lenguaje (la parte fácil), y otra más difícil que es
aprender a resolver los problemas de un modo que nos permita darle instrucciones a un ordenador para que lo
lleve a cabo.
Estos procedimientos secuenciales de cómo resolver un cierto tipo de problemas es lo que se conoce como
un algoritmo.
Según el problema que abordemos el algoritmo será más o menos complicado pero aprender a programar tiene
más que ver con desarrollar esta capacidad de resolver problemas lógicos en una secuencia de pasos que
podamos codificar en un ordenador.
Por cierto, cualquiera puede aprender a programar. No lo dudéis. Solo que como en todo, a unos les lleva más
tiempo que a otros desarrollar la habilidad necesaria. Al principio muchos me dicen que les duele la cabeza de
pensar en este tipo de cosas, pero os animo a continuar (poco a poco si es preciso) porque os encontrareis que
vale la pena.
RESUMEN DE LA SESIÓN
.
En esta sesión hemos aprendido varias cosas importantes:
La instrucción For, nos permite iterar un bloque de instrucciones tantas veces le indiquemos.
Hemos visto uno de los tipos de variables que C++ acepta: los enteros.
Hemos introducido el concepto de algoritmo, como un procedimiento secuencial para resolver un problema
concreto y lo hemos aplicado a varios ejemplos de programas sencillos con luces.
OBJETIVOS
.
o Comprender las diferencias entre analógico y digital.
o Conocer las salidas cuasi analógicas de Arduino.
o Modulación PWM
MATERIAL REQUERIDO.
TIENDA ESPAÑA TIE
TIENDA ESPAÑA TIE
Kit inicio UNO K
Kit Inicio Mega K
ANALÓGICO Y DIGITAL
Todas las señales que hemos manejado hasta ahora con nuestro Arduino , de entrada o de salida, comparten
una característica común: Son digitales, es decir que pueden tomar un valor HIGH o LOW pero no valores
intermedios.
Si representamos una el valor de una señal digital a lo largo del tiempo veríamos algo así:
En la vida muchas cosas son así, apruebas o suspendes, enciendes la luz o la apagas, pero muchas otras son
variables mensurables continuas y pueden tomar cualquier valor que imaginemos, como el ángulo del reloj o la
temperatura, que aun dentro de valores finitos pueden tomar tantos valores intermedios como podamos
imaginar,
A esta clase de variables las llamamos analógicas y una representación por contraposición a lo digital, sería
algo como esto:
No es raro que queramos controlar algo del mundo exterior con una señal analógica de forma que el
comportamiento del sistema siga esa señal. Podemos por ejemplo querer variar la luminosidad de un diodo LED
y no simplemente apagarlo o encenderlo
En esta sesión aprenderemos a enviar señales analógicas a los pines de salida de Arduino.
SALIDAS CUASI ANALÓGICAS
.
Hasta ahora hemos visto como activar las salidas digitales de Arduino, para encender y apagar un LED por
ejemplo. Pero no hemos visto como modificar la intensidad del brillo de ese LED. Para ello, tenemos que
modificar la tensión de salida de nuestro Arduino, o en otras palabras tenemos que poder presentar un valor
analógico de salida.
Para empezar tenemos que dejar claro que los Arduino carecen de salidas analógicas puras que puedan hacer
esto (con la notable excepción del Arduino DUE).
Pero como los chicos de Arduino son listos, decidieron emplear un truco, para que con una salida digital
podamos conseguir que casi parezca una salida analógica.
A este truco se le llama PWM, siglas de Pulse Width Modulation, o modulación de ancho de pulsos. La idea
básica es poner salidas digitales que varían de forma muy rápida de modo que el valor eficaz de la señal de
salida sea equivalente a una señal analógica de menor voltaje.
Lo sorprendente es que el truco funciona.
Fijaros en la anchura del pulso cuadrado de arriba. Cuanto mas ancho es, mas tensión promedio hay presente
entre los pines, y esto en el mundo exterior es equivalente a un valor analógico de tensión comprendido entre 0
y 5V. Al 50% es equivalente a una señal analogica del 50% de 5V, es decir 2,5. Si mantenemos los 5V un 75%
del tiempo, será el equivalente a una señal analógica de 75% de 5V = 3,75 V.
Para poder usar un pin digital de Arduino como salida analógica, lo declaramos en el Setup() igual que si fuera
digital:
pinMode( 9, OUTPUT) ;
La diferencia viene a la hora de escribir en el pin:
digitalWrite(9, HIGH); //Pone 5V en la salida
digitalWrite(9, LOW); //Pone 0V en la salida
analogWrite( 9, V) ;
analogWrite escribe en el pin de salida un valor entre 0 y 5V, dependiendo de V (que debe estar entre 0 y 255).
De este modo si conectamos un LED a una de estas salidas PWM podemos modificar su brillo sin más que
variar el valor que escribimos en el pin.
Pero hay una restricción. No todos los pines digitales de Arduino aceptan poner valores PWM en la salida.
Solamente aquellos que tienen un símbolo ~ delante del número. Fijaros en la numeración de los pines de la
imagen:
solo los que llevan simbolo
Solamente los pines 3, 5, 6, 9, 10 y 11 pueden hacer PWM y simular un valor analógico en su salida.
Si intentas hacer esto con un pin diferente, Arduino acepta la orden tranquilamente, sin error, pero para valores
de 0 a 127 entiende que es LOW y para el resto pone HIGH y sigue con su vida satisfecho con el deber
cumplido.
MODIFICANDO EL BRILLO DE UN LED
.
Vamos a hacer el típico montaje de una resistencia y un diodo LED, similar al de la sesión 3, pero
asegurándonos de usar uno de los pines digitales que pueden dar señales PWM. En la imagen he usado el pin
9.
Podemos escribir un programa parecido a esto:
void setup() //Prog_10_1
{
pinMode( 9, OUTPUT) ;
}
void loop()
{
for ( int i= 0 ; i<255 ; i++)
{
analogWrite (9, i) ;
delay( 10);
}
}
El LED va aumentando el brillo hasta un máximo y vuelve a empezar bruscamente. Podemos modificar un poco
el programa para que la transición sea menos violenta:
void setup() // Prog 10_2
{
pinMode( 9, OUTPUT) ;
}
void loop()
{
for ( int i= -255 ; i<255 ; i++)
{
analogWrite (9, abs(i)) ;
delay( 10);
}
}
Aquí aprovecho ( por pura vagancia) para hacer el ciclo de subir y bajar el brillo del LED con un único bucle. La
función abs(num), devuelve el valor absoluto o sin signo de un número num, y por eso mientras que i viaja de -
255 a 255, abs(i) va de 255 a 0 y vuelta a subir a 255. ¿Que os parece el truco?
RESUMEN DE LA SESIÓN
.
o Describimos a grandes rasgos la diferencia ente valores digitales y valores analógicos.
o Hemos visto como simular valores analógicos en una salida digital de Arduino.
Solo con las salidas que lo aceptan: pines 3, 5, 6, 9, 10 y 1.
Podemos asignar valores entre 0 y 255.
LOS DIODOS RGB
.
Hasta ahora hemos usado varias combinaciones de LEDS, pero siempre de un color definido. Habitualmente
los rojos y amarillos son los más fáciles de conseguir, pero se pueden comprar también en tonos azules, verdes
y hasta blancos. No suele haber grandes diferencias entre ellos excepto en el color.
Pero a veces es interesante disponer de una luz piloto que cambie de color según las condiciones. Por ejemplo,
todos identificamos el verde como una señal de OK, mientras que el rojo indica problemas y el amarillo… bueno
pues algo intermedio.
Poner varios diodos para hacer esto es engorroso y complica el diseño, así que estaría bien disponer de un
diodo al que podamos indicar que color queremos que muestre. Esto es un LED RGB.
Para quien este acostumbrado al diseño por ordenador ya está familiarizado con la idea de que podemos
generar cualquier color en la pantalla con la mezcla, en diferentes grados de tres colores básicos:
Red : Rojo
Green: Verde
Blue: Azul
Es decir RGB, uno de esos acrónimos que surgen continuamente en imagen, TV, etc.
Un LED RGB es en realidad la unión de tres LEDs de los colores básicos, en un encapsulado común, compartiendo
el Ground (cátodo es otro nombre más para el negativo).
En función de la tensión que pongamos en cada pin podemos conseguir la mezcla de color que deseemos con
relativa sencillez
Para quien haya dibujado con lápices de colores o acuarelas, las mezclas de colores de arriba les resultará
extraña. Esto es porque cuando pintamos en un papel blanco, la mezcla de colores es substractiva: Si
mezclamos los tres colores obtenemos negro, o por lo menos algo oscuro
En cambio cuando pintamos con luz directamente, la mezcla es aditiva y obtenemos blanco al mezclar los tres
colores básicos. Las reglas de mezcla de color en ambos casos son opuestas.
Vamos a montar un pequeño circuito que nos permita gobernar el color que emite uno de éstos LEDs de RGB.
ESQUEMA DEL CIRCUITO
.
El montaje supone sencillamente conectar el negativo (el pin más largo) a Ground mediante una resistencia que
limite la intensidad, y luego identificar los pines de colores:
El pin más largo en estos LED es el GND.
Al lado de GND hay dos pines a un lado y uno solitario al otro. Por lo normal el solitario es el rojo R.
Así pues el pin out (patillaje) de un RGB LED suele ser R, GND, G, B.
De todos modos conviene asegurarse leyendo las especificaciones del fabricante, o bien identificando cada
PIN. Para identificarlos basta conectar el GND a nuestro Arduino e ir probando cada una de las patas
independientemente para ver qué color producen.
Si tu RGB tiene una montura Keyes, no tendrás que hacer esto, porque los pines vienen marcados y GND viene
rotulado como -.
Atención, en contra de la norma habitual, en este caso el cable rojo no indica la tensionVcc, sino el pin de
gobierno del LED rojo.
En este esquema hemos utilizado los pines 9, 10 y 11. Podemos usar otros pero aseguraros de que puedan
hacer PWM(los que tienen ~) para poder poner distintas intensidades.
PROGRAMA DE CONTROL RGB
Dado que nuestra idea es poder mezclar las tonalidades de los componentes RGB para generar diferentes
matices de colores, parece buena idea escribir una función que haga esta mezcla de colores y a la que
podamos recurrir de forma abstracta y práctica (además de para encapsular una utilidad curiosa, a la que
podremos recurrir en futuros ejemplos y de paso insistir en el concepto de función).
Lo primero sería definir en el setup() los pines a usar:
void setup()
{
for (int i =9 ; i<12 ; i++)
pinMode(i, OUTPUT);
}
Y después podríamos escribir una función como esta
void Color(int R, int G, int B)
{
analogWrite(9 , R) ; // Red - Rojo
analogWrite(10, G) ; // Green - Verde
analogWrite(11, B) ; // Blue - Azul
}
De este modo tendríamos fácil llamar a Color ( 0, 255, 0) para el verde. De hecho vamos a empezar
asegurándonos de que tenemos identificados correctamente los pines, escribiendo un sketch como este:
void loop()
{ Color(255 ,0 ,0) ;
delay(500);
Color(0,255 ,0) ;
delay(500);
Color(0 ,0 ,255) ;
delay(500);
Color(0,0,0);
delay(1000);
}
Este programa debería producir una secuencia de rojo, verde, azul, apagado y vuelta a empezar.
Conviene asegurarse de que hemos identificado correctamente los pines del RGB, porque de lo contrario, las
mezclas posteriores de colores no serán lo que esperamos.
Vamos a ver como averiguar qué mezcla de RGB necesitamos para conseguir un color determinado. Para
quienes uséis Windows disponéis del programa Paint incluido (en el menú de accesorios) y para quienes uséis
Mac o Linux tenéis programas similares.
Si arrancáis el Paint(o equivalente) suele tener un selector de colores:
Pulsándolo aparecerá algo parecido a esto:
Si vais pinchando en la zona de colores de la derecha, en la barra vertical aparecen los matices próximos al que
habéis pinchado y podéis elegir el que más os guste. Debajo podéis ver la separación en RGB precisa para
conseguir un tono determinado.
Así pues para conseguir ese tono de azulito de la imagen basta con que llaméis a
Color(13, 227, 201) ;
Dado que Arduino nos permite escribir valores de 0 a 255 en los pines digitales, cuando utilizamos
analogWrite(), en la práctica tendremos 255 x 255 x 255 colores diferentes o lo que es igual: 16.581.375 colores
posibles.
La función Color() que hemos creado en esta sesión es muy sencilla pero se va añadiendo a otras que
hemos ido creando en sesiones anteriores con lo que vamos haciendo una pequeña colección de ellas.
El grupo de desarrollo de Arduino ha ido creando también muchas funciones que están disponibles para
incorporar en nuestros programas y que por razones de espacio resultan imposibles de ver más que muy por
encima.
Solo como ejemplo introduciremos una de ellas. La función La función random( N ) devuelve un valor al azar,
comprendido entre 0 y N y en este caso, se presta especialmente bien para generar colores aleatorios en
nuestro LED RGB. Puedes intentarlo?