Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ejemplos Con Arduino
Ejemplos Con Arduino
ndice de contenido
1
ARDUINO ..................................................................................................................................... 6
2.1
INTRODUCCIN A ARDUINO ................................................................................................... 6
2.1.1
Qu es Arduino? ........................................................................................................ 6
2.1.2
Qu significa que Arduino sea Open Hardware?[4] ................................................ 6
2.1.3
Por qu Arduino? ...................................................................................................... 7
2.2
LAS PLACAS ARDUINO ........................................................................................................... 8
2.2.1
Qu significa que una placa sea Arduino? ................................................................ 8
2.2.2
Placas de entradas y salidas ....................................................................................... 8
2.2.3
"Shields" y otras placas de terceros .......................................................................... 10
2.2.4
Construir nuestro propio Arduino ............................................................................. 12
2.2.5
Cmo obtener una placa Arduino? ......................................................................... 12
2.2.6
Nuestra eleccin: El Arduino UNO ........................................................................... 12
2.2.6.1
2.2.6.2
2.2.6.3
2.3
EL ENTORNO DE TRABAJO .................................................................................................... 15
2.3.1
El entorno de desarrollo y los drivers de la placa para Windows ............................ 15
2.3.2
Descargar y ejecutar un ejemplo de aplicacin Arduino .......................................... 18
2.3.2.1
2.3.2.2
2.3.2.3
Editor ..................................................................................................................................... 18
Compilador ............................................................................................................................ 19
Cargar y depurar .................................................................................................................... 20
2.4
LENGUAJE DE PROGRAMACIN ARDUINO ............................................................................ 22
2.4.1
Introduccin e historia .............................................................................................. 22
2.4.2
Funciones bsicas y operadores ............................................................................... 22
2.4.2.1
2.4.2.2
2.4.2.3
2.4.3
2.4.3.1
2.4.3.2
Estructuras ............................................................................................................................. 23
Variables ................................................................................................................................ 24
Funciones............................................................................................................................... 25
3.5.2
El ensamblado ........................................................................................................... 35
3.6
EL SOFTWARE ...................................................................................................................... 37
3.6.1
Diseo de la pantalla ................................................................................................ 37
3.6.1.1
3.6.1.2
3.6.2
El programa de control de Arduino .......................................................................... 40
3.6.3
El programa de control del PC ................................................................................. 43
3.7
JUEGO DE PRUEBAS .............................................................................................................. 44
3.7.1
Test sobre el caudalmetro ........................................................................................ 44
3.7.2
Test sobre la captura de pulsos ................................................................................. 45
3.7.3
4
4.2.3
4.2.3.1
4.2.3.2
4.2.3.3
4.2.3.4
4.2.3.5
4.2.3.6
4.2.3.7
4.2.4
5
El ATmega328P........................................................................................................ 55
Un breve resumen .................................................................................................................. 55
Puertos de entrada y salida digital ......................................................................................... 55
Uso de la USART/comunicacin serie .................................................................................. 58
Las interrupciones en los ATmega328P ................................................................................ 60
Interrupciones por cambio de PIN ......................................................................................... 64
Uso de temporizadores y PWM ............................................................................................. 66
Uso del conversor ADC ......................................................................................................... 74
PRESUPUESTO ......................................................................................................................... 78
5.1
PRECIOS UNITARIOS ............................................................................................................. 78
5.2
PRECIOS DESCOMPUESTOS ................................................................................................... 78
5.2.1
Captulo 1: Estudios previos ..................................................................................... 78
5.2.2
Captulo 2: Diseo y montaje del hardware ............................................................. 79
5.2.3
Captulo 3: Diseo del firmware ............................................................................... 79
5.2.4
Captulo 4: Diseo del software de PC ..................................................................... 79
5.2.5
Captulo 5: Documentacin ...................................................................................... 80
5.3
RESUMEN DEL PRESUPUESTO ............................................................................................... 80
ndice de ilustraciones
Ilustracin 1: Logo oficial de Arduino ......................................................................... 8
Ilustracin 2: En la parte superior Arduino MEGA y en la inferior Arduino UNO .... 9
Ilustracin 3: Arduino con tres "shields" ................................................................... 10
Ilustracin 4: RobotShop Rover ................................................................................. 11
Ilustracin 5: Arduino Single-Sided Serial o Severino .............................................. 12
Ilustracin 6: Arduino UNO, vista frontal ................................................................. 13
Ilustracin 7: Arduino UNO, vista trasera ................................................................. 13
Ilustracin 8: Pines de Arduino contra ATmega328 .................................................. 14
Ilustracin 9: Arduino en el administrador de dispositivos de Windows .................. 16
Ilustracin 10: Entorno SW de Arduino..................................................................... 17
Ilustracin 11: Acceso a los ejemplos a travs del men ........................................... 19
Ilustracin 12: Acceso a los ejemplos a travs de la barra de herramientas .............. 19
Ilustracin 13: Ejemplo de cdigo Arduino ............................................................... 19
Ilustracin 14: Resultado de verificacin correcto..................................................... 20
Ilustracin 15: Resultado de verificacin incorrecto. ................................................ 20
Ilustracin 16: Ubicacin del LED de test en la placa Arduino ................................. 21
3
Ilustracin 52: Generacin PWM en modo Phase and Frequency Correct PWM.. 73
Ilustracin 53: Uso del temporizador como Input capture ..................................... 73
Ilustracin 54: Configuracin opciones de optimizacin del compilador ................. 76
Ilustracin 55: Configuracin opciones de optimizacin del linker .......................... 76
Ilustracin 56: Resultado de la construccin del proyecto en AVRStudio ................ 77
Ilustracin 57: Modificacin del fichero ColorLCDShield.cpp. 1era parte ............... 84
Ilustracin 58: Modificacin del fichero ColorLCDShield.cpp. 2da parte ................ 85
Ilustracin 59: Configuracin de una herramienta externa en AVRStudio ............... 99
Ilustracin 60: Vista para crear un botn para las herramientas externas en
AVRStudio ........................................................................................................................ 100
Ilustracin 61: Cuadro de opciones para botn en la barra de herramientas. I ........ 100
Ilustracin 62: Cuadro de opciones para botn en la barra de herramientas. II ....... 101
Ilustracin 63: Vista del botn en la barra de herramientas ..................................... 101
Ilustracin 64: Estructura de carpetas del soporte digital ........................................ 112
ndice de anexos
ANEXOS ............................................................................................................................................. 83
ANEXO 1: INFORMACIN USO LIBRERA LCD ................................................................................ 83
Modificaciones sobre la librera................................................................................................. 84
ANEXO 2: PROGRAMA DE CONTROL DE ARDUINO. ......................................................................... 86
ANEXO 3: PROGRAMA DE CONTROL DEL PC. ................................................................................. 91
ANEXO 4: CONFIGURACIN DEL AVRSTUDIO PARA DESCARGAR EL CDIGO EN ARDUINO. .......... 97
Contenido de Upload.cmd ...................................................................................................... 97
Contenido de UploadFromAVRStudio.cmd ............................................................................ 98
Uso de herramientas externas en AVRStudio ............................................................................. 98
ANEXO 5: LIBRERA DE USO DE LA COMUNICACIN SERIE EN AVRSTUDIO ................................. 101
Contenido de Arduino_SERIAL_API.h ................................................................................ 101
Contenido de Arduino_SERIAL.c ......................................................................................... 102
ANEXO 6: COMUNICACIN SERIE CON INTERRUPCIONES DE RECEPCIN ...................................... 103
Contenido de Arduino_SERIAL_INTRx_API.h .................................................................... 103
Contenido de Arduino_SERIAL_INTRx.c ............................................................................ 103
Contenido de Arduino_SERIAL_INTERRUPT_example.c ................................................... 104
ANEXO 7: MEDIDOR DE CAUDAL IMPLEMENTADO CON AVRSTUDIO ........................................... 105
Contenido de medidorCaudal_AVR.cpp .............................................................................. 105
Parte del contenido modificado de ColorLCDShield.h ........................................................ 110
ANEXO 8: CONTENIDO DEL SOPORTE DIGITAL DEL PFC ............................................................... 111
El objetivo principal de este proyecto fin de carrera es conocer Arduino con todo su
ecosistema de herramientas y accesorios, y evaluar sus capacidades y posibilidades.
Se ha definido como segundo objetivo la evaluacin de las capacidades
formativas/lectivas de la plataforma Arduino en el mbito de la educacin tanto secundaria
como universitaria.
Para alcanzar tales objetivos propongo la realizacin de un medidor de caudal como
hilo conductor para poder conocer y evaluar tanto el hardware como el software, as como
conocer los distintos canales de distribucin.
Arduino
Arduino UNO.
Es una placa Arduino que se conecta al PC a travs de un cable USB estndar.
A travs de esta conexin la alimentacin y, adems, permite programarla y
utilizarla.
Arduino UNO es la ltima revisin de este tipo de placas que se conectan al
USB. Entre las mltiples revisiones que se han hecho encontraramos la
Duemilanove, Diecimila, NG (Nuova Generazione) o Extreme.
Arduino Mega
Es una placa Arduino similar a la USB, pero ms grande y potente. La ltima
revisin posee el chip ATmega2560. Tiene mayor nmero de pines de entradas
y salidas digitales, ms pines PWM, entradas analgicas, etc.
Arduino Pro
Es una placa similar al Arduino UNO, pero diseada con la intencin de
instalaciones semipermanentes. La placa se entrega sin los distintos conectores
o headers, es compatible con las distintas extensiones de Arduino, y existe
una versin de 3.3V para ser alimentado con bateras.
Arduino Ethernet
Similar al Arduino UNO, sin soporte USB, pero con un conector RJ-45 para dar
soporte Ethernet. Existe la posibilidad de tomar la alimentacin de la propia
Ethernet.
Arduino Fio
Un Arduino orientado para usarlo como nodo inalmbrico. Posee conectores
para un mdulo Xbee (mdulo inalmbrico)[13], un conector para una batera
LiPo (Polmeros de litio), y un circuito para cargar la batera.
Arduino LilyPad
Una placa Arduino circular, reducida al mximo, diseada para ser cosida a la
ropa o a otro tipo de soporte flexible. Necesita un adaptador adicional para
comunicarse con el PC.
Arduino BT
El Arduino BT contiene un mdulo bluetooth integrado para las
comunicaciones mviles.
Arduino Nano
El Arduino Nano es un todo-en-uno, diseo compacto para usar en una placa de
prototipo.
Arduino Serial
Las versiones serial de Arduino se vendieron principalmente como kits no
ensamblados o solo PCBs para que lo montara uno mismo, ya sea a modo de
aprendizaje o para reducir costes.
Arduino Mini
El Arduino Mini es la placa compacta de Arduino. Para reducir espacio, la
comunicacin con el PC se hace a travs de un adaptador de USB a Arduino
Mini.
RobotShop Rover
Es una pequea plataforma mvil diseada entorno a Arduino. Los usuarios
pueden personalizar su mvil aadiendo funcionalidad.
12
2.2.6.2 Caractersticas
La descripcin completa del Arduino UNO se puede encontrar en su pgina web
oficial. Este es un resumen de las principales caractersticas:
Microcontrolador
ATmega328
Voltaje de funcionamiento
5V
7-12V
6-20V
40 mA
50 mA
Memoria Flash
32 KB (ATmega328) de las cuales 0,5
KB las usa el gestor de arranque (boot loader)
SRAM
2 KB (ATmega328)
EEPROM
1 KB (ATmega328)
Velocidad de reloj
16 Mhz
El Arduino UNO puede ser alimentado va la conexin USB o con una fuente de
alimentacin externa. El origen de la alimentacin se selecciona automticamente.
Adems, algunos de los pines tienen funciones especializadas:
Serie: Pin 0 (RX) y 1 (TX). Usados para recibir (RX) y transmitir (TX) datos
a travs de puerto serie TTL. Estos pines estn conectados a los pines
correspondientes del chip de FTDI responsable de la conversin USB-toTTL.
LED: Pin 13. Hay un LED integrado en la placa conectado al pin digital 13,
cuando este pin tiene un valor HIGH(5V) el LED se enciende y cuando este
tiene un valor LOW(0V) el LED se apaga.
14
La descarga:
Descargamos la ltima versin del software Arduino de la pgina oficial [26].
El paquete de software Arduino est contenido en un nico fichero
comprimido. No es necesario instalarlo, simplemente lo extraemos en la carpeta
deseada asegurndonos que mantenemos la estructura de subcarpetas.
15
16
caso Arduino Uno. En el mismo men Tools, submen Serial Port, seleccionaremos
el puerto correspondiente, en nuestro caso COM3.
La barra de herramientas nos proporciona un acceso rpido a las siguientes
funciones:
Verify -
18
Esto nos abrir una nueva ventana con el cdigo de este boceto, el objetivo del cual
no es ms que encender y apagar el LED de test, montado en la placa Arduino, cada
segundo (secuencia infinita de un segundo encendido, un segundo apagando. Blink).
19
21
22
2.4.2.1 Estructuras
Al estar basado en Processing, Java y/o C, las estructuras de control son muy
similares a ellos y entre ellos.
Sintaxis bsica
/ (divisin)
% (resto)
++ (incremento en uno)
{} (llaves. Delimitador de
bloques de cdigo)
-- (decremento en uno)
+= (suma y asignacin)
/* */ (comentarios en
mltiples lneas)
-= (resta y asignacin)
*= (multiplicacin y
asignacin)
/= (divisin y asignacin)
#define (definicin de
precompilador)
Operadores de comparacin
Estructuras de control
== (igual a)
!= (distinto de)
if (comparador si-entonces)
continue (continuacin en
bloque de cdigo)
Operadores Booleanos
&& (y)
|| (o)
! (negacin)
* operador de indireccin
Operadores Aritmticos
= (asignacin)
+ (suma)
- (resta)
* (multiplicacin)
23
2.4.2.2 Variables
Los tipos de los datos, su uso y declaracin, es muy similar a otros lenguajes de
programacin, como el C o Java.
Constantes
Las constantes que vienen predefinidas en el lenguaje de Arduino se usan para
facilitar la lectura de los programas.
Tipos de Datos
Las variables pueden ser declaradas en cualquier punto del programa y, si no se
indica lo contrario, valen cero.
float (Valor en coma flotante de 32 bits. Se debe evitar usar estos tipos ya
que consumen mucho tiempo de CPU, espacio de cdigo y pueden
ocasionar problemas en comparaciones, ya que por ejemplo 6.0 dividido por
3.0 puede no ser igual a 2.01)
void (Vaco)
String (Des de la versin 0019 existe la clase String() que permite manipular
cadenas de caracteres de un modo sencillo, permitiendo concatenaciones o
Se debe tener en cuanta que el uso de float se realiza a travs de libreras sw, y que adems la propia
codificacin IEEE-754 que usa el tipo float tiene limitaciones.
24
gestin automtica del fin de cadena. Hasta ese momento el uso de string se
limitaba a vectores de caracteres sobre los cuales se deba tener en cuenta el
final de cadena /0 para poder usarlo con funciones tipo print())
Conversin
Estas son una serie de funciones que permiten el cambio entre tipos.
volatile Voltil Una variable debe ser declarada volatile siempre que su
valor pueda ser modificado por algo ms all de la seccin del cdigo en el
que aparece. En Arduino, el nico lugar en el que se podra dar el caso es en
secciones de cdigo asociadas a interrupciones.
2.4.2.3 Funciones
Aqu se muestran muchas funciones ya implementadas en el entorno Arduino para
simplificar la tarea de desarrollo para problemas comunes. Muchas de ellas estn limitadas
a ser usadas en pines concretos y pueden necesitar de argumentos que no se detallan en
este apartado. Para informacin adicional se puede consultar la pgina de referencia del
lenguaje del proyecto Arduino [28].
E/S Digital
E/S Analgica
25
E/S Avanzada
Tiempo
Clculo
Trigonometra
Nmeros aleatorios
26
Bits y Bytes
bit(n) Devuelve un byte con sus bits a cero a excepcin del bit n. Por
ejemplo, bit(0) devolvera un 1 en decimal, bit(1) un 2, bit(2) un 4 en
decimal.
Interrupciones externas
Interrupciones
Comunicacin (estas dos son clases, con lo que no se pueden invocar directamente,
sino que se debe invocar el mtodo que necesitemos)
Serial
Stream
Wire - Interfaz de dos cables, Two Wire Interface (TWI/I2C), para enviar y
recibir datos a travs de una red de dispositivos y sensores.
Sensores:
28
Displays y LEDs:
Motores y PWM:
Medicin de Tiempo:
29
30
31
21.90
32.90
Subtotal:
54.80
3.50
IVA 18%:
9.86
0.63
Total:
68.79
Y el sensor de caudal en la tienda HellFire ToyZ [34] de eBay para pagar lo mnimo
en gastos de envo.
1 x Koolance INS-FM17N Coolant Flow Meter for LCS
$22,99 USD
Envo y manipulacin
$11,68 USD
Total
$34,67 USD
Tipo de cambio:
Total Euros
El total del material asciende a 94.66
32
3.5 El hardware
3.5.1 Caractersticas tcnicas de los componentes
3.5.1.1 Shield LCD color
33
34
Ya que simplemente mide a qu velocidad fluye el lquido por el interior del sensor,
el hecho que el sensor no est totalmente lleno (presencia de bolsas de aire) provocar una
falta de precisin en la lectura del caudal.
Para no perder pulsos conectaremos el sensor de caudal en una entrada de
interrupcin externa de la placa Arduino, en el pin 2.
3.5.2 El ensamblado
Despus de estudiar como ensamblar la shield y decidir a travs de que pines
conectaremos el caudalmetro, el montaje quedara as.
35
36
37
Ilustracin 28: Uso de una librera una vez instalada en el entorno Arduino
Para usarla en nuestro sketch debemos incluirla al igual como se hara en C.
#include <ColorLCDShield.h>
Normalmente, dentro de las libreras hay un fichero de texto donde se nos explica
cmo se puede o debe usar la librera, as como programas con ejemplos de uso. En nuestra
librera hay un fichero llamado Readme, donde nos indica la licencia de uso de esta
38
librera y como usarla2. En un modo resumido, nos indica que debemos instar el
constructor de la librera usando la declaracin:
LCDShield lcd;
Una vez declarado el objeto de la librera, nos indica varios mtodos a usar, entre
ellos el mtodo de inicializacin
lcd.init(EPSON);
Vase ANEXO 1
39
40
41
Loop()
Tarea_1sec()
Interrupcin()
contadorPulsos = 0;
tarea_periodica(){
/* Inicio zona segura intercambio de datos /
noInterrupts();
unsigned int contadorPulsosLocal = contadorPulsos;
contadorPulsos = 0;
interrupts();
/* Fin zona segura intercambio de datos */
}
rutina_servicio_interrupcio(){
contadorPulsos++;
}
42
La parte de crear una ventana y dibujar la grfica se realiza a travs de una librera
python con lo que la totalidad del programa se puede reducir a unas 300 lneas de cdigo.3
Vase ANEXO 3
43
44
45
El hecho de dar la masa del caudalmetro a travs de una salida digital nos permite
testear la captura de pulsos si configuramos este pin como salida PWM.
Para genera un PWM de 31Hz en el pin D6 aadimos la siguiente lnea al principio
de la funcin loop():
tone(caudalGNDPin,31);
46
47
detalles. Pero estos detalles son precisamente lo que nos va a interesar a partir de este
punto.
Para ello empezaremos configurando un entorno de desarrollo que nos permita
trabajar de un modo ms directo con el microcontrolador.
4.2.1 Usar AVRStudio, cdigo C y Arduino
En primer lugar vamos a instalar AVRStudio, que es el IDE y el conjunto de
herramientas oficial de Atmel (el fabricante de los microcontroladores utilizados en la
Arduinos). Podemos obtenerlo des de la propia pgina web de Atmel [37].
La versin sobre la que se ha trabajado se ha adjuntado en el soporte digital del PFC.
Nosotros instalamos el paquete AVR Studio 5.1 Installer - Full.
Para realizar la descarga es necesario registrarse en la web de Atmel, pero el proceso
es simple y rpido.
Una vez instalado todo lo necesario, el proceso es el tpico de Windows,
perfectamente guiado a travs de ventanas. Ejecutamos el AVRStudio y deberamos ver
algo como en la Ilustracin 42
49
Una vez hecho esto, tenemos que seleccionar con que dispositivo Atmel vamos a
trabajar. Nuestro Arduino tiene el ATmega328P, con lo que seleccionaremos este.
50
51
_delay_ms(1000);
//Espera 1 segundo
PORTB &= ~(1<<PB5);
//Apaga el LED
_delay_ms(1000);
//Espera 1 segundo
}
}
52
arduino-1.0\hardware\tools\avr\bin\avrdude.exe
arduino-1.0\hardware\tools\avr\bin\libusb0.dll
arduino-1.0\hardware\tools\avr\etc\avrdude.conf
arduino-1.0\hardware\arduino\boards.txt
arduino-1.0\hardware\tools\avr\doc\avrdude\avrdude.pdf
54
4.2.3 El ATmega328P
La intencin de este bloque es mostrar cmo se pueden usar los distintos perifricos
del microcontrolador de nuestro Arduino y realizar en C el mismo proyecto realizado en
lenguaje Arduino. No se entrar en detalle en todos los perifricos, ya que la hoja de
caractersticas (datasheet) del microcontrolador contiene todos los detalles.
La hoja de caractersticas del ATmega328P se puede abrir fcilmente des del propio
IDE del AVRStudio o en la pgina web del fabricante [37].
4.2.3.1 Un breve resumen
El ATmega328P es el microcontrolador que lleva el Arduino UNO, forma parte de la
familia de procesadores Atmel AVR.
Los AVR son una familia de microcontroladores RISC, la arquitectura de los cuales
fue concebida por dos estudiantes en el Norwegian Institute of Technology, y
posteriormente refinada y desarrollada en Atmel Norway, la empresa subsidiaria de Atmel,
fundada por los dos arquitectos del chip.
Los AVR son CPUs con arquitectura Harvard. Tiene 32 registros de propsito
general de 8 bits. Estos registros de propsito general, los registros de perifricos y la
memoria de datos forman un solo espacio de direcciones unificado, que se acceden
mediante operaciones de carga y de almacenamiento. A diferencia de los
microcontroladores PIC, la pila se ubica en este espacio de memoria unificado, y no est
limitado a un tamao fijo.
Los microcontroladores AVR tienen una caera o pipeline con dos etapas (traer y
ejecutar), que les permite utilizar un ciclo de reloj en la mayora de instrucciones, lo que
los hace relativamente rpidos entre los microcontroladores de 8 bits. El conjunto de
instrucciones es ms regular que la de la mayora de los microcontroladores de 8 bits. Sin
embargo, no es completamente ortogonal.
4.2.3.2 Puertos de entrada y salida digital
Hay distintos registros del microcontrolador que sirven para indicar como debe
comportarse cada pin, ya sea como un pin de entrada digital, de salida digital, de entrada
analgica, salida PWM
En el ATmega328P los registros para configurar y acceder a los pines estn
agrupados por puertos. En nuestro Arduino tenemos un ATmega de 28 pines, esto hace que
solo dispongamos el puerto B, C y D.
En la Ilustracin 8: Pines de Arduino contra ATmega328 (Pines de Arduino contra
ATmega328), se puede ver la correspondencia entre los pines del ATmega y del Arduino,
as como los distintos modos en los que puede funcionar cada uno de los pines.
Para cada uno de los puertos tenemos un registro DDRx asociado, donde la 'x' indica
el puerto al que hacemos referencia, por ejemplo DDRB hace referencia al puerto B. Este
registro nos permite configurar los distintos pines de puerto como entrada o salida digital.
El acrnimo DDR significa Data Direction Register, y cada bit dentro del registro hace
referencia al pin correspondiente. Escribir un 1 implica configurar el pin como salida y 0
como entrada.
55
Por ejemplo, para configurar como salida el pin digital 5 de nuestro Arduino vemos
que corresponde con el pin 5 del puerto B, haremos lo siguiente:
DDRB = 0b00100000;
Con esta instruccin tambin se ha configurado como entrada los dems pins del
puerto B. Ms adelante se comenta como evitar modificar todo el puerto para configurar un
nico pin.
Si ahora queremos asignar un valor de salida a este puerto debemos utilizar el
registro PORTx, donde 1 implica un nivel alto y 0 un nivel bajo.
PORTB = 0b00100000;
En este ejemplo tenemos configurados todos los pines del puerto B como entradas
menos el pin 5 que lo tenemos como salida a nivel alto. Para conocer el nivel de los pines
leeremos los registros PINx. Estos registros se pueden consultar independientemente de la
configuracin del pin, ya sea como entrada o como salida. Esto se puede utilizar para saber
el estado real en que se encuentra un pin.
char contenidoPuertoB = 0u;
contenidoPuertoB = PIND;
DDRB |= (1<<PB5);
SBI 0x04,5
PORTB |= (1<<PB5);
SBI 0x05,5
57
58
#include <util/delay.h>
*/
#define BAUDRATE
(9600u) /* Definimos a que velocidad
queremos utilizar la comunicacin serie */
#define BAUD_RATE_REGISTER
((F_CPU / (BAUDRATE * 16ul)) - 1u) /*
Datasheet. Tabla 20-1. Equations for Calculating Baud Rate Register Setting
*/
char String[]="Hola mundo!!";
/* Funcin de inicializacin. Datasheet 20.5 USART Initialization */
void USART_Init( unsigned int ubrr) {
/* Configuramos la velocidad de la comunicacin (baud rate) */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/* Valores por defecto despus de reset en el registre USCR0A.
Esta escritura no esta definida en el datasheet, pero parece
necesaria ya que de lo contrario el bit de "Double USART
Transmission Speed" parece activo, de modo que no configura
el baud rate como esperamos.
Posiblemente el bootloader de Arduino est configurando este
bit, ya que usa el perifrico para descargar el cdigo. */
UCSR0A = (1<<TXC0);
/* Activar la recepcin y la transmisin */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Configuramos el formato de la trama: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
/* Funcin de transmisin. Datasheet 20.6 Data Transmission The USART
Transmitter */
void USART_Transmit( unsigned char data ) {
/* Esperamos a vaciar el buffer de transmisin */
while ( !( UCSR0A & (1<<UDRE0) ) );
/* Ponemos el dato en el buffer y mandamos el dato */
UDR0 = data;
}
/* Funcin de recepcin. Datasheet 20.7 Data Reception The USART Receiver
*/
unsigned char USART_Receive( void ) {
/* Esperamos a recibir todo el dato */
while ( !(UCSR0A & (1<<RXC0) ) );
/* Devolvemos el dato del buffer */
return UDR0;
}
/* Esta funcin transmite una cadena de caracteres */
void USART_putstring(char* StringPtr){
while(*StringPtr != 0x00){ /* Mientras la cadena no esta vacia transmite
*/
USART_Transmit(*StringPtr);
StringPtr++;
}
}
int main( void ) {
USART_Init(BAUD_RATE_REGISTER); /* Inicializamos la comunicacin */
while(1){
USART_putstring(String); /* Mandamos Hola mundo!!! */
_delay_ms(5000); /* Esperamos 5 seg y volvemos a re-enviar el
mensaje cada 5 seg */
}
return 0;
59
Estas funciones son muy bsicas y no utilizan las interrupciones que el perifrico
ofrece para indicar que los buffers de recepcin y/o transmisin estn vacos/llenos, o si ha
detectado errores, Este cdigo sirve a modo de ejemplo para implementar una
funcionalidad similar a la que ofrece el mdulo Arduino.
En el ANEXO 5, se puede ver como estas funciones han sido exportadas a una
librera, de modo que en futuros proyectos simplemente hay que incluirla indicando la
velocidad de transmisin deseada y llamar a las funciones de transmisin/recepcin, de
manera que facilita enormemente el desarrollo y hace el cdigo ms legible:
/*
* Arduino_SERIAL_example.c
*/
#include <avr/io.h>
/* Esta libreria contiene la definicin de
todos los registros, SIEMPRE DEBE SER INCLUIDA */
#define F_CPU
(16000000UL) /* F_CPU indica al compilador
que nuestro cristal es de 16Mhz. Debe ser declarado antes que la libreria
delay.h */
#include <util/delay.h>
/* Contiene funciones de espera en ms y us
*/
#include "Arduino_SERIAL_Api.h" /* Contiene funciones para trbajar con la
comunicacin serie */
char String[]="Hola mundo!!";
int main( void ) {
SERIAL_Init(); /* Inicializamos la comunicacin */
while(1){
SERIAL_PutString(String); /* Mandamos Hola mundo!!! */
_delay_ms(5000); /* Esperamos 5 seg y volvemos a re-enviar el
mensaje cada 5 seg */
}
return 0;
}
60
El mecanismo funciona as: sin importar lo que est haciendo nuestro cdigo, cuando
ocurra la interrupcin la CPU har una pausa y pasar a ejecutar el cdigo de la ISR. Tras
terminarlo, la CPU regresar a la tarea que estaba realizando antes de la interrupcin, justo
donde la haba suspendido.
Las interrupciones son disparadas (llamadas) por eventos del hardware del
microcontrolador. El evento puede ser algn cambio en cierto pin de E/S, el
desbordamiento de un temporizador, la llegada de un dato serie, etc. Se puede deducir por
tanto que las fuentes de interrupcin estn relacionadas con la cantidad de recursos del
microcontrolador.
4.2.3.4.1 Los Vectores de Interrupcin
Cada interrupcin est identificada por un Vector de Interrupcin, que no es otra
cosa que una direccin particular en la memoria FLASH. Todos los Vectores estn
ubicados en posiciones consecutivas de la memoria FLASH y forman la denominada Tabla
de Vectores de Interrupcin. El RESET no es una interrupcin pero su direccin 0x0000
tambin se conoce como Vector de Reset. Por defecto, la Tabla de Vectores de
Interrupcin est ubicada en las primeras posiciones de la memoria, tal como se ve abajo.
Solo cuando se habilita el uso de la Seccin de Boot Loader toda la tabla se desplazar al
inicio de dicha seccin.
Aqu se presenta la tabla con las 26 interrupciones posibles en los ATmega328:
Num
Vector
Direccin de
Programa
Nombre de Vector
de Interrupcin
Fuente de interrupcin
0x0000
RESET
0x0002
INT0
0x0004
INT1
0x0006
PCINT0
0x0008
PCINT1
0x000A
PCINT2
0x000C
WDT
0x000E
TIMER2_COMPA
0x0010
TIMER2_COMPB
10
0x0012
TIMER2_OVF
Timer/Counter2 Overflow
11
0x0014
TIMER1_CAPT
12
0x0016
TIMER1_COMPA
13
0x0018
TIMER1_COMPB
14
0x001A
TIMER1_OVF
Timer/Counter1 Overflow
15
0x001C
TIMER0_COMPA
16
0x001E
TIMER0_COMPB
17
0x0020
TIMER0_OVF
Timer/Counter0 Overflow
18
0x0022
SPI_STC
19
0x0024
USART_RX
USART Rx Complete
20
0x0026
USART_UDRE
21
0x0028
USART_TX
USART, Tx Complete
61
22
0x002A
ADC
23
0x002C
EE_READY
EEPROM Ready
24
0x002E
ANALOG_COMP
Analog Comparator
25
0x0030
TWI
26
0x0032
SPM_READY
Para entender cmo funciona el mecanismo de las interrupciones debemos saber que
el Contador de Programa es un registro que dirige cada una de las instrucciones que ejecuta
la CPU. Al dispararse una interrupcin el hardware guardar en la pila el valor actual del
Contador de Programa y lo actualizar con el valor del Vector de Interrupcin respectivo.
De este modo la CPU pasar a ejecutar el cdigo que se encuentre a partir de esa direccin.
Al final del cdigo de la interrupcin debe haber una instruccin de retorno que restaure el
Contador de Programa con el valor que se haba guardado en la pila. La instruccin es
RETI. Esta instruccin la pone el compilador si le indicamos que la funcin ejecutada es
una interrupcin.
Si se llegara a producir el evento excepcional en que se disparen dos o ms
interrupciones al mismo tiempo, se ejecutarn las interrupciones en orden de prioridad.
Tiene mayor prioridad la interrupcin cuyo Vector se ubique ms abajo, es decir, entre
todas, la interrupcin INT0 tiene siempre las de ganar.
4.2.3.4.2 Las Funciones de Interrupcin
La Funcin de Interrupcin o ISR va siempre identificada por su Vector de
Interrupcin. Su esquema vara ligeramente entre un compilador y otro, puesto que no
existe en el lenguaje C un formato estndar. Lo nico seguro es que es una funcin que no
puede recibir ni devolver ningn parmetro.
En el compilador AVR GCC (WinAVR) la funcin de interrupcin se escribe
utilizando la palabra reservada ISR. En el caso de nuestro compilador, el Vector de
Interrupcin debe tener la terminacin _vect. En caso de dudas acerca de cmo est
declarada se puede buscar en la carpeta include del directorio de instalacin de WinAVR.
ISR (Vector_de_Interrupcion)
{
// Cdigo de la funcin de interrupcin.
// No requiere limpiar el flag respectivo. El flag se limpia por
hardware
}
Por otro lado, cada interrupcin tiene un bit de notificacin nico. Este se pone a 1
automticamente por hardware cuando ocurre el evento de dicha interrupcin. Eso pasar
independientemente de si la interrupcin est habilitada o no. Cada interrupcin habilitada
y disparada, saltar a su correspondiente Funcin de Interrupcin o ISR.
El bit de notificacin se limpia automticamente justo cuando se empieza a ejecutar
la funcin de interrupcin. La nica excepcin es la interrupcin de recepcin de la
USART que se limpia automticamente al leer el registro con el dato recibido. Este
comportamiento evita perder una interrupcin mientras se est atendiendo a ella misma, ya
que al acabar volvera a ejecutarse la funcin al encontrarse de nuevo el bit de notificacin
a 1.
Puesto que los bits de notificacin se activan independientemente de si las
interrupciones estn habilitadas o no, al momento de activarlas, puede ser necesario
limpiarlos manualmente para evitar entrar directamente por algn evento anterior. Para
borrar el bit de notificacin se debe escribir un 1 en el bit respectivo.
Al ejecutarse la funcin de interrupcin tambin se limpia por hardware el bit de
habilitacin general para evitar que se disparen otras interrupciones cuando se est
ejecutando la interrupcin actual. Sin embargo, si queremos interrupciones recurrentes o
anidadas podemos poner a 1 el bit de habilitacin general dentro de la ISR actual.
El bit de habilitacin general se puede escribir como cualquier otro bit de un registro
de E/S. Pero dada su especial importancia, existen dos instrucciones exclusivas de
ensamblador llamadas SEI (para habilitarlas) y CLI (para deshabilitarlas). El archivo
avr_compiler.h ofrece las macros sei() y cli() para usar estas instrucciones.
4.2.3.4.4 Recepcin de una trama serie por interrupcin
En el apartado anterior se ha visto como utilizar la USART sin las interrupciones.
Esto es una prdida de eficiencia, ya que nos obliga a estar escuchando el bus para recibir
una trama. La alternativa a esto es utilizar las interrupciones de recepcin de trama.
Para utilizar la interrupcin del puerto serie, es necesario configurar el bit RXCIE
(bit 7 del registro UCSRB) a 1, lo que activa la interrupcin. Tambin es necesario activar
las interrupciones globalmente.
El vector correspondiente a la interrupcin de recepcin de datos a travs del puerto
serie es USART_RX_vect.
El cdigo que deberamos aadir en la funcin SERIAL_init() sera:
/* Activar la interrupcin del puerto serie */
UCSR0B |= (1<<RXCIE0);
/* Activar interrupciones generales */
sei();
63
EIMSK
---
---
---
---
---
---
INT1
INT0
EIFR
---
---
---
---
---
---
INTF1
INTF0
EICRA
---
---
---
---
ISC11
ISC10
ISC01
ISC00
Para habilitar la interrupcin INTx hay que poner a 1 el bit INTx, del registro
EIMSK, adems del bit de habilitacin general de las interrupciones en el registro SREG
Una vez producido el evento, el hardware pondr a 1 la notificacin INTFx del
registro EIFR, y luego se disparar la interrupcin. Este evento se debe configurar
previamente en el registro EICRA y hay cuatro opciones posibles.
Modo ISCx1 ISCx0 Evento de la Interrupcin
0
64
EICRA
---
---
---
---
ISC11
ISC10
ISC01
ISC00
Como la mayora de los registros, EICRA inicia con todos sus bits a cero lo que
significa que por defecto la interrupcin INTx habilitada se disparar cuando dicho pin est
a nivel bajo.
La interrupcin externa INTx tiene la capacidad de despertar al AVR, es decir, de
sacarlo del modo sleep. Este modo sleep, es un modo de muy bajo consumo, muy
apropiado para aplicaciones que funcionan con bateras, donde el microcontrolador y todos
sus perifricos estn parados esperando un evento que lo despierte.
4.2.3.5.2 Interrupciones de Cambio de Pin, PCINTx
Esta interrupcin se dispara cada vez que se detecta un cambio de nivel lgico 1 a
0, o viceversa, en cualquiera de los pines de los puertos del ATmega, sin importar si
estn configurados como entrada o como salida. Se podra decir que se dispara con los
flancos de subida y de bajada en los pines de puertos. En ese sentido, se parece bastante a
las interrupciones INTx. La interrupcin de Cambio de Pin tambin puede sacar al AVR
del modo Sleep.
En el ATmega368 los PCINTx corresponden a los puertos siguientes:
PCICR
---
---
---
---
---
PCIE2
PCIE1
PCIE0
65
Registro de mscara
Puerto
PCMSK0
PORTB
PCMSK1
PORTC
PCMSK2
PORTD
PCINT7
PCINT6
PCINT5
PCINT4
PCINT3
PCINT2
PCINT1
PCINT0
PCMSK1
---
PCINT14
PCINT13
PCINT12
PCINT11
PCINT10
PCINT9
PCINT8
PCMSK2
PCINT23
PCINT22
PCINT21
PCINT20
PCINT19
PCINT18
PCINT17
PCINT16
Una vez producido el cambio de nivel en uno o varios de los pines habilitados para
interrupcin, se activar el bit de notificacin respectivo PCIF (Pin Change Interrupt Flag)
del registro PCIFR y luego se llamar a la funcin de interrupcin ISR . As como hay un
bit de habilitacin para cada puerto, tambin hay un bit de notificacin para uno.
PCIFR
---
---
---
---
---
PCIF2
PCIF1
PCIF0
TOP define el valor mximo que se puede contar con el temporizador, que
puede ser el valor mximo u otro valor definido por el usuario en el registro
OCRxA, en funcin del modo seleccionado.
La fuente de reloj para los temporizadores puede ser el propio reloj del sistema u una
fuente externa. En nuestro Arduino el reloj del sistema es de 16MHz, pero se pueden usar
divisores para conseguir distintos rangos de frecuencias segn nuestras necesidades. El
divisor del reloj se puede ajustar a 1, 8, 64, 256 o 1024.
66
TCCRxB
---
---
CSx2
---
---
---
CSx2
CSx1
CSx0
Los temporizadores tienen distintos modos de operacin, los 4 principales son phase
correct PWM, fast PWM, CTC(Clear Timer on Compare Match) y modo normal, donde
este se comporta como un simple contador. Dependiendo si usamos temporizadores de 8 o
16 bits pueden tener distintos sub-modos de funcionamiento.
TCCRxA
---
---
---
---
---
---
WGMx1
WGMx0
TCCRxB
---
---
---
---
WGMx2
---
---
---
Descripcin
Normal
TOP
Actualiza Activa el
OCRx en flag TOV
0xFF/0xFFFF Inmediato
CTC
Fast PWM
Reservado
---
---
---
OCRxA
TOP
BOTTOM
Reservado
---
---
---
Fast PWM
OCRxA
BOTTOM
TOP
MAX
TOP
BOTTOM
Inmediato
MAX
0xFF/0xFFFF BOTTOM
MAX
OCRxA
NUM_CUENTAS
7999999
999999
124999
31249
7811,5
(31249)
int main(void)
{
//Definimos el pin13/PORTB5 como salida
DDRB |= (1<<PB5);
//Configuramos el divisor del timer. El timer empieza a contar
TCCR1B = (1<<CS12); //1:256
while(1){
PORTB |= (1<<PB5);
//Enciende el LED
//Apaga el LED
68
}
}
Cada vez que el temporizador alcanza su valor mximo (TOP) pone a 1 el bit de
notificacin TOVx (Timer Overflow Flag) en el registro TIFRx (Timer Interrupt Flag
Register). Activando el bit TOIEx (Timer Overflow Interrupt Enable) del TIMSKx (Timer
Interrupt Mask Register) genera una interrupcin al alcanzar este punto. Este
comportamiento es muy til para ampliar el contaje del temporizador incrementando una
variable en la funcin de atencin de la interrupcin.
4.2.3.6.2 Modo CTC
El modo Clear Time on Compare match (CTC) nos activa una interrupcin cuando el
contador a alcanzado un valor pre-definido y vuelve a empezar el contaje. Este modo de
funcionamiento nos aporta una gran ventaja en el diseo de las aplicaciones, ya que no
debemos detener el flujo de ejecucin de nuestro programa para realizar alguna accin.
Volviendo al ejemplo del LED que parpadea, lo que haremos es cargar el valor a
contar en el registro OCRxA (Output Compare Register A) y lo configuraremos para que
nos dispare una interrupcin cuando alcance el valor definido pone a 1 el bit OCIExA
(Output Compare Match A Interrupt Enable) del registro TIMSKx (Timer Interrupt Mask
Register).
/*
* Arduino_blink_timer_INTERRUPT.c
*
* Parpadeo del LED de Arduino cada 0.5seg usando interrupciones de timers
* en lugar de la libreria delay.h
*/
#include <avr/io.h>
#include <avr/interrupt.h>
// Frequencia de la fuente de reloj en Hz
#define F_CPU
(16000000)
// Frequencia deseada en Hz. 2Hz => 0.5 sec
#define F_DESEADA
(2)
/*
Para seleccionar el divisor comprobamos cuantas cuentas del contador
necesitamos:
NUM_CUENTAS = (((F_CPU / DIVISOR) / F_DESEADA) - 1)
DIVISOR
1
8
64
256
1024
NUM_CUENTAS
7999999
999999
124999
31249
7811,5
69
COMxA1 COMxA0
---
---
---
---
---
---
Por ejemplo se puede generar un parpadeo (invertir su estado) cada vez que
alcancemos el valor configurado en OCRxA siempre que este pin este configurado como
salida. Todo esto gestionado por el propio micro controlador y sin que interrumpa el flujo
de ejecucin de nuestro programa.
70
Phase Correct se podra decir que la salida est centrada. Aplica el nuevo
periodo, ciclo de trabajo (duty) y/o frecuencia de manera que el punto medio
del semiciclo de ON caiga en la mitad del periodo.
71
72
Ilustracin 52: Generacin PWM en modo Phase and Frequency Correct PWM
Como norma general el modo Fast PWM es suficiente para la mayora de
aplicaciones como regulacin de potencia, rectificacin,
4.2.3.6.4 Uso del Input capture
El temporizador de 16bits tambin incorpora una unidad de input capture que
permite capturar eventos externos asociados a cambios en el pin ICP1 y ofrecer una marca
temporal de frecuencia de ejecucin.
Tpicamente esta funcionalidad se utiliza para calcular la frecuencia y/o el ciclo de
trabajo (duty cycle) de una seal.
73
int main(void) {
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));
//Divisor a 128 frec.
del ADC a 125Khz
ADMUX |= (1<<REFS0);
ADMUX &= ~(1<<REFS1);
//Avcc(+5v) como tensin de referencia
ADCSRA |= (1<<ADEN);
//Alimentamos el ADC
ADCSRA |= (1<<ADSC);
//Empezamos la conversin
while(1){
for (channel=0;channel<=5;channel++){
ADMUX &= 0xF0;
//Borramos el anterior canal del
multiplexor
ADMUX |= channel;
//Definimos el nuevo canal a
convertir
ADCSRA |= (1<<ADSC);
//Empezamos una nueva conversin
while(ADCSRA & (1<<ADSC)); //Esperamos a finalizar la
conversin
adc_value[channel] = ADCW; //Guardamos el valor de la
conversin
}
}
return 0;
}
74
Para desligar la librera del fabricante del entorno Arduino, y evitar dependencias
durante la compilacin, la editaremos comentando la inclusin de Arduino.h y
corrigiendo los errores de dependencias aadiendo las libreras necesarias del entorno
AVRStudio, como por ejemplo math.h o delay.h.
La nica librera que utilizaremos del entorno Arduino es la de pins_arduino.h, que la
copiaremos del entorno Arduino a nuestra carpeta del proyecto AVRStudio, ya que esta
simplemente es la definicin de los puertos de entrada y salida, y nos ahorra el tener que
redefinirlos dentro de la propia librera.
En el ANEXO 7 se puede ver la codificacin del medidor de caudal en C++ as como
las libreras usadas.
Si utilizamos libreras de terceros es importante cambiar las opciones del compilador
y del enlazador (linker) para que el binario generado sea lo ms optimo posible.
Las siguientes opciones del compilador fuerzan al compilador a alojar cada funcin
en una seccin de memoria interna separada.
-ffunction-sections
-fdata-sections
Con las opciones del compilador anteriores y la siguiente opcin del enlazador
(linker) le indicamos que no incluya las funciones que no se utilizan.
Estas opciones son de gran ayuda para reducir tamao en memoria al usar libreras
genricas ya que no solemos usar todas las funciones que esta proporciona.
gc-sections
Para realizar esta modificaciones en el AVRStudio, iremos a Porperties en el
men Project. Esto nos abrir una nueva pestaa donde veremos las opciones de
configuracin de nuestro proyecto. En la pestaa ToolChain encontraremos las
configuraciones del compilador C, del C++ y del enlazador (linker).
75
medidorCaudal_AVR.elf
Program:
7380 bytes (22.5% Full)
(.text + .data + .bootloader)
Data:
1070 bytes (52.2% Full)
(.data + .bss + .noinit)
medidorCaudal_Arduino.cpp.elf
Program:
10390 bytes (31.7% Full)
(.text + .data + .bootloader)
Data:
1269 bytes (62.0% Full)
(.data + .bss + .noinit)
77
Presupuesto
PRECIO
IT001
25,00
VEINTICINCO EUROS
HW001
21,90
HW002
Arduino
Sparkfun
Color 32,90
HW003
Koolance INS-FM17N
Flow Meter for LCS
Coolant 25,87
HW004
HW005
Shield
LCD
UD
DESCRIPCIN
CANTIDAD
PRECIO
SUBTOTAL
IT001
80,00
25,00
2.000,00
IT001
220,00
25,00
5.500,00
Suma de la Partida
7.500,00
150,00
TOTAL PARTIDA
78
7.650,00
UD
DESCRIPCIN
CANTIDAD
PRECIO
SUBTOTAL
IT001
20,00
25,00
500,00
HW001
1,00
21,90
21,90
HW002
1,00
32,90
32,90
HW003
Koolance INS-FM17N
Flow Meter for LCS
Coolant 1,00
25,87
25,87
HW004
0,53
0,13
HW005
2,70
0.68
Suma de la Partida
581,48
Envo y manipulacin
TOTAL PARTIDA
10,00
591,48
UD
DESCRIPCIN
CANTIDAD
PRECIO
SUBTOTAL
IT001
10,00
25,00
250,00
25,00
25,00
625,00
15,00
25,00
375,00
20,00
25,00
500,00
IT001
IT001
Suma de la Partida
1.750,00
35,00
TOTAL PARTIDA
1.785,00
UD
DESCRIPCIN
CANTIDAD
PRECIO
SUBTOTAL
IT001
12,00
25,00
300,00
79
Implementacin de aplicacin en
Python
IT001
25,00
25,00
625,00
Suma de la Partida
925,00
18,50
TOTAL PARTIDA
943,50
UD
DESCRIPCIN
CANTIDAD
PRECIO
SUBTOTAL
IT001
80,00
25,00
2.000,00
Documentacin de todo el
proceso de estudio.
Suma de la Partida
2.000,00
40,00
TOTAL PARTIDA
2.040,00
RESUMEN
IMPORTE
Captulo 1
Estudios previos
7.650,00
Captulo 2
591,48
Captulo 3
1.785,00
Captulo 4
943,50
Captulo 5
Documentacin
2.040,00
13.009,98
1,691,30
780,60
15.481,87
18,00 % IVA
2.786,74
18.268,61
80
El objetivo principal de este PFC ha sido conocer Arduino a travs del montaje de un
caudalmetro. Despus de realizar este proyecto se puede concluir que Arduino es una muy
buena plataforma para realizar pequeos proyectos de sistemas basados en
microcontrolador.
La curva de aprendizaje de Arduino es realmente rpida. Dispone de gran cantidad
de documentacin oficial y no oficial. La comunidad de usuarios es muy grande, accesible
y colaborativa. Hay gran cantidad de ejemplos de uso y proyectos hechos con licencia
abierta, cosa que permite reaprovechar todo lo que ya funciona.
Hay una gran cantidad de canales de distribucin, tanto a nivel nacional como
internacional. El coste de las placas es realmente ajustado y no suele haber problemas de
aprovisionamiento. Esto facilita mucho el poder disponer del hardware necesario para
nuestros proyectos en plazos de tiempo pequeos y a un coste muy reducido.
El hecho de haber definido una manera estndar de crear extensiones, las shields, ha
permitido crear una gran cantidad de placas accesorias para cubrir la mayora de
necesidades habituales en proyectos de electrnica. Estas extensiones se consiguen a travs
de los mismos canales de distribucin. Estas suelen entregarse con ejemplos de uso o
incluso libreras de cdigo integrables en el entorno Arduino, con lo que amplifican mucho
el potencial de la plataforma.
El nivel de abstraccin de cmo funcionan los circuitos electrnicos o como se deben
programar los dispositivos es muy alto. Esto permite realizar operaciones complejas sin
gran esfuerzo. En contra, estas limitado al comportamiento proporcionado por las libreras
o por la funcionalidad de la circuitera de la que dispones.
El desempeo de estas libreras o extensiones no siempre es el ms ptimo y hay
veces que es necesario realizar modificaciones. Pero incluso en estos casos el soporte que
se puede encontrar en la comunidad de usuarios es muy grande y no debe suponer un gran
escollo para la realizacin del proyecto. En cualquier caso, siempre podemos crear nuestras
propias libreras, dando as soporte a nuevas funcionalidades o mejoras de rendimiento. En
estos casos s que es necesario un mayor nivel de conocimientos de electrnica o de
programacin, pero el alcanzar este nivel puede hacerse de un modo muy progresivo.
Enlazando con el segundo objetivo que nos habamos marcado en la realizacin de
este PFC, podemos decir que las capacidades lectivas o formativas de la plataforma
Arduino son muy grandes.
Los aplicativos para el PC son simples y fciles de usar. La sintaxis necesaria para el
desarrollo de aplicaciones es simple y tiene muchas funciones que ya implementan
operaciones habituales y relativamente complejas, como la generacin de un PWM o
lecturas analgicas. Esto permite poder introducir conceptos de programacin y algoritmia
a niveles de educacin secundaria.
El hecho de interactuar con el mundo real de un modo directo, puede generar una
mayor curiosidad en el alumnado. Esto permite adquirir unos conocimientos de electrnica
o programacin de un modo muy ameno.
El hecho que el coste de una placa sea razonablemente bajo, y el hardware muy
robusto, puede facilitar el acceso a este por gran parte de centros, permitiendo su uso
durante un largo camino formativo. Se podra decir que tiene un bajo coste por el
rendimiento que puede ofrecer.
81
82
ANEXOS
ANEXO 1: Informacin uso librera LCD
************************************
*
*
*
ColorLCDShield
*
*
*
*
an Arduino Library
*
*
*
*
by Jim Lindblom
*
*
SparkFun Electronics
*
*
*
************************************
License: CC-BY SA 3.0 - Creative commons share-alike 3.0 use this code
however you'd like, just keep this license and attribute. Let me know if you
make hugely, awesome, great changes.
Huge thanks to Jim Lynch, Mark Sproul, and Peter Davenport. If I'm missing
anyone, I apologize, all of this code's been through the ringer more than a
few times.
This is a (hopefully) simple Arduino library for use specifically with
SparkFun Electronics' Color LCD Shield
(http://www.sparkfun.com/products/9363). It'll no doubt work with other
incarnations of LCD breakouts and what not, you just might have to do some
modifying of the pin defintions.
The code gives you access to the following LCD functions:
LCDShield(); - The library's constructor. An instance of the lcd must be
created at the beginning of any code. e.g:
LCDShield lcd;
void init(int type); - This initializes an LCD. Either EPSON or PHILLIPS
should be passed as the type variable. This function should be called near
the beginning of any function (setup()!). Turns on the display, sets the
contrast and uinitializes the LCD into 12-bit RGB color mode.
void clear(int color); - Clears the entire screen, filling it with the 12bit RGB color passed to it. There are a number of predefined colors in
ColorLCDShield.h
void contrast(char setting); - Manually adjusts the contrast. A value
between 0 and 60 should be passed. 40 works pretty well for me.
void setPixel(int color, unsigned char x, unsigned char y); - Draws a single
pixel at the specified x, y location. Color is a 12-bit RGB value.
void setCircle (int x0, int y0, int radius, int color); - Draws a circle
centered around x0, y0, of the specified radius and color. Radius is in
pixels, color is a 12-bit RGB value.
void setChar(char c, int x, int y, int fColor, int bColor); - Sets a single
character down at the specified x/y coordinate. You can pick both the
foreground and background color, they're 12-bit RGB values. Only one font is
83
84
85
//
columns, rows,
//
columns, rows,
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
space 0x20
!
"
#
$
%
&
'
(
)
*
+
,
.
/ (forward slash)
0 0x30
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
@ 0x40
A
B
C
D
{0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E
{0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F
{0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G
{0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H
{0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I
{0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J
{0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K
{0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L
{0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M
{0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N
{0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O
{0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P
{0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q
{0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R
{0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S
{0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T
{0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U
{0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V
{0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W
{0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X
{0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y
{0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z
{0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [
{0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // \
{0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ]
{0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a
{0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b
{0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c
{0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d
{0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e
{0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g
{0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h
{0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i
{0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j
{0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k
{0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l
{0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m
{0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n
{0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o
{0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q
{0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r
{0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s
{0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t
{0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u
{0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v
{0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w
{0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x
{0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y
{0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z
{0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // {
{0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // |
{0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // }
{0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00} // ~
};
0x50
(back slash)
0x60
0x70
86
* en un linea de interrupcion.
* Muestra en una pantalla LCD la cantidad de litros detectados y el flujo
instantaneo.
* El LCD tiene tres botones con distintas acciones programadas:
* - 1er boton: Cambia la informacion a mostrar en la pantalla.
* - 2do boton: Pone a zero un primer contador parcial.
* - 3er boton: Pone a zero un segundo contador parcial.
*/
/*
* Incluye la libreria de la pantalla LCD
*/
#include <ColorLCDShield.h>
/*
* Variables y constantes usadas para el LCD y los botones
*/
LCDShield lcd; // Objeto LCD
const byte lcdContraste = 40;
// Valor del contraste par el LCD
char lcdStr[16]; // Cadena usada para mostrar textos en el LCD
/* Mapeo de los botones del LCD contra los pines del Arduino */
const int lcdBotones[3] = {3, 4, 5}; // S1 = PIN 3, S2 = PIN 4, S3 = PIN
5
const byte botonAntirebote = 10; // Numero de veces que se debe leer un
valor estable en los botones
/*
* Variables y constantes usadas para el temporizado
*/
/* Las siguientes variables son tipo long ya que mediremos el tiempo en
milisegundos
y en seguida creceran y un integer no seria suficiente. */
const unsigned int intervalo_1000ms = 1000; // Intervalo de ejecucion de
la tarea periodica (ms)
unsigned long previoMilis = 0; // instante anterior de ejecucion
int contadorSegundos = 0;
int contadorSegundosParcial_1 = 0;
int contadorSegundosParcial_2 = 0;
/*
* Variables y
*/
const byte
const byte
const byte
/*
* Variables y constantes usadas para el contaje de volumen
*/
const float contadorRelacion = 0.307; // Relacion entre pulsos y litros
por minuto
volatile unsigned int contadorPulsos = 0; // volatile ya que se accede
des de interrupcion
unsigned int contadorPulsosLocal = 0;
float litrosMinuto = 0.0;
float litrosTotales = 0.0;
float litrosParcial_1 = 0.0;
float litrosParcial_2 = 0.0;
/*
* Variables y constantes usadas para la gestion de las pantallas
*/
const byte numeroPantallas = 2; // Numero de distintas pantallas a
mostrar
byte pantalla = 0; // Pantalla inicial a mostrar
/*
87
88
89
break;
case 1:
pantalla_parcial_1();
break;
case 2:
pantalla_parcial_2();
break;
default:
break;
}
}
/*
* Pantalla principal a mostrar
*/
void pantalla_principal()
{
lcd.setStr("Tiempo total", 3, 3, BLACK, WHITE);
lcd.setStr("
segundos", 19, 3, BLACK, WHITE);
itoa(contadorSegundos,lcdStr,10);
lcd.setStr(lcdStr, 19, 11, BLACK, WHITE);
lcd.setStr("Consumo actual", 35, 3, BLACK, WHITE);
lcd.setStr("
l x min", 48, 3, BLACK, WHITE);
dtostrf(litrosMinuto, 4, 2, lcdStr);
lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);
lcd.setStr("Litros totales ", 64, 3, BLACK, WHITE);
lcd.setStr("
", 80, 3, BLACK, WHITE);
dtostrf(litrosTotales, 6, 2, lcdStr);
lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);
lcd.setStr("Cont.1
Cont.2 ", 96, 3, BLACK, WHITE);
lcd.setStr("
", 112, 3, BLACK, WHITE);
dtostrf(litrosParcial_1, 4, 2, lcdStr);
lcd.setStr(lcdStr, 112, 3, BLACK, WHITE);
dtostrf(litrosParcial_2, 4, 2, lcdStr);
lcd.setStr(lcdStr, 112, 75, BLACK, WHITE);
}
/*
* Pantalla contadores parciales 1
*/
void pantalla_parcial_1()
{
lcd.setStr("Tiempo parcial 1", 0, 3, BLACK, WHITE);
lcd.setStr("
segundos ", 16, 3, BLACK, WHITE);
itoa(contadorSegundosParcial_1,lcdStr,10);
lcd.setStr(lcdStr, 16, 11, BLACK, WHITE);
lcd.setStr("Consumo actual ", 32, 3, BLACK, WHITE);
lcd.setStr("
l x min", 48, 3, BLACK, WHITE);
dtostrf(litrosMinuto, 4, 2, lcdStr);
lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);
lcd.setStr("Litros parcial 1", 64, 3, BLACK, WHITE);
lcd.setStr("
", 80, 3, BLACK, WHITE);
dtostrf(litrosParcial_1, 4, 2, lcdStr);
lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);
lcd.setStr("
Totales ", 96, 3, BLACK, WHITE);
lcd.setStr("
", 112, 3, BLACK, WHITE);
dtostrf(litrosTotales, 6, 2, lcdStr);
lcd.setStr(lcdStr, 112, 59, BLACK, WHITE);
}
/*
90
91
import serial
# The recommended way to use wx with mpl is with the WXAgg
# backend.
#
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar
import numpy as np
import pylab
class DataGet(object):
""" Get the number of pulses received from serial port
"""
def __init__(self, init=0):
self.data = self.init = init
self.ser = serial.Serial(
port='\\.\COM3',
baudrate=9600,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=1
)
def next(self):
test = self.ser.readline()
if (test != '') and (test[0].isdigit()):
self.data = int(test,10)*0.307
return self.data
class BoundControlBox(wx.Panel):
""" A static box with a couple of radio buttons and a text
box. Allows to switch between an automatic mode and a
manual mode with an associated value.
"""
def __init__(self, parent, ID, label, initval):
wx.Panel.__init__(self, parent, ID)
self.value = initval
box = wx.StaticBox(self, -1, label)
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
self.radio_auto = wx.RadioButton(self, -1,
label="Auto", style=wx.RB_GROUP)
self.radio_manual = wx.RadioButton(self, -1,
label="Manual")
self.manual_text = wx.TextCtrl(self, -1,
size=(35,-1),
value=str(initval),
92
style=wx.TE_PROCESS_ENTER)
self.Bind(wx.EVT_UPDATE_UI, self.on_update_manual_text,
self.manual_text)
self.Bind(wx.EVT_TEXT_ENTER, self.on_text_enter, self.manual_text)
manual_box = wx.BoxSizer(wx.HORIZONTAL)
manual_box.Add(self.radio_manual, flag=wx.ALIGN_CENTER_VERTICAL)
manual_box.Add(self.manual_text, flag=wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.radio_auto, 0, wx.ALL, 10)
sizer.Add(manual_box, 0, wx.ALL, 10)
self.SetSizer(sizer)
sizer.Fit(self)
def on_update_manual_text(self, event):
self.manual_text.Enable(self.radio_manual.GetValue())
def on_text_enter(self, event):
self.value = self.manual_text.GetValue()
def is_auto(self):
return self.radio_auto.GetValue()
def manual_value(self):
return self.value
class GraphFrame(wx.Frame):
""" The main frame of the application
"""
title = 'Demo: dynamic matplotlib graph'
def __init__(self):
wx.Frame.__init__(self, None, -1, self.title)
self.dataget = DataGet()
self.data = [self.dataget.next()]
self.paused = False
self.create_menu()
self.create_status_bar()
self.create_main_panel()
self.redraw_timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_redraw_timer, self.redraw_timer)
self.redraw_timer.Start(100)
def create_menu(self):
self.menubar = wx.MenuBar()
menu_file = wx.Menu()
m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S", "Save plot to
file")
self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)
menu_file.AppendSeparator()
93
=
=
=
=
BoundControlBox(self.panel,
BoundControlBox(self.panel,
BoundControlBox(self.panel,
BoundControlBox(self.panel,
-1,
-1,
-1,
-1,
"X
"X
"Y
"Y
min",
max",
min",
max",
0)
50)
0)
100)
flag=wx.ALL)
flag=wx.ALL)
flag=wx.ALL)
flag=wx.ALL)
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.vbox.Add(self.canvas, 1, flag=wx.LEFT | wx.TOP | wx.GROW)
self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_LEFT | wx.TOP)
self.vbox.Add(self.hbox2, 0, flag=wx.ALIGN_LEFT | wx.TOP)
self.panel.SetSizer(self.vbox)
94
self.vbox.Fit(self)
def create_status_bar(self):
self.statusbar = self.CreateStatusBar()
def init_plot(self):
self.dpi = 100
self.fig = Figure((3.0, 3.0), dpi=self.dpi)
self.axes = self.fig.add_subplot(111)
self.axes.set_axis_bgcolor('black')
self.axes.set_title('Liters per minute', size=12)
pylab.setp(self.axes.get_xticklabels(), fontsize=8)
pylab.setp(self.axes.get_yticklabels(), fontsize=8)
# plot the data as a line series, and save the reference
# to the plotted line series
#
self.plot_data = self.axes.plot(
self.data,
linewidth=1,
color=(1, 1, 0),
)[0]
def draw_plot(self):
""" Redraws the plot
"""
# when xmin is on auto, it "follows" xmax to produce a
# sliding window effect. therefore, xmin is assigned after
# xmax.
#
if self.xmax_control.is_auto():
xmax = len(self.data) if len(self.data) > 50 else 50
else:
xmax = int(self.xmax_control.manual_value())
if self.xmin_control.is_auto():
xmin = xmax - 50
else:
xmin = int(self.xmin_control.manual_value())
# for ymin and ymax, find the minimal and maximal values
# in the data set and add a mininal margin.
#
# note that it's easy to change this scheme to the
# minimal/maximal value in the current display, and not
# the whole data set.
#
if self.ymin_control.is_auto():
ymin = round(min(self.data), 0) - 1
else:
ymin = int(self.ymin_control.manual_value())
if self.ymax_control.is_auto():
ymax = round(max(self.data), 0) + 1
95
else:
ymax = int(self.ymax_control.manual_value())
self.axes.set_xbound(lower=xmin, upper=xmax)
self.axes.set_ybound(lower=ymin, upper=ymax)
# anecdote: axes.grid assumes b=True if any other flag is
# given even if b is set to False.
# so just passing the flag into the first statement won't
# work.
#
if self.cb_grid.IsChecked():
self.axes.grid(True, color='gray')
else:
self.axes.grid(False)
# Using setp here is convenient, because get_xticklabels
# returns a list over which one needs to explicitly
# iterate, and setp already handles this.
#
pylab.setp(self.axes.get_xticklabels(),
visible=self.cb_xlab.IsChecked())
self.plot_data.set_xdata(np.arange(len(self.data)))
self.plot_data.set_ydata(np.array(self.data))
self.canvas.draw()
def on_pause_button(self, event):
self.paused = not self.paused
def on_update_pause_button(self, event):
label = "Resume" if self.paused else "Pause"
self.pause_button.SetLabel(label)
def on_cb_grid(self, event):
self.draw_plot()
def on_cb_xlab(self, event):
self.draw_plot()
def on_save_plot(self, event):
file_choices = "PNG (*.png)|*.png"
dlg = wx.FileDialog(
self,
message="Save plot as...",
defaultDir=os.getcwd(),
defaultFile="plot.png",
wildcard=file_choices,
style=wx.SAVE)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self.canvas.print_figure(path, dpi=self.dpi)
self.flash_status_message("Saved to %s" % path)
96
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = GraphFrame()
app.frame.Show()
app.MainLoop()
97
:Error
echo.
echo Debes indicar el puerto serie de Arduino y el binario a descargar.
echo
upload SERIAL_PORT FILE_TO_FLASH
echo.
echo Si la ruta del binario incluye espacios en blanco, encierralo entre
comillas.
echo.
echo Ejemplo:
echo
upload COM3 "Arduino Blink.hex"
echo.
PAUSE
GOTO End
:Execute
avrdude -F -V -c arduino -p %micro% -P %port% -b 115200 -D -U
flash:w:"%file%"
:End
Pause
Contenido de UploadFromAVRStudio.cmd
echo off
cls
REM Detectamos des de donde debemos ejecutarnos
set currentFolder=%~dps0
REM Vamos a la unidad correcta
%~d0
REM Vamos a la carpeta donde tenemos el avrdude
cd %currentFolder%
REM Eliminamos la '\' extra que aade AVRStudio en el path de donde se
encuentra nuestro proyecto
set folder=%~1
set folder=%folder:~0,-1%
set fileNameWithExt=%~2
REM Eliminamos la extensin del fichero que nos proporciona AVRStudio
set fileName=%fileNameWithExt:.atsln=%
echo %fileName%
REM Componemos la ruta donde se encuentra el binario a descargar con el
parametro Debug o Release del AVRStudio
set binaryFile=%folder%%fileName%\%3\%fileName%.hex
REM Copiamos el fichero a descargar en esta misma carpeta
copy "%binaryFile%"
REM Lanzamos el batch que tenemos preparado para el avrdude des de la linea
de comandos
call upload "%4" "%fileName%.hex"
REM Borramos el binario que hemos descargado
del /F /Q "%fileName%.hex"
98
Una vez tenemos esto, podemos aadir esta llamada a la barra de herramientas, de
modo que tendramos un acceso parecido al que ofrece el propio entorno Arduino.
Pulsamos con el botn izquierdo del ratn sobre el desplegable de la barra de
herramientas del AVRStudio, seleccionado Customize
99
Ilustracin 60: Vista para crear un botn para las herramientas externas en AVRStudio
Una vez dentro de las opciones, debemos aadir un nuevo comando, y seleccionar
External Command 1 o la posicin en la que hayamos definido nuestra external tool.
100
(9600U)
(16000000UL)
101
Contenido de Arduino_SERIAL.c
/*
* Arduino_SERIAL.c
*/
#include <avr/io.h>
/* Esta libreria contiene la definicin de
todos los registros, SIEMPRE DEBE SER INCLUIDA */
#include "Arduino_SERIAL_Api.h"
#define BAUD_RATE_REGISTER
((F_CPU / (SERIAL_BAUDRATE * 16ul)) - 1u) /*
Datasheet. Tabla 20-1. Equations for Calculating Baud Rate Register Setting
*/
/* Inicializacin de la comunicacin serie */
void SERIAL_Init( void ) {
/* Configuramos la velocidad de la comunicacin (baud rate) */
UBRR0H = (unsigned char)(BAUD_RATE_REGISTER>>8);
UBRR0L = (unsigned char)BAUD_RATE_REGISTER;
/* Valores por defecto despus de reset en el registre USCR0A.
Esta escritura no esta definida en el datasheet, pero parece
necesaria ya que de lo contrario el bit de "Double USART
Transmission Speed" parece activo, de modo que no configura
el baud rate como esperamos.
Posiblemente el bootloader de Arduino est configurando este
bit, ya que usa el perifrico para descargar el cdigo. */
UCSR0A = (1<<TXC0);
/* Activar la recepcin y la transmisin */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Configuramos el formato de la trama: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
/* Funcin de transmisin de un caracter */
void SERIAL_Transmit( unsigned char data ) {
/* Esperamos a vaciar el buffer de transmisin */
while ( !( UCSR0A & (1<<UDRE0) ) );
/* Ponemos el dato en el buffer y mandamos el dato */
UDR0 = data;
}
/* Funcin de recepcin de un caracter */
unsigned char SERIAL_Receive( void ) {
/* Esperamos a recibir todo el dato */
while ( !(UCSR0A & (1<<RXC0) ) );
/* Devolvemos el dato del buffer */
return UDR0;
}
/* Funcin de transmisin de una cadena de caracteres */
void SERIAL_PutString(char* StringPtr){
while(*StringPtr != 0x00){ /* Mientras la cadena no esta vacia transmite
*/
SERIAL_Transmit(*StringPtr);
StringPtr++;
}
/* Aadimos salto de linea y retorno de carro al final de la cadena */
SERIAL_Transmit(0x0Du);
SERIAL_Transmit(0x0Au);
}
102
(9600U)
(16000000UL)
Contenido de Arduino_SERIAL_INTRx.c
/*
* Arduino_SERIAL_INTRx.c
*/
#include <avr/io.h>
/* Esta libreria contiene la definicin de
todos los registros, SIEMPRE DEBE SER INCLUIDA */
#include "Arduino_SERIAL_INTRx_Api.h"
#define BAUD_RATE_REGISTER
((F_CPU / (SERIAL_BAUDRATE * 16ul)) - 1u) /*
Datasheet. Tabla 20-1. Equations for Calculating Baud Rate Register Setting
*/
/* Inicializacin de la comunicacin serie */
void SERIAL_Init( void ) {
/* Configuramos la velocidad de la comunicacin (baud rate) */
UBRR0H = (unsigned char)(BAUD_RATE_REGISTER>>8);
UBRR0L = (unsigned char)BAUD_RATE_REGISTER;
/* Valores por defecto despus de reset en el registre USCR0A.
Esta escritura no esta definida en el datasheet, pero parece
necesaria ya que de lo contrario el bit de "Double USART
Transmission Speed" parece activo, de modo que no configura
el baud rate como esperamos.
Posiblemente el bootloader de Arduino est configurando este
bit, ya que usa el perifrico para descargar el cdigo. */
UCSR0A = (1<<TXC0);
/* Activar la recepcin y la transmisin */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Configuramos el formato de la trama: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
/* Activar la interrupcin del puerto serie */
UCSR0B |= (1<<RXCIE0);
/* Activar interrupciones generales */
sei();
}
/* Funcin de transmisin de un caracter */
103
Contenido de Arduino_SERIAL_INTERRUPT_example.c
/*
* Arduino_SERIAL_INTERRUPT_example.c
*/
#include <avr/io.h>
/* Esta libreria contiene la definicin de
todos los registros, SIEMPRE DEBE SER INCLUIDA */
#define F_CPU
(16000000UL) /* F_CPU indica al compilador
que nuestro cristal es de 16Mhz. Debe ser declarado antes que la libreria
delay.h */
#include <util/delay.h>
/* Contiene funciones de espera en ms y us
*/
#include "Arduino_SERIAL_INTRx_Api.h" /* Contiene funciones para trbajar con
la comunicacin serie */
volatile unsigned char read;
int main( void ) {
int index = 0;
char indexCh[2];
SERIAL_Init(); /* Inicializamos la comunicacin */
/* Ejemplo de como escribir enteros en el terminal a modo de cuenta
atras */
for(index=3;index>0;index--){
itoa(index,indexCh,10);
SERIAL_PutString(indexCh);
SERIAL_PutString("\r\n");
_delay_ms(500);
}
SERIAL_PutString("Empieza a escribir en el terminal. \r\n");
read = 0;
while(read != 0x18){ /* Para salir Ctr + x */
/* Solo romperemos este bucle des de la interrupcin de recepcin */
}
SERIAL_PutString("\r\n Buen trabajo !!!");
return 0;
}
104
ISR(USART_RX_vect)
{
read = SERIAL_Receive();
SERIAL_Transmit(read); /* Mandamos lo que recivimos a modo de eco */
}
105
#define F_DESEADA
(1) // 1Hz => 1 segundo
#define DIVISOR
(256)
#define TIEMPO_A_ESPERAR
(((F_CPU / DIVISOR) / F_DESEADA) - 1)
#if TIEMPO_A_ESPERAR >= 65535 // Mximo del contador de 16bits
#error El tiempo a esperar es demasiado grande
#endif
volatile unsigned char segundos = 0; // Se actualiza en la interrupcin
del timer
static unsigned int contadorSegundos = 0;
static unsigned int contadorSegundosParcial_1 = 0;
static unsigned int contadorSegundosParcial_2 = 0;
/*
* Variables y constantes usadas para el contaje de volumen
*/
#define CONTADOR_RELACION
(0.307F) // Relacion entre pulsos y litros
por minuto
volatile unsigned int contadorPulsos = 0; // volatile ya que se accede
des de interrupcion
static unsigned int contadorPulsosLocal = 0;
static float litrosMinuto = 0.0;
static float litrosTotales = 0.0;
static float litrosParcial_1 = 0.0;
static float litrosParcial_2 = 0.0;
/*
* Variables y constantes usadas para la gestion de las pantallas
*/
#define NUMERO_PANTALLAS
(3) // Numero de distintas pantallas a
mostrar
unsigned char pantalla = 0; // Pantalla inicial a mostrar
/*
* Definicin de prototipos
*/
void inicializacion(void);
void lecturaPulsadorLCD(void);
void task_1000ms(void);
void pantalla_principal(void);
void pantalla_parcial_1(void);
void pantalla_parcial_2(void);
/*
* Definicin de funciones
*/
/*
* Funcin principal
*/
int main(void){
inicializacion();
while(1){
if (segundos >= 1){
/* Inicio zona segura intercambio de datos. No hay
interrupciones */
cli(); // DesHabilitamos las interrupciones generales
segundos--;
sei(); // Habilitamos las interrupciones generales
/* Fin zona segura intercambio de datos */
task_1000ms();
}
lecturaPulsadorLCD();
}
return 0;
}
106
/*
* Inicializacin de perifricos (puerto serie, timer, LCD e
interrupciones)
*/
void inicializacion(void){
/* Configuramos la comunicacin serie */
SERIAL_Init();
SERIAL_PutString("Empecemos...");
/* Configuracion del LCD */
lcd.init(EPSON); // Inicializa el LCD, utilizar PHILLIPS si no
funciona
lcd.contrast(LCD_CONTRASTE); // Inicializamos el contraste
lcd.clear(WHITE); // Fondo de pantalla en blanco (sin color)
/* Configuracin del sensor */
DDRD = (1<<PORTD6); // Pin digital 6 - PD6 como salida las demas
como entrada
PORTD = ((1<<PORTD2) | (1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5)); //
PullUp en las entradas
contadorPulsos = 0;
/* Configuramos interrupciones del pin INT 0 */
EIMSK = (1<<INT0); // INT 0
EICRA = (1<<ISC01); // Flanco de bajada
/* Configuramos el timer en modo CTC y el divisor del timer.
El timer empieza a contar */
TCCR1B = ((1<<WGM12)|(1<<CS12)); // CTC y 1:256
OCR1A = TIEMPO_A_ESPERAR; // Cargamos el valor a contar
TIMSK1 = (1<<OCIE1A); // Habilitamos las interrupciones del timer
sei(); // Habilitamos las interrupciones generales
}
/*
* Chequea el estado de los switches del LCD
*/
void lecturaPulsadorLCD(void){
/* Variables para gestion del anti rebote (debouncing) de los
botones */
static unsigned char boton0 = 0;
static unsigned char boton1 = 0;
static unsigned char boton2 = 0;
/* Lectura continua sobre los pulsadores con debouncing */
if ((PIND & (1<<PORTD3)) == 0){ // Pulsado
if (boton0 < 255){ // Control de rangos
boton0++;
}
}else{ // No pulsado
if (boton0 > LIMITE_ANTIRREBOTE){ // Ha estado pulsado al menos
"LIMITE_ANTIRREBOTE" veces
/* Ponemos a zero el contador parcial 2 */
contadorSegundosParcial_2 = 0;
litrosParcial_2 = 0.0;
}
boton0 = 0;
}
if ((PIND & (1<<PORTD4)) == 0){ // Pulsado
if (boton1 < 255){ // Control de rangos
boton1++;
}
}else{ // No pulsado
if (boton1 > LIMITE_ANTIRREBOTE){ // Ha estado pulsado al menos
"LIMITE_ANTIRREBOTE" veces
/* Ponemos a zero el contador parcial 1 */
contadorSegundosParcial_1 = 0;
107
litrosParcial_1 = 0.0;
}
boton1 = 0;
}
if ((PIND & (1<<PORTD5)) == 0){ // Pulsado
if (boton2 < 255){ // Control de rangos
boton2++;
}
}else{ // No pulsado
if (boton2 > LIMITE_ANTIRREBOTE){ // Ha estado pulsado al menos
"LIMITE_ANTIRREBOTE" veces
lcd.clear(WHITE); // Limpiamos la pantalla
pantalla++; // Cambiamos la pantalla a mostrar
if (pantalla >= NUMERO_PANTALLAS){
pantalla = 0;
}
}
boton2 = 0;
}
}
/*
* Funcion periodica cada 1 segundo.
* Cada segundo leemos los pulsos recibidos por el cuadalimetro,
* actualizamos los contadores de volumen acumulado e instantaneo,
* mandamos por la linea serie los pulsos detectados
* y refrescamos la pantalla a mostrar
*/
void task_1000ms(void){
float litrosUltimoMinuto;
/* Inicio zona segura intercambio de datos. No hay interrupciones */
cli(); // DesHabilitamos las interrupciones generales
contadorPulsosLocal = contadorPulsos;
contadorPulsos = 0; // Se escribe el la interrupcion y se limpia una
vez leido
sei(); // Habilitamos las interrupciones generales
/* Fin zona segura intercambio de datos */
itoa(contadorPulsosLocal,lcdStr,10);
SERIAL_PutString(lcdStr); // Mandamos los pulsos x segundo a la
linea serie
/* Convertimos los pulsos a litros por minuto y acumulamos los
totales */
litrosMinuto = contadorPulsosLocal * CONTADOR_RELACION;
litrosUltimoMinuto = (litrosMinuto / 60);
litrosTotales += litrosUltimoMinuto;
litrosParcial_1 += litrosUltimoMinuto;
litrosParcial_2 += litrosUltimoMinuto;
/* Incrementamos los contadores de tiempo */
contadorSegundos++;
contadorSegundosParcial_1++;
contadorSegundosParcial_2++;
/* Mostramos la pantalla que corresponda */
switch (pantalla){
case 0:
pantalla_principal();
break;
case 1:
pantalla_parcial_1();
break;
case 2:
pantalla_parcial_2();
break;
default:
108
break;
}
}
/*
* Pantalla principal a mostrar
*/
void pantalla_principal(void)
{
lcd.setStr("Tiempo total", 3, 3, BLACK, WHITE);
lcd.setStr("
segundos", 19, 3, BLACK, WHITE);
itoa(contadorSegundos,lcdStr,10);
lcd.setStr(lcdStr, 19, 11, BLACK, WHITE);
lcd.setStr("Consumo actual", 35, 3, BLACK, WHITE);
lcd.setStr("
l x min", 48, 3, BLACK, WHITE);
dtostrf(litrosMinuto, 4, 2, lcdStr);
lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);
lcd.setStr("Litros totales ", 64, 3, BLACK, WHITE);
lcd.setStr("
", 80, 3, BLACK, WHITE);
dtostrf(litrosTotales, 6, 2, lcdStr);
lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);
lcd.setStr("Cont.1
Cont.2 ", 96, 3, BLACK, WHITE);
lcd.setStr("
", 112, 3, BLACK, WHITE);
dtostrf(litrosParcial_1, 4, 2, lcdStr);
lcd.setStr(lcdStr, 112, 3, BLACK, WHITE);
dtostrf(litrosParcial_2, 4, 2, lcdStr);
lcd.setStr(lcdStr, 112, 75, BLACK, WHITE);
}
/*
* Pantalla contadores parciales 1
*/
void pantalla_parcial_1(void)
{
lcd.setStr("Tiempo parcial 1", 0, 3, BLACK, WHITE);
lcd.setStr("
segundos ", 16, 3, BLACK, WHITE);
itoa(contadorSegundosParcial_1,lcdStr,10);
lcd.setStr(lcdStr, 16, 11, BLACK, WHITE);
lcd.setStr("Consumo actual ", 32, 3, BLACK, WHITE);
lcd.setStr("
l x min", 48, 3, BLACK, WHITE);
dtostrf(litrosMinuto, 4, 2, lcdStr);
lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);
lcd.setStr("Litros parcial 1", 64, 3, BLACK, WHITE);
lcd.setStr("
", 80, 3, BLACK, WHITE);
dtostrf(litrosParcial_1, 4, 2, lcdStr);
lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);
lcd.setStr("
Totales ", 96, 3, BLACK, WHITE);
lcd.setStr("
", 112, 3, BLACK, WHITE);
dtostrf(litrosTotales, 6, 2, lcdStr);
lcd.setStr(lcdStr, 112, 59, BLACK, WHITE);
}
/*
* Pantalla contadores parciales 2
*/
void pantalla_parcial_2(void)
{
lcd.setStr("Tiempo parcial 2", 0, 3, BLACK, WHITE);
lcd.setStr("
segundos ", 16, 3, BLACK, WHITE);
itoa(contadorSegundosParcial_2,lcdStr,10);
lcd.setStr(lcdStr, 16, 11, BLACK, WHITE);
109
0
1
110
#undef F_CPU
#endif
#include "math.h"
#define F_CPU 16000000UL
#include <util/delay.h>
*/
#define delayMicroseconds(x)
#define delay(x)
111
112
Bibliografa y referencias
Bibliografa
Arduino team. Arduino homepage [En lnea] Pgina web del equipo de
Arduino [Fecha consulta: 01-01-2012] [Acceso gratuito] <http://arduino.cc/>
Wikipedia. Arduino [En lnea] Enciclopedia digital [Fecha consulta: 01-012012] [Acceso gratuito] <http://es.wikipedia.org/wiki/Arduino>
Arduino team. Arduino Uno. [En lnea] Artculo digital [Fecha consulta: 0101-2012] [Acceso gratuito] <http://arduino.cc/en/Main/ArduinoBoardUno>
Arduino team. Referencia del Lenguaje [En lnea] Artculo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/es/Reference/HomePage>
tronixstuff, Arduino Tutorials [En lnea] Artculo digital [Fecha consulta: 0101-2012] [Acceso gratuito] <http://tronixstuff.wordpress.com/tutorials/>
Atmel Corporation, AVR Studio 5 Overview [En lnea] Artculo digital [Fecha
consulta: 12-04-2012] [Acceso gratuito]
<http://www.atmel.com/dyn/products/tools_card.asp?tool_id=17212&source
=avr_5_studio_overview>
EngBlaze, Tutorial: Using AVR Studio 5 with Arduino projects [En lnea]
Artculo digital [Fecha consulta: 10-03-2012] [Acceso gratuito]
<http://www.engblaze.com/tutorial-using-avr-studio-5-with-arduinoprojects/>
Practical Arduino, Projects [En lnea] Artculo digital [Fecha consulta: 01-082012] [Acceso gratuito] < http://www.practicalarduino.com/projects/waterflow-gauge>
113
Teague Labs, DIY Arduino Water Meter [En lnea] Artculo digital [Fecha
consulta: 15-11-2011] [Acceso gratuito] <http://labs.teague.com/?p=722>
Referencias
[1]
Arduino team. Arduino homepage [En lnea] Pgina web del equipo de
Arduino [Fecha consulta: 10-11-2011] [Acceso gratuito] <http://arduino.cc/>
[2]
[3]
[4]
Definition of free cultural works, OSHW [En lnea] Artculo digital [Fecha
consulta: 10-11-2011] [Acceso gratuito] <http://freedomdefined.org/OSHW >
[5]
[6]
Parallax Inc, The BASIC Stamp [En lnea] Artculo digital [Fecha consulta:
10-11-2011] [Acceso gratuito]
<http://www.parallax.com/tabid/295/Default.aspx>
[7]
[8]
Phidgets, Products for USB Sensing and Control [En lnea] Artculo digital
[Fecha consulta: 10-11-2011] [Acceso gratuito] <http://www.phidgets.com/ >
[9]
The Handy Board, About [En lnea] Artculo digital [Fecha consulta: 10-112011] [Acceso gratuito] <http://handyboard.com/hb/about/>
[10] Freeduino, Home [En lnea] Artculo digital [Fecha consulta: 10-11-2011]
[Acceso gratuito] <http://www.freeduino.org/>
[11] Arduino team. Arduino compatible hardware [En lnea] Artculo digital
[Fecha consulta: 10-11-2011] [Acceso gratuito]
<http://www.arduino.cc/playground/Main/SimilarBoards#goArdComp>
[12] Arduino team. Hardware [En lnea] Artculo digital [Fecha consulta: 10-112011] [Acceso gratuito] <http://www.arduino.cc/en/Main/hardware>
[13] Digi, XBee-PRO 802.15.4 OEM RF Modules [En lnea] Artculo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://www.digi.com/products/wireless-wired-embedded-solutions/zigbeerf-modules/point-multipoint-rfmodules/xbee-series1-module#overview>
[14] Arduino team. Hardware for connecting to Arduino [En lnea] Artculo
digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://www.arduino.cc/playground/Main/SimilarBoards#goConn>
[15] NonGNU, AVR Libc Home Page [En lnea] Artculo digital [Fecha consulta:
01-01-2012] [Acceso gratuito] <http://www.nongnu.org/avr-libc/>
114
[16] Arduino team. Libraries [En lnea] Artculo digital [Fecha consulta: 01-012012] [Acceso gratuito] <http://arduino.cc/en/Reference/Libraries>
[17] Arduino team. Writing a Library for Arduino [En lnea] Artculo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/en/Hacking/LibraryTutorial>
[18] Sparkfun electronics, Color LCD Shield [En lnea] Artculo digital [Fecha
consulta: 15-08-2012] [Acceso gratuito]
<http://www.sparkfun.com/products/9363>
[19] Koolance Superior Liquid Cooling Solutions, Product manual v1.3 [En lnea]
Artculo digital [Fecha consulta: 15-08-2012] [Acceso gratuito] <
http://koolance.com/files/products/manuals/manual_insfm17,18_d130eng.pdf>
[20] RC Electronic World, ARDUIMU V2 QUADROTOR [En lnea] Artculo
digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://www.rcelectronicworld.co.cc/p/quadrotor.html>
[21] Android Arduino Handbag, Main [En lnea] Artculo digital [Fecha consulta:
01-01-2012] [Acceso gratuito]
<http://www.labradoc.com/i/follower/p/android-arduino-handbag>
[22] Arduino team. Getting Started w/ Arduino on Windows [En lnea] Artculo
digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/en/Guide/Windows>
[23] Arduino team. Placa Arduino monocapa [En lnea] Artculo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/es/Main/ArduinoBoardSerialSingleSided3>
[24] BricoGeek, Tienda [En lnea] Artculo digital [Fecha consulta: 01-01-2012]
[Acceso gratuito] <http://www.bricogeek.com/shop/>
[25] Electan, electrnica y robtica, Home [En lnea] Artculo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito] <http://www.electan.com>
[26] Proyecto Arduino, Download the Arduino Software [En lnea] Artculo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/en/Main/Software>
[27] SourceForge, WinAVR [En lnea] Artculo digital [Fecha consulta: 01-012012] [Acceso gratuito] <http://winavr.sourceforge.net/index.html>
[28] Proyecto Arduino, Referencia del Lenguaje [En lnea] Artculo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/es/Reference/HomePage>
[29] Seccin de tutorials de TronixStuff, Ttulo [En lnea] Artculo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito]
<http://tronixstuff.wordpress.com/tutorials/>
[30] Manual del Starter Kit de Earthshine Electronics, Arduino Starter Kit Manual
[En lnea] Artculo digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://www.earthshineelectronics.com/files/ASKManualRev5.pdf>
115
[31] Arduino playground wiki, Libraries for Arduino [En lnea] Artculo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/playground/Main/LibraryList>
[32] Pgina web de Koolance, Flow meters [En lnea] Artculo digital [Fecha
consulta: 01-12-2011] [Acceso gratuito] <http://www.koolance.com/watercooling/product_info.php?product_id=740>
[33] Tienda Tecniolid, CAUDAL LAVAVAJILLAS - Caudalimetro [En lnea]
Artculo digital [Fecha consulta: 01-12-2011] [Acceso gratuito]
<http://www.tiendatecniolid.com/epages/61636078.sf/es_ES/undefined/es_E
S/?ViewObjectID=5056775>
[34] eBay Stores, HELLFIRE TOYZ LLC [En lnea] Artculo digital [Fecha
consulta: 01-12-2011] [Acceso gratuito] <http://stores.ebay.com/HELLFIRETOYZ-LLC>
[35] Sparkfun electronics, Nokia LCD Display Driver [En lnea] Artculo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<https://docs.google.com/viewer?url=http://www.sparkfun.com/tutorial/Noki
a%25206100%2520LCD%2520Display%2520Driver.pdf>
[36] Richard Kaufmans blog, How to fix it: Backlight on SparkFuns Color LCD
Shield not working [En lnea] Artculo digital [Fecha consulta: 01-01-2012]
[Acceso gratuito] <http://richardkaufman.org/blog/how-to-fix-it-backlighton-sparkfuns-color-lcd-shield-not-working>
[37] Atmel, Main [En lnea] Artculo digital [Fecha consulta: 01-01-2012]
[Acceso gratuito] <http://www.atmel.com/>
[38] AVR freaks forum, GCC and the ROGMEM Attributes [En lnea] Artculo
digital [Fecha consulta: 20-07-2012] [Acceso gratuito]
<http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=
38003>
116