Kitabı oku: «Arduino para principiantes», sayfa 2
¿Cómo hacer que el LED parpadee?
Podrías intentar asignar de manera alternativa los valores HIGH y LOW en el bucle digitalWrite(), pero no te funcionaría. Puedes intentarlo tú mismo con este código:
void setup() {
pinMode(13,OUTPUT);
}
void loop() {
digitalWrite(13,HIGH);
digitalWrite(13,LOW);
}
Con bloques: (Archivo: tema01/1.1.b.bly)
En realidad el código debería funcionar, ¡y funciona! Pero como el controlador trabaja con 16 millones de hercios (hercio significa oscilaciones, pulsos; es decir, cuando una orden dura un pulso, el pin cambia de estado 16 millones de veces por segundo, es decir, el pin cambia una vez cada 0.0000000625 segundos), el ojo humano no puede detectar esos cambios en el LED. Hay que hacer mayor la distancia entre los cambios, y para ello se utiliza el comando delay(). Esta orden hace detenerse al controlador durante los milisegundos que le indiquemos (1000 ms = 1 segundo). Para conseguir que el LED parpadee por segundos, necesitamos el siguiente código:
void setup() {
pinMode(13,OUTPUT);
}
void loop() {
digitalWrite(13,HIGH);//LED encendido
delay(1000); //1 segundo de espera
digitalWrite(13,LOW);/LED apagado
delay(1000);//Otro segundo de espera
//Volvemos al principio del loop y vuelta a empezar. Ciclo infinito.
}
Con bloques: (Archivo: tema1/1.1.c.bly)
Y con esto tienes ya tu primer proyecto: el LED que parpadea. Ahora puedes guardarlo con FILE|SAVE bajo el nombre que elijas. El IDE de Arduino guarda todos los archivos con código fuente (archivos fuente) en un mismo lugar para que puedas utilizarlos más adelante. También puedes guardar el diagrama de bloques de Visualino con ARCHIVO|GUARDAR (formato blockly: *.bly)
Variables y lo que significan
Con esto ya tienes un primer código "en funcionamiento" con el que puedes controlar varios pines a la vez. Tal vez te estés preguntando cómo organizar los pines cuando se trabaja con 50 de ellos (Arduino Mega, por ejemplo, tiene más de 50 pines). Arduino te ofrece la posibilidad de darle un nombre a cada pin, lo que se realiza mediante las llamadas variables. En realidad, una variable tiene un contenido que se puede modificar, es decir, que es variable, de ahí su nombre. Lo contrario sucede con una constante, que no se puede modificar. En las variables se puede definir también el número de pines que queremos controlar. Para ello necesitamos una variable numérica, llamada variable Integer. Integer es la palabra inglesa para número entero, con lo que ya puedes imaginarte qué se guarda en ella. El ejemplo anterior, con variables, tiene este aspecto:
int led = 13; //asignación de una variable.
int pause = 1000;
void setup() {
pinMode(led,OUTPUT);
}
void loop() {
digitalWrite(led,HIGH); //Pin 13, led, activado
delay(pause); //Espera de 1 seg.
digitalWrite(led,LOW);
delay(pause);
}
Con bloques: (Archivo: tema01/1.1.d.bly)
Con tipodevariable nombredevariable = valor; se inicializa una variable. Los diferentes tipos de variables que nosotros utilizaremos son los siguientes:
Tipo variable | Contenido | Ejemplo |
int | Entero | 9 |
float | Flotante | 9.4 |
byte | Entero de -128 hasta 127 | 50 |
char | Carácter | 'e' |
bool | Valor booleano (en otras palabras, 1 o 0) | true/false o 1/0 |
Lo importante es que las variables nunca empiecen con un número ni contengan ningún espacio en blanco (en su lugar puedes utilizar guiones bajos, por ejemplo largo_nombre). Para ello has de tener en cuenta que una misma variable la has de escribir siempre igual, y que se diferencia entre mayúscula y minúsculas.
También has de tener en cuenta que cada variable tiene un determinado intervalo de valores que no se puede sobrepasar (por ejemplo: -128 a +127 en byte). Las comas en números decimales se representan con un punto (.), ya que es así como se hace en el mundo anglosajón (3,14 pasa a ser 3.14). En char, la letra tiene que ir siempre entre comillas voladas, y con bool solo se pueden utilizar los valores indicados anteriormente: true|false o 1|0. Más adelante en este capítulo explicaremos para qué sirve bool.
¿Cómo se organizan las variables en realidad?
Cada microcontrolador contiene una cierta cantidad de RAM, es decir, de memoria de trabajo de un microchip, organizada en pequeñas unidades. Según el tamaño de la variable, se reserva una cierta cantidad y se escribe con el valor. Por eso también es necesario disponer siempre de una cantidad suficiente de RAM libre, pues de lo contrario el programa podría ejecutarse con fallos. Un pequeño consuelo: todos los programas que aparecen en el libro funcionan perfectamente con Arduino Uno, y en algunos esquemas, se puede ocupar la memoria completamente mediante una ampliación propia, pero eso lo veremos separadamente.
Nuestro segundo programa: Juego de luces con LED
Ahora vamos a hacer algo práctico con las variables, un pequeño juego de luces con LED. Para ello necesitarás al menos cinco LED, de manera que se pueda reconocer algo. Mi propuesta es que utilices los pines 12 a 8. El otro punto decisivo es el cableado. Si tienes una breadboard, como aconsejamos, puedes hacerlo así (en la Introducción encontrarás una guía sobre el breadboard):
El conjunto es relativamente sencillo: conectas el pin 12 con el LED que está en el extremo izquierdo y, sucesivamente, el siguiente pin con el LED siguiente. Con eso queda hecha la conexión y ya podemos hacer el siguiente experimento.
Primero desarrollaremos simplemente un bucle que haga parpadear un LED y a continuación encienda el siguiente, y así sucesivamente. El código fuente necesario no contiene nada nuevo y es relativamente simple:
int pin1 = 8;
int pin2 = 9;
int pin3 = 10;
int pin4 = 11;
int pin5 = 12;
void setup() {
pinMode(pin1,OUTPUT);
pinMode(pin2,OUTPUT);
pinMode(pin3,OUTPUT);
pinMode(pin4,OUTPUT);
pinMode(pin5,OUTPUT);
}
void loop() {
//Parpadeo del Pin 1
digitalWrite(pin1,HIGH);
delay(100);
digitalWrite(pin1,LOW);
delay(100);
//Pin 2
digitalWrite(pin2,HIGH);
delay(100);
digitalWrite(pin2,LOW);
delay(100);
//Pin 3
digitalWrite(pin3,HIGH);
delay(100);
digitalWrite(pin3,LOW);
delay(100);
//Pin 4
digitalWrite(pin4,HIGH);
delay(100);
digitalWrite(pin4,LOW);
delay(100);
//Pin 5
digitalWrite(pin5,HIGH);
delay(100);
digitalWrite(pin5,LOW);
delay(100);
}
Con bloques: (Archivo: tema01/1.2.a.bly)
Nota: Solo hemos representado en el diagrama de bloques los dos primeros LED para no alargarnos.
Cómo funcionan las funciones
Como ves, nada nuevo, pero resulta un poco largo para ese pequeño efecto. Deberíamos poder acortar el código, ¿no crees?
Eso se puede hacer con funciones. El concepto ya lo has visto anteriormente, ahora vamos a escribir nosotros mismos una función. En nuestro caso, la función consiste en el procesamiento de unos cuantos comandos (en realidad, también de funciones, como por ejemplo digitalWrite()), "encapsuladas" en una sola llamada. Con funciones se puede organizar mejor el código. Esta técnica es un método para la programación estructurada. Incluye bucles y saltos, aunque los saltos no se tratan en este libro, ya que hoy día están desfasados y empeoran el código, es lo que se llama un Spaghetti-Code (no es una broma, ¡es el nombre real!).
Y ahora seguimos con las funciones. Miremos primero una función que ya conoces: void digitalWrite(int,int). Así se pueden resumir las funciones, con el nombre de la función y el tipo de los parámetros dados (en nuestro caso, dos números enteros). Antes de la función viene el tipo de respuesta, en este caso, void (la función no devuelve nada, esto es, se queda igual).
Y también puedes describir una función así:
Tipoderespuesta Nombredelafunción (parámetro) {códigodelafunción;}
Después del código anterior, tan largo, te voy a mostrar la función correspondiente:
void blink(int pin,int msek) {
digitalWrite(pin,HIGH);
delay(msek);
digitalWrite(pin,LOW);
delay(msek);
}
Así es nuestra primera función. En los paréntesis se escriben los parámetros, esto es, qué pin se ha de activar y durante cúanto tiempo. En las llaves se escribe el código perteneciente a la función.
En el diagrama de bloques será: (Archivo: tema01/1.2.b.bly)
En este caso los valores de la función se definen mediante la estrella de la esquina superior izquierda: (Archivo: tema01/1.2.b.bly)
Indicación: Después de las llaves no se escribe punto y coma.
Lo interesante llega ahora, cuando carguemos el código en Arduino. Veamos otra vez el conjunto de nuestro esquema actual:
void blink(int pin,int msek) {
digitalWrite(pin,HIGH);
delay(msek);
digitalWrite(pin,LOW);
delay(msek);
}
void setup() {
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
}
void loop() {
blink(8,1000); //Dauer in Millisekunden
blink(9,1000);
blink(10,1000);
blink(11,1000);
blink(12,1000);
}
En el programa principal con bloques para uno de los LED tendremos:
(Archivo: tema01/1.2.b.bly)
El código fuente es ahora bastante más corto, pero hace lo mismo; práctico, ¿no? Las definiciones de las funciones deben escribirse siempre fuera de cualquier otra función para que no haya errores. Y llegamos así a los intervalos de valores. Son algo difíciles de entender, pero muy importantes. Supongamos que defines una variable en blink. ¿Puedes utilizarla también en otras funciones? Lamentablemente, no, debido a los niveles de validez. Para que lo entiendas, vamos a ver un código fuente pequeño:
int global; //Se puede usar en cualquier lugar del programa
void setup() {
int funcion; //Solo dento de la función setup()
}
Las variables definidas a nivel global se pueden activar en cualquier punto. Las variables definidas a nivel de función solo se pueden activar/utilizar dentro de la función correspondiente.
Esto es práctico saberlo, aunque pocas veces lo necesitarás cuando programes. Mucho más importante es el tema de la lectura de los pines, con poca teoría y bastante más práctica.
Leer las entradas
La lectura de los pines, activados en Entrada (Input), es un tema importante que necesitarás también en el resto del libro. Supongamos el caso siguiente: quieres que un LED solo parpadee al pulsar un botón. Para ello necesitaremos la función contraria a digitalWrite(), es decir, digitalRead(). Para poder “armar” el código fuente necesitamos en primer lugar el siguiente circuito:
Lo mejor es que lo incorpores tal como muestra la ilustración siguiente. Es importante que cablees el botón tal como se indica, pues de lo contrario podrían producirse cortocircuitos. Ahora debes conectar también una resistencia, cuyo valor es difícil de reconocer. Es un valor de 10 Kiloohmios.
Si todo funciona bien, empecemos con el código fuente. Como de costumbre, primero el esquema y después la explicación:
int ledpin = 13;
int buttonpin = 2;
int buttonstate;
void setup() {
pinMode(ledpin,OUTPUT); // Colocamos el led como salida
pinMode(buttonpin,INPUT); // Y el botón como entrada.
}
void loop() {
buttonstate = digitalRead(buttonpin);
if (buttonstate == HIGH) {
digitalWrite(ledpin,HIGH);
} else { digitalWrite(ledpin,LOW); }
}
En el diagrama de bloques: (Archivo: tema01/1.2.c.bly)
If y Else: Si no funciona, haz lo siguiente
A continuación, verás varias funciones y técnicas nuevas de programación que te ayudarán en tus programaciones: la pregunta If -Else y la lectura y la definición de un "Inputstatus".
Veamos primero la ampliación de la función pinMode(): Con "INPUT" estamos indicando que el pin se debe leer internamente (en el microchip), y no "describirse" como hacíamos con la conexión de un LED. A continuación, la variable numérica buttonstate; aquí no asignamos directamente ningún valor en el bucle loop(), ya que toma el que devuelve la función digitalRead(). (En este caso: 0 = sin corriente, 1 = corriente.) En este capítulo aprenderás a programarlo tú mismo. La línea siguiente ya es más difícil, pues aparece la pregunta if. Para que lo entiendas mejor, vamos a ver esa parte del código en pseudocódigo (pseudocódigo significa anotar en palabras el contenido de la función, no la programación).
Si el botón esta presionado
-> entonces enciende el led
si no
-> apagar el led.
Las llaves, como en la definición de una función, sirven para asignar el contenido de la pregunta. De ese modo, el ordenador (Arduino) sabe cual es el código que aparece entre llaves después de if y anota los comandos que se han de ejecutar cuando el botón está ativado (pulsado).
Llegamos ahora a la pregunta if, que es más o menos así:
if (condición) {
//Ejecuta el código que se encuentra aquí
}
Una condición puede ser la comparación entre una variable y una constante, como en nuestro ejemplo entre la variable buttonstate y la constante HIGH. Hay que tener en cuenta que debemos usar dos signos de igualdad, pues así Arduino sabe que se trata de una comparación (buttonstate == HIGH) y no de una asignación de valor (int xy = 9). Naturalmente, no solo puedes probar igualdades sino también lo siguiente (suponiendo que x = 5):
Operador | Ej. | Resultado |
== (mismo) | x == 5 | Verdadero |
!= (distinto) | x != 5 | Falso, si x = 5 |
> (mayor) | x > 3 | Verdadero, x = 5 es mayor que 3 |
< (menor) | x < 10 | Verdadero, x = 5 es menor que 10 |
>= (mayor o igual) | 10 >= x | Verdadero, 10 es mayor o igual que 5 |
<= (menor o igual) | x <= 3 | Falso, x = 5 no es menor o igual que 3 |
Así puede parecer complicado, pero cuando sigas leyendo el capítulo, verás que entiendes mejor las tablas.
Vayamos ahora al else: else es una palabra inglesa que significa "de lo contrario". Leyendo el código fuente diríamos: si el estado del botón es HIGH, activa el LED, de lo contrario, desactívalo. Lo entenderás todavía mejor con el dibujo siguiente, que es un diagrama de flujo.
La parte del else también se escribe entre llaves y solo puede aparecer después de una pregunta if (en cualquier otro lugar no tendría ningún sentido). Ahora podemos anotar y representar todo el esquema de nuestro código fuente también en pseudocódigo:
* Lee si en el pin 11(buttonpin) hay corriente, activa el button;
-> Sí, escribe HIGH* en la variable,
-> de lo contrario escribe LOW* (no hay corriente).
* Comprueba si en la variable aparece HIGH
-> Si aparece HIGH, activa el LED.
-> Si aparece otra cosa (else), desactiva el LED (en nuestro caso aparecerá o HIGH o LOW).
Empieza otra vez desde el principio (bucle loop).
De ahí las variables íntegras.
Ahora ya deberías entender la función del esquema. Para que se te queden mejor las funciones, te proponemos una pequeña tarea.
Condiciones en la práctica
Escribe un programa que reste la variable y de la variable x y guarde el resultado en la variable z. Si z es mayor de 10, se encenderá un LED; de lo contrario, no. El código puede estar también en la parte del setup. Intenta encontrar la solución tú solo y mira después mi propuesta.
int x = 312; //Variable global x
int y = 9; //y es un entero
int z;
void setup() {
z = x – y; //z es igual a x - y.
if (z > 10) { //Si z es mayor de 10, mínimo. 11
digitalWrite(13,HIGH); //Encendemos el led en Pin 13
} else {
digitalWrite(13,LOW);//apagamos el led:
//apagamos el led:
//Hasta que no sea 11 el led continuara apagado
//Inicialmente el led estará apagado
}
}
void loop() {}
Con bloques: (Archivo: tema01/1.2.d.bly)
No era tan difícil, ¿no? El concepto inglés para la pregunta if, por cierto, es si (se cumple) - hacer.
Un consejo más. En caso de que hayas olvidado el contenido de una función oficial (por ejemplo, digitalWrite()): selecciona el nombre de la función y ve, en el menú contextual (botón derecho del ratón), a "Find in Reference". En tu navegador aparecerá una página con una breve explicación y un código de ejemplo con la aplicación/uso correctos (tienes que seleccionar solo la palabra que aparece sobre fondo naranja en el IDE).
Nuestro tercer programa: morse
Ahora vamos a desarrollar algo que tenga al menos un pequeño uso práctico. Había pensado en un aparato que nos ayude a comunicarnos por morse. El código morse lo desarrolló Samuel Morse en 1833 para poder transmitir signos con un telégrafo desarrollado también por él. Después de unas cuantas mejoras, surgió el código que todavía utilizamos hoy (colaboraron, entre otros, A. Vail y F. Gerke). Si quieres saber más sobre la historia de este código, puedes consultar la página de es.wikipedia.org/wiki/Código_morse.
Mi propuesta es que desarrollemos ahora un teclado morse que emita una señal acústica al pulsar un botón, así podrás practicar mejor el morse y, sobre todo, practicar el procedimiento para desarrollar tus propios proyectos.
Conectar el hardware
En primer lugar, debemos pensar qué hardware necesitaremos. Además de Arduino y el breadboard, cable incluido (nuestro equipamiento básico), en este proyecto necesitaremos un botón y un medio para emitir las señales morse: el LED, altavoces, puertos en serie (ver siguiente capítulo), e incluso protocolos en una microtarjeta SD (ver más adelante), nos vendrán muy bien. Yo añadiré un altavoz, pero te enseñaré antes que es muy fácil trasladarlo a un LED. Por tanto, necesitamos también un pequeño altavoz. Si te resulta muy caro encontrar el adecuado, puedes utilizar simplemente la segunda versión con LED. Pero primero desarrollaremos la conexión y así tendremos "algo" de hardware que incorporar. La conexión del altavoz se realiza a través de Arduino, por lo que necesitamos dos circuitos (Arduino & Botón y Arduino & Altavoz).
En la figura siguiente podemos ver cómo es nuestro conexionado. Los cables se han salido un poco de ángulo pero, aún así, el circuito debería quedar claro. Primero se conectan con los powerrails (los contactos colocados más afuera de la placa de prototipos (breadboard)) que van marcados con más y menos (en dos soportes/líneas) y después con el botón. El cable amarillo va al Input del microcontrolador.
Veamos ahora el plan prometido para la conexión:
Tal vez tengas que hacer también un puente en medio del powerrail, ya que en algunos breadboards presentan ahí una interrupción.
El software
Llegamos con ello al código fuente, nuestro esquema. Puedes buscar una función en Internet para emitir sonidos por el altavoz (palabra clave: tone()), ese sería el procedimiento al crear un proyecto propio. Pero también puedes mirar el siguiente código fuente:
int buttonstate;
int note = 720; //Tono (frecuencia) de la nota
void setup() {
pinMode(7,INPUT);
}
void loop() {
buttonstate = digitalRead(7);
if (buttonstate == HIGH) {
tone(8,note); // Sonido
} else {
noTone(8); // De lo contrario, silencio.
}
}
En el ejemplo parto de que el altavoz está conectado al pin 8, y el botón al pin 7. En la variable int note aparece la altura del tono con que se debe escribir en el altavoz (para ser más exactos, es la frecuencia). A continuación viene otra pregunta if y la única función: tone(). Una secuencia relativamente sencilla. El primer parámetro es el pin (en este caso, el pin 8) y el segundo parámetro es la frecuencia (guardado en la variable note). Ahora podemos llevarlo todo a un LED, cosa que deberías intentar hacer tú solo. Aunque es muy fácil, te damos la solución:
int buttonstate;
void setup() {
pinMode(7,INPUT);
pinMode(8,OUTPUT); //LED en Pin 8,
//el circuito de botones permanece igual
}
void loop() {
buttonstate = digitalRead(7);
if (buttonstate == HIGH) {
digitalWrite(8,HIGH);
} else {
digitalWrite(8,LOW);
}
}
No ha sido muy complicado. Lo difícil llega cuando queremos que el código sea muy compacto. El siguiente código muestra lo que queremos decir, aunque no es para principiantes y no te aconsejo que intentes utilizarlo, ya que es de difícil lectura y podría dar errores.
void setup() {pinMode(7,INPUT);}
void loop()
{digitalRead(7) == 1 ? tone(8,720) : noTone(8);}
Con los bloques:(Archivo: tema01/1.3.bly)
Ücretsiz ön izlemeyi tamamladınız.