Hasta ahora hemos visto estructuras de control, variables, funciones entre otros. En la segunda entrada de este curso vimos como realizar comunicación por el puerto serie y, hoy, vamos a llevarlo un paso más allá. No solo vamos a utilizar el puerto serie para hacer debug de nuestro programa y conocer información, si no que vamos a ser capaces de dar ordenes a nuestra placa ZUM BT 328, o cualquier placa Arduino, a través del monitor serie. Con esto podremos, por ejemplo, enviar un vector a nuestro robot indicando la dirección y la velocidad a la que tiene que moverse.
Además, vamos a aprender a realizarlo con una señal analógica a través de los pines PWM de Arduino, los cuales utilizaremos para modificar el color del LED RGB. La función PWM de las placas Arduino nos permiten generar una señal analógica a través de señales digitales. Si quieres conocer más sobre el PWM puedes acceder a la página de referencia de PWM.
Lista de materiales
- ZUM BT-328, placa Arduino o compatible.
- Breadboard (o placa de pruebas o protoboard).
- Led RGB de cátodo común, en este caso.
- Cables Jumper.
Conexiones eléctricas
Al utilizar una breadboard , si estamos empezando un proyecto o si el proyecto es pequeño, puede no tener mucha importancia, pero cuando el tamaño va aumentando es importante utilizar cableado de colores para facilitar la comprensión del circuito de manera visual. Por ejemplo, en el caso del LED RGB podemos facilitar las conexiones si utilizamos, por ejemplo, un cable rojo para el pin que controlará el color rojo del LED RGB.
Es costumbre marcar la alimentación del circuito con un cable de color rojo y la conexión a tierra o GND – del Inglés Ground – con un cable de color negro o marrón.
El módulo LED que utilizamos en el ejemplo, incluye resistencias para limitar la corriente en el propio módulo, pero si el que vas a utilizar no dispone de dichas resistencias, asegúrate de conectar una resistencia por cada color, para evitar quemar el LED. Podéis encontrar un ejemplo de como conectar un LED sin resistencias integradas en la imagen:
En el caso de éste proyecto, conectaremos el LED RGB y la placa ZUM BT-328 de la siguiente manera:
ZUM BT-328 | LED RGB |
GND | GND |
6 | R |
5 | G |
3 | B |
El código
Como siempre, vamos a empezar declarando las variables de los pines:
1 |
int redPin = 6, greenPin = 5, bluePin = 3; |
Además vamos a declarar unas variables que utilizaremos a lo largo del sketch:
1 2 3 |
int delayLed = 10; // Tiempo que pasará entre cada cambio de LED (ms) // Variables que almacenarán el ultimo color de cada uno de los leds int red_old = 0, green_old = 0, blue_old = 0; |
En la variable delayLed almacenaremos el tiempo, en milisegundos, que pasará en las transiciones entre un valor del LED y el siguiente. Es recomendable utilizar un valor muy bajo, ya que es un delay que se utiliza para hacer que la transición sea más suave, por lo que hay que tener en cuenta que cuanto mayor sea el valor más aumentará el tiempo que tardará en realizarse la transición, por ejemplo, para el valor de 10 ms la transición desde negro (en el caso del led sin brillo) a blanco, o desde (0,0,0) hasta (255,255,255), tarda 7,6 segundos en completarse. La misma transición con 5 ms tarda 3,8 segundos en completarse.
A continuación utilizamos la función setup para inicializar nuestro programa:
1 2 3 4 5 6 7 8 9 10 11 |
void setup() { // Iniciar el puerto serie. Serial.begin(9600); // Marcamos como salidas los pines utilizados. pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT); Serial.println("¡Preparado!"); } |
En setup iniciamos el puerto serie, que utilizaremos para realizar la comunicación entre Arduino y el ordenador. Además, establecemos como salida los diferentes pines utilizados para cada uno de los colores.
Dentro del bucle loop, encontramos un par de métodos que no conocíamos hasta ahora, parseInt y constrain.
El método parseInt se utiliza junto a Serial con la orden Serial.parseInt(); y busca en la información que recibe por el puerto serie la siguiente cadena de números enteros hasta que encuentra una coma. Puedes consultar la referencia aquí.
La función constrain se utiliza para “obligar” a que un valor se encuentre entre otros dos, es decir, si el valor esta en el rango A-B tomara su valor, si es menor tomará el valor de A y si es mayor tomará el valor de B. Puedes consultar la referencia aquí.
El código del bucle loop es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
void setup() { // Iniciar el puerto serie. Serial.begin(9600); // Marcamos como salidas los pines utilizados. pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT); Serial.println("¡Preparado!"); } void loop() { // Si hay informacion disponible en el puerto serie la utilizamos: while (Serial.available() > 0) { int red = 0, green = 0, blue = 0; // busca la siguiente cadena de números enteros valida y // asigna el valor convertido a entero a la variable correspondiente red = Serial.parseInt(); // vuelve a buscar. green = Serial.parseInt(); // vuelve a buscar: blue = Serial.parseInt(); // busca el caracter de fin de linea. Indica al programa que se ha terminado de introducir datos. // Si utilizas el IDE de arduino u otro ide que permita incluir el formato // de nueva linea al enviar datos por el monitor serie, elimina el comentario // de la linea 33 y comenta la linea 34. // if (Serial.read() == '\n'){ if (Serial.read() == '*'){ // Con constrain nos aseguramos de que el valor esté en el rango del pwm //Para leds de anodo común utiliza, para rojo, por ejemplo: red = 255 - constrain(red, 0, 255); red = constrain(red, 0, 255); green = constrain(green, 0, 255); blue = constrain(blue, 0, 255); // print the three numbers in one string as hexadecimal: Serial.print(red, HEX); Serial.print(green, HEX); Serial.println(blue, HEX); //Modificamos el color del led RGB fade(redPin, red, red_old); fade(greenPin, green, green_old); fade(bluePin, blue, blue_old); Serial.println("Color conseguido"); //Almacenamos los datos de color anteriores. red_old = red; green_old = green; blue_old = blue; } } } |
Dentro de loop podemos ver que se llama a fade, que es una función que hemos creado que nos permite llevar al led desde el color actual hasta el próximo color mediante una transición suave. La función fade esta definida después de loop y es así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void fade(int pin, int newValue, int aktValue) { // Esta funcion se encarga de llevar cada color desde su valor actual hasta el siguiente // Distinguimos dos casos: // 1 - El nuevo valor es mayor que el valor actual, por lo que hay que aumentarlo // 2 - El nuevo valor es menor que el valor actual, por lo que hay que reducirlo if (newValue < aktValue) { for (int i = aktValue; i <= newValue; i++) { analogWrite(pin, i); delay(delayLed); } } else if (newValue > aktValue) { for (int i = aktValue; i >= newValue; i--) { analogWrite(pin, i); delay(delayLed); } } } |
En esta función distinguimos dos casos:
- El siguiente valor es mayor que el valor actual, por lo que tenemos que incrementar el valor del led.
- El siguiente valor es menor que el valor actual, por lo que tenemos que disminuir el valor del led.
En esta función aparece también un comando que no habíamos visto hasta ahora, analogWrite, que se encarga de utilizar las capacidades PWM, del Inglés Pulse Width Modulation o modulación de ancho de pulso, de nuestra placa. El PWM simula una señal analógica mediante pulsos discretos de una señal digital. En la página de referencia de PWM podéis encontrar más información.