Professional Documents
Culture Documents
Fundamentos
Esta pgina alberga explicaciones de algunos de los elementos del hardware y
software de Arduino y los los conceptos que hay tras ellos.
Conceptos Bsicos
Microcontroladores
Pines Digitales: Como trabajan los pines y que significa configuralos como de
entrada o de salida.
Pines de Entrada Analgicos: Detalles respecto a la conversin analgico a
digital y otros usos de los pines.
PWM: Como la funcin analogWrite() simula una salida analgica usando
modulacin por ancho de pulso.
Memoria: Los distintos tipos de memoria disponibles en la placa Arduino.
Tcnica de Programacin
Circuitos
Qu es Arduino ?
Arduino es una herramienta para hacer que los ordenadores puedan sentir y
controlar el mundo fsico a travs de tu ordenador personal. Es una plataforma de
desarrollo de computacin fsica (physical computing) de cdigo abierto, basada en una
placa con un sencillo microcontrolador y un entorno de desarrollo para crear software
(programas) para la placa.
Puedes usar Arduino para crear objetos interactivos, leyendo datos de una gran
variedad de interruptores y sensores y controlar multitud de tipos de luces, motores y
otros actuadores fsicos. Los proyecto de Arduino pueden ser autnomos o comunicarse
con un programa (software) que se ejecute en tu ordenador (ej. Flash, Processing,
MaxMSP). La placa puedes montarla tu mismo o comprarla ya lista para usar, y el
software de desarrollo es abierto y lo puedes descargar gratis.
El lenguaje de programacin de Arduino es una implementacin de Wiring, una
plataforma de computacin fsica parecida, que a su vez se basa en Processing, un
entorno de programacin multimedia.
Por qu Arduino?
Hay muchos otros microcontroladores y plataformas con microcontroladores
disponibles para la computacin fsica. Parallax Basic Stamp, BX-24 de Netmedia,
Phidgets, Handyboard del MIT, y muchos otros ofrecen funcionalidades similares.
Todas estas herramientas organizan el complicado trabajo de programar un
microcontrolador en paquetes fciles de usar. Arduino, adems de simplificar el proceso
de trabajar con microcontroladores, ofrece algunas ventajas respecto a otros sistemas a
profesores, estudiantes y amateurs:
Primer Sketch.
En la gua de inicio (Windows, Mac OS X, Linux), subiste un sketch que hace
parpadear un LED. En este tutorial, aprenderas como funciona cada parte de ese sketch.
Sketch
Un sketch es el nombre que usa Arduino para un programa. Es la unidad de
codigo que se sube y ejecuta en la placa Arduino.
Comentarios
Las primeras lineas del sketch Blink son un comentario:
/*
* Blink
*
* The basic Arduino example. Turns on an LED on for one second,
* then off for one second, and so on... We use pin 13 because,
* depending on your Arduino board, it has either a built-in LED
* or a built-in resistor so that you need only an LED.
*
* http://www.arduino.cc/en/Tutorial/Blink
*/
Variables.
Una variable es un lugar donde se almacena un dato. Posee un nombre, un tipo y
un valor. Por ejemplo, la linea del sketch Blink anterior declara una variable con el
nombre ledPin, de tipo int, y con el valor inicial 13. Esta siendo utilizada para indicar
que pin de Arduino se conecta al LED. Cada vez que el nombre ledPin aparece en el
codigo, su valor sera utilizado. En este caso, la persona que escribio el codigo podria no
haberse molestado en definir la variable ledPin y utilizar simplemente 13 en todas las
partes en que debiese especificar el numero del pin. La ventaja de utilizar una variable
es que se hace mucho ms fcil mover el LED a un pin diferente: solo necesitas editar la
linea en que se asigna el valor inicial a la variable.
Con frecuencia, el valor de una variable cambiara a medida que se ejecuta el
sketch. Por ejemplo, podras almacenar en una variable el valor ledo desde un input.
Hay ms informacin en el tutorial de variables.
Funciones.
Una funcin (tambin conocida como procedimiento o sub-rutina) es un pedazo
de cdigo que puede ser utilizado desde cualquier otro punto del sketch. Por ejemplo,
aqu esta la definicin de la funcin setup() en el ejemplo Blink:
void setup()
{
pinMode(ledPin, OUTPUT);
}
digitalWrite(ledPin, HIGH);
modifica ledPin (pin 13) como HIGH, o 5 volts. Enviando LOW a un pin lo conecta a
tierra, o 0 volts.
delay() hace a Arduino esperar por el numero especificado de milisegundos antes de
continuar con la siguiente linea. Hay 1000 milisegundos en un segundo, por lo que la
linea:
delay(1000);
setup()
loop()
pinMode()
digitalWrite()
delay()
Pines Digitales.
Los pines del Arduino pueden configurarse como entradas o salidas. Este
documento explica el funcionamiento de los pines en esos modos. Si bien el ttulo de
este documento se refiere a los pines digitales, es importante sealar que la gran
mayora de los pines analgicos de Arduino (Atmega), pueden configurarse y utilizarse,
exactamente de la misma manera que los pines digitales.
Propiedades de los Pines Configurados como Entrada (INPUT)
Los pines de Arduino (Atmega) por defecto son de entrada, por lo que no es
necesario configuraros explcitamente como entradas con pinMode(). Se dice que los
pines configurados como entradas estn en estado de alta impedancia. Una forma de
explicar esto es que los terminales de entrada hacen demandas extremadamente
pequeas en el circuito que estn muestreando, se dice que equivale a una resistencia en
serie de 100 megaohmio frente al pin. Esto significa que se necesita muy poca corriente
para pasar el pin de entrada de un estado a otro, y puede hacer posible el uso de los
pines para tareas como la utilizacin de un sensor capacitivo al tacto, la lectura de un
LED como un fotodiodo, o la lectura de un sensor analgico con un esquema como el
RCTime.
Esto tambin significa sin embargo, que los terminales de entrada sin conectar
nada a ellos, o con los cables conectados a ellos sin estar conectados a otros circuitos,
reflejarn cambios aparentemente aleatorios en el estado de pin, recogiendo el ruido
elctrico del entorno, o el acoplamiento capacitivo del estado de un pin prximo.
Resistencias Pullup
A menudo es til para colocar un pin de entrada en un estado conocido si no hay
un estado de entrada. Puede hacerse aadiendo una resistencia pull-up (a +5 V), o una
resistencia pull-down (resistencia a tierra) en la entrada, 10K suele ser un valor muy
comn.
Tambin hay resistencias pullup de 20K conveniente integradas en el chip
Atmega a las que se puede acceder desde el software. Estos resistencias pull-up
incorporadas son accedidas de la siguiente manera.
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
Ten en cuenta que las resistencias pull-up proporcionan suficiente corriente para
dar una luz tenue con un LED conectado a un pin que se ha configurado como entrada.
Si el LED de un proyecto parece estar funcionando pero muy tenuemente, es posible
que sea esto lo que est pasando, y el programador ha olvidado usar pinMode() para
ajustar los pines como salidas.
Tambin debes tener en cuenta que las resistencias pull-up son controladas por
los mismos registros (posiciones de memoria interna del chip) que controlan si un pin
est alto (HIGH) o bajo (LOW). Por consiguiente, un pin que se configura para tener las
7
resistencias pullup activadas cuando esta configurado como entrada, debe tener el pin a
alto (HIGH) si el pin es cambiado como salida (OUTPUT) con pinMode(). Esto
funciona en la otra direccin tambin, y un pin de salida que queda en un estado alto
tendr las resistencias pull-up activas, si cambia a entrada (INPUT) con pinMode().
NOTA: El pin Digital 13 es ms difcil de usar que otros pines digitales porque tiene un
LED y una resistencia asociada soldados a la placa en la mayora de las placas. Si activa
la resistencia pull-up 20k del interior, se pondra en alrededor de 1,7 V en lugar de los
5V que se esperan debido a que el LED integrado y la resistencia en serie bajan el nivel
del voltaje, lo que se traduce en que siempre retornar bajo (LOW). Si ests obligado a
usar el pin 13 como entrada digital, utiliza una resistencia pulldown externa.
Propedades de los Pines Configurados com salida (OUTPUT )
Los pines configurados como salida (OUTPUT) con pinMode() se dice que estn
en un estado de baja impedancia. Esto significa que puede proporcionar una cantidad
sustancial de corriente a otros circuitos. Los pines del Atmega pueden proporcionar
corriente positiva o proporcionar corriente negativa de hasta 40 mA (miliamperios) a
otros dispositivos o circuitos. Esta es suficiente corriente para la brillante luz de un LED
(no te olvides de la resistencia en serie), o para utilizar muchos sensores por ejemplo,
pero no es corriente suficiente para utilizar la mayora de rels, solenoides o motores.
Los cortocircuitos en los pines de Arduino, o intentos de extraer mucha corriente
de ellos, pueden daar o destruir los transistores de salida en el pin, o daar
completamente el chip Atmega. A menudo, esto se traducir en un pin del
microcontrolador "muerto", pero el resto del chip seguir funcionando adecuadamente.
Por esta razn es buena idea conectar los pines de salida a otros dispositivos con
resistencias de 470 o 1k, limitando la corriente mxima que desde los pines es
requerida para una aplicacin particular.
Volver a Fundamentos
Ver Tambin
pinMode()
digitalWrite()
digitalRead()
10
PWM.
El ejemplo "Fading" demuestra el uso de una salida analgica (PWM) para
atenuar y aumentar la luminosidad de un LED. Lo tienes disponible en la opcin "File>Sketchbook->Examples->Analog" del men del software de Arduino.
La Modulacin por Ancho de Pulso (PWM = Pulse Width Modulation) es una
tecnica para simular una salida analgica con una salida digital. El control digital se usa
para crear una onda cuadrada, una seal que conmuta constantemente entre encendido y
apagado. Este patron de encendido-apagado puede simular voltajes entre 0 (siempre
apagado) y 5 voltios (siempre encendido) simplemente variando la proporcin de
tiempo entre encendido y apagado. A la duracin del tiempo de encendido (ON) se le
llama Ancho de Pulso (pulse width). Para variar el valor analgico cambiamos, o
modulamos, ese ancho de pulso. Si repetimos este patrn de encendido-apagado lo
suficientemente rapido por ejemplo con un LED el resultado es como si la seal variara
entre 0 y 5 voltios controlando el brillo del LED.
En el grafico de abajo las lineas verdes representan un periodo regular. Esta
duracin o periodo es la inversa de la frecuencia del PWM. En otras palabras, con la
Arduino la frecuencia PWM es bastante proxima a 500Hz lo que equivale a periodos de
2 milisegundos cada uno. La llamada a la funcin analogWrite() debe ser en la escala
desde 0 a 255, siendo 255 el 100% de ciclo (siempre encendido), el valor 127 ser el
50% del ciclo (la mitad del tiempo encendido), etc.
11
12
Memoria.
Existen 3 fuentes de memoria en el microcontrolador utilizado por la placa Arduino
(ATmega168):
Ten en cuenta que no hay mucha SRAM disponible. Es fcil utilizarla toda al
tener muchas cadenas (strings) en tu programa. Por ejemplo, una declaracin como:
char message[] = "Ah, qu hermoso..., qu hermoso."
pone 32 bytes en la SRAM (cada caracter utiliza un byte). Esto pude no parecer mucho,
pero no toma mucho ms llegar hasta 1024, especialmente si tienes largas cantidades de
texto que enviar a una pantalla, o una tabla de datos muy grande, por ejemplo.
Si se te acaba la SRAM, tu programa fallara de manera improvista; parecera subir a
la placa de manera correcta, pero no se ejecutara, o se ejecutara de manera extraa. Para
comprobar si esto es lo que sucede, puedes intentar comentado o acortando las cadenas
de texto u otras estructuras de datos en tu sketch (sin alterar el cdigo). Si entonces este
funciona correctamente, es probable que el problema haya sido la SRAM llena. Hay
unas pocas cosas que puedes hacer para solucionar este problema:
13
If you don't need to modify the strings or data while your sketch is running, you
can store them in flash (program) memory instead of SRAM; to do this, use the
PROGMEM keyword.
14
Variables.
Una variable es una ubicacin para almacenar una porcin de informacin.
Tiene un nombre, un valor y un tipo. Por ejemplo, esta sentencia (llamado una
declaracin):
int pin = 13;
crea una variable cuyo nombre es pin, whose value is 13, y su tipo es int. Mas tarde en
el programa, puedes hacer referencia a esta variable por su nombre, momento en el que
puedes acceder a su valor y utilizarlo. Por ejemplo, en esta sentencia:
pinMode(pin, OUTPUT);
es el valor de pin (13) el que ser pasado a la funcinpinMode(). En este caso, realmente
no necesitas usar una variable, esta sentencia funcionara igual de bien:
pinMode(13, OUTPUT);
La ventaja de una variable en este caso es que solo necesitas especificar el
nmero del pin una nica vez, pero puedes usarlo montones de veces. As, si mas tarde
decides cambiar el pin 13 por el 12, solo tienes que cambiarlo en un punto del cdigo.
Adems puedes usar un nombre descriptivo que tenga que ver con el uso que vas a dar a
la variable (ej. un programa para controlar un LED RGB (Rojo, Verde y Azul) podra
tener variables llamada PinRojo, PinVerde y PinAzul).
Una variable tiene otras ventajas sobre un valor como un nmero. La ms
importante, puedes cambiar el valor de una variable mediante un asignador
(representado por el signo igual). Por ejemplo:
pin = 12;
cambiar el valor de la variable a 12. Observa que no se especifica el tipo de la variable:
este no cambia con la asignacin. Es decir, el nombre de la variable est
permanentemente asociado a un tipo; slo esto cambia valor. [1] Ten en cuenta que
tienes que declarar una variable antes de asignarle un valor. Si se incluye la instruccin
anterior en un programa sin la previa declaracin anterior, obtendras un mensaje del
estilo: "error: pin was not declared in this scope" ("Error: pin no ha sido declarado en
este mbito").
Cuando se asigna una variable a otra, ests haciendo una copia de su valor y
almacenando dicha copia en la ubicacin de memoria asociada a la otra variable.
Cambiando una no tiene efecto en la otra. Por ejemplo, despus de:
int pin = 13;
int pin2 = pin;
pin = 12;
slo pin tiene el valor 12; pin2 tiene todava 12.
15
Y ahora qu, puede que te preguntes que significa la palabra "scope" (alcance)
en ese mensaje de error anterior? Se refiere a la parte de tu programa en el que se puede
usar la variable. Esto se determina por el lugar donde se declara. Por ejemplo, si quieres
poder utilizar una variable en cualquier parte de tu programa, puedes declararla en la
parte superior de tu cdigo. Esto se llama variable global, aqu tienes un ejemplo:
int pin = 13;
void setup()
{
pinMode(pin, OUTPUT);
}
void loop()
{
digitalWrite(pin, HIGH);
}
Como puedes ver, pin se usa tanto en la funcin setup() como en loop(). Ambas
funciones hacen referencia a la misma variable, por lo que un cambio en una afectar al
valor que tendr en la otra, como en:
int pin = 13;
void setup()
{
pin = 12;
pinMode(pin, OUTPUT);
}
void loop()
{
digitalWrite(pin, HIGH);
}
Aqu, a la funcin digitalWrite() llamada desde loop() se le pasa el valor 12, ya que es el
valor que se le asigna a la variable en la funcin setup().
Si tienes que utilizar una variable en una sola funcin, puedes declararla en la misma, en
cuyo caso el mbito (scope) de utilizacin se limita a esa funcin. Por ejemplo:
void setup()
{
int pin = 13;
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
}
En este caso, la variable pin slo podr ser usada dentro de la funcin setup(). Si tratas
de hacer algo como esto:
16
void loop()
{
digitalWrite(pin, LOW); // incorrecto: pin no tiene mbito aqu.
}
obtendrs el mismo mensaje que antes: "error: 'pin' was not declared in this scope"
("error: 'pin' no se declar en este mbito"). Es decir, a pesar de que has declarado pin
en algn sitio en tu programa, est tratando de utilizarlo en alguna parte fuera de su
mbito de aplicacin.
Te puedes preguntar por qu no hacemos todas las variables globales? Despus
de todo, si no s dnde puedo necesitar una variable, por qu limitar su alcance a una
sola funcin? La respuesta puede que sea ms fcil de averiguar lo que te parece. Si una
variable es global, su valor podra cambiarse en cualquier parte del cdigo, lo que
significa que necesita entender la totalidad del programa para saber qu va a pasar con
la variable. Por ejemplo, si la variable tiene un valor que no esperabas, puede ser mucho
ms fcil de averiguar de donde viene el valor si la variable tiene un alcance limitado.
[block scope] [size of variables]
[1] En algunos lenguages de programacin, como Python, los tipos se asocian con
valores, no a los nombres de variables, y se pueden asignar valores de cualquier tipo a
una variable. Esto se conoce como tipos dinmicos (dynamic typing).
17
Funciones.
Segmentar el cdigo en funciones permite al programador crear piezas
modulares de cdigo que realizan una tarea definida y vuelven a la zona del programa
en la que fueron llamadas. El caso tpico para crear un funcin es cuando uno necesita
realizar la misma accin mltiples veces dentro de un mismo programa.
Para programadores acostumbrados a utilizar BASIC las funciones en Arduino permiten
(y extienden) la utilidad de usar subrutinas (GOSUB en BASIC).
La estandarizacin de fragmentos de cdigo en funciones tiene diversas ventajas:
Al "invocar" a nuestra pequea funcin le pasamos parametros del tipo de dato que ella
espera.
void loop{
18
int i = 2;
int j = 3;
int k;
k = myMultiplyFunction(i, j); // k ahora contiene 6
}
Nuestra funcin necesita ser declarada fuera de cualquier otra funcin, por ello
"myMultiplyFunction()" puede ir antes o despues de la funcin "loop()".
El sketch completo podra ser algo como esto:
void setup(){
Serial.begin(9600);
}
void loop{
int i = 2;
int j = 3;
int k;
k = myMultiplyFunction(i, j); // k ahora contiene 6
Serial.println(k);
delay(500);
}
int myMultiplyFunction(int x, int y){
int result;
result = x * y;
return result;
}
Otro ejemplo:
Esta funcin leer un sensor cinco veces con analogRead() y calcular la media
de las cinco lecturas. Escala los datos a 8 bits (0-255), los invierte y devuelve el
resultado invertido.
int ReadSens_and_Condition(){
int i;
int sval;
for (i = 0; i < 5; i++){
sval = sval + analogRead(0);
}
return sval;
// devuelve el resultado
}
Para llamar a nuestra funcin solo tenemos que asignarla a una variable.
int sens;
sens = ReadSens_and_Condition();
20
segundo lugar, tenemos la variable ledPin que indica el pin a utilizar. Por ltimo, est la
llamada a pinMod () que inicializa el pin como salida.
Vamos a empezar a convertir el programa en una librera!
Para una librera necesita al menos dos arcivos: un archivo de cabecera (w / con
extensin. H) y el cdigo fuente (w / extensin. cpp). El archivo de cabecera contiene
definiciones para la librera: bsicamente un listado de todo lo que hay dentro, mientras
que el archivo del cdigo fuente tiene el cdigo real. Vamos a llamar a nuestra librera
"Morse", por lo que nuestro archivo de cabecera ser Morse.h. Echemos un vistazo a lo
que contiene. Puede parecer un poco extrao al principio, pero tendr ms sentido una
vez que vea el cdigo fuente que lo acompaa.
El archivo de cabecera consiste bsicamente en una clase con una lnea para cada
funcin de la librera, junto con las variables que se van a usar:
class Morse {
public:
Morse(int pin);
void punto();
void raya();
private:
int _pin;
};
Una clase es simplemente una coleccin de funciones y variables agrupadas en
un mismo lugar. Estas funciones y variables pueden ser pblicas, lo que significa que
las podrn usar las personas que estn utilizando la librera, o privada, lo que significa
que slo se puede acceder a ellas desde la propia clase. Cada clase tiene una funcin
especial conocida como constructor, que se utiliza para crear una instancia de la clase (o
sea, un objeto). El constructor tiene el mismo nombre que la clase, y no devuelve nada.
Se necesitan un par cosas ms en el archivo de encabezado. Una de ellas es una
instruccin # include que da acceso a los tipos estndar y las constantes del lenguaje
Arduino (esto se agrega automticamente a los programas normales, pero no a las
libreras). Se parece a esto (y se coloca antes de la definicin de la clase mostrada
anteriormente):
1. Include "WProgram.h"
Por ltimo, es comn aadir las siguientes lineas de cdigo :
1. Ifndef Morse_h
2. Define Morse_h
// La declaracin # include y el cdigo van aqu ...
1. endif
22
1. ifndef Morse_h
2. define Morse_h
3. include "WProgram.h"
class Morse {
public:
Morse(int pin);
void punto();
void raya();
private:
int _pin;
};
1. endif
Vamos a repasar las distintas partes del cdigo fuente de Morse.cpp.
Lo primero son un par de # include. Con esto el resto del cdigo tendr acceso a las
funciones estndar de Arduino, y a las definiciones definidas en Morse.h:
1. Include "WProgram.h"
2. Include "Morse.h"
A continuacin viene el constructor. Una vez ms, en el constructor se establece lo
que debe ocurrir cuando alguien crea una instancia de la clase. En este caso, el usuario
especifica el pin que le gustara utilizar. Configuramos el pin como salida en una
variable privada para su uso en las otras funciones:
MORSE:: Morse (pin int) ( pinMode (pin, OUTPUT); _pin = pin; )
23
Hay un par de cosas extraas en este cdigo. La primera es el Morse:: antes del
nombre de la funcin. Esto indica que la funcin es parte de la clase Morse. Vers esto
en otras funciones de la clase. Lo segundo es el subrayado en el nombre de nuestra
variable privada, _pin. Esta variable puede tener cualquier nombre, siempre y cuando
coincida con la definicin que figura en el archivo de encabezado. Agregar un
subrayado al inicio del nombre es una convencin comn para dejar claro que las
variables son privadas, y tambin para diferenciarlas del argumento de la funcin (el pin
en este caso).
Despus viene el cdigo del programa que estamos convirtiendo en una librera
(por fin!). Se ve ms o menos lo mismo, salvo Morse:: delante de los nombres de las
funciones, y en lugar de _pin pin:
void Morse::punto() {
digitalWrite(_pin, HIGH);
delay(250);
digitalWrite(_pin, LOW);
delay(250);
}
void Morse::raya() {
digitalWrite(_pin, HIGH);
delay(1000);
digitalWrite(_pin, LOW);
delay(250);
}
Por ltimo, es tpico incluir un comentario en la parte superior del cdigo fuente.
Vamos a ver el cdigo:
/*
Morse.cpp - Library for flashing Morse code.
Created by David A. Mellis, November 2, 2007.
Released into the public domain.
1. include "WProgram.h"
2. include "Morse.h"
Morse::Morse(int pin) {
pinMode(pin, OUTPUT);
_pin = pin;
24
}
void Morse::punto() {
digitalWrite(_pin, HIGH);
delay(250);
digitalWrite(_pin, LOW);
delay(250);
}
void Morse::raya() {
digitalWrite(_pin, HIGH);
delay(1000);
digitalWrite(_pin, LOW);
delay(250);
}
Y eso es todo lo que necesita (hay algunas otras cosas opcionales, pero
hablaremos de eso ms adelante). Vamos a ver cmo usar la librera.
En primer lugar, hay que crear el directorio Morse dentro del subdirectorio de
libreras . Copia o mueve los archivos Morse.h y Morse.cpp a ese directorio. Ahora
ejecuta el IDE de Arduino. Si vas al men Sketch > Import Library deberas ver el una
opcin Morse. La librera ser compilada con los programas que la utilizan. Si no
aparece la librera, asegrate de que los nombres de los archivos terminan realmente ten
.cpp y .h (y no en .pde o .txt, por ejemplo).
Vamos a ver cmo podemos modificar nuestro programa de SOS para hacer uso de la
nueva librera:
1. include <Morse.h>
Morse morse(13);
void setup() { }
void loop() {
morse.punto(); morse.punto(); morse.punto();
morse.raya(); morse.raya(); morse.raya();
morse.punto(); morse.punto(); morse.punto();
delay(3000);
}
Hay algunas diferencias con el programa original (aparte del hecho de que parte
del cdigo se ha trasladado a la librera).
25
26
27