|epub|

Apuntes sobre Arduino.

KReilly
XMPP: kreilly@blah.im

Licencia.

licencia
Reconocimiento - No comercial - Compartir igual
CC BY-NC-SA

Obra original de Brian W. Evans, de la que se aplica la licencia.
https://playground.arduino.cc/uploads/Main/arduino_notebook_v1-1.pdf

Utilizada como referencia la traducción y adaptación de José Manuel Ruiz Gutiérrez y José Manuel Escuder Martínez.
https://openlibra.com/en/book/arduino-programming-notebook-ed-espanola

Referencia de Arduino, https://www.arduino.cc/reference/en/

Apéndice general de Glosario de términos de programación.
https://www.mhe.es/universidad/informatica/8448136640/archivos/apendice_general_4.pdf

Hecho con:
Arduino | Revisión del código.
Atom | Escritura de los archivos markdown y edición del CSS.
Pandoc | Conversión a Epub.
Sigil | Edición del Epub.

Prólogo del original.

Estos apuntes son una sencilla referencia de la estructura de comandos y la sintaxis básica del microcontrolador Arduino. Para mantenerlos sencillos hubo que hacer algunos descartes, por lo que es más bien una guía de apoyo a otros materiales web, libros, talleres o clases. Esta decisión llevó a enfatizar el uso de Arduino para propósitos autónomos, excluyendo otros como los más complejos de los arrays (colecciones) o de las formas avanzadas de comunicación en serie.

Empezando por la estructura básica del lenguaje derivado de C que utiliza Arduino, estos apuntes continúan describiendo la sintaxis de los elementos más comunes del lenguaje e ilustran su uso con ejemplos y fragmentos de código. Esto incluye varias funciones del núcleo de librerías seguidos por un apéndice con esquemas de ejemplo y programas de iniciación. El formato genérico establecido por Physical Computing de O'Sullivan y Igoe se ha respetado siempre que ha sido posible.

Para una introducción a la placa Arduino y diseño interactivo se puede acudir al libro de Banzi Getting Started with Arduino, conocido como el Arduino Booklet. Para los pocos atrevidos interesados en las complejidades de programar en C el libro de Kernighan y Ritchie The C Programming Language, segunda edición, y el de Prinz y Crawford C in a Nutshell darán una cierta visión sobre la sintaxis de programación original.

Además de todo lo anterior, estos apuntes no habrían sido posibles sin la gran comunidad de makers y la enorme cantidad de material que se puede encontrar en la web de Arduino, en su wiki y en el foro en https://www.arduino.cc.

Estructura.

La estructura básica del lenguaje de programación de Arduino es bastante simple, y se ejecuta en al menos dos partes. Estas dos partes necesarias, o funciones, contienen bloques de sentencias.

declaraciones;
// primera parte o programa
void setup()
{
sentencias;
}
// segunda parte o programa
void loop()
{
sentencias;
}

Del mismo modo que setup() es la configuración, loop() es la ejecución. Ambas funciones son necesarias para que el programa funcione.

La función de configuración setup() debe ejecutarse tras la declaración de las variables, al comienzo del programa. Es la primera función que se va a ejecutar, lo va a hacer sólo una vez y lo hará para configurar los pines a través de pinMode o la comunicación en serie.

La función bucle loop() siguiente contiene el código que se ejecutara continuamente (leyendo entradas, activando salidas, etc). Esta función es el núcleo de todos los programas de Arduino y la que realiza la mayor parte del trabajo.

setup()

La función setup() se invoca una sola vez cuando el programa empieza. Se utiliza para iniciar el modo de trabajo de los pines o el puerto serie. Debe ser incluida en un programa aunque no haya sentencia que ejecutar.

void setup()
{
// configura el pin 13 como salida
pinMode(13, OUTPUT);
}

loop()

Después de llamar a setup(), la función loop() hace precisamente lo que sugiere su nombre (bucle): se ejecuta de forma cíclica, permitiendo al programa cambiar, responder y controlar la placa Arduino.

void loop()
{
// enciende el pin
digitalWrite(13, HIGH);  
// espera un 1000ms
delay(1000);
// apaga el pin
digitalWrite(13, LOW);
// espera un segundo
delay(1000);
}

Funciones.

Una función es un bloque de código que tiene un nombre y un conjunto de sentencias que son ejecutadas cuando se la llama. Ya conocemos dos, void setup() y void loop(). Hablaremos de otras funciones incorporadas del sistema más adelante.

Se pueden escribir funciones de usuario para llevar a cabo tareas repetitivas y para disminuir el desorden en un programa. Primero se declara el tipo de valor que va a devolver la función —por ejemplo 'int', si va a ser un número entero, o 'void' (vacío), si no va a devolver ninguno—, después el nombre y, entre paréntesis, los parámetros que se le darán.

tipo nombreFuncion(parametros) {
sentencias;
}

