Documentos de Académico
Documentos de Profesional
Documentos de Cultura
1821pub PDF
1821pub PDF
2 ARDUINO ..................................................................................................................................... 6
2.1 INTRODUCCIÓN 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 ¿Cómo obtener una placa Arduino? ......................................................................... 12
2.2.6 Nuestra elección: El Arduino UNO ........................................................................... 12
2.2.6.1 El porqué de nuestra elección ................................................................................................ 12
2.2.6.2 Características ........................................................................................................................ 13
2.2.6.3 Esquema y pines .................................................................................................................... 14
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 aplicación Arduino .......................................... 18
2.3.2.1 Editor ..................................................................................................................................... 18
2.3.2.2 Compilador ............................................................................................................................ 19
2.3.2.3 Cargar y depurar .................................................................................................................... 20
2.4 LENGUAJE DE PROGRAMACIÓN ARDUINO ............................................................................ 22
2.4.1 Introducción e historia .............................................................................................. 22
2.4.2 Funciones básicas y operadores ............................................................................... 22
2.4.2.1 Estructuras ............................................................................................................................. 23
2.4.2.2 Variables ................................................................................................................................ 24
2.4.2.3 Funciones............................................................................................................................... 25
2.4.3 Uso de librerías ......................................................................................................... 27
2.4.3.1 Librerías Estándar .................................................................................................................. 27
2.4.3.2 Librerías de terceros .............................................................................................................. 28
3 NUESTRO PROYECTO ARDUINO ....................................................................................... 30
3.1 MEDIDOR DE CAUDAL .......................................................................................................... 30
3.2 REQUERIMIENTOS INICIALES ............................................................................................... 30
3.3 ELECCIÓN DE LOS COMPONENTES ........................................................................................ 31
3.4 LISTA DE MATERIAL Y PRESUPUESTO ................................................................................... 32
3.5 EL HARDWARE ..................................................................................................................... 33
3.5.1 Características técnicas de los componentes ............................................................ 33
3.5.1.1 Shield LCD color ................................................................................................................... 33
3.5.1.2 Sensor de caudal .................................................................................................................... 34
3.5.2 El ensamblado ........................................................................................................... 35
3.6 EL SOFTWARE ...................................................................................................................... 37
3.6.1 Diseño de la pantalla ................................................................................................ 37
3.6.1.1 Uso de la librería del shield LCD a color de Sparkfun .......................................................... 37
3.6.1.2 Información a mostrar e interfaz ............................................................................................ 39
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 caudalímetro ........................................................................................ 44
3.7.2 Test sobre la captura de pulsos ................................................................................. 45
2
3.7.3 Test de funcionamiento general................................................................................. 47
4 USO DE ARDUINO EN ENTORNOS LECTIVOS ................................................................ 48
4.1 EDUCACIÓN SECUNDARIA .................................................................................................... 48
4.2 EDUCACIÓN TÉCNICA SUPERIOR .......................................................................................... 48
4.2.1 Usar AVRStudio, código C y Arduino ....................................................................... 49
4.2.2 Simular y ejecutar el código C en nuestro microcontrolador ................................... 52
4.2.2.1 Simular el código en el PC. AVRSimulator........................................................................... 53
4.2.2.2 Descargar el código en nuestra placa Arduino. AVRDude. ................................................... 53
4.2.2.3 Uso de entornos de depuración y programación .................................................................... 54
4.2.3 El ATmega328P........................................................................................................ 55
4.2.3.1 Un breve resumen .................................................................................................................. 55
4.2.3.2 Puertos de entrada y salida digital ......................................................................................... 55
4.2.3.3 Uso de la USART/comunicación serie .................................................................................. 58
4.2.3.4 Las interrupciones en los ATmega328P ................................................................................ 60
4.2.3.5 Interrupciones por cambio de PIN ......................................................................................... 64
4.2.3.6 Uso de temporizadores y PWM ............................................................................................. 66
4.2.3.7 Uso del conversor ADC ......................................................................................................... 74
4.2.4 Codificación del medidor de caudal en C ................................................................. 75
5 PRESUPUESTO ......................................................................................................................... 78
5.1 PRECIOS UNITARIOS ............................................................................................................. 78
5.2 PRECIOS DESCOMPUESTOS ................................................................................................... 78
5.2.1 Capítulo 1: Estudios previos ..................................................................................... 78
5.2.2 Capítulo 2: Diseño y montaje del hardware ............................................................. 79
5.2.3 Capítulo 3: Diseño del firmware ............................................................................... 79
5.2.4 Capítulo 4: Diseño del software de PC ..................................................................... 79
5.2.5 Capítulo 5: Documentación ...................................................................................... 80
5.3 RESUMEN DEL PRESUPUESTO ............................................................................................... 80
6 CONCLUSIONES Y VALORACIÓN PERSONAL ............................................................... 81
Índice de ilustraciones
Ilustración 1: Logo oficial de Arduino ......................................................................... 8
Ilustración 2: En la parte superior Arduino MEGA y en la inferior Arduino UNO .... 9
Ilustración 3: Arduino con tres "shields" ................................................................... 10
Ilustración 4: RobotShop Rover ................................................................................. 11
Ilustración 5: Arduino Single-Sided Serial o Severino .............................................. 12
Ilustración 6: Arduino UNO, vista frontal ................................................................. 13
Ilustración 7: Arduino UNO, vista trasera ................................................................. 13
Ilustración 8: Pines de Arduino contra ATmega328 .................................................. 14
Ilustración 9: Arduino en el administrador de dispositivos de Windows .................. 16
Ilustración 10: Entorno SW de Arduino..................................................................... 17
Ilustración 11: Acceso a los ejemplos a través del menú ........................................... 19
Ilustración 12: Acceso a los ejemplos a través de la barra de herramientas .............. 19
Ilustración 13: Ejemplo de código Arduino ............................................................... 19
Ilustración 14: Resultado de verificación correcto..................................................... 20
Ilustración 15: Resultado de verificación incorrecto. ................................................ 20
Ilustración 16: Ubicación del LED de test en la placa Arduino ................................. 21
3
Ilustración 17: Monitor de comunicación serie integrado en el entorno Arduino ..... 22
Ilustración 18: Diagrama de bloques del caudalímetro .............................................. 31
Ilustración 19: Shield LCD a color ............................................................................ 33
Ilustración 20: Punto a cortocircuitar para activar la retro iluminación..................... 34
Ilustración 21: Sensor de caudal Koolance ................................................................ 34
Ilustración 22: Relación entre litros y frecuencia del medidor de caudal .................. 34
Ilustración 23: Esquema de montaje .......................................................................... 35
Ilustración 24: Esquema de conexionado del caudalímetro ....................................... 36
Ilustración 25: Vista lateral del montaje final ............................................................ 36
Ilustración 26: Vista frontal del montaje final ........................................................... 37
Ilustración 27: Listado de las librerías en el entorno Arduino ................................... 38
Ilustración 28: Uso de una librería una vez instalada en el entorno Arduino ............ 38
Ilustración 29: Pantalla principal ............................................................................... 40
Ilustración 30: Pantalla contadores parciales 1 .......................................................... 40
Ilustración 31: Pantalla contadores parciales 2 .......................................................... 40
Ilustración 32: Diagrama de flujo del firmware ......................................................... 41
Ilustración 33: Diagrama temporal del firmware ....................................................... 42
Ilustración 34: Salida del programa de visualización en el PC .................................. 43
Ilustración 35: Tren de pulsos del caudalímetro girando a baja velocidad ................ 44
Ilustración 36: Tren de pulsos del caudalímetro girando a media velocidad ............. 45
Ilustración 37: Tren de pulsos del caudalímetro girando a alta velocidad ................. 45
Ilustración 38: Respuesta ante un tren de pulsos de 31Hz ......................................... 46
Ilustración 39: Muestra de la pantalla principal ante una entrada de 31Hz ............... 46
Ilustración 40: Secuencia de acciones en funcionamiento normal............................. 47
Ilustración 41: Prueba de precisión del contador de segundos .................................. 48
Ilustración 42: Vista inicial del AVR Studio ............................................................. 49
Ilustración 43: Selección de dispositivo en AVR Studio ........................................... 50
Ilustración 44: Vista de codificación del AVR Studio ............................................... 51
Ilustración 45: Resultado de la compilación en el AVR Studio................................. 52
Ilustración 46: Vista del simulador integrado en AVR Studio .................................. 53
Ilustración 47: Vista de ensamblador en AVRSimulator ........................................... 57
Ilustración 48: Puerto general de entrada/salida digital ............................................. 58
Ilustración 49: Ejemplo de uso del temporizador en modo CTC ............................... 71
Ilustración 50: Generación PWM en modo “Fast PWM” .......................................... 72
Ilustración 51: Generación PWM en modo “Phase Correct PWM” .......................... 72
4
Ilustración 52: Generación PWM en modo “Phase and Frequency Correct PWM”.. 73
Ilustración 53: Uso del temporizador como “Input capture” ..................................... 73
Ilustración 54: Configuración opciones de optimización del compilador ................. 76
Ilustración 55: Configuración opciones de optimización del linker .......................... 76
Ilustración 56: Resultado de la construcción del proyecto en AVRStudio ................ 77
Ilustración 57: Modificación del fichero ColorLCDShield.cpp. 1era parte ............... 84
Ilustración 58: Modificación del fichero ColorLCDShield.cpp. 2da parte ................ 85
Ilustración 59: Configuración de una herramienta externa en AVRStudio ............... 99
Ilustración 60: Vista para crear un botón para las herramientas externas en
AVRStudio ........................................................................................................................ 100
Ilustración 61: Cuadro de opciones para botón en la barra de herramientas. I ........ 100
Ilustración 62: Cuadro de opciones para botón en la barra de herramientas. II ....... 101
Ilustración 63: Vista del botón en la barra de herramientas ..................................... 101
Ilustración 64: Estructura de carpetas del soporte digital ........................................ 112
Índice de anexos
ANEXOS ............................................................................................................................................. 83
ANEXO 1: INFORMACIÓN USO LIBRERÍA LCD ................................................................................ 83
Modificaciones sobre la librería................................................................................................. 84
ANEXO 2: PROGRAMA DE CONTROL DE ARDUINO. ......................................................................... 86
ANEXO 3: PROGRAMA DE CONTROL DEL PC. ................................................................................. 91
ANEXO 4: CONFIGURACIÓN DEL AVRSTUDIO PARA DESCARGAR EL CÓDIGO EN ARDUINO. .......... 97
Contenido de “Upload.cmd” ...................................................................................................... 97
Contenido de “UploadFromAVRStudio.cmd” ............................................................................ 98
Uso de herramientas externas en AVRStudio ............................................................................. 98
ANEXO 5: LIBRERÍA DE USO DE LA COMUNICACIÓN SERIE EN AVRSTUDIO ................................. 101
Contenido de “Arduino_SERIAL_API.h” ................................................................................ 101
Contenido de “Arduino_SERIAL.c” ......................................................................................... 102
ANEXO 6: COMUNICACIÓN SERIE CON INTERRUPCIONES DE RECEPCIÓN ...................................... 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
5
1 Objetivo del PFC
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 evaluación de las capacidades
formativas/lectivas de la plataforma Arduino en el ámbito de la educación tanto secundaria
como universitaria.
Para alcanzar tales objetivos propongo la realización 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 distribución.
2 Arduino
6
Publicar la documentación, incluyendo los archivos de los diseños mismos, que
debe permitir su modificación y distribución.
Especificar que porción del diseño es abierta en caso de que no se liberen todos sus
componentes.
Ofrecer el software para el visionado de los archivos de diseño y de la
documentación, para que se pueda escribir el código open-source fácilmente.
Ofrecer una licencia que permita producir derivados y modificaciones, además de
su re-distribución bajo la licencia original, así como su venta y manufactura.
La licencia no debe restringir que se venda o comparta la documentación necesaria.
No pide una tarifa por su venta o la de sus derivados.
La licencia no debe discriminar a ningún grupo o persona
La licencia no debe de restringir a ningún campo o actividad el uso de la obra. Es
decir, no se puede limitar su uso únicamente para negocios o prohibir sea utilizado
para investigación nuclear.
El licenciamiento de la obra no puede depender de un producto en particular.
La licencia no debe restringir otro hardware o software, es decir que no puede
insistir en que otros componentes de hardware o software externos a los
dispositivos sean también open-source.
La licencia tiene que ser neutral, ninguna disposición de la misma debe de basarse
en una tecnología específica, parte o componente, material o interfaz para su uso.
7
librerías de C++, y si se está interesado en profundizar en los detalles
técnicos, se puede dar el salto a la programación en el lenguaje C en el que
está basado. De igual modo se puede añadir directamente código en C en los
programas.
Hardware ampliable y de Código abierto - Arduino está basado en los
microcontroladores ATMEGA168, ATMEGA328 y ATMEGA1280. Los
planos de los módulos están publicados bajo licencia Creative Commons,
por lo que diseñadores de circuitos con experiencia pueden hacer su propia
versión del módulo, ampliándolo u optimizándolo. Incluso usuarios
relativamente inexpertos pueden construir la versión para placa de
desarrollo para entender cómo funciona y ahorrar algo de dinero.
8
Ilustración 2: En la parte superior Arduino MEGA y en la inferior Arduino UNO
9
Una placa Arduino circular, reducida al máximo, diseñada 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 módulo bluetooth integrado para las
comunicaciones móviles.
Arduino Nano
El Arduino Nano es un todo-en-uno, diseño 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
comunicación con el PC se hace a través de un adaptador de USB a Arduino
Mini.
Arduino Pro Mini
Igual que el Arduino Mini, pero sin los “headers” ni lo conectores montados,
con la intención de tenerlo en instalaciones semipermanentes o permanentes.
Arduino Single-Sided Serial
También conocido como "Severino". Esta es la versión de la placa Arduino de
una sola cara, haciéndola fácil de hacer a mano. No fue manufacturada, sino
que fue publicada en la web de Arduino para que la gente se la pudiese hacer
ellos mismos a modo de aprendizaje de todo el proceso de grabación de PCB.
El objetivo de Arduino y sus placas es ofrecer a la gente la posibilidad de seguir la filosofía
DIY (Do it yourself).
10
A continuación se citan las shields oficiales de Arduino, pero existe multitud de
shields de terceros.
Arduino Ethernet Shield
Esta shield permite a una placa Arduino conectarse a una red Ethernet y tener
acceso a y desde Internet.
Arduino Wireless Proto Shield
Esta shield le da a una placa Arduino la posibilidad de comunicarse de manera
inalámbrica basándose en los módulos Xbee[13], y ofrece al usuario una
pequeña área para soldar componentes (prototipage).
Arduino Wireless SD Shield
Igual que la anterior, pero dando soporte para acceder a una tarjeta de memoria
tipo SD.
Arduino Motor Shield
Esta shield permite a Arduino controlar motores eléctricos de corriente
continua, servos y motores paso a paso, y leer encoders.
Arduino Proto Shield
Esta shield ofrece al usuario un área para soldar componentes.
Uno de los principales distribuidores y desarrolladores de shields es
Sparkfun, aunque no el único. Esta página web http://shieldlist.org/ intenta
mantener una lista de todas las shields de Arduino, tanto las oficiales como las
no oficiales.
A parte de las shields existe un buen número de plataformas que están listas
para ser controladas por una placa Arduino[14]. Entre estas plataformas, quizás
una de las más vistosas seria:
RobotShop Rover
Es una pequeña plataforma móvil diseñada entorno a Arduino. Los usuarios
pueden personalizar su móvil añadiendo funcionalidad.
11
2.2.4 Construir nuestro propio Arduino
Al ser OSHW puede montarse los distintos módulos uno mismo. La placa Arduino
Single-Sided Serial (cara simple y mono capa) o Severino ha sido diseñada para que sea
especialmente fácil de grabar el PCB y montar los distintos componentes.
12
Ilustración 6: Arduino UNO, vista frontal Ilustración 7: Arduino UNO, vista trasera
2.2.6.2 Características
La descripción completa del Arduino UNO se puede encontrar en su página web
oficial. Este es un resumen de las principales características:
Microcontrolador ATmega328
Voltaje de funcionamiento 5V
Voltaje de entrada (recomendado) 7-12V
Voltaje de entrada (limite) 6-20V
Pines E/S digitales 14 (6 proporcionan salida PWM)
Pines de entrada analógica 6
Intensidad máxima por pin 40 mA
Intensidad en pin 3.3V 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 vía la conexión USB o con una fuente de
alimentación externa. El origen de la alimentación se selecciona automáticamente.
Además, algunos de los pines tienen funciones especializadas:
Serie: Pin 0 (RX) y 1 (TX). Usados para recibir (RX) y transmitir (TX) datos
a través de puerto serie TTL. Estos pines están conectados a los pines
correspondientes del chip de FTDI responsable de la conversión USB-to-
TTL.
Interrupciones Externas: Pin 2 y 3. Estos pines se pueden configurar para que
interrumpan la ejecución del programa al detectar un flanco o un nivel.
PWM: Pin 3, 5, 6, 9, 10, y 11. Proporciona una salida PWM (Pulse-width
modulation, modulación por ancho de pulsos) con temporizadores de 8 bits
de resolución.
13
SPI: Pin 10 (CS/SS), 11 (MOSI), 12 (MISO), 13 (SCK). Estos pines
proporcionan comunicación SPI (Serial Peripheral Interface).
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.
6 entradas analógicas, cada una de ellas proporciona una resolución de 10bits
(1024 valores). Por defecto se mide de tierra a 5 voltios, aunque es posible
cambiar la cota superior de este rango usando el pin AREF
I2C: Pin 4 (SDA) y 5 (SCL). Soporte del protocolo de comunicaciones I2C
/TWI.
AREF. Este pin proporciona un voltaje de referencia para las entradas
analógicas.
Reset. Si en este pin se suministra un valor bajo (0V) se reinicia el
microcontrolador.
El ATmega328 en las placas Arduino UNO viene precargado con un gestor de
arranque (boot loader) que permite cargar nuevo código sin necesidad de un programador
por hardware externo. La carga de un nuevo código se realiza a través del entorno de
desarrollo Arduino y la conexión serie/USB.
También es posible saltar el gestor de arranque y programar directamente el
microcontrolador a través del puerto ICSP (In Circuit Serial Programming). En tal caso, se
debe utilizar un programador externo.
14
2.3 El entorno de trabajo
Para empezar a trabajar debemos instalar todo el entorno necesario en el PC. Vamos
a describir brevemente este proceso en un entorno Windows.
Existe gran cantidad de guías acerca de cómo realizar este proceso, incluyendo una
explicación en la propia página del proyecto Arduino[22].
Debo indicar que este proyecto se ha realizado con la versión 1.0 del entorno de
programación Arduino. Esta es la primera versión no “Alfa” del entorno Arduino, y
presenta grandes cambios en comparación de las anteriores. La mayoría de cambios son a
nivel estético (distribución de iconos en las barra de herramientas, esquema de colores,…),
pero hay un gran cambio a nivel funcional, los ficheros Arduino han pasado de tener
extensión .pde a extensión .ino
Estos últimos cambios implican que la mayor parte de la documentación que se
encuentra en internet a día de hoy es incorrecta o desfasada con la revisión actual del
entorno software de Arduino.
15
Ilustración 9: Arduino en el administrador de dispositivos de Windows
16
Ilustración 10: Entorno SW de Arduino
Antes que nada debemos saber que un “sketch”, o boceto, es el nombre que usa
Arduino para un programa. Es la unidad de código que se sube y se ejecuta en la placa
Arduino. El concepto de sketch o boceto, sería el equivalente a proyecto.
Un “sketch” puede contener múltiples archivos (pestañas). Cuando un sketch es
compilado, todas las pestañas serán concatenadas juntas para formar el archivo principal
del sketch.
Arduino puede utilizar librerías y código C/C++. Las pestañas .c o .cpp se
compilaran por separado y deberán ser incluidas en el sketch usando #include.
Es importante configurar correctamente la placa Arduino que vamos a utilizar, y a
través de qué puerto de comunicaciones estará conectada. Para tal efecto, debemos ir al
menú “Tools” escoger el submenú “Board” e indicar la placa que usaremos, en nuestro
17
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 rápido a las siguientes
funciones:
Verify - Se utiliza para compilar y así comprobar que nuestro boceto
Verificar/Compilar es correcto antes de cargarlo a la placa Arduino.
Serial monitor - Abre una ventana con un monitor del bus serie al que está
conectado nuestro Arduino.
Monitor serie
Esta es una herramienta muy útil, especialmente para depurar
el código. El monitor muestra datos serie que se envían desde
la placa Arduino (USB o RS232) y también puede enviar
datos serie de vuelta a la placa Arduino.
En la parte inferior izquierda del monitor serie se puede
seleccionar la velocidad de transmisión de datos. La
configuración por defecto es 9600 baud.
2.3.2.1 Editor
En el IDE Arduino, seleccionaremos el menú “File”, submenú “Examples” (o bien
directamente, el icono “Open ”) y dentro de “1.Basics” seleccionaremos el boceto
(“sketch”) “Blink”.
18
Ilustración 11: Acceso a los ejemplos a Ilustración 12: Acceso a los ejemplos a
través del menú través de la barra de herramientas
Esto nos abrirá una nueva ventana con el código de este boceto, el objetivo del cual
no es más 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).
2.3.2.2 Compilador
Como se puede observar en la “Ilustración 13: Ejemplo de código Arduino“, el
código necesario para realizar tal acción es bastante simple. Ahora solo falta comprobar
que realmente es correcto.
Para tal cosa, simplemente pulsando sobre el icono “Verify” , el IDE de Arduino
va a verificar y compilar el código escrito en la ventana activa. El entorno Arduino siempre
compila el código de las pestañas de la ventana activa como un único boceto.
19
El resultado debería ser correcto y lo veremos en el “área de estado” o de
“notificaciones”:
Aquí nos indica el estado del proceso, el tamaño de memoria usada y la disponible en
nuestra placa Arduino.
20
Ilustración 16: Ubicación del LED de test en la placa Arduino
21
Ilustración 17: Monitor de comunicación serie integrado en el entorno Arduino
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.
23
>> (desplazamiento de bits a |= (or - 'o' a nivel de bits y
la derecha) asignación)
&= (and - 'y' a nivel de bits y
asignación)
2.4.2.2 Variables
Los tipos de los datos, su uso y declaración, es muy similar a otros lenguajes de
programación, 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.
HIGH | LOW (estado de un pin de E/S digital)
INPUT | OUTPUT (comportamiento de un pin de E/S digital)
true | false (estado de un resultado lógico)
Tipos de Datos
Las variables pueden ser declaradas en cualquier punto del programa y, si no se
indica lo contrario, valen cero.
boolean (Booleano. Puede ser cierto o falso. Ocupa 8 bits en memoria)
char (Carácter. Almacena un único ASCII, tiene signo y ocupa 8 bits en
memoria)
unsigned char (Carácter sin signo).
byte (Dato de 8 bits, sin signo)
int (Entero de 16 bits, con signo)
unsigned int (Entero de 16 bits, sin signo)
word (Palabra. Equivalente a unsigned int)
long (Entero de 32 bits con signo)
unsigned long (Entero de 32 bits sin signo)
float (Valor en coma flotante de 32 bits. Se debe evitar usar estos tipos ya
que consumen mucho tiempo de CPU, espacio de código y pueden
ocasionar problemas en comparaciones, ya que por ejemplo 6.0 dividido por
3.0 puede no ser igual a 2.01)
double (En Arduino, es lo mismo que float)
array (Vector de elementos)
void (Vacío)
String (Des de la versión 0019 existe la clase String() que permite manipular
cadenas de caracteres de un modo sencillo, permitiendo concatenaciones o
1 Se debe tener en cuanta que el uso de float se realiza a través de librerías sw, y que además la propia
codificación IEEE-754 que usa el tipo float tiene limitaciones.
24
gestión automática del fin de cadena. Hasta ese momento el uso de string se
limitaba a vectores de caracteres sobre los cuales se debía tener en cuenta el
final de cadena /0 para poder usarlo con funciones tipo print())
Conversión
Estas son una serie de funciones que permiten el cambio entre tipos.
char(x) – Convierte el valor de tipo x a carácter.
byte(x) – Convierte el valor de tipo x a byte.
int(x) – Convierte el valor de tipo x a int.
long(x) – Convierte el valor de tipo x a long.
float(x) – Convierte el valor de tipo x a float.
Ámbito de las variables y calificadores
Las variables en el lenguaje de programación usado por Arduino, al igual que el C, tienen
una propiedad llamada ámbito. Al contrario de lo que pasa en lenguajes como BASIC en
los que todas las variables son globales. En Arduino solo las declaradas fuera de una
función son globales. En el caso de declararse dentro de una sección de código delimitada
por llaves “{…}”, como el caso de una función, la variable se libera al salir de esta sección
y se vuelve a crear con el valor inicial al volver a entrar en esta sección. Esto se debe tener
especialmente en cuenta al declarar variables dentro de la función loop().
static – Estática – Las variables que se declaran como estáticas sólo se
crearan e inicializarán la primera vez que se ejecute el bloque de código en
el que están contenidas.
volatile – Volátil – Una variable debe ser declarada volatile siempre que su
valor pueda ser modificado por algo más allá de la sección del código en el
que aparece. En Arduino, el único lugar en el que se podría dar el caso es en
secciones de código asociadas a interrupciones.
const – Constante – Es un calificador de variable que modifica el
comportamiento de la misma, haciendo una variable de "sólo-lectura". Sería
equivalente a utilizar #define.
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 están limitadas
a ser usadas en pines concretos y pueden necesitar de argumentos que no se detallan en
este apartado. Para información adicional se puede consultar la página de referencia del
lenguaje del proyecto Arduino [28].
E/S Digital
pinMode(pin, modo) – configura el pin a modo de entrada o salida
digitalWrite(pin, valor) - escritura digital
digitalRead(pin) – devuelve una lectura digital
E/S Analógica
25
analogReference(tipo) – configura el tipo de referencia analógica
analogRead(pin) – devuelve una lectura analógica
analogWrite(pin, valor) – “escritura analógica”. Generará una onda
cuadrada con el ciclo de trabajo que se le indique como parámetro (0-255
implica un ciclo de trabajo de 0 a 100%). La frecuencia de la señal PWM
será de 490 Hz por diseño de Arduino. Proporciona una manera simple de
implementar un control de intensidad luminosa sobre un LED.
E/S Avanzada
tone(pin, frecuencia) - Genera una onda cuadrada de la frecuencia en Hz
especificada. Opcionalmente se puede definir la duración del tono en ms.
noTone(pin) – Deja de generar el tono en el pin especificado
shiftOut(pinDatos, pinReloj, ordenBits, valor) - Desplaza un byte de datos
bit a bit a través del SPI.
pulseIn(pin, value) - Devuelve la anchura de un pulso en microsegundos
empezando a medir cuando el pin se encuentra al nivel definido en value.
Tiempo
millis(). Tiempo des del arranque en ms.
micros(). Tiempo des del arranque en us.
delay(ms). Espera activa en ms.
delayMicroseconds(us). Espera activa en us.
Cálculo
min(x, y) – Devuelve el mínimo de dos números.
max(x, y) – Devuelve el máximo de dos números.
abs(x) - Devuelve el valor absoluto
constrain(x, a, b) – Devuelve x siempre que este entre a y b. En caso
contrario devuelve los límites a o b.
map(value, fromLow, fromHigh, toLow, toHigh) – Devuelve el valor de un
“re-mapeo” de un rango hacia otro. Por ejemplo para realizar un cambio de
escala de un valor de 0 a 1024 a un rango de 0 a 255.
pow(base, exponente) – Devuelve el valor de un número elevado a otro
número.
sqrt(x) – Devuelve la raíz cuadrada
Trigonometría
sin(rad) – Devuelve el seno
cos(rad) - Devuelve el coseno
tan(rad) - Devuelve la tangente
Números aleatorios
26
randomSeed(seed) – Inicializa el generador de números pseudoaleatorios.
Se puede usar como semilla una entrada mínimamente aleatoria como
analogRead() en un pin desconectado.
random() – Devuelve un valor pseudoaleatorio.
Bits y Bytes
lowByte(x) – Devuelve el byte de menor peso (big-endian, el de más al
derecha) de una variable
highByte(x) - Devuelve el byte de mayor peso (big-endian, el de más al
izquierda) de una variable
bitRead(x, n) – Devuelve el valor del bit n en x.
bitWrite(x, n, b) – Escribe b en el bit n de x.
bitSet(x, n) – Pone a 1 el bit n de x.
bitClear(x, n) – Pone a 0 el bit n de x.
bit(n) – Devuelve un byte con sus bits a cero a excepción del bit n. Por
ejemplo, bit(0) devolvería un 1 en decimal, bit(1) un 2, bit(2) un 4 en
decimal.
Interrupciones externas
attachInterrupt(inter, funcion, modo) – Con el parámetro inter indicamos
que ISR externa vamos a configurar. Con el parámetro modo indicamos el
motivo que la va a disparar (CHANGE, LOW, RISING o FALLING) y con
el parámetro función, la función que va a ejecutarse al ser disparada.
detachInterrupt(inter) – Desactiva la interrupción inter
Interrupciones
interrupts() - Habilita las interrupciones
noInterrupts() - Desactiva las interrupciones
Comunicación (estas dos son clases, con lo que no se pueden invocar directamente,
sino que se debe invocar el método que necesitemos)
Serial
Stream
27
Ethernet - Para conectarse a una red usando el shield Ethernet.
Firmata – Para comunicarse con aplicaciones en un PC que se comporta como
servidor (host) usando el protocolo Firmata.
LiquidCrystal - Para controlar Displays de cristal líquido (LCD)
Servo - Para controlar servomotores.
SoftwareSerial - Para la comunicación seria utilizando cualquier pin digital.
Stepper - Para controlar motores paso a paso (Stepper motors).
Wire - Interfaz de dos cables, ó Two Wire Interface (TWI/I2C), para enviar y
recibir datos a través de una red de dispositivos y sensores.
28
Capacitive Sensing – Implementa un sensor táctil capacitivo uniendo un pin
de escritura con una resistencia relativamente alta (100kOhm – 50MOhm),
una lamina de metal o cable y un condensador pequeño (20 - 400 pF) a un pin
de lectura, detectando cambios en este al acercarse o tocar la lámina con el
dedo.
Debounce - Para una lectura filtrada de entradas digitales con rebotes
(típicamente las entradas conectadas a botones).
Displays y LEDs:
Improved LCD library - Arregla errores de inicialización del LCD de la
librería LCD oficial de Arduino.
GLCD - Rutinas gráficas para LCDs basados en el chipset KS0108 o
equivalentes.
LedControl - Para controlar matrices de LEDs o displays de siete segmentos
con MAX7221 o MAX7219.
LedDisplay - Control para marquesina de LED HCMS-29xx.
Matrix - Librería para manipular displays de matrices de LED básicas.
Sprite - Librería básica para manipulación de sprites para usar en animaciones
con matrices de LEDs.
Motores y PWM:
TLC5940 - Manejador para el chip TLC5940 de Texas Instruments
implementando el control de hasta 16 servomotores a la vez.
Medición de Tiempo:
DateTime - Librería para llevar registro de fecha y hora actual en el software.
Metro - Útil para cronometrar acciones en intervalos regulares.
MsTimer2 - Utiliza la interrupción del temporizador 2 para disparar una
acción cada N milisegundos.
Utilidades de cadenas de texto:
TextString, PString, Streaming – Implementan métodos de salida más
completos para cadenas de texto.
Adicionalmente, muchos de los desarrolladores y distribuidores de shields generan
sus propias librerías para utilizar las shields, de modo que la cantidad de librerías
disponibles es enrome.
Además, nosotros podemos crear nuestras propias librerías y utilizarlas para nuestros
proyectos e incluso distribuirlas[17].
A raíz del cambio mayor de versión (de alfa a 1.0) en el entorno de programación
Arduino, muchas de las librerías de terceros han quedado obsoletas/desactualizadas por la
inclusión de ficheros de encabezados (.h) que han sido renombrados en esta nueva versión,
entre ellos “Wprogram.h” ha sido renombrado a “Arduino.h”, con lo que nos obligará a
modificar el código de estas librerías incluyendo el nuevo fichero.
29
3 Nuestro proyecto Arduino
30
Ilustración 18: Diagrama de bloques del caudalímetro
31
3.4 Lista de material y presupuesto
Una vez identificado el material necesario, se ha lanzado la orden de compra a los
distintos proveedores:
En la tienda Electan [25] se ha realizado el pedido de la placa Arduino y la pantalla:
Y el sensor de caudal en la tienda HellFire ToyZ [34] de eBay para pagar lo mínimo
en gastos de envío.
32
3.5 El hardware
33
Ilustración 20: Punto a cortocircuitar para activar la retro iluminación
34
Ya que simplemente mide a qué velocidad fluye el líquido por el interior del sensor,
el hecho que el sensor no esté totalmente lleno (presencia de bolsas de aire) provocará una
falta de precisión en la lectura del caudal.
Para no perder pulsos conectaremos el sensor de caudal en una entrada de
interrupción externa de la placa Arduino, en el pin 2.
3.5.2 El ensamblado
Después de estudiar como ensamblar la “shield” y decidir a través de que pines
conectaremos el caudalímetro, el montaje quedaría así.
Los shields son diseñados para montarse encima de la placa Arduino, con lo que los
pines se corresponden uno a uno.
El caudalímetro se conecta con un cable a masa y el otro a una entrada digital con
pullUp. El ATmega tiene una resistencia de pullUp interna de 20k ohmios con lo que no
necesitamos circuitería extra. Cada vez que el aspa del caudalímetro pasa por el interruptor
normalmente abierto provoca un cortocircuito a masa. En este momento se lee un cero en
la entrada digital. Si la entrada del caudalímetro la situamos en una entrada digital con
interrupción por flanco de Arduino, nos aseguramos no perder ningún pulso durante el
contaje.
35
Ilustración 24: Esquema de conexionado del caudalímetro
El otro cable del caudalímetro se ha conectado al pin digital D6. Este pin se
configura como salida a cero dando así la masa al caudalímetro. Esta distribución se ha
hecho para simplificar las conexiones y poder realizar ciertas pruebas sin el caudalímetro.
Si configuramos el pin D6 como salida PWM nos permite “emular” el funcionamiento del
caudalímetro. Para tal fin utilizaremos la función tone() de Arduino.
En la siguiente fotografía se puede apreciar el montaje del shield LCD sobre la placa
Arduino.
Finalmente, aquí se puede ver el montaje final, con la pantalla LCD y el sensor de
caudal.
36
Ilustración 26: Vista frontal del montaje final
3.6 El software
37
Ilustración 27: Listado de las librerías en el entorno Arduino
En nuestro caso, hemos extraído los ficheros “.cpp” y “.h” del fichero Zip de la
librería en una carpeta a la que hemos llamado “ColorLCDShield” dentro de “libraries”.
Una vez reiniciado el entorno Arduino, se puede ver como la nueva librería ya está
disponible.
Ilustración 28: Uso de una librería una vez instalada en el entorno Arduino
38
librería y como usarla2. En un modo resumido, nos indica que debemos instar el
constructor de la librería usando la declaración:
LCDShield lcd;
Una vez declarado el objeto de la librería, nos indica varios métodos a usar, entre
ellos el método de inicialización
lcd.init(EPSON);
o métodos para escribir en ella
lcd.clear(int color);
lcd.setStr(char *pString, int x, int y, int fColor, int bColor);
2 Véase ANEXO 1
39
Ilustración 29: Pantalla principal
40
Ilustración 32: Diagrama de flujo del firmware
La tarea periódica se lanza cada 1 segundo. Aquí se pone a cero el contador de pulsos
detectados y lleva la cuenta en cada contador. También es la responsable de refrescar los
valores que se muestran en la pantalla LCD y los valores instantáneos que se mandan por
el puerto serie.
De manera asíncrona, y con mayor prioridad, el código asociado a la interrupción de
flanco se encarga de contar los pulsos generados por el caudalímetro.
41
Loop() Tarea_1sec() Interrupción()
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
3.6.3 El programa de control del PC
El programa de control de Arduino nos manda cada segundo, a través del puerto
serie, el caudal instantáneo. En el PC hemos realizado un programa capaz de interpretar
estos datos y dibujar en la pantalla una gráfica en tiempo real de las mediciones realizadas
por nuestro Arduino.
La pantalla de nuestro programa de PC es la siguiente:
La parte de crear una ventana y dibujar la gráfica se realiza a través de una librería
python con lo que la totalidad del programa se puede reducir a unas 300 líneas de código.3
3 Véase ANEXO 3
43
3.7 Juego de pruebas
Para verificar que nuestro sistema funciona como esperamos se han realizado una
serie de pruebas a distintos niveles.
44
Ilustración 36: Tren de pulsos del caudalímetro girando a media velocidad
45
El hecho de dar la masa del caudalímetro a través 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 añadimos la siguiente línea al principio
de la función loop():
tone(caudalGNDPin,31);
Si quitamos el caudalímetro y cortocircuitamos los dos pines, el programa de control
debería detectar 31 pulsos cada segundo.
Lo verificamos viendo que por la comunicación serie está mandando continuamente
un 31.
46
3.7.3 Test de funcionamiento general
Con el código final y el caudalímetro conectado, verificamos que al pulsar el 1er
botón cambiamos de pantalla a mostrar.
Al pulsar el segundo botón, el contador de litros y tiempo parcial 1 se pone a cero.
Al pulsar el tercer botón, el contador de litros y tiempo parcial 2 se pone a cero.
47
Ilustración 41: Prueba de precisión del contador de segundos
En la pantalla principal soplamos sobre el caudalímetro y vemos que el contador de
consumo actual incrementa y que los litros totales también crecen.
48
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 más directo con el microcontrolador.
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
Ilustración 44: Vista de codificación del AVR Studio
El ejemplo que queremos implementar es uno de los más típicos en las placas
Arduino. Aprovechando que la propia placa tiene el pin D13 conectado a un LED, vamos a
hacer que este LED este encendiéndose y apagándose para siempre, 1 segundo encendido y
1 segundo apagado.
Este sería el código a implementar:
/*
* Arduino_blink.c
*/
int main(void)
{
DDRB |= (1<<PB5); //Definimos el pin13/PORTB5 como salida para poder
encender y apagar nuestro LED
51
_delay_ms(1000); //Espera 1 segundo
PORTB &= ~(1<<PB5); //Apaga el LED
_delay_ms(1000); //Espera 1 segundo
}
}
52
4.2.2.1 Simular el código en el PC. AVRSimulator.
El AVRSimulator es una herramienta gráfica integrada en el propio AVRStudio que
nos permite ejecutar nuestro código viendo e interactuando con todos los registros internos
del microcontrolador, así como sus pines de entrada y salida.
Al mismo tiempo nos sirve como depurador, ya que nos permite poner “breakpoints”
en el código y ver el valor de las variables, así como modificarlas y forzar otras ramas de
ejecución, pudiendo probar mejor nuestro código.
53
documentos del usuario que ha instalado el AVRStudio. Dentro de esta carpeta
“AVRStudio 5.1”.
Los archivos necesarios para poder usar el AVRDude se encuentran en la ruta de
instalación del entrono Arduino bajo las siguientes rutas relativas:
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
El siguiente fichero, aun no siendo obligatorio, contiene la información
necesaria para poder usar el AVRDude con la configuración apropiada.
arduino-1.0\hardware\arduino\boards.txt
arduino-1.0\hardware\tools\avr\doc\avrdude\avrdude.pdf
La línea de comandos a ejecutar para descargar nuestro código sería la siguiente:
avrdude -F -V -c arduino -p ATMEGA328P -P COM3 -b 115200 -D -U
flash:w:Arduino_Blink.hex
54
4.2.3 El ATmega328P
La intención de este bloque es mostrar cómo se pueden usar los distintos periféricos
del microcontrolador de nuestro Arduino y realizar en C el mismo proyecto realizado en
lenguaje Arduino. No se entrará en detalle en todos los periféricos, ya que la hoja de
características (datasheet) del microcontrolador contiene todos los detalles.
La hoja de características del ATmega328P se puede abrir fácilmente des del propio
IDE del AVRStudio o en la página web del fabricante [37].
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 instrucción también se ha configurado como entrada los demás pins del
puerto B. Más 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
configuración 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;
56
Ilustración 47: Vista de ensamblador en AVRSimulator
57
Ilustración 48: Puerto general de entrada/salida digital
58
#include <util/delay.h> /* Contiene funciones de espera en ms y us
*/
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 básicas y no utilizan las interrupciones que el periférico
ofrece para indicar que los buffers de recepción y/o transmisión están vacíos/llenos, o si ha
detectado errores,… Este código sirve a modo de ejemplo para implementar una
funcionalidad similar a la que ofrece el módulo Arduino.
En el ANEXO 5, se puede ver como estas funciones han sido exportadas a una
librería, de modo que en futuros proyectos simplemente hay que incluirla indicando la
velocidad de transmisión deseada y llamar a las funciones de transmisión/recepción, de
manera que facilita enormemente el desarrollo y hace el código más legible:
/*
* Arduino_SERIAL_example.c
*/
#include <avr/io.h> /* Esta libreria contiene la definición 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
*/
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 código, cuando
ocurra la interrupción la CPU hará una pausa y pasará a ejecutar el código de la ISR. Tras
terminarlo, la CPU regresará a la tarea que estaba realizando antes de la interrupción, justo
donde la había suspendido.
Las interrupciones son disparadas (llamadas) por eventos del hardware del
microcontrolador. El evento puede ser algún 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 interrupción están relacionadas con la cantidad de recursos del
microcontrolador.
61
22 0x002A ADC ADC Conversion Complete
23 0x002C EE_READY EEPROM Ready
24 0x002E ANALOG_COMP Analog Comparator
25 0x0030 TWI 2-wire Serial Interface
26 0x0032 SPM_READY Store Program Memory Ready
Para entender cómo 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 interrupción el hardware guardará en la pila el valor actual del
Contador de Programa y lo actualizará con el valor del Vector de Interrupción respectivo.
De este modo la CPU pasará a ejecutar el código que se encuentre a partir de esa dirección.
Al final del código de la interrupción debe haber una instrucción de retorno que restaure el
Contador de Programa con el valor que se había guardado en la pila. La instrucción es
RETI. Esta instrucción la pone el compilador si le indicamos que la función ejecutada es
una interrupción.
Si se llegara a producir el evento excepcional en que se disparen dos o más
interrupciones al mismo tiempo, se ejecutarán las interrupciones en orden de prioridad.
Tiene mayor prioridad la interrupción cuyo Vector se ubique más abajo, es decir, entre
todas, la interrupción INT0 tiene siempre las de ganar.
62
Por otro lado, cada interrupción tiene un bit de notificación único. Este se pone a 1
automáticamente por hardware cuando ocurre el evento de dicha interrupción. Eso pasará
independientemente de si la interrupción está habilitada o no. Cada interrupción habilitada
y disparada, saltará a su correspondiente Función de Interrupción o ISR.
El bit de notificación se limpia automáticamente justo cuando se empieza a ejecutar
la función de interrupción. La única excepción es la interrupción de recepción de la
USART que se limpia automáticamente al leer el registro con el dato recibido. Este
comportamiento evita perder una interrupción mientras se está atendiendo a ella misma, ya
que al acabar volvería a ejecutarse la función al encontrarse de nuevo el bit de notificación
a 1.
Puesto que los bits de notificación se activan independientemente de si las
interrupciones están habilitadas o no, al momento de activarlas, puede ser necesario
limpiarlos manualmente para evitar entrar directamente por algún evento anterior. Para
borrar el bit de notificación se debe escribir un 1 en el bit respectivo.
Al ejecutarse la función de interrupción también se limpia por hardware el bit de
habilitación general para evitar que se disparen otras interrupciones cuando se esté
ejecutando la interrupción actual. Sin embargo, si queremos interrupciones recurrentes o
anidadas podemos poner a 1 el bit de habilitación general dentro de la ISR actual.
El bit de habilitación 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.
63
Desde la función principal, o en cualquier parte del código, podríamos consultar el
contenido del dato recibido sin depender de en qué momento nos han mandado el mensaje.
En el ANEXO 6 se puede ver un ejemplo completo de la librería para la
comunicación serie utilizando interrupciones de recepción para realizar un eco del dato
recibido y la recepción de “Ctr + x” para finalizar el programa.
64
Modo ISCx1 ISCx0 Evento de la Interrupción
3 1 1 Flanco de subida detectado en el pin INTx.
Como la mayoría de los registros, EICRA inicia con todos sus bits a cero lo que
significa que por defecto la interrupción INTx habilitada se disparará cuando dicho pin esté
a nivel bajo.
La interrupción 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 baterías, donde el microcontrolador y todos
sus periféricos están “parados” esperando un evento que lo despierte.
65
Registro de máscara Puerto
PCMSK0 PORTB
PCMSK1 PORTC
PCMSK2 PORTD
Otra forma de seleccionar los pines de interrupción es ubicándolos directamente por
sus nombres PCINTx.
PCMSK0 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
interrupción, se activará el bit de notificación respectivo PCIF (Pin Change Interrupt Flag)
del registro PCIFR y luego se llamará a la función de interrupción ISR . Así como hay un
bit de habilitación para cada puerto, también hay un bit de notificación para uno.
PCIFR --- --- --- --- --- PCIF2 PCIF1 PCIF0
66
TCCRxB --- --- --- --- --- CSx2 CSx1 CSx0
Los temporizadores tienen distintos modos de operación, 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 --- --- ---
67
llegando a desbordarse en 15,9375us en el caso de utilizar el 0 o el 2, ya que son de 8bits; o
en poco más de 4ms en el caso de usar el de 16bits.
Esta es la importancia del divisor. Si nosotros quisiéramos realizar una espera de 1
segundo nos quedaríamos fuera de escala. Si dividimos por 1024 obtenemos incrementos
del temporizador de 64us con lo que nos daría para contar hasta 16.320ms con 8bits o
4.18424 segundos con 16bits.
Esta configuración nos permite poder leer el estado del TCNTx en distintos
momentos. Sabiendo que tiempo ha transcurrido podemos implementar nuestra propia
función de espera, similar a la de la librería delay.
En este ejemplo se implementa el ejemplo del parpadeo del LED de nuestra placa
Arduino utilizando el timer 1 en lugar de usar la librería delay.h
/*
* Arduino_blink_timer.c
*
* Parpadeo del LED de Arduino cada 0.5seg usando timers en lugar de la
* libreria delay.h
*/
#include <avr/io.h>
DIVISOR NUM_CUENTAS
1 7999999
8 999999
64 124999
256 31249
1024 7811,5
int main(void)
{
//Definimos el pin13/PORTB5 como salida
DDRB |= (1<<PB5);
while(1){
PORTB |= (1<<PB5); //Enciende el LED
68
}
}
DIVISOR NUM_CUENTAS
1 7999999
8 999999
64 124999
256 31249
1024 7811,5
69
el contador alcance 31249 habrá transcurrido 0.5 seg (2 Hz)
*/
#define TIEMPO_A_ESPERAR (31249)
int main(void)
{
//Definimos el pin13/PORTB5 como salida
DDRB |= (1<<PB5);
while(1){
/*
* Ahora podemos implementar otras funcionalidades sin
* preocuparnos del parpadeo del LED, ya que se gestiona des
* de la interrupción del timer
*/
}
}
ISR(TIMER1_COMPA_vect){
PORTB ^= (1<<PB5); // Invertimos el estado del LED a cada ejecución
}
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 ejecución de nuestro programa.
70
Ilustración 49: Ejemplo de uso del temporizador en modo CTC
“Phase Correct” se podría 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
Ilustración 50: Generación PWM en modo “Fast PWM”
72
Ilustración 52: Generación PWM en modo “Phase and Frequency Correct PWM”
73
4.2.3.7 Uso del conversor ADC
El conversor analógico digital permite que convirtamos los niveles analógicos de
tensión a una representación digital. Esto nos permite leer cosas como la salida de un
potenciómetro, sensores de temperatura, sensores de humedad, acelerómetros y giroscopios
que tienen una tensión de salida analógica, sensores de presión y mucho más las cosas.
El ADC interno de nuestro microcontrolador tiene una resolución de 10 bits. Esto
significa que el voltaje de entrada se convierte en un valor numérico entre 0 y 1023. El
ATmega328P dispone de 6 pines que son capaces de ser utilizados como pines de entrada
analógicos pero sólo hay un ADC en el microcontrolador de modo que entre los pines y el
conversor hay un multiplexor analógico.
El ATmega se alimenta con 5v con lo que podemos conectar cualquier señal de entre
0 y 5V en la entrada. También podemos cambiar la tensión máxima que el ADC utiliza
como tensión de referencia, en el pin Aref.
Hay que tener en cuenta que la frecuencia máxima de trabajo del ADC es de 200Khz.
Esta se genera a partir del reloj del sistema de 16MHz y un divisor (2, 4, 8, 16, 32, 64 y
128). Dada la alta frecuencia a la que trabaja nuestro Arduino y la limitación del ADC,
solo podemos configurar el divisor a 128 y así obtener una frecuencia de trabajo del
conversor analógico de 125kHz. En caso de configurar una frecuencia mayor se pierde
mucha precisión. Por ejemplo a 250kHz (divisor a 64) la precisión esta alrededor de 8bits.
Por defecto el ADC está deshabilitado. Hasta que no lo habilitamos, la selección de
la tensión de referencia o de canal, no surge ningún efecto. Para reducir el consumo se
recomienda deshabilitarlo cuando no se necesite o antes de entrar en modos de bajo
consumo.
A continuación podemos ver un ejemplo básico donde va convirtiendo cíclicamente
las distintas entradas analógicas:
#include <avr/io.h>
int adc_value[5]; //Valor leido del ADC
int main(void) {
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 conversión
while(ADCSRA & (1<<ADSC)); //Esperamos a finalizar la
conversión
adc_value[channel] = ADCW; //Guardamos el valor de la
conversión
}
}
return 0;
}
74
4.2.4 Codificación del medidor de caudal en C
Una vez revisados los periféricos que necesitamos para realizar el caudalímetro
vamos a proceder a ensamblar las distintas partes de código que hemos visto.
Para controlar la pantalla LCD se utilizará la librería que nos proporciona el
fabricante como ya hicimos con el proyecto de Arduino. Esta librería está escrita en C++
cosa que nos obliga a crear un proyecto C++ en AVRStudio.
El hecho de crear un proyecto en C++ tiene muy poco impacto para nosotros. Solo
que si queremos aprovechar, a modo de librería, parte del código que hemos creado en C,
deberemos incluirlo dentro de un bloque indicando que es C.
extern "C" { /* Indica que la librería es en C */
#include "Arduino_SERIAL_Api.h" /* Contiene funciones para trabajar con
la comunicación serie */
}
/* Librería en C++ */
#include "ColorLCDShield.h"
Para desligar la librería del fabricante del entorno Arduino, y evitar dependencias
durante la compilación, la editaremos comentando la inclusión de “Arduino.h” y
corrigiendo los errores de dependencias añadiendo las librerías necesarias del entorno
AVRStudio, como por ejemplo math.h o delay.h.
La única librería 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 definición de los puertos de entrada y salida, y nos ahorra el tener que
redefinirlos dentro de la propia librería.
En el ANEXO 7 se puede ver la codificación del medidor de caudal en C++ así como
las librerías usadas.
Si utilizamos librerías de terceros es importante cambiar las opciones del compilador
y del enlazador (linker) para que el binario generado sea lo más optimo posible.
Las siguientes opciones del compilador fuerzan al compilador a alojar cada función
en una sección de memoria interna separada.
-ffunction-sections
-fdata-sections
Con las opciones del compilador anteriores y la siguiente opción del enlazador
(linker) le indicamos que no incluya las funciones que no se utilizan.
Estas opciones son de gran ayuda para reducir tamaño en memoria al usar librerías
genéricas 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 pestaña donde veremos las opciones de
configuración de nuestro proyecto. En la pestaña “ToolChain” encontraremos las
configuraciones del compilador C, del C++ y del enlazador (linker).
75
Ilustración 54: Configuración opciones de optimización del compilador
76
Ilustración 56: Resultado de la construcción del proyecto en AVRStudio
El propio entorno de compilación del AVR-GCC nos proporciona una herramienta
que determina las necesidades de memoria flash y RAM de un fichero .elf. Este fichero es
el binario a descargar. Este también contiene toda la información de depuración y la
distribución de la memoria.
Ejecutando esta herramienta sobre el fichero que hemos generado con el AVRStudio
obtenemos el siguiente resultado:
avr-size.exe -C --mcu=atmega328p medidorCaudal_AVR.elf
AVR Memory Usage
----------------
Device: atmega328p
77
Se puede observar que al desarrollar en C y teniendo mayor control sobre las
opciones a aplicar al compilador y al enlazador (linker) conseguimos usar un 10% menos
de memoria, tanto flash como RAM.
5 Presupuesto
En este presupuesto se pretende mostrar el coste de la realización del proyecto en sí
mismo, pero diferenciando claramente el coste de realizarlo en entorno Arduino y en
AVRStudio y C.
El objetivo es poder ver de una forma clara la diferencia en la curva de aprendizaje
de Arduino vs AVRStudio.
78
5.2.2 Capítulo 2: Diseño y montaje del hardware
CÓDIGO UD DESCRIPCIÓN CANTIDAD PRECIO SUBTOTAL
IT001 h Ingeniero Técnico Industrial 20,00 25,00 500,00
HW001 u Arduino UNO con ATMega328 1,00 21,90 21,90
HW002 u Arduino Shield LCD Color Sparkfun 1,00 32,90 32,90
HW003 u Koolance INS-FM17N Coolant 1,00 25,87 25,87
Flow Meter for LCS
HW004 u Tira de pines macho 40 pines paso 0,25 0,53 0,13
2,54 mm
HW005 u Rollo de cable de 10Mts sección 0,25 2,70 0.68
0,5 mm2
79
Implementación de aplicación en
Python
IT001 h Ingeniero Técnico Industrial. 25,00 25,00 625,00
Testeo y corrección de errores
80
6 Conclusiones y valoración personal
El objetivo principal de este PFC ha sido conocer Arduino a través del montaje de un
caudalímetro. Después de realizar este proyecto se puede concluir que Arduino es una muy
buena plataforma para realizar pequeños proyectos de sistemas basados en
microcontrolador.
La curva de aprendizaje de Arduino es realmente rápida. Dispone de gran cantidad
de documentación 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 distribución, 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 pequeños y a un coste muy reducido.
El hecho de haber definido una manera estándar de crear extensiones, las shields, ha
permitido crear una gran cantidad de placas accesorias para cubrir la mayoría de
necesidades habituales en proyectos de electrónica. Estas extensiones se consiguen a través
de los mismos canales de distribución. Estas suelen entregarse con ejemplos de uso o
incluso librerías de código integrables en el entorno Arduino, con lo que amplifican mucho
el potencial de la plataforma.
El nivel de abstracción de cómo funcionan los circuitos electrónicos 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 librerías
o por la funcionalidad de la circuitería de la que dispones.
El desempeño de estas librerías o extensiones no siempre es el más ó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 realización del proyecto. En cualquier caso, siempre podemos crear nuestras
propias librerías, dando así soporte a nuevas funcionalidades o mejoras de rendimiento. En
estos casos sí que es necesario un mayor nivel de conocimientos de electrónica o de
programación, pero el alcanzar este nivel puede hacerse de un modo muy progresivo.
Enlazando con el segundo objetivo que nos habíamos marcado en la realización 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 fáciles 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 generación de un PWM o
lecturas analógicas. Esto permite poder introducir conceptos de programación y algoritmia
a niveles de educación 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 electrónica
o programación 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 podría decir que tiene un bajo coste por el
rendimiento que puede ofrecer.
81
En ámbitos más técnicos o superiores, la plataforma ofrece la posibilidad seguir
aprendiendo implementando nuestras propias librerías. Esto obliga a tener un mayor
conocimiento de los dispositivos con los que se va a trabajar.
Si queremos abandonar las herramientas software que nos proporciona Arduino, el
propio fabricante del microcontrolador ofrece un gran número de herramientas para
permitir el desarrollo ensamblador, C y C++. Esto permite que sobre el mismo hardware
Arduino se pueda aprender cómo funciona un microcontrolador des de cero, ofreciendo
una plataforma continuista hacia nuevos niveles de conocimiento.
Las placas Arduino, el microcontrolador usado en estas y el conjunto de recursos
gratuitos disponibles, permiten aprender todo lo relativo a un proyecto de electrónica y
software embebido de una manera progresiva y sin perder visibilidad en ningún punto. Se
puede definir un camino formativo que pase des del diseño de la placa, su funcionalidad y
el algoritmo de control; hasta las optimizaciones del compilador, la definición del mapa de
memoria o todo el proceso de construcción (make).
Ha sido muy enriquecedor trabajar y conocer una plataforma tan versátil y fácil de
usar como Arduino. Siempre aparecen contratiempos pero son fáciles de superar gracias a
la gran comunidad que existe. El potencial de la plataforma es enorme y las limitaciones
iniciales del software Arduino se pueden superar fácilmente al poder trabajar en C.
Es realmente una plataforma muy recomendable para todo aquel que tenga una
mínima inquietud para hacerse el mismo las cosas. DIY!!!
82
ANEXOS
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.
void clear(int color); - Clears the entire screen, filling it with the 12-
bit RGB color passed to it. There are a number of predefined colors in
ColorLCDShield.h
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
available in this library. Definitely room for growth, though at an added
cost of memory.
void setStr(char *pString, int x, int y, int fColor, int bColor); - Sets a
string of characters down, beginning at x/y coordinates. You can pick both
the foreground and background color, they're 12-bit RGB values. Only one
font is available in this library. Definitely room for growth, though at an
added cost of memory.
void setLine(int x0, int y0, int x1, int y1, int color); - Draws a line from
x0,y0 to x1,y1. Color is a 12-bit RGB value.
void setRect(int x0, int y0, int x1, int y1, unsigned char fill, int color);
- Draws a rectangle with opposing corners at x0,y0 and x1,y1. A 1 for fill
will fill the entire rectangle, a 0 will only draw the border. Color is a
12-bit RGB value.
void off(void); - Turns the display off. You'll still see the backlight on!
84
Ilustración 58: Modificación del fichero ColorLCDShield.cpp. 2da parte
En el fichero ColorLCDShield.h se ha definido el nuevo tipo de fuente:
const unsigned char FONT8x8[97][8] = {
{0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows,
num_bytes_per_char
{0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows,
num_bytes_per_char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space 0x20
{0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // !
{0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // "
{0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // #
{0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $
{0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // %
{0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // &
{0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // '
{0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // (
{0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // )
{0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // *
{0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // ,
{0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // .
{0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // / (forward slash)
{0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0 0x30
{0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1
{0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2
{0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3
{0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4
{0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5
{0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6
{0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7
{0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8
{0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ;
{0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // <
{0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // =
{0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // >
{0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ?
{0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @ 0x40
{0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A
{0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B
{0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C
{0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D
85
{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 0x50
{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}, // \ (back slash)
{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}, // ` 0x60
{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 0x70
{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} // ~
};
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 constantes usadas para las interrupciones
*/
const byte caudalInt = 0; // 0 = pin 2; 1 = pin 3
const byte caudalPin = 2;
const byte caudalGNDPin = 6;
/*
* 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
* Funcion de inicializacion del sistema
*/
void setup()
{
/* Configuracion puerto serie (USB) */
Serial.begin(9600);
Serial.println("Empecemos...");
/*
* Funcion principal
*/
void loop()
{
unsigned long currentMillis = millis();
/* Variables para gestion del anti rebote (debouncing) de los botones */
static byte boton0 = 0;
static byte boton1 = 0;
static byte boton2 = 0;
88
if (boton1 < 255){ // Control de rangos
boton1++;
}
}else{ // No pulsado
if (boton1 > botonAntirebote){ // Ha estado pulsado al menos
"botonAntirebote" veces
/* Ponemos a zero el contador parcial 1 */
contadorSegundosParcial_1 = 0;
litrosParcial_1 = 0.0;
}
boton1 = 0;
}
if (!digitalRead(lcdBotones[2])){ // Pulsado
if (boton2 < 255){ // Control de rangos
boton2++;
}
}else{ // No pulsado
if (boton2 > botonAntirebote){ // Ha estado pulsado al menos
"botonAntirebote" veces
lcd.clear(WHITE); // Limpiamos la pantalla
pantalla++; // Cambiamos la pantalla a mostrar
if (pantalla > numeroPantallas){
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()
{
float litrosUltimoMinuto;
/* Inicio zona segura intercambio de datos. No hay interrupciones */
noInterrupts();
contadorPulsosLocal = contadorPulsos;
contadorPulsos = 0; // Se escribe el la interrupción y se limpia una vez
leido
interrupts();
/* Fin zona segura intercambio de datos */
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);
/*
* 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);
/*
90
* Pantalla contadores parciales 2
*/
void pantalla_parcial_2()
{
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);
/*
* Funcion llamada por la interrupcion 0 a cada deteccion de flanco de
bajada
* del caudalimetro.
*/
void isr_caudalimetro()
{
contadorPulsos++; // Incrementamos el contador de pulsos
}
Note: press Enter in the 'manual' text box to make a new value
affect the plot.
91
import serial
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
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)
self.SetSizer(sizer)
sizer.Fit(self)
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
m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
self.Bind(wx.EVT_MENU, self.on_exit, m_exit)
self.menubar.Append(menu_file, "&File")
self.SetMenuBar(self.menubar)
def create_main_panel(self):
self.panel = wx.Panel(self)
self.init_plot()
self.canvas = FigCanvas(self.panel, -1, self.fig)
self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)
self.hbox1.Add(self.pause_button, border=5, flag=wx.ALL |
wx.ALIGN_CENTER_VERTICAL)
self.hbox1.AddSpacer(20)
self.hbox1.Add(self.cb_grid, border=5, flag=wx.ALL |
wx.ALIGN_CENTER_VERTICAL)
self.hbox1.AddSpacer(10)
self.hbox1.Add(self.cb_xlab, border=5, flag=wx.ALL |
wx.ALIGN_CENTER_VERTICAL)
self.hbox2 = wx.BoxSizer(wx.HORIZONTAL)
self.hbox2.Add(self.xmin_control, border=5, flag=wx.ALL)
self.hbox2.Add(self.xmax_control, border=5, flag=wx.ALL)
self.hbox2.AddSpacer(24)
self.hbox2.Add(self.ymin_control, border=5, flag=wx.ALL)
self.hbox2.Add(self.ymax_control, border=5, 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)
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)
self.plot_data.set_xdata(np.arange(len(self.data)))
self.plot_data.set_ydata(np.array(self.data))
self.canvas.draw()
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
def on_redraw_timer(self, event):
# if paused do not add data, but still redraw the plot
# (to respond to scale modifications, grid change, etc.)
#
if not self.paused:
self.data.append(self.dataget.next())
self.draw_plot()
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = GraphFrame()
app.frame.Show()
app.MainLoop()
Contenido de “Upload.cmd”
@ECHO OFF
cls
Set micro=ATMEGA328P
REM Chequeamos los argumentos de la linea de comandos
If "%~1"=="" goto NoParam
If "%~2"=="" goto NoParam
If NOT "%~3"=="" goto Error
Set port=%~1
Set file=%~2
Goto CheckPort
:NoParam
Set /P port=Introduce el puerto serie al que esta conectado el Arduino
[COM3]:
If "%port%"=="" goto Error
Set /P file=Introduce el binario a descargar:
If "%file%"=="" goto Error
Goto CheckPort
:CheckPort
IF /I NOT %port:~0,3%==COM GOTO Error
Goto Execute
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 añade AVRStudio en el path de donde se
encuentra nuestro proyecto
set folder=%~1
set folder=%folder:~0,-1%
set fileNameWithExt=%~2
REM Eliminamos la extensión 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
Ilustración 59: Configuración de una herramienta externa en AVRStudio
En el cuadro de dialogo que se nos aparece, debemos usar el botón “Add” y rellenar
los siguientes campos de este modo:
Title: El nombre que le queramos poner a la herramienta, en mi caso:
Program Arduino Debug
Command: Ruta completa de donde tengamos el fichero
“uploadFromAVRStudio.cmd” que hemos creado anteriormente, en mi caso:
d:\Mis documentos\Documents\My Dropbox\Arduino\Code\AVRStudio
5.1\ArduinoUpload\uploadFromAVRStudio.cmd
Arguments: Aquí utilizamos las variables que tiene configuradas el propio
AVRStudio para indicarle al fichero por lotes donde se encuentra el fichero a
descargar, el nombre que tiene, si utilizamos una compilación “Debug” o
“Release” y el puerto en que se encuentra nuestro puerto serie. En mi caso:
$(SolutionDir) $(SolutionFileName) Debug COM12
Una vez tenemos esto, podemos añadir esta llamada a la barra de herramientas, de
modo que tendríamos un acceso parecido al que ofrece el propio entorno Arduino.
Pulsamos con el botón izquierdo del ratón sobre el desplegable de la barra de
herramientas del AVRStudio, seleccionado “Customize…”
99
Ilustración 60: Vista para crear un botón para las herramientas externas en AVRStudio
Una vez dentro de las opciones, debemos añadir un nuevo comando, y seleccionar
“External Command 1” o la posición en la que hayamos definido nuestra “external tool”.
100
Ilustración 62: Cuadro de opciones para botón en la barra de herramientas. II
Donde obtendremos como resultado un nuevo botón para programar nuestro Arduino
de manera cómoda y sin tener que salir del AVRStudio.
Contenido de “Arduino_SERIAL_API.h”
Este es el contenido de la API se ha creado para poder interactuar con la
comunicación serie en C de un modo cómodo.
/*
* Arduino_SERIAL_API.h
*/
101
Contenido de “Arduino_SERIAL.c”
/*
* Arduino_SERIAL.c
*/
#include <avr/io.h> /* Esta libreria contiene la definición de
todos los registros, SIEMPRE DEBE SER INCLUIDA */
#include "Arduino_SERIAL_Api.h"
102
ANEXO 6: Comunicación serie con interrupciones de recepción
Contenido de “Arduino_SERIAL_INTRx_API.h”
Este es el contenido de la API se ha creado para poder interactuar con la
comunicación serie en C de un modo cómodo.
/*
* Arduino_SERIAL_INTRx_API.h
*/
#include <avr/interrupt.h>
Contenido de “Arduino_SERIAL_INTRx.c”
/*
* Arduino_SERIAL_INTRx.c
*/
#include <avr/io.h> /* Esta libreria contiene la definición de
todos los registros, SIEMPRE DEBE SER INCLUIDA */
#include "Arduino_SERIAL_INTRx_Api.h"
103
void SERIAL_Transmit( unsigned char data ) {
/* Esperamos a vaciar el buffer de transmisión */
while ( !( UCSR0A & (1<<UDRE0) ) );
/* Ponemos el dato en el buffer y mandamos el dato */
UDR0 = data;
}
Contenido de “Arduino_SERIAL_INTERRUPT_example.c”
/*
* Arduino_SERIAL_INTERRUPT_example.c
*/
#include <avr/io.h> /* Esta libreria contiene la definición 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
*/
read = 0;
while(read != 0x18){ /* Para salir Ctr + x */
/* Solo romperemos este bucle des de la interrupción de recepción */
}
return 0;
}
104
ISR(USART_RX_vect)
{
read = SERIAL_Receive();
SERIAL_Transmit(read); /* Mandamos lo que recivimos a modo de eco */
}
Contenido de “medidorCaudal_AVR.cpp”
/*
* Medidor de caudal
*
* Recibe una serie de pulsos proporcionales al caudal detectado por un
caudalimetro
* 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.
*
* Este codigo esta implementado en C y no utiliza las "facilidades" del
entorno Arduino
*/
/*
* Importación de librerias
*/
#include <avr/io.h> /* Esta libreria contiene la definición
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 "string.h"
#include "stdlib.h"
#include "math.h"
#include <util/delay.h> /* Contiene funciones de espera en ms y
us */
#include <avr/interrupt.h>
#include "ColorLCDShield.h"
extern "C" {
/* Importamos las librerias definidas en C */
#include "Arduino_SERIAL_Api.h" /* Contiene funciones para trabajar
con la comunicación serie */
}
/*
* Variables y constantes usadas para el LCD
*/
static LCDShield lcd; // Objeto LCD
#define LCD_CONTRASTE (40) // Valor del contraste par el LCD
char lcdStr[16]; // Cadena usada para mostrar textos en el LCD
#define LIMITE_ANTIRREBOTE (10) // Numero de veces que se debe leer
un valor estable en los botones
/*
* Variables y constantes usadas para el temporizado
*/
/* NUM_CUENTAS = (((F_CPU / DIVISOR) / F_DESEADA) - 1) */
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 // Máximo del contador de 16bits
#error El tiempo a esperar es demasiado grande
#endif
volatile unsigned char segundos = 0; // Se actualiza en la interrupción
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
/*
* Definición 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);
/*
* Definición de funciones
*/
/*
* Función 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
/*
* Inicialización de periféricos (puerto serie, timer, LCD e
interrupciones)
*/
void inicializacion(void){
/* Configuramos la comunicación serie */
SERIAL_Init();
SERIAL_PutString("Empecemos...");
/*
* 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;
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
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);
/*
* 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);
/*
* 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
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);
/*
* Incrementa el contador de segundos
*/
ISR(TIMER1_COMPA_vect){
segundos++;
}
/*
* Incrementa el contador de pulsos
*/
ISR(INT0_vect){
contadorPulsos++;
}
#ifndef ColorLCDShield_H
#define ColorLCDShield_H
#define PHILLIPS 0
#define EPSON 1
#include <inttypes.h>
/* Para aseguranos que trabajamos con la frequencia correcta para nuestro
Arduino */
#ifdef F_CPU
110
#undef F_CPU
#endif
#include "math.h"
#define F_CPU 16000000UL
#include <util/delay.h> /* Contiene funciones de espera en ms y us
*/
#define delayMicroseconds(x) _delay_us(x)
#define delay(x) _delay_ms(x)
111
Ilustración 64: Estructura de carpetas del soporte digital
112
Bibliografía y referencias
Bibliografía
Arduino team. Arduino homepage [En línea] Página web del equipo de
Arduino [Fecha consulta: 01-01-2012] [Acceso gratuito] <http://arduino.cc/>
Wikipedia. Arduino [En línea] Enciclopedia digital [Fecha consulta: 01-01-
2012] [Acceso gratuito] <http://es.wikipedia.org/wiki/Arduino>
Arduino team. Arduino Uno. [En línea] Artículo digital [Fecha consulta: 01-
01-2012] [Acceso gratuito] <http://arduino.cc/en/Main/ArduinoBoardUno>
HeKilledMyWire. How to start using AvrStudio, C code and Arduino. [En
línea] Artículo digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://hekilledmywire.wordpress.com/2010/12/04/22/>
Arduino team. Referencia del Lenguaje [En línea] Artículo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/es/Reference/HomePage>
tronixstuff, Arduino Tutorials [En línea] Artículo digital [Fecha consulta: 01-
01-2012] [Acceso gratuito] <http://tronixstuff.wordpress.com/tutorials/>
www.EarthshineElectronics.com, A Complete Beginners Guide to the
Arduino [En línea] Artículo digital [Fecha consulta: 10-02-2012] [Acceso
gratuito] <http://www.earthshineelectronics.com/files/ASKManualRev5.pdf>
Atmel Corporation, AVR Studio 5 Overview [En línea] Artículo 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>
Atmel Corporation, ATmega328P [En línea] Artículo digital [Fecha consulta:
10-01-2012] [Acceso gratuito]
<http://www.atmel.com/dyn/products/product_card.asp?PN=ATMEGA328P
#datasheets>
cursomicros.com, Las Interrupciones en los AVR [En línea] Artículo digital
[Fecha consulta: 20-05-2012] [Acceso gratuito]
<http://www.cursomicros.com/avr/interrupciones/interrupciones.html>
EngBlaze, Tutorial: Using AVR Studio 5 with Arduino projects [En línea]
Artículo digital [Fecha consulta: 10-03-2012] [Acceso gratuito]
<http://www.engblaze.com/tutorial-using-avr-studio-5-with-arduino-
projects/>
tty1.net, Optimisations of AVR programs using avr-gcc [En línea] Artículo
digital [Fecha consulta: 12-06-2012] [Acceso gratuito]
<http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html>
Practical Arduino, Projects [En línea] Artículo digital [Fecha consulta: 01-08-
2012] [Acceso gratuito] < http://www.practicalarduino.com/projects/water-
flow-gauge>
113
Teague Labs, DIY Arduino Water Meter [En línea] Artículo digital [Fecha
consulta: 15-11-2011] [Acceso gratuito] <http://labs.teague.com/?p=722>
Referencias
[1] Arduino team. Arduino homepage [En línea] Página web del equipo de
Arduino [Fecha consulta: 10-11-2011] [Acceso gratuito] <http://arduino.cc/>
[2] Wiring programming framework, Homepage [En línea] Artículo digital
[Fecha consulta: 10-11-2011] [Acceso gratuito] <http://wiring.org.co/>
[3] Processing programming language, Homepage [En línea] Artículo digital
[Fecha consulta: 10-11-2011] [Acceso gratuito]
<http://www.processing.org/>
[4] Definition of free cultural works, OSHW [En línea] Artículo digital [Fecha
consulta: 10-11-2011] [Acceso gratuito] <http://freedomdefined.org/OSHW >
[5] Creative Commons, Attribution-ShareAlike 2.5 Generic [En línea] Artículo
digital [Fecha consulta: 10-11-2011] [Acceso gratuito]
<http://creativecommons.org/licenses/by-sa/2.5/>
[6] Parallax Inc, The BASIC Stamp [En línea] Artículo digital [Fecha consulta:
10-11-2011] [Acceso gratuito]
<http://www.parallax.com/tabid/295/Default.aspx>
[7] BasicX, Home [En línea] Artículo digital [Fecha consulta: 10-11-2011]
[Acceso gratuito] <http://www.basicx.com/>
[8] Phidgets, Products for USB Sensing and Control [En línea] Artículo digital
[Fecha consulta: 10-11-2011] [Acceso gratuito] <http://www.phidgets.com/ >
[9] The Handy Board, About [En línea] Artículo digital [Fecha consulta: 10-11-
2011] [Acceso gratuito] <http://handyboard.com/hb/about/>
[10] Freeduino, Home [En línea] Artículo digital [Fecha consulta: 10-11-2011]
[Acceso gratuito] <http://www.freeduino.org/>
[11] Arduino team. Arduino compatible hardware [En línea] Artículo digital
[Fecha consulta: 10-11-2011] [Acceso gratuito]
<http://www.arduino.cc/playground/Main/SimilarBoards#goArdComp>
[12] Arduino team. Hardware [En línea] Artículo digital [Fecha consulta: 10-11-
2011] [Acceso gratuito] <http://www.arduino.cc/en/Main/hardware>
[13] Digi, XBee-PRO 802.15.4 OEM RF Modules [En línea] Artículo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://www.digi.com/products/wireless-wired-embedded-solutions/zigbee-
rf-modules/point-multipoint-rfmodules/xbee-series1-module#overview>
[14] Arduino team. Hardware for connecting to Arduino [En línea] Artículo
digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://www.arduino.cc/playground/Main/SimilarBoards#goConn>
[15] NonGNU, AVR Libc Home Page [En línea] Artículo digital [Fecha consulta:
01-01-2012] [Acceso gratuito] <http://www.nongnu.org/avr-libc/>
114
[16] Arduino team. Libraries [En línea] Artículo digital [Fecha consulta: 01-01-
2012] [Acceso gratuito] <http://arduino.cc/en/Reference/Libraries>
[17] Arduino team. Writing a Library for Arduino [En línea] Artículo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/en/Hacking/LibraryTutorial>
[18] Sparkfun electronics, Color LCD Shield [En línea] Artículo 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 línea]
Artículo digital [Fecha consulta: 15-08-2012] [Acceso gratuito] <
http://koolance.com/files/products/manuals/manual_ins-
fm17,18_d130eng.pdf>
[20] RC Electronic World, ARDUIMU V2 QUADROTOR [En línea] Artículo
digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://www.rcelectronicworld.co.cc/p/quadrotor.html>
[21] Android Arduino Handbag, Main [En línea] Artículo 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 línea] Artículo
digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/en/Guide/Windows>
[23] Arduino team. Placa Arduino monocapa [En línea] Artículo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/es/Main/ArduinoBoardSerialSingleSided3>
[24] BricoGeek, Tienda [En línea] Artículo digital [Fecha consulta: 01-01-2012]
[Acceso gratuito] <http://www.bricogeek.com/shop/>
[25] Electan, electrónica y robótica, Home [En línea] Artículo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito] <http://www.electan.com>
[26] Proyecto Arduino, Download the Arduino Software [En línea] Artículo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/en/Main/Software>
[27] SourceForge, WinAVR [En línea] Artículo digital [Fecha consulta: 01-01-
2012] [Acceso gratuito] <http://winavr.sourceforge.net/index.html>
[28] Proyecto Arduino, Referencia del Lenguaje [En línea] Artículo digital [Fecha
consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/es/Reference/HomePage>
[29] Sección de tutorials de TronixStuff, Título [En línea] Artículo 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 línea] Artículo digital [Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://www.earthshineelectronics.com/files/ASKManualRev5.pdf>
115
[31] Arduino playground wiki, Libraries for Arduino [En línea] Artículo digital
[Fecha consulta: 01-01-2012] [Acceso gratuito]
<http://arduino.cc/playground/Main/LibraryList>
[32] Página web de Koolance, Flow meters [En línea] Artículo digital [Fecha
consulta: 01-12-2011] [Acceso gratuito] <http://www.koolance.com/water-
cooling/product_info.php?product_id=740>
[33] Tienda Tecniolid, CAUDAL LAVAVAJILLAS - Caudalimetro [En línea]
Artículo 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 línea] Artículo digital [Fecha
consulta: 01-12-2011] [Acceso gratuito] <http://stores.ebay.com/HELLFIRE-
TOYZ-LLC>
[35] Sparkfun electronics, Nokia LCD Display Driver [En línea] Artículo 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 Kaufman’s blog, How to fix it: Backlight on SparkFun’s Color LCD
Shield not working [En línea] Artículo digital [Fecha consulta: 01-01-2012]
[Acceso gratuito] <http://richardkaufman.org/blog/how-to-fix-it-backlight-
on-sparkfuns-color-lcd-shield-not-working>
[37] Atmel, Main [En línea] Artículo digital [Fecha consulta: 01-01-2012]
[Acceso gratuito] <http://www.atmel.com/>
[38] AVR freaks forum, GCC and the ROGMEM Attributes [En línea] Artículo
digital [Fecha consulta: 20-07-2012] [Acceso gratuito]
<http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=
38003>
116