Referencia rápida de Arduino A continuación le mostramos una guía de referencia rápida de todas las instrucciones estándar admitidas por el lenguaje de Arduino. Si necesita más información al respecto, visite http:/arduino.ccies/pmwik.php?n=Referente/ HomePage. Estructura Un sketch de Arduino se ejecuta en dos partes: void setup() En esta parte configuramos todo lo que tiene que ejecutarse antes de que se inicie el bucle principal del sketch y que después no se necesitará más. void loop() Contiene el código principal de nuestro sketch. Es un conjunto de instrucciones que se repite una y otra vez hasta que se apaga la placa. Símbolos especiales Arduino incluye diversos símbolos para definir líneas de código, comentarios y bloques de código. ; (punto y coma) Toda instrucción (línea de código) se termina con un punto y coma. Esta sintaxis nos permite aplicar al código el formato que deseemos. Podemos incluso colocar dos instrucciones en la misma línea, siempre que las separemos con punto y coma (sin embargo, esta práctica dificulta la lectura del código). Ejemplo: delay(100); {} (llaves) Las llaves se usan para marcar bloques de código. Por ejemplo, cuando escribimos código para la función l oop O , tenemos que usar llaves antes y después del código. Ejemplo: void loop() { Serial.println("hola"); } Comentarios Los comentarios son partes de texto que ignora el microcontrolador de Arduino, pero que son muy útiles para recordarnos (a nosotros y a otras personas) el cometido de un fragmento de código. Existen dos estilos de comentarios en Arduino: // una sola línea: este texto se ignora hasta el final de la línea /* varias líneas: aquí podemos escribir un poema completo */ Constantes Arduino incluye un conjunto de palabras predefinidas con valores especiales. Por ejemplo, HIGH y LOW se usan cuando queremos activar o desactivar un pin de Arduino. INPUT y OUTPUT se usan para establecer un pin específico como entrada o como salida. Las constantes true y false se indican si una condición o expresión es verdadera o falsa, respectivamente. Se suele usar con operadores de comparación. Variables Las variables son áreas con nombre de la memoria de Arduino en las que podemos guardar datos. El sketch puede usar y manipular estos datos haciendo referencia a los mismos por medio del nombre de variable. Como sugiere su nombre, se pueden cambiar tantas veces como queramos. Como Arduino es un microcontrolador muy simple, al declarar una variable tenemos que especificar su tipo. Esto le indica al procesador el tamaño del valor que queremos guardar. Estos son los tipos de datos disponibles: boolean (booleano) Pueden tener uno de dos valores: true o false. char (carácter) Contiene un solo carácter, como por ejemplo la letra A. Como sucede en otros ordenadores, Arduino guarda este dato como un número, aunque nosotros veamos texto. Cuando se usan caracteres para guardar números, pueden contener valores comprendidos entre -128 y 127. Nota: En los sistemas informáticos, hay dos conjuntos principales de caracteres: ASCII y UNICODE. ASCII es un conjunto de 127 caracteres que se usaba, entre otras cosas, para transmitir texto entre terminales en serie y sistemas informáticos de tiempo compartido, como mainframes y miniordenadores. UNICODE es un conjunto de valores mucho más amplio utilizado por los sistemas operativos modernos para representar caracteres en una amplia variedad de lenguajes. ASCII sigue siendo útil para intercambiar fragmentos cortos de información en idiomas como español o inglés, que usan caracteres latinos, números arábigos y símbolos de escritura comunes para la puntuación, etc. byte Contiene un número comprendido entre O y 255. Igual que los caracteres, los bytes solo usan un byte de memoria pero al contrario de estos, solo pueden almacenar números positivos. int (entero) Usa dos bytes de memoria para representar un número comprendido entre -32.768 y 32.767; es el tipo de datos más común en Arduino. Si no sabe qué tipo de datos usar, pruebe con int. unsigned int (entero sin signo) Igual que int, usa dos bytes pero el prefijo unsigned indica que no puede guardar números negativos, por lo que su rango es de O a 65.535. long (largo) Duplica el tamaño de un entero y contiene números comprendidos entre -2.147.483.648 a 2.147.483.647. unsigned long (largo sin signo) Versión sin signo de long, con un rango de O a 4.294.967.295. float (decimal flotante) Esta variable es bastante grande y puede contener valores de coma flotante, una forma elegante de decir que podemos usarla para guardar números con coma o punto decimal. Usará hasta cuatro bytes de nuestra preciosa RAM y las funciones que los procesan usan también mucha memoria de código. Por tanto, es mejor que use esta variable solo cuando la necesite. double (flotante de 32 bits) Número decimal de doble precisión, con un valor máximo de 1,7976931348623157 x 10308. iEnorme! string (cadena de caracteres) Conjunto de caracteres ASCII que se usa para guardar información de texto (podríamos usar una cadena para enviar un mensaje a través de un puerto serie o para mostrarla en una pantalla LCD). Para almacenamiento, usan solo un byte por cada carácter de la cadena, más un carácter null para indicarle a Arduino que es el final de la cadena. Los siguientes códigos son equivalentes: char string1[] = "Arduino"; char string2[8]= "Arduino"; / / 7 ca racte re s + 1 ca rácte r nul l // Igual que el anterior array (matriz ) Una lista de variables a la que se puede acceder a través de un índice. Se usan para crear tablas de valores a las que se pueda acceder fácilmente. Por ejemplo, si queremos guardar distintos niveles de brillo para usarlos para debilitar la intensidad de un LED, podemos crear seis variables denominadas luz01, luz02, etc. Mejor aún, podemos usar una sencilla matriz como la siguiente: int luz[6] = {O, 20, 50, 75, 100}; En realidad, la palabra "matriz" no está en la declaración de variable: dicha palabra queda sustituida por los corchetes [ ] y las llaves { }. Las matrices son perfectas para realizar la misma operación con un grupo de datos, ya que puede escribir la operación una sola vez y ejecutarla en cada variable de la matriz con tan solo cambiar el índice, por ejemplo por medio de un bucle. Ámbito o alcance de variables En Arduino, las variables cuentan con una propiedad denominada ámbito o alcance (“scope” en inglés). Las variables pueden ser locales o globales, en función de dónde se declaren. Una variable global es la que se puede ver (y utilizar) en todas las funciones del programa. Las variables locales solamente son visibles para la función en la que se declaran. Cuando aumenta el tamaño y la complejidad de un programa, las variables locales resultan muy útiles para garantizar que todas las funciones tienen acceso a sus propias variables. De este modo se evitan errores de programación si una función modifica accidentalmente las variables utilizadas por otra. Las variables que deban usarse en varias funciones pueden ser globales. En el entorno de Arduino, toda variable declarada fuera de una función (como por ejemplo setup(), loop() o sus propias funciones, es una variable global. Toda variable declarada en función es local (y accesible) solamente desde dicha función. En ocasiones resulta muy útil declarar e inicializar una variable dentro de un bucle for. De este modo se crea una variable a la que solamente se puede acceder desde las llaves del bucle for. De hecho, siempre que una variable se declara entre llaves, se considera local solamente en ese bloque de código. Estructuras de control Arduino incluye palabras clave para controlar el flujo lógico de nuestros sketch. if ... else (Si….entonces…) Esta estructura toma decisiones en nuestro programa. A i f le sigue una pregunta especificada como expresión entre paréntesis. Si la expresión es t rue, se ejecutará lo que sigue. Si es false, se ejecutará el bloque de código que sigue a la cláusula else. La cláusula else es opcional. También es posible implementar más operaciones de comparación mediante la forma else if. Ejemplo#1: if (val == 1) { //Si val vale 1 -> se prende el led digitalWite(LED,HIGH); } Ejemplo#2: if (val == 1) { //Si val vale 1 -> se prende el led digitalWite(LED,HIGH); } else{ //Si val no vale 1 -> se apaga el led digitalWite(LED,LOW); } Ejemplo#3: if (val == 1) { digitalWite(LED,HIGH); } else if (val==2){ digitalWite(LED,LOW); } else{ serial.print(“la variable val es distinta de 1 y de 2”); } for Nos permite repetir un bloque de código una cantidad especificada de veces. Ejemplo: for (int i = 0; i < 10; i++) { serial.print("hola"); } //Se imprime 10 veces “hola” switch case Similar a if, la estructura switch case permite al programa tomar varias direcciones, dependiendo del valor de una variable. Es muy útil para mantener limpio nuestro código, ya que reemplaza a las largas listas de instrucciones if. No olvide incluir la instrucción break al final de cada caso o Arduino ejecutará las instrucciones de los demás casos hasta que llegue a una instrucción break o al final de la instrucción switch. Ejemplo: switch (sensorValue) { case 23: digitalwrite(13,HIGH); break; case 46: digitalwrite(12,HIGH); break; default: // si nada coincide, se ejecuta este código digitalwrite(12,L0w); digitalWrite(13,L0w); } while De forma similar a if, la estructura while ejecuta un bloque de código siempre y cuando una determinada condición sea true. if ejecuta el bloque una sola vez, mientras que while continua ejecutando el bloque mientras la condición siga siendo true. Ejemplo: // hacer parpadear a un LED cuando el sensor está por debajo de 512 sensorvalue = analogRead(1); while (sensorvalue < 512) { digital Wri te (13, HIGH) ; delay(100); digitalwrite(13,HIGH); delay(100); sensorvalue = analogRead(1); } do while Igual que while, pero el código se ejecuta antes de evaluar la condición. Esta estructura se usa cuando queremos que el código que se encuentra dentro del bloque se ejecute al menos una vez antes de comprobar la condición. Ejemplo: do { digitalWrite(13,HIGH); delay(100); digitalwtite(13,HIGH); delay(100); sensorvalue = analogRead(1); } while (sensorValue < 512); break Este término nos permite salir de un bucle while o for aunque la condición del bucle indique que debe continuar. También se usa para separar distintas secciones de una instrucció n switch case . Ejemplo: // hacer parpadear un LED cuando el sensor está por debajo de 512 do { // Dejar el bucle si se pulsa un botón if (digitalRead(7)== HIGH) break; digitalwrite(13,HIGH); delay(100); digitalwrite(13,LOW); delay(100); sensorvalue = analogRead(1); } while (sensorvalue < 512); continue Cuando se usa dentro de un bucle, nos permite omitir el resto del código y forzar a que se vuelva a probar la condición. Ejemplo: for (light = 0; light < 255; light++){ // omitir intensidades entre 140 y 200 if ((x > 140) && (x < 200)) continue; analogwrite(PWMpin, light); delay(10); } continue es similar a break, pero break permite salir del bucle, mientras que continue prosigue con la siguiente repetición del bucle. return Detiene la ejecución de una función y vuelve al punto desde el que se haya invocado. También se puede usar para devolver un valor desde el interior de una función. Por ejemplo, si tenemos una función denominada computeTem pe ratu re O y queremos devolver el resultado a la parte de código que invoca la función, escribiríamos lo siguiente: int computeTemperature() { int temperature — 0; temperature = (analogRead(0) + 45) / 100; return temperature; } Aritmética y formulas Puede usar Arduino para realizar cálculos complejos usando una sintaxis especial. Los signos de suma + y resta - funcionan como tales y la multiplicación se representa con un asterisco (*) mientras que la división se expresa con una barra inclinada (/). Existe un operador adicional denominado modulo (%), que devuelve el resto de una división de enteros. Podemos usar tantos niveles de paréntesis como sean necesarios para agrupar expresiones. Al contrario de lo que aprendimos en el colegio, los corchetes y las llaves se reservan para otros propósitos (índices de matrices y bloques, respectivamente). Ejemplo: a = 2 + 2; light = ((12 * sensorValue) - 5 ) / 2; remainder = 3 % 2; // devuelve 1 Operadores de comparación Cuando especificamos condiciones o pruebas para las instrucciones if, while y for, podemos usar los siguientes operadores: == Igual a != No igual a < Menor que > Mayor que <= Menor que o igual a >= Mayor que o igual a Al realizar pruebas de igualdad, asegúrese de usar el operador de comparación == y no el de asignación =, o su programa no se comportara de la forma esperada. Operadores booleanos Estos operadores se usan cuando queremos combinar varias condiciones. Por ejemplo, si queremos comprobar si un valor proveniente de un sensor se encuentra comprendido entre 5 y 10, escribiremos lo siguiente: if ((sensor => 5) && (sensor <=10)) Hay tres operadores: “y”, representado por &&, “o”, representado por || y “no”, representado por ! Operadares compuestos Son operadores especiales utilizados para que el código sea más conciso para algunas operaciones comunes, como el incremento de un valor. Por ejemplo, para incrementar un valor en una unidad, escribiríamos lo siguiente: value = value +1; pero, con un operador compuesto, se convertiría en: value++; Puede optar por no utilizar estos operadores compuestos pero son tan habituales que, como principiante, le resultara complicado aprender de los ejemplos si no los entiende. Incremento y decremento (- - y ++) Estos operadores incrementan o disminuyen un valor en una unidad. Tenga cuidado, ya que si escribe variable++, incrementara variable en 1 y se evaluará el equivalente a variable+1, y si escribe ++valor, se evaluará el valor de variable y después se incrementará. Lo mismo se aplica a --. Operadores “+ =” , “- =”, “*=” y “/=” Son similares a ++ y --, pero le permiten incrementar y reducir por valores distintos a 1, además de permitir operaciones de multiplicación y división. Las siguientes expresiones son equivalentes: a = a + 5; es lo mismo que escribir a += 5; Funciones de entrada y salida Arduino incluye funciones para controlar la entrada y salida. Ya hemos visto algunos ejemplos en los programas del libro. pinMode(pin, modo) Reconfigura un pin digital para que se comporte como entrada o como salida. Ejemplo: pinMode(7,INPUT); // convierte el pin 7 en una entrada Una causa habitual de salida fallida o de funcionamiento defectuoso es por haberse olvidado de establecer pines en salidas por medio de pinMode(). Aunque se suela usar en setup(), pinMode() también se puede usar en un bucle si es necesario cambiar el comportamiento del pin. digitalWrite(pin, valor) Convierte un pin digital en HIGH o LOW. Los pines se tienen que convertir explícitamente en salida usando pinMode() antes de que digitalwrite() tenga el efecto deseado. Ejemplo: digitalWrite(8,HIGH); // establece el pin digital 8 en 5V Aunque HIGH o LOW suelen corresponderse a encendido o apagado, respectivamente, depende de cómo se utilice el pin. Por ejemplo, un LED conectado entre 5V y un pin se enciende cuando dicho pin es LOW y se apaga cuando es HIGH. int digitalRead(pin) Lee el estado de un pin de entrada y devuelve HIGH si el pin detecta voltaje o LOW si no se aplica voltaje alguno. Ejemplo: val= digitalRead(7); // lee el pin 7 en val int analogRead(pin) Lee el voltaje aplicado a un pin analógico de entrada y devuelve un número comprendido entre O y 1023, que representa los voltajes comprendidos entre O y 5V. Ejemplo: val = analogRead(0); // lee el pin analógico de entrada 0 analogWrite(pin, valor) Cambia la velocidad PWM en uno de los pines marcados como PWM. pin solo puede ser un pin que admita PWM, es decir, los pines 3, 5, 6, 9, 10 u 11 en la placa Uno y los pines 3, 5, 6, 9, 10, 11 o 13 en el modelo Leonardo. valor debe ser un número comprendido entre O y 255. Imagine que valor representa la cantidad media de energía proporcionada por Arduino, siendo 0 el equivalente a estar totalmente apagado y 255 a totalmente encendido. Ejemplo: analogWrite(9,128); // Reducir la luz del LED en el pin 9 en un 50% Si valor es 0 se establece la salida en establece en H IGH . LOW, mientras que si es 255 se shift0ut(dataPin, clockPin, bitOrder, valor) Envía datos a un registro de cambios, un dispositivo que se usa para ampliar el número de entradas digitales. Este protocolo usa un pin para los datos (dataPin) y otro para el reloj (clockPin). bitOrder indica el orden de los bytes (del menos significativo al más significativo) y valor son los datos que se van a enviar. Ejemplo: shiftOut(dataPin, clockPin, LSBFIRST, 255); unsigned long pulseIn(pin, valor) Mide la duración de un pulso entrante en una de las entradas digitales; algo útil, por ejemplo, para leer sensores de infrarrojos o acelerómetros que envían su valor como pulsos de duración variable. Ejemplo: time = pulsein(7,HIGH); // mide el tiempo que el siguiente pulso // permanece activado Funciones temporales Arduino incluye funciones para medir el tiempo transcurrido y también para pausar el sketch. unsigned long millis() Devuelve el tiempo transcurrido en milésimas de segundo desde que se inició el sketch. Ejemplo: duration = millis()-lastTime; // calcula el tiempo transcurrido desde lastTime delay(ms) Pausa el programa durante la cantidad de milésimas de segundo especificada. Ejemplo: delay(500); // detiene el programa durante medio segundo delayMicroseconds(us) Pausa el programa durante una determinada cantidad de microsegundos. Ejemplo: d e la yM icr o se co nd s( 1 0 00 ) ; // espera durante una milésima d e s eg und o Funciones matemáticas Arduino incluye diversas funciones matemáticas y trigonométricas: min(x, y) Devuelve el menor de x e y. Ejemplo: val = min(10,20); // val es ahora 10 max(x, y) Devuelve el mayor de x e y. Ejemplo: val = max(10,20); // val es ahora 20 abs(x) Devuelve el valor absoluto de x, convirtiendo los números negativos en positivos. Si x es 5 devolverá 5, pero si es -5, devolverá también 5. Ejemplo: val = abs(-5); // val es ahora 5 constrain(x, a, b) Devuelve el valor de x, limitado entre a y b. Si x es menor que a, solo devolverá a y si x es mayor que b, solo devolverá b. Ejemplo: val = constrain(analogRead(0), 0, 255); // rechaza los valores // superiores a 255 map(value, fromLow, fromHigh, toLow, toHigh) Asigna un valor dentro del rango fromLow y fromHigh al rango de toLow y toHigh. Es muy útil para procesar valores de sensores analógicos. Ejemplo: val = map(analogRead(0),0,1023,100, 200);// asigna el valor analógico del // pin 0 a un valor comprendido // entre 100 y 200 double pow(base, exponente) Devuelve el resultado de elevar un número (base) a un valor (exponente). Ejemplo: double x = pow(y, 32); // establece que se eleve x a la 32 potencia double sqrt(x) Devuelve la raíz cuadrada de un número. Ejemplo: double a = sqrt(1138); // aproximadamente 33,73425674438 double sin(rad) Devuelve el seno de un ángulo especificado en radianes. Ejemplo: double sine = sin(2); // aproximadamente 0,90929737091 double cos(rad) Devuelve el coseno de un ángulo especificado en radianes. Ejemplo: double cosine = cos(2); // aproximadamente -0,41614685058 double tan(rad) Devuelve la tangente de un ángulo especificado en radianes. Ejemplo: double tangent = tan(2); // aproximadamente -2,18503975868 Funciones de números aleatorios Si tenemos que generar números aleatorios, podemos usar el generador de números seudoaleatorios de Arduino. Los números aleatorios son muy útiles para que el comportamiento de un programa varíe cada vez que lo utilicemos. randomSeed(seed) Restablece el generador de números seudoaleatorios de Arduino. Aunque la distribución de números devuelta por random() es básicamente aleatoria la secuencia es predecible. Por tanto, debemos restablecer el generador a un valor aleatorio. Si tenemos un pin analógico sin conectar, recogerá un ruido aleatorio del entorno que le rodea (ondas de radio, rayos cósmicos, interferencias electromagnéticas de teléfonos móviles y luces fluorescentes, etc), por lo que será impredecible. Ejemplo: randomSeed(analogRead(5)); // generar número aleatorio usandz // el ruido del pín 5 long random(max), long random(min, max) Devuelven un valor entero long seudo-aleatorio comprendido entre min y max. Si no se especifica min, el límite inferior es 0. Ejemplo: long randnum = random(0, 100); // un número comprendido entre 0 y 99 long randnum = random(11); // un número comprendido entre 0 y 11 Comunicación en serie Arduino puede comunicarse con otros dispositivos a través del puerto USB usando un protocolo de comunicación en serie. A continuación le mostramos las funciones en serie. Serial.begin(velocidad) Prepara al Arduino para empezar a enviar y recibir datos en serie . Generalmente, con el monitor serie del IDE de Arduino se usan 9.600 baudios (bits por segundo), pero hay otras velocidades disponibles, normalmente no superiores a 115.200 bps. La velocidad de baudios concreta es irrelevante mientras que ambos lados acuerden utilizar la misma. Ejemplo: Serial.begin(9600); Serial.print(datos), Serial.print(datos, codificación) Envía datos al puerto serie. La codificación es opcional. Si no se suministra los datos se tratan como texto plano, tanto como sea posible. Ejemplos (en el último se utiliza Seri al . wri te): Serial.print(75); // Imprime "75" Serial.print(75, DEC); // Igual que en el caso anterior. Serial.print(75, HEX); // "4B" (75 en hexadecimal) Serial.print(75, OCT); // "113" (75 en octal) Serial.print(75, BIN); // "1001011" (75 en binario) Serial.println(datos), Serial.println(datos, codificación) Igual que Serial.print() pero añade un retorno de carro y un salto de línea (\r\n) como si hubiésemos escrito los datos y después pulsado Intro o Retorno. Ejemplos: Serial.println(75); Serial.println(75, DEC); Serial.println(75, HEX); Serial.println(75, OCT); Serial.println(75, BIN); // // // // // Imprime "75\r\n" Igual que en el caso anterior. "4B\r\n" "113\r\n" "1001011\r\n" int Serial.available() Devuelve los bytes sin leer disponibles en el puerto serie para su lectura a través de la función read(). Después de tenerlos disponibles a través de read(), serial.available() devuelve 0 hasta que llegan nuevos datos al puerto serie. Ejemplo: int count = Serial.available(); int Serial.read() Recupera un único byte de los datos de serie entrantes. Ejemplo: int data Serial.read(); Serial.flush() Como los datos pueden llegar a través del puerto serie más rápido de lo que nuestro programa puede procesarlos, Arduino mantiene todos los datos entrantes en un búfer. Si tenemos que limpiar el búfer y dejar que se llene de datos nuevos, debemos usar la función flush() . Ejemplo: Serial.flush();