La función int (entero) del ejemplo siguiente, delayVal(), se va a utilizar para configurar el valor de demora (delay) en un programa leyendo el valor de un potenciómetro. Primero declara una variable local 'v', la configura con el valor del potenciómetro que da un número entre 0 y 1023, lo divide entre 4 para obtener un valor final entre 0-255, y devuelve ese valor al programa principal.

int delayVal()
/* una variable creada dentro de una función sólo
   puede ser leída por ella (variable local),
   se crea una variable local de nombre 'v'*/
{
int v;
// lee el valor del potenciómetro
v = analogRead(pot);
// convierte 0-1023 a 0-255
v /= 4;
// devuelve el valor final
return v;
}

{} corchetes.

Las llaves sirven para definir el principio y el final de un bloque de función como void() y loop() o de sentencias como for e if.

type funcion()
{
sentencias;
}

Una llave de apertura “{“ siempre debe ir seguida de una llave de cierre “}”. Se suele decir que tienen que estar balanceadas. El que no lo estén suele conducir a crípticos e impenetrables errores de compilador que pueden a veces ser complicados de encontrar en programas extensos.

El entorno de programación de Arduino incluye una herramienta de gran utilidad para comprobar el equilibrio de las llaves. Sólo tienes que poner el cursor delante o detrás de una de ellas y su compañera lógica aparecerá resaltada.

; punto y coma.

El punto y coma “;” se utiliza para finalizar una sentencia y separar unas de otras en el programa. También se utiliza para separar elementos en un bucle 'for'.

// declara la variable 'x' como tipo entero y de valor 13
int x = 13;

Nota: Si olvidáis poner fin a una línea con un punto y coma se producirá en un error de compilación. El texto de error puede ser obvio y se referirá a la falta de un punto y coma, pero puede que no. Si se produce un error indescifrable o aparentemente ilógico una de las primeras cosas a buscar es un punto y coma perdido cerca de la línea que el compilador nos muestre.

/*..*/ comentarios en bloque.

Los comentarios en bloque o de línea múltiple son áreas de texto ignorados por el programa, y se usan para hacer largas descripciones del código y comentarios que puedan ayudar a otros a entender partes del mismo. Empiezan por / y terminan con \/ y pueden contener varias líneas.

/*  Esto es un bloque de comentario.
    No olvides el texto de cierre.
    ¡Las aperturas y los cierres
    tienen que estar balanceados!
*/

Como los comentarios son ignorados por el programa no ocupan memoria, así que pueden ser utilizados con generosidad. También se usan para describir bloques de código con vistas a la depuración del código.

Nota: Se puede utilizar una línea de comentarios (//) dentro de un bloque de comentarios (/*… */), pero no se puede incluir un bloque de comentarios dentro de otro.

// linea de comentarios.

Una línea de comentario empieza con // y termina con la siguiente línea de código. Al igual que los comentarios de bloque los de línea son ignorados por el programa y no ocupan espacio en la memoria.

// esto es un comentario de una línea

Una línea de comentario se utiliza a menudo después de una sentencia para proporcionar más información acerca de lo que hace, o para crear un recordatorio.

Variables.

Una variable es un modo de nombrar y almacenar un valor numérico para un uso posterior. Como su nombre indica pueden ser cambiadas continuamente, en oposición a las constantes cuyo valor no cambia jamás. Una variable necesita ser declarada y tener opcionalmente un valor asignado que necesitemos almacenar. El siguiente código declara una variable llamada variableEntrada y le asigna el valor obtenido en la entrada analógica pin 2:

// declara una variable y le asigna el valor 0
int variableEntrada = 0;
// la variable recoge el valor analógico del PIN2
variableEntrada = analogRead(2);

'variableEntrada' es la variable. La primera línea declara que contendrá un valor tipo int, un entero. La segunda línea configura la variable con el valor del pin analógico 2. Esto hace que este valor sea accesible en cualquier parte del código.

Una vez que una variable ha sido asignada, o reasignada, puedes comprobar su valor para ver si cumple ciertas condiciones, o puedes utilizarlo directamente. Como ejemplo para ilustrar tres operaciones útiles con variables, el código siguiente comprueba si variableEntrada es menor que cien, si es cierto le asigna el valor 100, y entonces configura un retardo (delay) basado en ella, que tendrá ahora un valor mínimo de 100.

// pregunta si la variable es menor que 100
if (entradaVariable < 100)
// si es cierto le asigna el valor 100
{
    entradaVariable = 100;
}
// y usa el valor como retardo
delay(entradaVariable);

Nota: Las variables deben tener nombres descriptivos para hacer el código más legible. Nombres de variable como 'sensorInclinacion' o 'pulsador' ayudarán al programador y a todos los demás a leer el código y entender qué representa. Nombres de variable como 'var' o 'valor', por otra parte, no sirven de mucha ayuda y se usan aquí sólo como ejemplos. Una variable puede ser nombrada de cualquier modo que no sea una de las palabras clave (keywords) del lenguaje Arduino.

Declaración de variables.

Todas las variables deben ser declaradas antes de poder ser utilizadas. Hacerlo significa definir el tipo de valor que va a contener (como int, log, float, etc), establecer el nombre y opcionalmente asignarle un valor inicial. Esto sólo necesita hacerse una vez en el programa, pero el valor de la variable puede ser modificado en cualquier momento utilizando aritmética o cualquier otro tipo de asignación.

El siguiente ejemplo declara que 'entradaVariable' es un int, un entero, y que su valor inicial es cero. A esto se le llama una asignación simple.

int entradaVariable = 0;

Una variable puede ser declarada en multitud de localizaciones, y dónde suceda esta definición determinará qué partes del programa pueden utilizarla.

Alcance de una variable.

Una variable puede ser declarada al inicio del programa antes de la parte de configuración setup(), a nivel local dentro de las funciones, y, a veces, dentro de un bloque, como para los bucles del tipo if.. for.., etc. En función del lugar de declaración de la variable así se determinara el ámbito de aplicación, o la capacidad de ciertas partes de un programa para hacer uso de ella.

Una variable global es aquella que puede ser vista y utilizada por cualquier función y estamento de un programa. Esta variable se declara al comienzo del programa, antes de setup().

Una variable local es aquella que se define dentro de una función o como parte de un bucle. Sólo es visible y sólo puede utilizarse dentro de la función en la que se declaró. Por lo tanto, es posible tener dos o más variables del mismo nombre en diferentes partes del mismo programa que pueden contener valores diferentes. La garantía de que sólo una función tiene acceso a sus variables dentro del programa simplifica y reduce el potencial de errores de programación.

El siguiente ejemplo muestra cómo declarar a unos tipos diferentes de variables y la visibilidad de cada variable:

// 'value' es visible para cualquier función
int value;

void setup()
{
// no es necesario configurar nada en este ejemplo
}

void loop()
{
// 'i' solo es visible dentro del bucle for
  for (int i = 0; i < 20;)
  {
    i++
  }
// 'f' es visible solo dentro de loop()
  float f;
}

Tipos de datos.

byte

Byte almacena un valor numérico de 8 bits sin decimales. Tienen un rango entre 0 y 255.

// declara a 'unaVariable' de tipo byte
byte unaVariable = 180;

int

Enteros son un tipo de datos primarios que almacenan valores numéricos de 16 bits sin decimales comprendidos en el rango 32,767 a -32,768.

// declara a 'unaVariable' de tipo entero
int unaVariable = 1500; //

Nota: Las variables de tipo entero “int” pueden sobrepasar su valor máximo o mínimo como consecuencia de una operación. Por ejemplo, si x = 32767 y una posterior declaración agrega 1 a x, x = x + 1 entonces el valor se x pasará a ser -32.768.

long

El formato de variable numérica de tipo extendido “long” se refiere a números enteros (tipo 32 bits) sin decimales que se encuentran dentro del rango -2147483648 a 2147483647.

// declara 'unaVariable' como de tipo long
long unaVariable = 90000;

float

El formato de dato del tipo punto flotante (float) se aplica a los números con decimales. Los números de punto flotante tienen una mayor resolución que los enteros y se almacenan como un valor de 32 bits, con un rango comprendido entre 3.4028235E+38 a -3.4028235E+38.

/* declara 'unaVariable'
  como de tipo flotante
*/
float unaVariable = 3.14;

Nota: Los números de punto flotante no son exactos, y pueden producir resultados extraños en las comparaciones. Los cálculos matemáticos de punto flotante son también mucho más lentos que los del tipo de números enteros, por lo que debe evitarse su uso si es posible.

array

Un array (lista, vector) es un conjunto de valores a los que se accede con un número índice. Cualquier valor puede ser recogido haciendo uso del nombre de la matriz y el número del índice. La numeración comienza en cero, así que el primer valor de la lista tendrá asignado el vector 0. Un array necesita ser declarado y opcionalmente tener valores asignados antes de poder usarse.

int miArray[] = {valor0, valor1, valor2...}

Del mismo modo es posible declarar una matriz indicando el tipo de datos y el tamaño y, posteriormente, asignar valores a una posición especifica:

/* declara un array de
   enteros de 6 posiciones
*/
int miArray[5];
// asigna el valor 10 a la posición 4
miArray[3] = 10;

Para leer desde un array basta con escribir el nombre y la posición índice que necesitemos:

/* x ahora es igual a 10,
   tercera posición del array
*/
x = miArray[3];

Las listas se utilizan a menudo para sentencias de tipo bucle, en los que la variable de incremento del contador del bucle se utiliza como índice o puntero del array. El siguiente ejemplo usa una matriz para el parpadeo de un LED. Utilizando un bucle tipo for, el contador comienza en cero 0 y escribe el valor que figura en esa posición en la serie que hemos escrito dentro del array 'parpadeo[]', en este caso 180, que se envía a la salida analógica tipo PWM configurada en el PIN10, se hace una pausa de 200 ms y a continuación se pasa al siguiente valor que asigna el índice “i”.

// LED en el PIN 10
int ledPin = 10;
// array de 8 valores
byte parpadeo[] = {180, 30, 255, 200, 10, 90, 150, 60};

void setup()
// configura la salida
{
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  for (int i = 0; i < 7; i++)
  {
    analogWrite(ledPin, parpadeo[i]);
    delay(200); // espera 200ms
  }
}

Aritmética.

Los operadores aritméticos incluyen suma, resta, multiplicación y división. Devuelven la adición, diferencia, producto o cociente de dos operandos.

y = y + 3;
x = x - 7;
i = j * 6;
r = r / 5;

La operación se efectúa utilizando el tipo de dato de los operandos, así que por ejemplo 9 / 4 dará como resultado 2 en vez de 2.25. Ambos son enteros y no pueden utilizar puntos decimales. También implica que la operación puede desbordarse (overflow) si el resultado es más grande que lo que el tipo de dato puede almacenar.

Elige el tamaño de las variables que sea el suficiente para almacenar los resultados más grandes de tus cálculos. Conoce en qué punto tu variable se desbordará y qué sucede en la otra dirección, por ejemplo (0 - 1) o (0 - - 32768). Para los cálculos que requieran fracciones utiliza variables de coma flotante (float), pero tiene consecuencias, aumenta el tamaño pero reduce la velocidad de computación.

Nota: Utilice el operador (int) para convertir un tipo de variable a otro sobre la marcha. Por ejemplo, i = (int) 3,6 establecerá i igual a 3.

Asignaciones compuestas.

Las asignaciones compuestas combinan una operación aritmética con una variable asignada. Estas son comúnmente utilizadas en los bucles tal como se describe más adelante. Estas asignaciones compuestas pueden ser:

x ++ // igual que x = x +1, o incremento de x en +1
x -- // igual que x = x - 1, o decremento de x en -1
x += y // igual que x = x + y, o incremento de x en +y
x -= y // igual que x = x - y, o decremento de x en -y
x *= y // igual que x = x * y, o multiplica x por y
x /= y // igual que x = x / y, o divide x por y

Nota: Por ejemplo, x * = 3 hace que x se triplique y el nuevo valor lo reasigna a la variable x.

Operadores de comparación.

Las comparaciones de una variable o constante con otra se utilizan con frecuencia en las estructuras condicionales del tipo if para comprobar si una condición es verdadera.En los ejemplos que veremos en las siguientes páginas '??' se utiliza para indicar alguna de las siguientes condiciones:

x == y // x es igual a y
x != y // x no es igual a y
x < y // x es menor que y
x > y // x es mayor que y
x <= y // x es menor o igual que y
x >= y // x es mayor o igual que y

Operadores lógicos.

Los operadores lógicos son una forma de comparar dos expresiones y devolver un verdadero (TRUE) o falso (FALSE) dependiendo del operador. Existen tres operadores lógicos, AND (&&), OR (||) y NOT (!), que a menudo se utilizan en estamentos de tipo if:

Logica AND:

// cierto sólo si las dos expresiones son ciertas
if (x > 0 && x < 5)

Logica OR:

// cierto si una cualquiera de las expresiones es cierta
if (x > 0 || y > 0)

Logica NOT:

// cierto solo si la expresión es falsa
if (!x > 0)

Constantes.

El lenguaje de programación de Arduino tiene unos valores predefinidos, que son llamados constantes. Se utilizan para hacer los programas más fáciles de leer. Las constantes se clasifican en grupos.

true/false (cierto/falso).

Constantes Booleanas que definen niveles lógicos. FALSE se define como 0 (cero), y TRUE se define habitualmente como 1, pero puede ser cualquier cosa excepto cero. En un sentido Booleano, -1, 2 y -200 también se definen como TRUE.

if (b == TRUE);
{
  ejecutar las instrucciones;
}

HIGH/LOW (alto/bajo).

Definen los niveles de los pines en HIGH o LOW y se utilizan cuando se leen o escriben pines digitales. HIGH se define como nivel lógico 1, encendido (ON) o 5 voltios mientras que LOW es nivel lógico 0, apagado (OFF) o 0 voltios.

// activa la salida 13 con un nivel alto (5v)
digitalWrite(13, HIGH);

INPUT/OUTPUT (entrada/salida).

Se utilizan con la función pinMode() para definir si un pin digital es una entrada (INPUT) o una salida (OUTPUT)

// designamos que el PIN 13 es una salida
pinMode(13, OUTPUT);

Control de flujo.

if

El bloque de sentencias 'if' comprueba si se cumple una condición, como si un valor analógico está por encima de cierto número, y ejecuta las sentencias dentro de los corchetes si la sentencia es cierta. Si es falsa el programa se salta el resto del bloque.

if (unaVariable ?? valor)
{
  hazAlgo;
}

El ejemplo de arriba compara unaVariable con 'valor', que puede ser tanto una variable como una constante. Si la condición del paréntesis es cierta se ejecutarán las sentencias del interior de los corchetes, si no el programa las omitirá hasta el final del corchete.

if... else

Permite aplicar una alternativa. Por ejemplo, si quieres comprobar una entrada digital y hacer una cosa si está en estado HIGH y otra si está en LOW, escribirás:

if (inputPin == HIGH)
{
  instruccionesA;
}
else
{
  instruccionesB;
}

Else puede incluso preceder otra comprobación if, así que multiples y mutuamente excluyentes comprobaciones pueden ser ejecutadas al mismo tiempo. Es incluso posible tener un ilimitado número de ramas else. Sin embargo, sólo una de las sentencias se ejecutará dependiendo de las comprobaciones de condiciones.

if (inputPin < 500)
{
  instrucciones A;
}
else if (inputPin >= 1000)
{
  instruccionesB;
}
else
{
  instruccionesC;
}

Nota: una sentencia if simplemente comprueba si una condición dentro del paréntesis es verdadera o falsa. Esta sentencia puede ser cualquiera válida del lenguaje C como en el primer ejemplo, if (inputPin == HIGH). En el ejemplo, if sólo comprobará si de hecho en la entrada especificada el estado lógico es 1, 5v.

for

La sentencia for se utiliza para repetir un bloque de sentencia rodeada de corchetes un número específico de veces. Se utiliza un contador incremental para incrementar y terminar el bucle. Hay tres partes, separadas por punto y coma (;), en el encabezado del bucle for:

for (inicialización; condición; expresión)
{
Instrucciones;
}

El inicio de la variable local se produce una sola vez y la condición se comprueba cada vez que se termina la ejecución de las instrucciones dentro del bucle. Si la condición sigue cumpliéndose, las instrucciones del bucle se vuelven a ejecutar. Cuando la condición no se cumple, el bucle termina.

El siguiente ejemplo empieza con el entero i a 0, comprueba si es menor que 20 y, si es cierto, incrementa i en una unidad y ejecuta las sentencias entre corchetes:

// declara i y prueba si es menor que 20, incrementa i.
for (int i=0; i<20; i++)
{
// enciende el pin 13
digitalWrite(13, HIGH);
// espera 1/4 seg.
delay(250);
// apaga el pin 13
digitalWrite(13, LOW);
// espera 1/4 de seg.
delay(250);
}

Nota: El lenguaje C es más flexible que otros lenguajes para los bucles, incluyendo BASIC. Cualquiera de los tres encabezados puede ser omitido, aunque los puntos y coma son requeridos. Las sentencias para inicialización, condición y expresión pueden ser cualquier sentencia C válida con variables no relacionadas. Estos tipos inusuales de sentencias pueden dar solución a infrecuentes problemas de programación.

while

While hará un bucle continuo, e infinito, hasta que la expresión dentro del paréntesis se vuelva falsa. Algo debe cambiar la variable que se comprueba, o el bucle no terminará nunca. Puede estar en el código, como una variable incrementada, o puede ser una condición externa como un sensor.

while (unaVariable ?? valor)
{
ejecutarSentencias;
}

El siguiente ejemplo comprueba cuándo 'unaVariable' es menor que 200, y si es cierto ejecuta las sentencias dentro de los corchetes, y continúa en bucle hasta que 'unaVariable' deja de ser menor que 200.

// comprueba si es menor que 200
While (unaVariable < 200)
/* ejecuta las sentencias
entre llaves */
{
// incrementa la variable en 1
unaVariable++;
}

do... while

El bucle do es igual que el while, pero la condición se comprueba al final del bucle, así que la sentencia entre corchetes se ejecutará siempre al menos una vez.

do
{
Instrucciones;
} while (unaVariable ?? valor);

El siguiente ejemplo asigna leeSensor() a la variable X, hace una pausa de 50 ms y comienza el bucle hasta que x deja de ser menor que 100.

do
{
x = leeSensor();
delay(50);
} while (x < 100);

E/S digitales.

pinMode(pin, mode)

Se utiliza en void setup() para configurar que un pin específico se comporte como una entrada (INPUT) o una salida (OUTPUT).

// configura ‘pin’ como salida
pinMode(pin, OUTPUT);

Los pines digitales en Arduino se comportan por defecto como de entrada, así que no es necesario que sean declarados como tales con pinMode. Los pines configurados como entrada se dice que están en estado de alta impedancia.

Estos pines tienen a nivel interno una resistencia de 20 KΩ a las que se puede acceder mediante software. Se accede a ellas de la siguiente manera:

// configura el ‘pin’ como entrada
pinMode(pin, INPUT);
// activa las resistencias internas
digitalWrite(pin, HIGH);

Las resistencias internas normalmente se utilizan para conectar las entradas como interruptores. Observa en el ejemplo de arriba que no convierte el pin en una salida, sino que es sólo un método para activar las resistencias internas.

Los pins configurados como salida se dice que están en un estado de baja impedancia, y pueden proveer de 40 mA (miliamperios) de corriente a otros dispositivos o circuitos. Es la suficiente como para encender un LED (no olvides la resistencia en serie), pero no la suficiente para la mayoría de relés, solenoides o motores.

Los cortocircuitos en los pines de Arduino y la excesiva corriente pueden dañar o destruir el pin de salida, e incluso dañar todo el chip Atmega. Suele ser una buena idea utilizar una resistencia de 470Ω o 1000Ω al conectar un pin de salida a un dispositivo externo en serie.

digitalRead(pin)

Lee el valor de un pin digital especificado dando como resultado HIGH o LOW. El pin puede declararse como una variable o una constante (0-13).

/* hace que 'valor' sea igual
al estado leído en el pin*/
valor = digitalRead(Pin);

digitaWrite (pin, value)

Envía el nivel lógico HIGH o LOW (enciende o apaga) a un pin especificado. El pin puede declararse como una variable o una constante (0-13).

// envía a 'pin' el valor HIGH
digitalWrite(pin, HIGH);

El siguiente ejemplo lee un pulsador conectado a una entrada digital y enciende un LED conectado a una salida digital cuando se presiona el botón:

// asigna a LED el valor 13
int led = 13;
// asigna a botón el valor 7
int pulsador = 7;
// define el valor y le asigna el valor 0
int valor = 0;

void setup()
{
// configura el led (pin13) como salida
  pinMode(led, OUTPUT);
// configura pulsador (pin7) como entrada
  pinMode(pulsador, INPUT);
}

void loop()
{
//lee el estado de la entrada botón
  valor = digitalRead(boton);
// envía a la salida 'led' el valor leído
  digitalWrite(led, valor);
}

E/S analógicas.

analogRead(pin)

Lee el valor de un pin analógico especificado con una resolución de 10 bit. Esta función sólo opera en los pines analógicos de 0 a 5. El valor del entero resultante tiene un rango de entre 0 y 1023.

// asigna a 'valor' lo que lee en la entrada ´pin'
valor = analogRead(pin);

Nota: Los pines analógicos, a diferencia de los digitales, no necesitan ser declarados previamente como INPUT (entrada) u OUTPUT (salida).

analogWrite(pin, value)

Escribe un valor pseudoanalógico utilizando el procedimiento por modulación de ancho de pulso (PWM, por las siglas 'pulse with modulation' en inglés) a un pin de salida PWM. En los Arduinos con el chip ATmega168 está función se puede utilizar en los pines 3, 5, 6, 9, 10 y 11. En aquellos con el chip ATmega8 sólo en los pines 9, 10 y 11. El valor puede ser especificado como una variable o una constante con un valor entre 0 y 255.

/*
  escribe 'valor' en el 'pin'
  definido como analógico
*/
analogWrite(pin, valor);

Un valor 0 genera una salida constante de corriente de 0 voltios en el pin especificado, una de 255 genera una de 5 voltios. Para valores entre 0 y 255 el pin alterna rápidamente entre 0 y 255, cuanto más alto sea el valor, con más frecuencia el estado del pin es HIGH. Por ejemplo, un valor de 64 será 0 voltios tres cuartas partes del tiempo y 5 voltios el resto. Un valor de 128 estará a 0 la mitad del tiempo y la otra mitad a 255. Un valor de 192 será 0 voltios un cuarto del tiempo y 5 voltios los tres cuartos restantes.

Al ser una función de hardware el pin generará de fondo una onda constante tras una llamada a analogWrite hasta la siguiente llamada (o una llamada a digitalRead o digitalWrite en el mismo pin).

Nota: Los pines analógicos, a diferencia de los digitales, no necesitan ser declarados previamente como INPUT (entrada) u OUTPUT (salida).

El sigiente ejemplo lee un valor analógico de un pin de entrada analógica, convierte el valor dividiéndolo entre cuatro y saca una señal PWM en un pin PWM:

// define el pin 10 como ´led´
int led = 10;
// define el pin 0 como ´analog´
int analog = 0;
// define la variable ´valor´
int valor;

// no es necesario configurar nada
void setup() {}

void loop()
{
// lee el pin 0 y lo asocia a la variable valor
  valor = analogRead(analog);
//divide valor entre 4 y lo reasigna a valor
  valor /= 4;
// escribe en el pin10 valor
  analogWrite(led, value);
}

Control del tiempo.

delay(ms)

Pausa el programa la cantidad de tiempo que se especifica en milisegundos (1000ms equivale a un segundo).

// espera 1 segundo
delay(1000);

millis() ***

Devuelve, con un unsigned valor long, el tiempo en milisegundos desde que la placa Arduino empezó a ejecutar el programa actual.

// valor recoge el número de milisegundos
valor = millis();

Nota: El número se desbordará (reseteándose a cero) después de aproximadamente 9 horas.

Matemáticas.

min(x, y)

Calcula el mínimo de dos números de cualquier tipo de dato y devuelve el más pequeño.

/* Asigna a 'valor' el más pequeño de
   entre el mismo 'valor' o 100,
   asegurándote de que nunca
   queda debajo de 100.
*/
valor = min(valor, 100);

max(x, y)

Calcula el máximo de dos números de cualquier tipo de dato y devuelve el más grande.

/* Asigna a 'valor' el mayor
   de los dos números, 'valor' o 100.
   'Valor' siempre será al menos 100.
*/
valor = max(valor, 100);

Aleatorios.

randomSeed(seed)

Establece un valor, o semilla, como punto de partida para la función random().

// hace que valor sea la semilla del random
randomSeed(valor);

Como Arduino no es capaz de crear un verdadero número aleatorio, randomSeed() te permite colocar una variable, constante u otra función en la función aleatoria (randomSeed), lo que ayuda a generar números algo más 'aleatorios'. Hay una variedad de semillas o funciones que pueden utilizarse aquí, incluyendo millis() o incluso analogRead() para leer el ruido electrico a través de un pin analógico.

random(min, max)

La función random devuelve un número aleatorio entero de un intervalo de valores especificado entre los valores min y max.

// asigna a la variable 'valor' un numero aleatorio comprendido entre 100-200
valor = random(100, 200);

Nota: Use esta función después de usar el randomSeed().

El siguiente ejemplo genera un valor aleatorio entre 0-255 y lo envía a una salida analógica PWM:

// variable que almacena el valor aleatorio
int randNumber;
// define led como 10
int led = 10;
// no es necesario configurar nada
void setup() {}

void loop()
{
// genera una semilla para aleatorio a partir de la función millis()
  randomSeed(millis());
// genera un número aleatorio entre 0-255
  randNumber = random(255);
// envía a la salida led de tipo PWM el valor
  analogWrite(led, randNumber);
// espera 0,5 seg.
  delay(500);
}

Comunicación en serie.

Serial.begin(rate)

Abre el puerto serie y fija la velocidad en baudios para la transmisión de datos. El valor típico de velocidad para comunicarse con el ordenador es 9600, aunque otras velocidades están disponibles.

void setup()
{
// abre el Puerto serie configurando la velocidad en 9600 bps
  Serial.begin(9600);
}

Nota: Cuando se utiliza la comunicación serie los pins digital 0 (RX) y 1 (TX) no pueden utilizarse al mismo tiempo.

Serial.println(data)

Imprime los datos en el puerto serie, seguido por un retorno de carro automático y salto de línea. Este comando toma la misma forma que Serial.print(), pero es más fácil para la lectura de los datos en el Monitor Serie del software.

// envía el valor 'analogValue' al puerto
Serial.println(analogValue);

Nota: Para obtener más información sobre las distintas posibilidades de Serial.println () y Serial.print () consulta arduino.cc

El siguiente ejemplo toma de una lectura analógica pin0 y envía estos datos al ordenador cada 1 segundo.

void setup()
{
// configura el puerto serie a 9600bps
  Serial.begin(9600);
}

void loop()
{
// envía valor analógico
  Serial.println(analogRead(0));
// espera 1 segundo
  delay(1000);
}

Apéndice.

Salida digital.

*Salida digital*

Este es el básico programa "hola, mundo" en el que simplemente encendemos y apagamos algo. En el ejemplo, un LED conectado al pin 13 que parpadea cada segundo. La resistencia puede ser omitida, el pin 13 es el LED integrado en la placa.

// LED en el pin digital 13 configura el pin de salida
int ledPin = 13;

void setup()
{
// configura el pin 13 como salida
  pinMode(ledPin, OUTPUT);
}

// inicia el bucle del programa
void loop()
{
// activa el LED
  digitalWrite(ledPin, HIGH);
// espera 1 segundo
  delay(1000);
// desactiva el LED
  digitalWrite(ledPin, LOW);
// espera 1 segundo
  delay(1000);
}

Entrada digital.

Esta es la forma más sencilla de entrada con sólo dos estados posibles: encendido o apagado. El ejemplo lee un interruptor o un pulsador conectado al pin 2, y cuando el interruptor está cerrado el pin de entrada leerá el estado HIGH y encenderá un led.

// pin 13 asignado a ledPin
int ledPin = 13;
// pin 2 asignado al pulsador
int inPin = 2;

// Configura entradas y salidas
void setup()
{
// declara el puerto del led como salida
  pinMode(ledPin, OUTPUT);
// y el del pulsador como entrada
  pinMode(inPin, INPUT);
}

void loop()
{
// testea si la entrada esta activa
  if (digitalRead(inPin) == HIGH)
  {
// enciende el led
    digitalWrite(ledPin, HIGH);
// espera 1 segundo
    delay(1000);
// apaga el led
    digitalWrite(ledPin, LOW);
  }
}

Salida de alta corriente.

A veces es necesario controlar cargas de más de los 40 mA que es capaz de suministrar la tarjeta Arduino. En este caso se hace uso de un transistor MOSFET, que puede alimentar cargas de mayor consumo de corriente. El siguiente ejemplo muestra como el transistor MOSFET conmuta 5 veces cada segundo.

Nota: El esquema muestra un motor con un diodo de protección por ser una carga inductiva. En los casos que las cargas no sean inductivas no será necesario colocar el diodo.

// pin de salida para el MOSFET
int outPin = 5;

void setup()
{
// pin5 como salida
  pinMode(outPin, OUTPUT);
}

void loop()
{
// repetir bucle 5 veces
  for (int i = 0; i <= 5; i++)
  {
// activa el MOSFET
    digitalWrite(outPin, HIGH);
// espera 1/4 segundo
    delay(250);
// desactiva el MOSFET
    digitalWrite(outPin, LOW);
// espera 1/4 segundo
    delay(250);
  }
// espera 1 segundo
  delay(1000);
}

Salida analógica de tipo PWM.

La Modulación de Impulsos en Frecuencia (PWM) es una forma de conseguir una “falsa” salida analógica. Se puede utilizar para modificar el brillo de un led o controlar un servo motor. El siguiente ejemplo hace que un led se ilumine y se apague lentamente haciendo bucles for.

// pin PWM para el led
int ledPin = 9;

// no es necesario configurar nada
void setup() {}

void loop()
{
// el valor de i asciende
  for (int i = 0; i <= 255; i++)
  {
// se escribe el valor de i en el PIN de salida del led
    analogWrite(ledPin, i);
// pauses for 100ms
    delay(100);
  }
// el valor de i desciende
  for (int i = 255; i >= 0; i--)
  {
// se escribe el valor de i
    analogWrite(ledPin, i);
// pausa durante 100ms
    delay(100);
  }
}

Entrada con potenciómetro.

Usando un potenciómetro y uno de los pines de entrada analógica-digital de Arduino (ADC), es posible leer valores analógicos en el rango 0-1024. El siguiente ejemplo utiliza un potenciómetro para controlar el tiempo de parpadeo de un led.

// pin entrada para potenciómetro
int potPin = 0;
// pin de salida para el led integrado
int ledPin = 13;

void setup()
{
// declara ledPin como SALIDA
  pinMode(ledPin, OUTPUT);
}
void loop()
{
// enciende ledPin
  digitalWrite(ledPin, HIGH);
// detiene la ejecución el tiempo que marca 'potPin'
  delay(analogRead(potPin));
// apaga ledPin
  digitalWrite(ledPin, LOW);
// detiene la ejecución el tiempo que marca 'potPin'
  delay(analogRead(potPin));
}

Entrada con resistencia variable.

Las resistencias variables incluyen sensores de luz, termistores, sensores de flexión, etc. Este ejemplo hace uso de una función para leer el valor analógico y establecer un tiempo de retardo (delay). Controla la velocidad con la que un led se ilumina y se apaga.

// Salida analógica PWM para conectar a led
int ledPin = 9;
// resistencia variable en la entrada analógica pin 0
int analogPin = 0;
// no es necesario configurar nada
void setup() {}

void loop()
{
// incremento de valor de i
  for (int i = 0; i <= 255; i++)
  {
// configura el nivel brillo con el valor de i
    analogWrite(ledPin, i);
// espera un tiempo
    delay(delayVal());
  }
// decrementa el valor de i
  for (int i = 255; i >= 0; i--)
  {
// configura el nivel de brillo con el valor de i
    analogWrite(ledPin, i);
// espera un tiempo
    delay(delayVal());
  }
}
int delayVal()
{
// crea una variable temporal local
  int v;
// lee valor analógico
  v = analogRead(analogPin);
// convierte el valor leído de 0-1024 a 0-128
  v /= 8;
// devuelve el valor v
  return v;
}

Salida con servo.

Los servos de modelismo son un tipo de motor independiente que puede moverse en un arco de 180º. Todo lo que necesitan es un pulso cada 20 ms. Este ejemplo usa la función servoPulse para moverlo de 10º a 170º y vuelve a empezar.

// servo conectado al pin digital 2
int servoPin = 2;
// ángulo del servo de 0-180
int myAngle;
// anchura del pulso para la función
int pulseWidth;
// servoPulse
void setup()
{
// configura pin 2 como salida
  pinMode(servoPin, OUTPUT);
}
void servoPulse(int servoPin, int myAngle)
{
// determina retardo
  pulseWidth = (myAngle * 10) + 600;
// activa el servo
  digitalWrite(servoPin, HIGH);
// pausa
  delayMicroseconds(pulseWidth);
// desactiva el servo
  digitalWrite(servoPin, LOW);
// retardo de refresco
  delay(20);
}

// el servo inicia su recorrido en 10º y gira hasta 170º
void loop()
{
  for (myAngle = 10; myAngle <= 170; myAngle++)
  {
    servoPulse(servoPin, myAngle);
  }
// el servo vuelve desde 170º hasta 10º
  for (myAngle = 170; myAngle >= 10; myAngle--)
  {
    servoPulse(servoPin, myAngle);
  }
}