ejemplo de aplicación con arduino: medida de caudal

116
Ejemplo de aplicación con Arduino: medida de caudal. TITULACIÓN: Ingeniería Técnica Industrial en Electrónica Industrial AUTOR: Josep Fernandez Daroca DIRECTOR: José Luís Ramírez Falo FECHA: Septiembre / 2012.

Upload: lykien

Post on 06-Jan-2017

231 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Ejemplo de aplicación con Arduino: medida de caudal

Ejemplo de aplicación con Arduino: medida de caudal.

TITULACIÓN: Ingeniería Técnica Industrial en Electrónica Industrial

AUTOR: Josep Fernandez Daroca

DIRECTOR: José Luís Ramírez Falo

FECHA: Septiembre / 2012.

Page 2: Ejemplo de aplicación con Arduino: medida de caudal

2

Índice de contenido

1 OBJETIVO DEL PFC ................................................................................................................. 6

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

Page 3: Ejemplo de aplicación con Arduino: medida de caudal

3

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

Page 4: Ejemplo de aplicación con Arduino: medida de caudal

4

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

Page 5: Ejemplo de aplicación con Arduino: medida de caudal

5

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

Page 6: Ejemplo de aplicación con Arduino: medida de caudal

6

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

2.1 Introducción a Arduino

La mayor parte de esta sección es una recopilación de la información disponible en la

página web del proyecto Arduino y de la entrada de la Wikipedia que hace referencia a

Arduino.

2.1.1 ¿Qué es Arduino?

“Arduino es una plataforma de electrónica abierta para la creación de

prototipos basada en software y hardware flexibles y fáciles de usar. Se creó

para artistas, diseñadores, aficionados y cualquiera interesado en crear entornos

u objetos interactivos.”(Página principal de la web del proyecto Arduino [1])

Arduino es una plataforma de hardware libre (Open Source Hardware, OSHW)

basada en una placa con un microcontrolador y un entorno de desarrollo.

El hardware consiste en una placa con un microcontrolador Atmel AVR y varios

puertos de entrada/salida, tanto digitales como analógicos, así como salidas PWM y de

comunicaciones, para el control de objetos físicos (LEDs, servos, botones, etc.).

Los microcontroladores más usados son el ATmega328 y el ATmega168 para las

placas básicas, el ATmega1280 para la de mayor capacidad y el ATmega8 para las placas

más antiguas. Todos estos microcontroladores incluyen un cargador de arranque (boot

loader) de manera que sea lo más simple posible empezar a trabajar con ellos.

El microcontrolador en la placa Arduino se programa mediante el lenguaje de

programación Arduino (basado en Wiring[2]) y el entorno de desarrollo Arduino (basado

en Processing[3]).

2.1.2 ¿Qué significa que Arduino sea Open Hardware?[4]

El hardware open-source (de fuente abierta o libre) comparte muchos de los

principios y metodologías del software libre y de código abierto.

Algunos de los principios que se pretenden promover para considerar productos

físicos como open hardware son los siguientes:

Page 7: Ejemplo de aplicación con Arduino: medida de caudal

7

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.

Cumpliendo con estas premisas, los diseños y esquemas de Arduino se distribuyen

bajo licencia “Creative Commons Attribution-ShareAlike 2.5”[5].

Al seguir este tipo de licencias, donde toda la información es pública, todas las

placas pueden ser construidas por uno mismo o bien comprarlas ya montadas. El software

puede ser descargado de forma gratuita. Los ficheros de diseño de referencia (CAD), al

estar disponibles bajo una licencia abierta, pueden ser libremente adaptados a las

necesidades particulares.

2.1.3 ¿Por qué Arduino?

Hay distintas soluciones comerciales que facilitan el trabajo de programar un

microcontrolador y poder interactuar con ellos, como podrían ser Parallax Basic Stamp[6],

BX-24 de Netmedia[7], Phidgets[8] o Handyboard del MIT[9] por citar algunos.

Arduino, además de simplificar este proceso intenta ofrecer otras ventajas:

Asequible – Las placas Arduino son más asequibles comparadas con otras

plataformas de microcontroladores. La versión más cara de un modulo de

Arduino puede ser montada a mano, e incluso ya montada cuesta bastante

menos de 60€

Multi-Plataforma - El software de Arduino funciona en los sistemas

operativos Windows, Macintosh OSX y Linux. La mayoría de los entornos

para microcontroladores están limitados a Windows.

Entorno de programación simple y directo - El entorno de programación

de Arduino es fácil de usar para principiantes y lo suficientemente flexible

para los usuarios avanzados.

Software ampliable y de código abierto - El software Arduino esta

publicado bajo una licencia libre, y preparado para ser ampliado por

programadores experimentados. El lenguaje puede ampliarse a través de

Page 8: Ejemplo de aplicación con Arduino: medida de caudal

8

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.

2.2 Las placas Arduino

2.2.1 ¿Qué significa que una placa sea Arduino?

Ilustración 1: Logo oficial de Arduino

“Arduino” es el nombre del proyecto “microcontrolador Arduino oficial”, alojado en

http://arduino.cc. Aunque el nombre "Arduino" no está oficialmente registrado,

generalmente es respetado por la comunidad como propiedad del equipo Arduino.

Al tratarse de OSHW existen multitud de proyectos y placas basadas en Arduino que

pueden ser totalmente compatibles con este, o que han sufrido ligeras modificaciones, ya

sea para hacerlas especificas para ciertos trabajos o bien para reducir su coste.

"Freeduino"[10] es un nombre que identifica las variantes del proyecto Arduino que

no fueron creadas por el equipo oficial de desarrollo Arduino.

Algunos de estos freeduinos serian Boarduino, uDUINO, iDuino, ArduPilot,...[11]

2.2.2 Placas de entradas y salidas

Existe una gran variedad de placas Arduino, y de todas ellas se han hecho varias

revisiones.

Page 9: Ejemplo de aplicación con Arduino: medida de caudal

9

Ilustración 2: En la parte superior Arduino MEGA y en la inferior Arduino UNO

Las placas Arduino oficiales a día de hoy son[12]:

Arduino UNO.

Es una placa Arduino que se conecta al PC a través de un cable USB estándar.

A través de esta conexión la alimentación y, además, permite programarla y

utilizarla.

Arduino UNO es la última revisión de este tipo de placas que se conectan al

USB. Entre las múltiples revisiones que se han hecho encontraríamos la

Duemilanove, Diecimila, NG (Nuova Generazione) o Extreme.

Arduino Mega

Es una placa Arduino similar a la USB, pero más grande y potente. La última

revisión posee el chip ATmega2560. Tiene mayor número de pines de entradas

y salidas digitales, más pines PWM, entradas analógicas, etc.

Arduino Mega ADK

El Arduino ADK es una placa similar al Arduino Mega, pero con una interface

USB para conectar con teléfonos basados en Android.

Arduino Pro

Es una placa similar al Arduino UNO, pero diseñada con la intención de

instalaciones semipermanentes. La placa se entrega sin los distintos conectores

o “headers”, es compatible con las distintas extensiones de Arduino, y existe

una versión de 3.3V para ser alimentado con baterías.

Arduino Ethernet

Similar al Arduino UNO, sin soporte USB, pero con un conector RJ-45 para dar

soporte Ethernet. Existe la posibilidad de tomar la alimentación de la propia

Ethernet.

Arduino Fio

Un Arduino orientado para usarlo como nodo inalámbrico. Posee conectores

para un módulo Xbee (módulo inalámbrico)[13], un conector para una batería

LiPo (Polímeros de litio), y un circuito para cargar la batería.

Arduino LilyPad

Page 10: Ejemplo de aplicación con Arduino: medida de caudal

10

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).

2.2.3 "Shields" y otras placas de terceros

Las shields son placas que se colocan encima de la placa Arduino y que amplían una

nueva función para que sea controlada desde Arduino, para controlar diferentes aparatos,

adquirir datos, etc.

Ilustración 3: Arduino con tres "shields"

Page 11: Ejemplo de aplicación con Arduino: medida de caudal

11

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.

Ilustración 4: RobotShop Rover

Page 12: Ejemplo de aplicación con Arduino: medida de caudal

12

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.

Ilustración 5: Arduino Single-Sided Serial o Severino

Se puede encontrar una extensa documentación, incluyendo un detallado manual, en

la página web oficial [23].

2.2.5 ¿Cómo obtener una placa Arduino?

Se puede adquirir una placa Arduino desde uno de los distribuidores oficiales, o a

través de múltiples tiendas online de electrónica.

En la página principal de Arduino se puede encontrar una extensa lista de

distribuidores en función del país o región.

Después de evaluar la mayoría de ellos por variedad, disponibilidad, precio y gastos

de envío, me inclino por recomendar las siguientes:

Tienda BricoGeek.com [24]

ELECTAN Electrónica y Robótica [25]

2.2.6 Nuestra elección: El Arduino UNO

2.2.6.1 El porqué de nuestra elección

El principal objetivo de este proyecto es evaluar las capacidades de Arduino a través

de la realización de un pequeño proyecto.

Para lograr este objetivo se debía trabajar con un módulo real, pero no era el caso de

estudio el montaje ni la depuración de los posibles errores del hardware, con lo que se optó

por la compra de módulo ya montado.

Como punto de partida, teniendo en cuenta que no necesitabamos gran cantidad de

entradas y salidas, se decidió usar una placa Arduino que tuviera todo lo necesario para

empezar a trabajar al coste más acotado posible. La actual revisión que mejor encaja con

estas características es el Arduino UNO.

Page 13: Ejemplo de aplicación con Arduino: medida de caudal

13

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.

Page 14: Ejemplo de aplicación con Arduino: medida de caudal

14

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.

2.2.6.3 Esquema y pines

Los esquemas completos del Arduino UNO se pueden encontrar en su página web

oficial.

En la siguiente imagen se puede ver la correspondencia de pines entre el

ATmega168/328 y Arduino.

Ilustración 8: Pines de Arduino contra ATmega328

Page 15: Ejemplo de aplicación con Arduino: medida de caudal

15

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.

2.3.1 El entorno de desarrollo y los drivers de la placa para Windows

La descarga:

Descargamos la última versión del software Arduino de la página oficial [26].

El paquete de software Arduino está contenido en un único fichero

comprimido. No es necesario instalarlo, simplemente lo extraemos en la carpeta

deseada asegurándonos que mantenemos la estructura de subcarpetas.

Los controladores (drivers):

Seguiremos instalando los drivers de nuestro Arduino. Para realizar este paso

necesitaremos conectar el Arduino a nuestro PC, simplemente con un cable USB

tipo A-B (el comúnmente usado por las impresoras).

Los drivers necesarios para utilizar la placa Arduino junto con su entorno se

encuentran en la subcarpeta “\drivers” del paquete que acabamos de extraer. Una

vez conectemos nuestra placa Arduino en nuestro PC, deberemos indicarle a

Windows que debe buscarlos en esta carpeta.

Dependiendo de la versión de Windows usada, y de la variante de la placa

Arduino, este proceso puede variar e incluso no funcionar del modo esperado

(especialmente Windows 7). En tal caso, nos dirigimos al “Administrador de

dispositivos” y veremos algo parecido a esto:

Page 16: Ejemplo de aplicación con Arduino: medida de caudal

16

Ilustración 9: Arduino en el administrador de dispositivos de Windows

En este caso, nos dirigiremos al dispositivo desconocido, el Arduino Uno.

Con el botón derecho actualizaremos el software del controlador indicándole la ruta

donde hemos extraído el software de Arduino\drivers. Deberemos aceptar la

advertencia de que este software no está firmado por Microsoft.

Una vez finalizado este proceso, deberíamos ver un nuevo puerto de

comunicaciones, en nuestro caso el COM3, que será nuestro Arduino, ya que este

driver se comporta como un puerto serie en el PC, con lo que nos añade uno nuevo

sobre el último.

El IDE (“Integrated Development Environment” o "entorno de desarrollo

integrado"):

Ya tenemos nuestro PC y nuestra placa Arduino listos para trabajar.

En la raíz de la carpeta donde hemos extraído el software Arduino

deberíamos encontrar un “arduino.exe”, lo ejecutamos y nos abrirá el entorno de

trabajo: el IDE. Para facilitar futuros accesos podemos crear un “acceso directo”.

Una vez abierto el entorno Arduino deberíamos ver algo como esto:

Page 17: Ejemplo de aplicación con Arduino: medida de caudal

17

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

Page 18: Ejemplo de aplicación con Arduino: medida de caudal

18

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 -

Verificar/Compilar

Se utiliza para compilar y así comprobar que nuestro boceto

es correcto antes de cargarlo a la placa Arduino.

Upload -

Cargar/Programar

Cargar el boceto actual a la placa Arduino. Debemos

asegurarnos que la placa y el puerto seleccionado (en el menú

Herramientas) es correcto antes de cargar el código.

New -

Nuevo

Creará un nuevo boceto para poder empezar a introducir

código.

Open -

Abrir

Presenta una lista de bocetos almacenados en su entorno, así

como una lista de bocetos de ejemplo. Estos se pueden utilizar

para comprobar que los periféricos funcionan correctamente.

Save -

Guardar

Guarda el boceto de la ventana en el archivo de boceto. Una

vez finalizado muestra un mensaje en el área de estado,

debajo de la zona de edición de código.

Serial monitor -

Monitor serie

Abre una ventana con un monitor del bus serie al que está

conectado nuestro Arduino.

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 Descargar y ejecutar un ejemplo de aplicación Arduino

Tenemos conectado la placa Arduino en nuestro PC. Hemos instalado los drivers y

ejecutado el IDE de Arduino. Conocemos los conceptos básicos acerca de los bocetos de

Arduino. Verifiquemos ahora que nuestra placa y el PC funcionan correctamente.

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”.

Page 19: Ejemplo de aplicación con Arduino: medida de caudal

19

Ilustración 11: Acceso a los ejemplos a

través del menú

Ilustración 12: Acceso a los ejemplos a

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).

Ilustración 13: Ejemplo de código Arduino

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.

Page 20: Ejemplo de aplicación con Arduino: medida de caudal

20

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.

Ilustración 14: Resultado de verificación correcto.

Si modificamos el código del ejemplo para forzar un error en la fase de

verificación/compilación, nos encontraríamos con esto:

Ilustración 15: Resultado de verificación incorrecto.

Hemos remplazado la llamada a la función “PinMode” por “PinModo”, y hemos

eliminado el “;” del final de la llamada a la función “delay(1000)”.

Al compilar, el entorno Arduino nos advierte de estos errores en la zona de estado,

indicando los errores detectados, así como las líneas en que se encuentran.

2.3.2.3 Cargar y depurar

Si volvemos al código original, y lo compilamos, ya solo nos falta un paso para

poder probarlo en nuestra placa Arduino: Cargar el código.

Con la placa Arduino conectada al PC a través del puerto USB, y teniendo

configurado correctamente en el entorno nuestra placa Arduino y el puerto de

comunicaciones, pulsaremos sobre el icono “Upload” .

Page 21: Ejemplo de aplicación con Arduino: medida de caudal

21

Ilustración 16: Ubicación del LED de test en la placa Arduino

En breves instante, la barra de estado se completará y nos indicará que el proceso ha

finalizado. En ese momento, el entorno genera un “reset” a la placa Arduino, y el código

empieza a ejecutarse. En nuestro caso, veremos como el LED de test montado en la placa

Arduino empieza a encenderse y apagarse cada segundo.

Para poder depurar el código, y así ver en qué punto de la ejecución se encuentra,

Arduino nos brinda un gran herramienta: el “monitor serie”. El monitor serie sirve para que

nos podamos comunicar entre el PC y nuestra placa Arduino. Las posibilidades de este

pueden ser enormes, pero de momento lo usaremos de la forma más simple posible.

Modificaremos el código del ejemplo de “Blink” añadiendo unas llamadas al monitor

serie, de manera que durante la ejecución podremos ver en el PC qué punto del código se

está ejecutando en la placa Arduino.

Código “Blink” original Código “Blink” con depuración a través del

monitor serie

void setup() {

pinMode(13, OUTPUT);

}

void loop() {

digitalWrite(13, HIGH);

delay(1000);

digitalWrite(13, LOW);

delay(1000);

}

void setup() {

pinMode(13, OUTPUT);

Serial.begin(9600);

}

void loop() {

digitalWrite(13, HIGH);

Serial.println(HIGH);

delay(1000);

digitalWrite(13, LOW);

Serial.println(LOW);

delay(1000);

}

Compilamos y cargamos el código de nuevo, y ahora pulsamos sobre el icono del

“serial monitor” .

Esto nos ha abierto el monitor serie y, en él, podemos ver como escribe un “1” o un

“0” al ejecutar la función correspondiente.

Page 22: Ejemplo de aplicación con Arduino: medida de caudal

22

Ilustración 17: Monitor de comunicación serie integrado en el entorno Arduino

2.4 Lenguaje de programación Arduino

2.4.1 Introducción e historia

La plataforma Arduino se programa mediante el uso de un lenguaje propio basado en

el lenguaje de programación de alto nivel Processing[3], este a su vez está basado en Java.

El compilador usado por la plataforma de Arduino es el GNU AVR, bajo Windows

es el WinAVR [27]. Este compilador está dedicado para los procesadores AVR y está

configurado para compilar C y C++. Las librerías del estándar C implementadas en este

compilador son avr-libc[15] y están optimizadas para los procesadores AVR.

Adicionalmente Arduino tiene un gran conjunto de funciones ya implementadas para

realizar de un modo fácil tareas comunes como hacer una espera activa, leer un puerto

digital o escribir en él, entre muchas otras.

2.4.2 Funciones básicas y operadores

Todo programa Arduino debe contener, de manera obligatoria, al menos dos

funciones básica: setup() y loop().

La función setup() se ejecuta cuando se inicia un boceto (el programa o sketch). Se

emplea para iniciar variables, establecer el estado de las entradas y salidas, inicializar

librerías, etc. Esta función se ejecutará una única vez después de que se conecte la placa

Arduino a la fuente de alimentación, o cuando se pulse el botón de reinicio de la placa.

Después de ejecutar la función setup(), la función loop() se ejecuta de manera

consecutiva e ininterrumpida. Cuando se llega al final de esta función, se vuelve a ejecutar

desde el principio hasta que se vuelva a reiniciar la placa. En el interior de esta función es

donde se pone el código para controlar de forma activa la placa Arduino.

Los siguientes subapartados tienen el objetivo de dar una visión rápida acerca del

lenguaje de programación Arduino, pero no se pretende entrar en el detalle del lenguaje de

programación. Para tal efecto hay multitud de manuales disponibles por la red, entre ellos y

por citar algunos:

Página de referencia del lenguaje del proyecto Arduino [28]

Sección de tutoriales de TronixStuff [29]

Manual del “Starter Kit” de Earthshine Electronics. [30]

Page 23: Ejemplo de aplicación con Arduino: medida de caudal

23

2.4.2.1 Estructuras

Al estar basado en Processing, Java y/o C, las estructuras de control son muy

similares a ellos y entre ellos.

Sintaxis básica

; (punto y coma. Delimitador

de línea de código)

{} (llaves. Delimitador de

bloques de código)

// (comentarios en una línea)

/* */ (comentarios en

múltiples líneas)

#define (definición de

precompilador)

#include (inclusión de código

externo)

Estructuras de control

if (comparador si-entonces)

if...else (comparador si...si no)

for (bucle con contador)

switch case (comparador

múltiple)

while (bucle por comparación

booleana)

do... while (bucle por

comparación booleana)

break (salida de bloque de

código)

continue (continuación en

bloque de código)

return (devuelve valor a

programa)

goto (salta a una etiqueta)

Operadores Aritméticos

= (asignación)

+ (suma)

- (resta)

* (multiplicación)

/ (división)

% (resto)

++ (incremento en uno)

-- (decremento en uno)

+= (suma y asignación)

-= (resta y asignación)

*= (multiplicación y

asignación)

/= (división y asignación)

Operadores de comparación

== (igual a)

!= (distinto de)

< (menor que)

> (mayor que)

<= (menor o igual que)

>= (mayor o igual que)

Operadores Booleanos

&& (y)

|| (o)

! (negación)

Operadores de acceso a punteros

* operador de indirección

& operador de referencia

Operaciones a nivel de bits

& (and - 'y' a nivel de bits)

| (or - 'o' a nivel de bits)

^ (xor a nivel de bits)

~ (not a nivel de bits)

<< (desplazamiento de bits a

la izquierda)

Page 24: Ejemplo de aplicación con Arduino: medida de caudal

24

>> (desplazamiento de bits a

la derecha)

&= (and - 'y' a nivel de bits y

asignación)

|= (or - 'o' 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.

Page 25: Ejemplo de aplicación con Arduino: medida de caudal

25

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

Page 26: Ejemplo de aplicación con Arduino: medida de caudal

26

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

Page 27: Ejemplo de aplicación con Arduino: medida de caudal

27

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

2.4.3 Uso de librerías

El propio entorno Arduino contiene una serie de librerías integradas que facilitan

enormemente las tareas más comunes en el mundo del “hobby electrónico”.

Las Librerías proveen funcionalidad extra a nuestro sketch al trabajar con hardware o

al manipular datos. Para usar una librería dentro de un sketch, puedes seleccionarla desde

Sketch > Import Library (Importar Librería)[16].

2.4.3.1 Librerías Estándar

EEPROM - Para leer y escribir en memorias "permanentes".

Page 28: Ejemplo de aplicación con Arduino: medida de caudal

28

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.

2.4.3.2 Librerías de terceros

Si se desean usar librerías que no vienen junto con Arduino, es necesario instalarlas.

Las librerías suelen entregarse en un fichero comprimido y suelen contener una

carpeta propia con dos archivos, uno con sufijo ".h" y otro con sufijo ".cpp".

Para instalarla se debe copiar el contenido del fichero comprimido en la carpeta

“libraries” que se debería encontrar dentro de la carpeta sketchbook de Arduino. Al

reiniciar el IDE de Arduino debería aparecer la nueva librería en el menú Sketch > Import

Library.

Estas son algunas de las librerías que se pueden encontrar y que están referenciadas

en la propia página web del proyecto Arduino [16]. También se puede encontrar una lista

alternativa en la Wiki de Arduino [31].

Comunicación (networking y protocolos):

Messenger - Para procesar mensajes de texto mandados des del PC.

NewSoftSerial - Versión mejorada de la librería SoftwareSerial.

OneWire - Controla dispositivos (de Dallas Semiconductor) que usan el

protocolo One Wire.

PS2Keyboard - Lee caracteres de un teclado PS2.

Simple Message System - Envía mensajes entre Arduino y la computadora.

SSerial2Mobile - Envía mensajes de texto o emails usando un teléfono móvil

(vía comandos AT a través de SoftwareSerial)

Webduino - Librería de web server extensible (para usar con Arduino

Ethernet Shield)

X10 - Para enviar señales X10 a través de líneas de corriente AC.

XBee - Para comunicaciones entre XBees en modo API.

SerialControl - Para controlar remotamente otras Arduino a través de una

conexión serial.

Sensores:

Page 29: Ejemplo de aplicación con Arduino: medida de caudal

29

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.

Page 30: Ejemplo de aplicación con Arduino: medida de caudal

30

3 Nuestro proyecto Arduino

3.1 Medidor de caudal

La medición del consumo de un recurso que tiene unidades de volumen puede ser

más complicada de lo que parece. Recursos como el agua o el gas se suele medir por

indicadores que determinan el volumen acumulado en el tiempo, como los contadores

domésticos. Pero también puede interesar tener el caudal instantáneo. En estos casos la

medición se realiza a pequeños intervalos y se van acumulando las lecturas durante un

tiempo determinado.

Hay varios tipos de medidores de flujo o de caudal. Para medir líquidos, un diseño

muy común son los que se disponen en línea con el recurso a medir. Estos suelen tener

algún tipo de molinillo que gira al pasar el recurso a través de él y genera una serie de

pulsos proporcionales al caudal instantáneo. Para interpretarlo es necesario implementar un

frecuencímetro.

Este método es similar a como funcionan los velocímetros en muchos vehículos: un

sensor de la rueda genera un pulso por cada giro de una rueda que significa que la

frecuencia del pulso varía proporcionalmente a la velocidad del vehículo. En el

velocímetro se muestra una interpretación de la frecuencia de los pulsos para mostrar la

velocidad instantánea, mientras que el odómetro muestra un contador de pulsos

acumulativo para mostrar la distancia recorrida.

3.2 Requerimientos iniciales

La idea es utilizar un medidor de caudal que genere un tren de pulsos a una

frecuencia proporcional al caudal.

En el diseño se incluye un módulo LCD, de modo que la unidad pueda informar del

caudal y del volumen tanto a través de una conexión serie a un host (PC) o directamente a

través de la pantalla LCD.

El medidor de caudal debe calcular y mostrar el caudal actual. También se calculará

el volumen y el tiempo absoluto. Otros dos contadores acumulativos independientes

mostraran el volumen que ha fluido a través del sensor.

Dos pulsadores deben permitir poner a cero los contadores de forma independiente,

de manera que podamos tener un contador acumulativo a largo plazo y restablecer los otros

para tener medidas diferenciales a corto plazo.

Un ejemplo de uso real seria para conocer el agua que se consume para rellenar un

baño, programar un sistema de riego o en el funcionamiento de una lavadora.

Page 31: Ejemplo de aplicación con Arduino: medida de caudal

31

Ilustración 18: Diagrama de bloques del caudalímetro

3.3 Elección de los componentes

Para la realización de este pequeño proyecto, se ha partido de la placa Arduino UNO;

la más básica, pero no por ello menos versátil, de las placas Arduino.

La pantalla LCD usada, es una a color de 132x132 puntos. Se distribuye en formato

de "shield" para ser utilizada directamente con Arduino sin necesidad de realizar más

soldadura, la comunicación es vía SPI y los propios fabricantes te ofrecen las librerías de

control[18].

El mismo proyecto se podría realizar usando simplemente un LCD de 16x2 como el

"Arduino Shield LCD DFRobot" por unos 25€ (contra los 38€ del LCD 128x128), o

simplemente un LCD 16x2 que se podría montar por unos 15€.

Finalmente, para poder realizar la medición de caudal, se necesita un sensor. Los

sensores de caudal no son fáciles de conseguir a un bajo coste, ya que la gran mayoría son

para usos industriales de gran precisión, algo innecesario para la realización de un proyecto

de demostración como este.

Una alternativa de bajo coste es re-usar un caudalímetro utilizado para la

refrigeración líquida de PCs. El rango de trabajo de estos suele ser de 1.0 a 15 litros por

minuto, con lo que para una aplicación de monitorización del flujo de agua de un grifo

domestico, debería ser suficiente ya que estos suelen tener un máximo entre 15-20 l/min.

Encontramos que el caudalímetro Koolance INS-FM17N [32] cubre con los

requerimientos que nos habíamos marcado, y se encontró a un precio asequible.

Alternativas a este caudalímetro, podrían haber sido los usados en los lavavajillas

[33] el precio es similar, pero no se encontraron datos acerca del la relación

caudal/frecuencia.

Page 32: Ejemplo de aplicación con Arduino: medida de caudal

32

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:

1 x Arduino UNO con ATMega328 21.90€

1 x Arduino Shield LCD Color Sparkfun 32.90€

Subtotal: 54.80€

Correo Península y Baleares

(Entrega en aprox. 7 días. Solo pago con tarjeta o transferencia): 3.50€

IVA 18%: 9.86€

IVA Transporte 18%: 0.63€

Total: 68.79€

Y el sensor de caudal en la tienda HellFire ToyZ [34] de eBay para pagar lo mínimo

en gastos de envío.

1 x Koolance INS-FM17N Coolant Flow Meter for LCS $22,99 USD

Envío y manipulación $11,68 USD

Total $34,67 USD

Tipo de cambio: 1 Euro = 1,34016 Dólares

Total Euros €25,87 EUR

El total del material asciende a 94.66€

Page 33: Ejemplo de aplicación con Arduino: medida de caudal

33

3.5 El hardware

3.5.1 Características técnicas de los componentes

3.5.1.1 Shield LCD color

Ilustración 19: Shield LCD a color

El shield LCD a color proporciona un método fácil de conectar el LCD de un Nokia

6100 a un Arduino. La placa viene como una pantalla mini LCD de 128x128 color, así

como un circuito de control para la retro-iluminación (utiliza un elevador a 7V), y tres

pulsadores (vinculados a través de un puente a los pines D3-5).

El LCD del Nokia 6100 se controla a través un interfaz SPI de 9-bits. Los pines de

control de la pantalla LCD se conectan a los pines de hardware SPI de la placa Arduino

(D13-SCK, D11 - DIO), el pin CS está ligado a D9 y el pin de reset está conectado a D8.

La tensión del pin de '5V' de la placa Arduino se eleva a 7 V para alimentar la retro-

iluminación de la LCD.

En el enlace siguiente, se puede encontrar un manual acerca de como comunicarse

con el LCD y toda la información técnica necesaria para poder dibujar en la pantalla.

https://docs.google.com/viewer?url=http://www.sparkfun.com/tutorial/Nokia%25206

100%2520LCD%2520Display%2520Driver.pdf [35]

Este otro enlace explica un error de diseño en el shield que provoca que la retro-

iluminación no funcione correctamente.

http://richardkaufman.org/blog/how-to-fix-it-backlight-on-sparkfuns-color-lcd-

shield-not-working [36]

Este defecto se ha detectado en nuestro Shield. Para activar la retro-iluminación

debemos realizar un cortocircuito entre dos resistencias cada vez que se alimenta por

primera vez.

Page 34: Ejemplo de aplicación con Arduino: medida de caudal

34

Ilustración 20: Punto a cortocircuitar para activar la retro iluminación

3.5.1.2 Sensor de caudal

Ilustración 21: Sensor de caudal Koolance

El sensor de caudal usado es el Koolance INS-FM17N. Este está compuesto por un

interruptor magnético normalmente abierto que responde al paso de un imán situado en la

aspa de rotación interna.

El movimiento generado por el líquido que circula por su interior nos da una serie de

pulsos, que de acuerdo a la hoja de características del fabricante[19], sigue una relación

lineal entre litros por minuto (LPM) y pulsos por segundo (expresado en Hz), en función

del diámetro del tubo conectado, en nuestro caso 6mm.

Ilustración 22: Relación entre litros y frecuencia del medidor de caudal

Page 35: Ejemplo de aplicación con Arduino: medida de caudal

35

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í.

Ilustración 23: Esquema de montaje

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.

Page 36: Ejemplo de aplicación con Arduino: medida de caudal

36

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.

Ilustración 25: Vista lateral del montaje final

Finalmente, aquí se puede ver el montaje final, con la pantalla LCD y el sensor de

caudal.

Page 37: Ejemplo de aplicación con Arduino: medida de caudal

37

Ilustración 26: Vista frontal del montaje final

3.6 El software

3.6.1 Diseño de la pantalla

3.6.1.1 Uso de la librería del shield LCD a color de Sparkfun

En la mayoría de shields comerciales, el propio fabricante ofrece un set mínimo de

software para poder controlar el shield y/o verificar que este funciona correctamente una

vez ensamblado con la placa Arduino. Este tipo de software se conoce como librerías.

En nuestro caso la librería de control la proporciona Sparkfun y se pude encontrar en

la página de descripción del producto [18]. Estas suelen venir empaquetadas en un fichero

tipo Zip.

Para poder usarla en nuestro entorno es necesario instalarla. Copiamos el contenido

del Zip en una subcarpeta dentro de la carpeta “libraries” de nuestra instalación de Arduino

en el PC.

Page 38: Ejemplo de aplicación con Arduino: medida de caudal

38

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

Para usarla en nuestro sketch debemos incluirla al igual como se haría en C.

#include <ColorLCDShield.h>

Normalmente, dentro de las librerías hay un fichero de texto donde se nos explica

cómo se puede o debe usar la librería, así como programas con ejemplos de uso. En nuestra

librería hay un fichero llamado “Readme”, donde nos indica la licencia de uso de esta

Page 39: Ejemplo de aplicación con Arduino: medida de caudal

39

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);

Como ya se ha indicado, a raíz de la última actualización del entorno Arduino, hay

una gran cantidad de librerías que han dejado de funcionar, entre ellas la proporcionada

para nuestra pantalla LCD. Para solucionar los problemas de compatibilidad y

compilación, en el fichero ColorLCDShield.h se ha remplazado la inclusión de

WProgram.h por Arduino.h; y en ColorLCDShield.cpp se ha eliminado la inclusión de

wiring.h, ya que el contenido de este fichero ha sido incluido en Arduino.h y a su vez, este

ya lo habíamos incluido en ColorLCDShield.h.

Se ha detectado que la librería que nos proporciona el fabricante necesita mucha

memoria RAM debido al el tipo de fuente que utiliza. La fuente original de la librería es de

8x16 puntos de tamaño y se ha remplazado por otra de 8x8 para reducir el tamaño de RAM

requerido.

Existe la posibilidad de indicar al entorno Arduino que una variable tipo constante la

aloje directamente en la FLASH. Para ello se debe usar el modificador de tipo PROGMEM

de la librería pgmspace.h. Esta podría haber sido otra modificación a hacer sobre la librería

para reducir el uso de RAM[38].

3.6.1.2 Información a mostrar e interfaz

Se han definido tres pantallas distintas para mostrar la información relativa a las

mediciones absolutas y a las parciales.

Para conmutar de una pantalla a otra se va a utilizar el pulsador superior de la

pantalla. Los dos pulsadores inferiores servirán para borrar los dos contadores parciales.

Este es el aspecto deseado de las distintas pantallas:

2 Véase ANEXO 1

Page 40: Ejemplo de aplicación con Arduino: medida de caudal

40

Ilustración 29: Pantalla principal

Ilustración 30: Pantalla contadores parciales 1

Ilustración 31: Pantalla contadores parciales 2

3.6.2 El programa de control de Arduino

Este sería el diagrama de flujo del programa de control que hemos implementado.

Page 41: Ejemplo de aplicación con Arduino: medida de caudal

41

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.

Page 42: Ejemplo de aplicación con Arduino: medida de caudal

42

Loop() Tarea_1sec() Interrupción()

Ilustración 33: Diagrama temporal del firmware

La variable que se utiliza dentro de la función de la interrupción debe ser declarada

como volatile para indicar al compilador que puede ser modificada des de diferentes

contextos y así evitar optimizaciones. Esto obliga al compilador a acceder siempre a la

dirección de memoria donde se encuentra la variable y no copiarla en registros para

mejorar la velocidad de acceso.

Los accesos a esta variable desde el contexto de menos prioridad (la tarea periódica)

se deben realiza a través de una sección crítica. Esto implica que los accesos a esta variable

se harán con las interrupciones deshabilitadas.

volatile unsigned int contadorPulsos = 0;

tarea_periodica(){

/* Inicio zona segura intercambio de datos /

noInterrupts();

unsigned int contadorPulsosLocal = contadorPulsos;

contadorPulsos = 0;

interrupts();

/* Fin zona segura intercambio de datos */

}

rutina_servicio_interrupcio(){

contadorPulsos++;

}

Esto debe hacerse porque al tratarse de una variable de 16 bits, y el microcontrolador

de Arduino de 8 bits, implica que como mínimo necesitaremos dos instrucciones para

acceder a este dato. Si mientras se esta ejecutando la primera instrucción de acceso a la

variable recibimos una nueva interrupción, el valor de esta variable se modificará por la

interrupción. Al volver a la tarea periódica se ejecutará la segunda instrucción de acceso a

la variable pero el valor ya será distinto.

Por ejemplo: La variable es igual a 0x00FF. Mientras leemos la parte baja (0xFF) se

ejecuta la interrupción y la incrementa en 1 (ahora valdría 0x0100), al volver a la tarea

periódica y leer la parte alta del dato, veríamos un 0x01. Entonces nuestra variable valdría

0x01FF y no 0x0100 que seria el valor correcto.

El código fuente del programa Arduino se puede encontrar en el ANEXO 2.

Page 43: Ejemplo de aplicación con Arduino: medida de caudal

43

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:

Ilustración 34: Salida del programa de visualización en el PC

Esta aplicación ha sido realizada en python. Este es un lenguaje interpretado de muy

alto nivel, lo que nos permite establecer una comunicación con nuestra placa Arduino con

muy pocas líneas de código.

Lo primero es importar la librería:

import serial

Luego procedemos a conectarnos al puerto de serie con una sencilla función y

encapsulamos dicha conexión en un objeto:

ser = serial.Serial(port='\\.\COM3', baudrate=9600)

Ahora es el momento de leer lo que Arduino nos dice:

while 1:

ser.readline()

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

Page 44: Ejemplo de aplicación con Arduino: medida de caudal

44

3.7 Juego de pruebas

Para verificar que nuestro sistema funciona como esperamos se han realizado una

serie de pruebas a distintos niveles.

3.7.1 Test sobre el caudalímetro

Para verificar que la configuración de los pines es la correcta, se ha monitorizado la

entrada del caudalímetro (D2) con un osciloscopio mientras hacíamos girar las aspas.

El resultado debería ser un tren de pulsos de una frecuencia entre 0 Hz y poco más de

30 Hz, ya que es el rango de trabajo del caudalímetro. El tiempo a nivel bajo de este tren

de pulsos, debería ser del 15-20% del pulso. Esto se debe a que el caudalímetro tiene 4

aspas y solo una de ellas activa el interruptor magnético.

A continuación se pueden ver distintas capturas de osciloscopio verificando que el

montaje funciona.

Ilustración 35: Tren de pulsos del caudalímetro girando a baja velocidad

Page 45: Ejemplo de aplicación con Arduino: medida de caudal

45

Ilustración 36: Tren de pulsos del caudalímetro girando a media velocidad

Ilustración 37: Tren de pulsos del caudalímetro girando a alta velocidad

3.7.2 Test sobre la captura de pulsos

El objetivo de esta prueba es asegurar que capturamos los pulsos que esperamos.

Page 46: Ejemplo de aplicación con Arduino: medida de caudal

46

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.

Ilustración 38: Respuesta ante un tren de pulsos de 31Hz

En la pantalla del LCD debe reportar que el consumo actual es de 9.52 litros por

minuto (31Hz x 0.302 = 9.517 LPM), acorde con la hoja de características del

caudalímetro.

Ilustración 39: Muestra de la pantalla principal ante una entrada de 31Hz

Page 47: Ejemplo de aplicación con Arduino: medida de caudal

47

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.

Ilustración 40: Secuencia de acciones en funcionamiento normal

Con la ayuda de un cronómetro verificamos que el contador de segundos funciona

con suficiente precisión. Esperaremos unos 10 minutos para poder detectar mejor las

desviaciones.

Page 48: Ejemplo de aplicación con Arduino: medida de caudal

48

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.

4 Uso de Arduino en entornos lectivos

4.1 Educación secundaria

Arduino fue diseñado para que personas sin un conocimiento profundo de electrónica

pudieran realizar pequeños proyectos donde se necesita un microcontrolador.

Encontramos en internet varios ejemplos de proyectos hechos con Arduino, desde un

simple caudalímetro a un cuadricoptero[20], robots seguidores, controlar un Arduino con

un móvil Android[21],… y cualquier cosa que encaje en la filosofía DYI (Do It Yourself).

En apartados anteriores hemos visto como sin tener demasiados conocimientos

acerca de microcontroladores y con una sintaxis básica hemos podido realizar un proyecto

relativamente complejo.

Esto ofrece un gran potencial en entornos lectivos, especialmente en secundaria, ya

que es posible despertar la curiosidad por la tecnología, instruir conceptos de electrónica

básica de un modo práctico y hacer una buena introducción a la algoritmia de un modo

ameno y visual.

4.2 Educación técnica superior

Arduino no deja de ser una placa con un microcontrolador y todo lo necesario para

interactuar con él. Esto implica que no solo se puede utilizar como pequeña plataforma

para proyectos, sino que en el aprendizaje de microcontroladores puede tener un gran

potencial, ya que en la red existen varias herramientas para el microcontrolador Atmel

AVR.

Hasta este punto apenas se ha mencionado el Atmel AVR ya que las placas Arduino,

y todo su entorno software, ha sido desarrollado para no tener que entrar en este tipo de

Page 49: Ejemplo de aplicación con Arduino: medida de caudal

49

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.

4.2.1 Usar AVRStudio, código C y Arduino

En primer lugar vamos a instalar AVRStudio, que es el IDE y el conjunto de

herramientas oficial de Atmel (el fabricante de los microcontroladores utilizados en la

Arduinos). Podemos obtenerlo des de la propia página web de Atmel [37].

La versión sobre la que se ha trabajado se ha adjuntado en el soporte digital del PFC.

Nosotros instalamos el paquete “AVR Studio 5.1 Installer - Full”.

Para realizar la descarga es necesario registrarse en la web de Atmel, pero el proceso

es simple y rápido.

Una vez instalado todo lo necesario, el proceso es el típico de Windows,

perfectamente guiado a través de ventanas. Ejecutamos el AVRStudio y deberíamos ver

algo como en la Ilustración 42

Ilustración 42: Vista inicial del AVR Studio

Aquí seleccionamos “New project”, en la nueva ventana seleccionamos de los

“Installed templates” el “AVR GCC → C → C Executable Project”, indicándole en el

campo nombre “Arduino_Blink”, como el típico ejemplo Arduino, y “OK”.

Page 50: Ejemplo de aplicación con Arduino: medida de caudal

50

Una vez hecho esto, tenemos que seleccionar con que dispositivo Atmel vamos a

trabajar. Nuestro Arduino tiene el ATmega328P, con lo que seleccionaremos este.

Ilustración 43: Selección de dispositivo en AVR Studio

Como se puede ver, en la parte derecha de la pantalla de selección nos proporciona el

acceso a la hoja de características (datasheet) y las herramientas que tendremos disponibles

para este dispositivo. Entre ellas la que quizás más nos puede interesar para nuestros

desarrollos: el “AVR Simulator”.

Al darle “OK”, el entorno nos va a crear un proyecto listo para introducir el código C

que queramos.

Page 51: Ejemplo de aplicación con Arduino: medida de caudal

51

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

*/

#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

int main(void)

{

DDRB |= (1<<PB5); //Definimos el pin13/PORTB5 como salida para poder

encender y apagar nuestro LED

while(1) //Este es el bucle infinito obligatorio en la programación

de micro-controladores. Todo nuestro código estará aquí dentro

{

PORTB |= (1<<PB5); //Enciende el LED, este es el LED incluido en

la placa Arduino, en el pin digital 13

Page 52: Ejemplo de aplicación con Arduino: medida de caudal

52

_delay_ms(1000); //Espera 1 segundo

PORTB &= ~(1<<PB5); //Apaga el LED

_delay_ms(1000); //Espera 1 segundo

}

}

Como podíamos ver en la Ilustración 8 (Pines de Arduino contra ATmega328)

debemos tener en cuenta la correspondencia entre los pines del ATMEGA con los de la

placa Arduino.

Pulsamos la tecla F7, o en menú “Build → Build Solution”, para iniciar el proceso de

generación de los ficheros ejecutables (compilado, ensamblado y enlazado). Si todo ha ido

bien, deberíamos ver en la parte inferior del IDE un mensaje indicando que no hay errores

y un resumen de memoria usada; y en la parte derecha los ficheros que se han generado

durante el proceso:

Ilustración 45: Resultado de la compilación en el AVR Studio

4.2.2 Simular y ejecutar el código C en nuestro microcontrolador

En este punto deberíamos ser capaces de compilar, enlazar y generar un fichero .hex.

Este fichero será el ejecutable en el microcontrolador, el equivalente a un .exe en un PC.

Ahora querremos ejecutar nuestro código, y verificar que se comporta como nosotros

esperamos. Para tal fin tenemos distintas opciones, entre ellas simular el código en el PC,

descargarlo en nuestro Arduino o utilizar herramientas de depuración más avanzadas.

Page 53: Ejemplo de aplicación con Arduino: medida de caudal

53

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.

Ilustración 46: Vista del simulador integrado en AVR Studio

4.2.2.2 Descargar el código en nuestra placa Arduino. AVRDude.

Nuestro ATmega por el hecho de estar en una placa Arduino lleva grabado un gestor

de descarga o boot loader. El AVRStudio no soporta la comunicación con este gestor de

descarga de manera nativa, ya que no ha sido diseñado para entornos Arduino.

El AVRDude es una herramienta que nos permite descargar nuestro código una vez

compilado a nuestra placa Arduino a través de su propio gestor de descarga. Esto significa

que no necesitamos ningún tipo de hardware adicional para poder trabajar con el ATmega,

ni con la placa Arduino.

El AVRDude forma parte del software de Arduino, para utilizarlo de una manera

cómoda des de nuestro entorno integrado, se han copiado los ficheros necesarios a una

nueva carpeta llamada “ArduinoUpload” en la misma carpeta que los proyectos del

AVRStudio. Esta suele ser una carpeta llamada “AVRStudio 5.1”, en la carpeta de

Page 54: Ejemplo de aplicación con Arduino: medida de caudal

54

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

El significado de esos parámetros esta descrito en la documentación del propio

AVRDude que hemos copiado en nuestra carpeta, el fichero “avrdude.pdf”.

Para facilitar esta tarea se ha creado un fichero por lotes de MS-DOS llamado

“upload.cmd” como el que se puede encontrar en el ANEXO 4, donde solo le deberemos

indicar el puerto serie a utilizar y el nombre del binario a descargar…

A su vez, crearemos otro fichero por lotes de MS-DOS que será llamado desde el

propio AVRStudio, como una herramienta externa, que será incluida en la barra de

botones, de manera que el proceso de descargar el código en la placa será similar al

utilizado en el propio entorno Arduino.

Este otro fichero por lotes, llamado “uploadFromAVRStudio.cmd”, también se

puede encontrar en el ANEXO 4, así como la manera de configurar la herramienta externa

en el AVRStudio.

4.2.2.3 Uso de entornos de depuración y programación

Existen distintas herramientas de Atmel para programar sus microcontroladores e

incluso poder depurar el código realizando ejecuciones paso a paso en el propio

microcontrolador.

Muchas de estas herramientas son simples programadores, fáciles de montar uno

mismo y de bajo coste, que nos permitirían poder descargar el boot loader o directamente

nuestra aplicación en un microcontrolador virgen. Alguno de estos seria el USBtinyISP,

USBasp entre muchas otras propuestas disponibles en internet.

En cuanto a los depuradores (debuggers) que permiten programar y ejecutar código

paso a paso en el dispositivo real y utilizar múltiples “breakpoints” son bastante costosos

siendo quizás el más económico el AVR Dragon (50€ aprox.).

Page 55: Ejemplo de aplicación con Arduino: medida de caudal

55

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].

4.2.3.1 Un breve resumen

El ATmega328P es el microcontrolador que lleva el Arduino UNO, forma parte de la

familia de procesadores Atmel AVR.

Los AVR son una familia de microcontroladores RISC, la arquitectura de los cuales

fue concebida por dos estudiantes en el Norwegian Institute of Technology, y

posteriormente refinada y desarrollada en Atmel Norway, la empresa subsidiaria de Atmel,

fundada por los dos arquitectos del chip.

Los AVR son CPUs con arquitectura Harvard. Tiene 32 registros de propósito

general de 8 bits. Estos registros de propósito general, los registros de periféricos y la

memoria de datos forman un solo espacio de direcciones unificado, que se acceden

mediante operaciones de carga y de almacenamiento. A diferencia de los

microcontroladores PIC, la pila se ubica en este espacio de memoria unificado, y no está

limitado a un tamaño fijo.

Los microcontroladores AVR tienen una cañería o “pipeline” con dos etapas (traer y

ejecutar), que les permite utilizar un ciclo de reloj en la mayoría de instrucciones, lo que

los hace relativamente rápidos entre los microcontroladores de 8 bits. El conjunto de

instrucciones es más regular que la de la mayoría de los microcontroladores de 8 bits. Sin

embargo, no es completamente ortogonal.

4.2.3.2 Puertos de entrada y salida digital

Hay distintos registros del microcontrolador que sirven para indicar como debe

comportarse cada pin, ya sea como un pin de entrada digital, de salida digital, de entrada

analógica, salida PWM…

En el ATmega328P los registros para configurar y acceder a los pines están

agrupados por puertos. En nuestro Arduino tenemos un ATmega de 28 pines, esto hace que

solo dispongamos el puerto B, C y D.

En la Ilustración 8: Pines de Arduino contra ATmega328 (Pines de Arduino contra

ATmega328), se puede ver la correspondencia entre los pines del ATmega y del Arduino,

así como los distintos modos en los que puede funcionar cada uno de los pines.

Para cada uno de los puertos tenemos un registro DDRx asociado, donde la 'x' indica

el puerto al que hacemos referencia, por ejemplo DDRB hace referencia al puerto B. Este

registro nos permite configurar los distintos pines de puerto como entrada o salida digital.

El acrónimo DDR significa Data Direction Register, y cada bit dentro del registro hace

referencia al pin correspondiente. Escribir un 1 implica configurar el pin como salida y 0

como entrada.

Page 56: Ejemplo de aplicación con Arduino: medida de caudal

56

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;

El ATmega tiene funcionalidad real de lectura-modificación-escritura para todos los

registros de entrada/salida (concretamente los registros del 0x00 al 0x1F). Esto significa

que tiene una instrucción que permite cambiar un bit de un registro sin modificar los

demás. Estas instrucciones en ensamblador son SBI y CBI.

La manera en C más estándar de actuar sobre un pin en concreto es utilizando

mascaras y desplazamientos de bits. Para tal efecto el compilador AVR lib-c tiene una

serie de constantes definidas para tal fin, como Px0..7. Utilizando estas constantes y la

lógica de bits, tenemos que para poner a nivel alto el pin 5 y no modificar los demás pines

podemos hacer:

PORTB |= (1<<PB5);

y si quisiéramos ponerlo a nivel bajo:

PORTB &= ~(1<<PB5);

Del mismo modo, si quisiéramos actuar en función de una entrada haríamos:

if ((PINB & (1<<PB2)) != 0){

/* Pin a nivel alto */

}else{

/* Pin a nivel bajo */

}

Utilizando el AVRStudio y ejecutando estas instrucciones en el AVRSimulator,

utilizando la vista de “Disassembly” fácilmente podemos ver el código en ensamblador que

ha generado el compilador.

DDRB |= (1<<PB5);

00000040 SBI 0x04,5 Set bit in I/O register

PORTB |= (1<<PB5);

00000041 SBI 0x05,5 Set bit in I/O register

y podemos ver como se comportaría el código en el microcontrolador real.

Page 57: Ejemplo de aplicación con Arduino: medida de caudal

57

Ilustración 47: Vista de ensamblador en AVRSimulator

Si asignamos un valor a un pin en PORTx y luego lo leemos desde PINx, se debe

esperar un ciclo para que PINx se sincronice, por ejemplo,

unsigned char val;

PORTD = (1 << PD3 | 1 << PD5);

/*Esperamos un ciclo para sincronización */

asm volatile("nop");

/*Leemos los pines */

val = PINB;

Esto es debido al diseño de la circuitería de un pin de entrada y salida, donde en el

registro de entrada hay un “latch” que se comporta como sincronizador para evitar

metaestabilidad si hay cambios en el nivel del pin cerca del flanco del reloj interno.

Page 58: Ejemplo de aplicación con Arduino: medida de caudal

58

Ilustración 48: Puerto general de entrada/salida digital

4.2.3.3 Uso de la USART/comunicación serie

El entorno Arduino utiliza básicamente el puerto serie para depurar el código e

interaccionar con el PC. En este apartado se mostrará cómo realizar las operaciones

equivalentes a través del periférico del ATmega y código C.

El protocolo de comunicación serie utiliza 2 cables, uno para recibir datos y otro para

enviar. La masa debe ser común entre la placa Arduino/micro-controlador y el otro

dispositivo. La interfaz serie permite enviar entre 5 y 9 bits de datos con un bit de inicio y

uno o dos de parada, así como un bit de paridad. La USART hace todo el trabajo acerca de

la configuración de inicio, del bit de parada y de la paridad. La comunicación es asíncrona

y sólo es necesario indicar a la USART la velocidad de reloj que queremos usar, la

velocidad de transmisión.

La propia documentación del microcontrolador (datasheet) nos indica una serie de

funciones en ensamblador y en código C a modo de ejemplo para utilizar la USART. A

partir de estos ejemplos, aquí podemos ver un ejemplo de código para mandar y recibir a

través del puerto serie.

/*

* Arduino_USART.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 */

Page 59: Ejemplo de aplicación con Arduino: medida de caudal

59

#include <util/delay.h> /* Contiene funciones de espera en ms y us

*/

#define BAUDRATE (9600u) /* Definimos a que velocidad

queremos utilizar la comunicación serie */

#define BAUD_RATE_REGISTER ((F_CPU / (BAUDRATE * 16ul)) - 1u) /*

Datasheet. Tabla 20-1. Equations for Calculating Baud Rate Register Setting

*/

char String[]="Hola mundo!!";

/* Función de inicialización. Datasheet “20.5 USART Initialization” */

void USART_Init( unsigned int ubrr) {

/* Configuramos la velocidad de la comunicación (baud rate) */

UBRR0H = (unsigned char)(ubrr>>8);

UBRR0L = (unsigned char)ubrr;

/* Valores por defecto después de reset en el registre USCR0A.

Esta escritura no esta definida en el datasheet, pero parece

necesaria ya que de lo contrario el bit de "Double USART

Transmission Speed" parece activo, de modo que no configura

el baud rate como esperamos.

Posiblemente el bootloader de Arduino está configurando este

bit, ya que usa el periférico para descargar el código. */

UCSR0A = (1<<TXC0);

/* Activar la recepción y la transmisión */

UCSR0B = (1<<RXEN0)|(1<<TXEN0);

/* Configuramos el formato de la trama: 8data, 2stop bit */

UCSR0C = (1<<USBS0)|(3<<UCSZ00);

}

/* Función de transmisión. Datasheet “20.6 Data Transmission – The USART

Transmitter” */

void USART_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;

}

/* Función de recepción. Datasheet 20.7 Data Reception – The USART Receiver”

*/

unsigned char USART_Receive( void ) {

/* Esperamos a recibir todo el dato */

while ( !(UCSR0A & (1<<RXC0) ) );

/* Devolvemos el dato del buffer */

return UDR0;

}

/* Esta función transmite una cadena de caracteres */

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){ /* Mientras la cadena no esta vacia transmite

*/

USART_Transmit(*StringPtr);

StringPtr++;

}

}

int main( void ) {

USART_Init(BAUD_RATE_REGISTER); /* Inicializamos la comunicación */

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;

Page 60: Ejemplo de aplicación con Arduino: medida de caudal

60

}

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

*/

#include "Arduino_SERIAL_Api.h" /* Contiene funciones para trbajar con la

comunicación serie */

char String[]="Hola mundo!!";

int main( void ) {

SERIAL_Init(); /* Inicializamos la comunicación */

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;

}

La configuración de la velocidad de la comunicación serie se encuentra definida en el

fichero Arduino_SERIAL_API.h. Se ha implementado de este modo para que el cálculo

del valor del registro lo haga el pre-compilador, de manera que no se añada más código

innecesario en la aplicación final.

Para poder comunicar el PC y nuestra placa con la comunicación serie,

necesitaremos un programa en el PC que haga de monitor. Hay infinidad, pero por

simplicidad, y por la no necesidad de instalación, yo recomendaría “Terminal”, que se

puede encontrar en https://sites.google.com/site/terminalbpp/ y se ha añadido en el soporte

digital del PFC.

De igual modo como hemos creado una herramienta externa en AVRStudio para el

AVRDude, ahora podemos hacer lo mismo para el monitor serie, copiando así las

facilidades del entrono de desarrollo de Arduino.

4.2.3.4 Las interrupciones en los ATmega328P

Una interrupción es una llamada “inesperada”, urgente e inmediata a una función

especial denominada Interrupt Service Routine (ISR).

Page 61: Ejemplo de aplicación con Arduino: medida de caudal

61

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.

4.2.3.4.1 Los Vectores de Interrupción

Cada interrupción está identificada por un Vector de Interrupción, que no es otra

cosa que una dirección particular en la memoria FLASH. Todos los Vectores están

ubicados en posiciones consecutivas de la memoria FLASH y forman la denominada Tabla

de Vectores de Interrupción. El RESET no es una interrupción pero su dirección 0x0000

también se conoce como Vector de Reset. Por defecto, la Tabla de Vectores de

Interrupción está ubicada en las primeras posiciones de la memoria, tal como se ve abajo.

Solo cuando se habilita el uso de la Sección de Boot Loader toda la tabla se desplazará al

inicio de dicha sección.

Aquí se presenta la tabla con las 26 interrupciones posibles en los ATmega328:

Num

Vector

Dirección de

Programa

Nombre de Vector

de Interrupción

Fuente de interrupción

1 0x0000 RESET

External Pin, Power-on Reset, Brown-out Reset

and Watchdog System Reset

2 0x0002 INT0 External Interrupt Request 0

3 0x0004 INT1 External Interrupt Request 1

4 0x0006 PCINT0 Pin Change Interrupt Request 0

5 0x0008 PCINT1 Pin Change Interrupt Request 1

6 0x000A PCINT2 Pin Change Interrupt Request 2

7 0x000C WDT Watchdog Time-out Interrupt

8 0x000E TIMER2_COMPA Timer/Counter2 Compare Match A

9 0x0010 TIMER2_COMPB Timer/Counter2 Compare Match B

10 0x0012 TIMER2_OVF Timer/Counter2 Overflow

11 0x0014 TIMER1_CAPT Timer/Counter1 Capture Event

12 0x0016 TIMER1_COMPA Timer/Counter1 Compare Match A

13 0x0018 TIMER1_COMPB Timer/Coutner1 Compare Match B

14 0x001A TIMER1_OVF Timer/Counter1 Overflow

15 0x001C TIMER0_COMPA Timer/Counter0 Compare Match A

16 0x001E TIMER0_COMPB Timer/Counter0 Compare Match B

17 0x0020 TIMER0_OVF Timer/Counter0 Overflow

18 0x0022 SPI_STC SPI Serial Transfer Complete

19 0x0024 USART_RX USART Rx Complete

20 0x0026 USART_UDRE USART, Data Register Empty

21 0x0028 USART_TX USART, Tx Complete

Page 62: Ejemplo de aplicación con Arduino: medida de caudal

62

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.

4.2.3.4.2 Las Funciones de Interrupción

La Función de Interrupción o ISR va siempre identificada por su Vector de

Interrupción. Su esquema varía ligeramente entre un compilador y otro, puesto que no

existe en el lenguaje C un formato estándar. Lo único seguro es que es una función que no

puede recibir ni devolver ningún parámetro.

En el compilador AVR GCC (WinAVR) la función de interrupción se escribe

utilizando la palabra reservada ISR. En el caso de nuestro compilador, el Vector de

Interrupción debe tener la terminación _vect. En caso de dudas acerca de cómo está

declarada se puede buscar en la carpeta include del directorio de instalación de WinAVR.

ISR (Vector_de_Interrupcion)

{

// Código de la función de interrupción.

// No requiere limpiar el flag respectivo. El flag se limpia por

hardware

}

4.2.3.4.3 Control de las Interrupciones

Hay dos tipos de bits para controlar las interrupciones: los Bits Enable, que habilitan

las interrupciones, y los Bits de Flag, que notifican cuál ha sido la interrupción que se ha

producido.

Hay un bit de habilitación individual para cada interrupción y además hay un bit de

habilitación general, ubicado en el registro SREG, que afecta a todas las interrupciones.

Para habilitar una interrupción hay que poner un 1 en su bit de habilitación individual

y en el bit de habilitación general. Ninguna habilitación individual tendrá efecto si el bit de

habilitación general está a 0.

Page 63: Ejemplo de aplicación con Arduino: medida de caudal

63

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.

4.2.3.4.4 Recepción de una trama serie por interrupción

En el apartado anterior se ha visto como utilizar la USART sin las interrupciones.

Esto es una pérdida de eficiencia, ya que nos obliga a estar escuchando el bus para recibir

una trama. La alternativa a esto es utilizar las interrupciones de recepción de trama.

Para utilizar la interrupción del puerto serie, es necesario configurar el bit RXCIE

(bit 7 del registro UCSRB) a 1, lo que activa la interrupción. También es necesario activar

las interrupciones globalmente.

El vector correspondiente a la interrupción de recepción de datos a través del puerto

serie es USART_RX_vect.

El código que deberíamos añadir en la función SERIAL_init() sería:

/* Activar la interrupción del puerto serie */

UCSR0B |= (1<<RXCIE0);

/* Activar interrupciones generales */

sei();

También deberíamos incluir la librería de interrupciones en nuestro fichero API:

#include <avr/interrupt.h>

Y la Función de Interrupción debe ser parecida a:

ISR(USART_RX_vect)

{

read = SERIAL_Receive(); SERIAL_Transmit(read); /* Mandamos lo que recivimos a modo de eco */

}

Page 64: Ejemplo de aplicación con Arduino: medida de caudal

64

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.

4.2.3.5 Interrupciones por cambio de PIN

Existen dos tipos de interrupción por cambio de PIN, las INTx y las PCINTx.

Las primeras son disparadas por un flanco (de subida y/o de bajada) o un nivel bajo

detectado en el pin INTx del micro controlador.

La PCINTx se dispara cada vez que se detecta un cambio de nivel lógico ‘1’ a ‘0’, o

viceversa, en cualquiera de los pines de los puertos del ATmega.

4.2.3.5.1 Las Interrupciones INT0 e INT1

El evento que puede disparar la interrupción INTx es un flanco (de subida y/o de

bajada) o un nivel bajo detectado en el pin INTx del ATmega, sin importar si ese pin está

configurado como entrada o como salida. Esto es relevante en el caso de querer tener

interrupciones vía software.

En el ATmega368, estas dos interrupciones están vinculadas a los pines PD2 y PD3

respectivamente (corresponden al digitalPin 2 y 3 de Arduino).

Los bits de habilitación (enable) y notificación (flag) de estas interrupciones se

encuentran en los registros

EIMSK = External interrupts Mask Register. Contiene los bits de

habilitación.

EIFR = External Interrupts Flags Register. Contiene los bits de notificación.

EICRA = External Interrupts Control Register A. Configura la señal externa

que va a generar la interrupción. Es A porque hay AVRs más grandes con

más interrupciones INTx donde además existe el registro EICRB.

EIMSK --- --- --- --- --- --- INT1 INT0

EIFR --- --- --- --- --- --- INTF1 INTF0

EICRA --- --- --- --- ISC11 ISC10 ISC01 ISC00

Para habilitar la interrupción INTx hay que poner a 1 el bit INTx, del registro

EIMSK, además del bit de habilitación general de las interrupciones en el registro SREG

Una vez producido el evento, el hardware pondrá a 1 la notificación INTFx del

registro EIFR, y luego se disparará la interrupción. Este evento se debe configurar

previamente en el registro EICRA y hay cuatro opciones posibles.

Modo ISCx1 ISCx0 Evento de la Interrupción

0 0 0 Nivel bajo en el pin INTx.

1 0 1 Cualquier flanco (de subida y/o de bajada) detectado en el pin INTx.

2 1 0 Flanco de bajada detectado en el pin INTx.

Page 65: Ejemplo de aplicación con Arduino: medida de caudal

65

Modo ISCx1 ISCx0 Evento de la Interrupción

3 1 1 Flanco de subida detectado en el pin INTx.

EICRA --- --- --- --- ISC11 ISC10 ISC01 ISC00

Configuración de interrupción INT 1 Configuración de interrupción INT 0

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.

4.2.3.5.2 Interrupciones de Cambio de Pin, PCINTx

Esta interrupción se dispara cada vez que se detecta un cambio de nivel lógico ‘1’ a

‘0’, o viceversa, en cualquiera de los pines de los puertos del ATmega, sin importar si

están configurados como entrada o como salida. Se podría decir que se dispara con los

flancos de subida y de bajada en los pines de puertos. En ese sentido, se parece bastante a

las interrupciones INTx. La interrupción de Cambio de Pin también puede sacar al AVR

del modo Sleep.

En el ATmega368 los PCINTx corresponden a los puertos siguientes:

PCINT0 corresponde al PUERTO B, PCINT[7:0] – PB[7:0]

PCINT1 corresponde al PUERTO C, PCINT[14:8] – PC[6:0]

PCINT2 corresponde al PUERTO D, PCINT[23:16] – PD[7:0].

Las interrupciones de cambio de pin se habilitan poniendo a 1 correspondiente para

los respectivos puertos que se encuentran en el registro PCICR (Pin Change Interrupt

Control Register).

PCICR --- --- --- --- --- PCIE2 PCIE1 PCIE0

Habilita interrupciones de PORT D Habilita interrupciones de PORT C Habilita interrupciones de PORT B

Después se deben poner a 1 los bits de habilitación que identifican individualmente

los pines de los puertos. Estos bits se encuentran en los registros de máscara PCMSK (Pin

Change Mask Register).

Page 66: Ejemplo de aplicación con Arduino: medida de caudal

66

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

Flag de interrupciones de PORT D Flag de interrupciones de PORT C Flag de interrupciones de PORT B

El bit de notificación PCIF es puesto a cero (limpiado) por el hardware al

ejecutarse el gestor de interrupción ISR. Sin embargo, como esta notificación se puede

activar sin necesidad de que esté habilidato el bit de habilitación general del registro

SREG, a veces se tendrá que limpiar por software. En este caso se limpia escribiendo un 1.

Es recomendable habilitar la Interrupción de Cambio de Pin después de realizar en

los puertos todas las operaciones necesarias que pudieran ocasionar cambios de nivel en

sus pines, por ejemplo, activar las pullUps.

4.2.3.6 Uso de temporizadores y PWM

El ATmega328p tiene 3 temporizadores, el timer 0, el timer 1 y el timer 2. La

principal diferencia entre ellos es que el 0 y el 2 son de 8 bits y el 1 de 16 bits.

Todos los temporizadores tienen tres valores/conceptos asociados el TOP, el

BOTTOM y el MAX:

TOP define el valor máximo que se puede contar con el temporizador, que

puede ser el valor máximo u otro valor definido por el usuario en el registro

OCRxA, en función del modo seleccionado.

BOTTOM es el valor mínimo y siempre es 0.

MAX es siempre el valor máximo que un temporizador puede contar, en el

temporizador de 16 bits 65535 y en los de 8bits 255.

La fuente de reloj para los temporizadores puede ser el propio reloj del sistema u una

fuente externa. En nuestro Arduino el reloj del sistema es de 16MHz, pero se pueden usar

divisores para conseguir distintos rangos de frecuencias según nuestras necesidades. El

divisor del reloj se puede ajustar a 1, 8, 64, 256 o 1024.

Page 67: Ejemplo de aplicación con Arduino: medida de caudal

67

TCCRxB --- --- --- --- --- CSx2 CSx1 CSx0

CSx2 CSx1 CSx0 Selección de la funte de reloj

0 0 0 No hay reloj (Timer/Counter parado)

0 0 1 Reloj del sitema (No divisor)

0 1 0 Reloj del sitema / 8 (Divisor interno)

0 1 1 Reloj del sitema / 64 (Divisor interno)

1 0 0 Reloj del sitema / 256 (Divisor interno)

1 0 1 Reloj del sitema / 1024 (Divisor interno)

1 1 0 Reloj externo en pin T0. Flanco de bajada

1 1 1 Reloj externo en pin T0. Flanco de subida

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 --- --- ---

Modo de operación

WGMx2 WGMx1 WGMx0 Descripción TOP Actualiza OCRx en

Activa el flag TOV

0 0 0 0 Normal 0xFF/0xFFFF Inmediato MAX

1 0 0 1 PWM, Phase Correct 0xFF/0xFFFF TOP BOTTOM

2 0 1 0 CTC OCRxA Inmediato MAX

3 0 1 1 Fast PWM 0xFF/0xFFFF BOTTOM MAX

4 1 0 0 Reservado --- --- ---

5 1 0 1 PWM, Phase Correct OCRxA TOP BOTTOM

6 1 1 0 Reservado --- --- ---

7 1 1 1 Fast PWM OCRxA BOTTOM TOP

La cantidad de registros y los distintos modos de funcionamiento hacen obligatorio el

uso de la documentación del microcontrolador (datasheet). Aquí solo se pretende explicar

cómo se comporta en cada modo y realizar algún pequeño ejemplo demostrativo.

4.2.3.6.1 Modo normal

Este es el modo básico de funcionamiento y el que está configurado después de reset.

Simplemente configurando la fuente del reloj este temporizador empezaría a contar.

Si configuramos la fuente de reloj para que utilice el reloj de sistema sin divisor, esto

implicaría que en el registro TCNTx incrementaría en uno a cada 0.0625us (1/16MHz),

Page 68: Ejemplo de aplicación con Arduino: medida de caudal

68

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>

// Frequencia de la fuente de reloj en Hz

#define F_CPU (16000000)

// Frequencia deseada en Hz. 2Hz => 0.5 sec

#define F_DESEADA (2)

/*

Para seleccionar el divisor comprobamos cuantas cuentas del contador

necesitamos:

NUM_CUENTAS = (((F_CPU / DIVISOR) / F_DESEADA) - 1)

DIVISOR NUM_CUENTAS

1 7999999

8 999999

64 124999

256 31249

1024 7811,5

Nuestros contadores son de 8 o 16 bits, con lo que como máximo pueden

contar hasta 255 o 65365.

Con las cuentas hechas anteriormente nos obliga a usar un contador de

16bits (el TCNT1) y un divisor configurado a 256, de manera que cuando

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);

//Configuramos el divisor del timer. El timer empieza a contar

TCCR1B = (1<<CS12); //1:256

while(1){

PORTB |= (1<<PB5); //Enciende el LED

while(TCNT1 <= TIEMPO_A_ESPERAR); // Esperamos el tiempo deseado

TCNT1 = 0; //Limpiamos el timer para que vuelva a empezar

PORTB &= ~(1<<PB5); //Apaga el LED

while(TCNT1 <= TIEMPO_A_ESPERAR); // Esperamos el tiempo deseado

TCNT1 = 0; //Limpiamos el timer para que vuelva a empezar

Page 69: Ejemplo de aplicación con Arduino: medida de caudal

69

}

}

En este ejemplo en particular utilizamos un temporizador de 16 bits cuando la

palabra del microcontrolador es de 8bits, esto hace que el registro TCNT1 en realidad sean

dos registros del micro controlador. El compilador de AVRStudio ya nos proporciona unas

librerías de manera que nosotros no nos tengamos de preocupar de esto.

La configuración del divisor involucra a 3 bits, el CS12, CS11 y CS10. Para

modificar los tres bits a la vez utilizaremos mascaras.

TCCR1B &= 0b11111000; // Limpiamos los 3 bits del CS

TCCR1B |= 0b00000100; // Configuramos el divisor 1:256 (CS = 100)

Cada vez que el temporizador alcanza su valor máximo (TOP) pone a 1 el bit de

notificación TOVx (Timer Overflow Flag) en el registro TIFRx (Timer Interrupt Flag

Register). Activando el bit TOIEx (Timer Overflow Interrupt Enable) del TIMSKx (Timer

Interrupt Mask Register) genera una interrupción al alcanzar este punto. Este

comportamiento es muy útil para ampliar el contaje del temporizador incrementando una

variable en la función de atención de la interrupción.

4.2.3.6.2 Modo CTC

El modo Clear Time on Compare match (CTC) nos activa una interrupción cuando el

contador a alcanzado un valor pre-definido y vuelve a empezar el contaje. Este modo de

funcionamiento nos aporta una gran ventaja en el diseño de las aplicaciones, ya que no

debemos detener el flujo de ejecución de nuestro programa para realizar alguna acción.

Volviendo al ejemplo del LED que parpadea, lo que haremos es cargar el valor a

contar en el registro OCRxA (Output Compare Register A) y lo configuraremos para que

nos dispare una interrupción cuando alcance el valor definido pone a 1 el bit OCIExA

(Output Compare Match A Interrupt Enable) del registro TIMSKx (Timer Interrupt Mask

Register).

/*

* Arduino_blink_timer_INTERRUPT.c

*

* Parpadeo del LED de Arduino cada 0.5seg usando interrupciones de timers

* en lugar de la libreria delay.h

*/

#include <avr/io.h>

#include <avr/interrupt.h>

// Frequencia de la fuente de reloj en Hz

#define F_CPU (16000000)

// Frequencia deseada en Hz. 2Hz => 0.5 sec

#define F_DESEADA (2)

/*

Para seleccionar el divisor comprobamos cuantas cuentas del contador

necesitamos:

NUM_CUENTAS = (((F_CPU / DIVISOR) / F_DESEADA) - 1)

DIVISOR NUM_CUENTAS

1 7999999

8 999999

64 124999

256 31249

1024 7811,5

Nuestros contadores son de 8 o 16 bits, con lo que como máximo pueden

contar hasta 255 o 65365.

Con las cuentas hechas anteriormente nos obliga a usar un contador de

16bits (el TCNT1) y un divisor configurado a 256, de manera que cuando

Page 70: Ejemplo de aplicación con Arduino: medida de caudal

70

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);

//Configuramos el timer en modo CTC y el divisor del timer.

//El timer empieza a contar

TCCR1B = (1<<WGM12)|(1<<CS12); // CTC y 1:256

// Cargamos el valor a contar

OCR1A = TIEMPO_A_ESPERAR;

// Habilitamos las interrupciones del timer

TIMSK1 = (1<<OCIE1A);

// Habilitamos las interrupciones generales

sei();

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

}

Dependiendo de cómo se configura los bits COMxA (Compare Match Output A

Mode) del registro TCCRxA (Timer Control Register A), el pin OCxA puede realizar una

acción pre configurada cuando se alcance el valor configurado.

TCCRxA COMxA1 COMxA0 --- --- --- --- --- ---

COMxA1 COMxA0 Comportamiento del pin OCxA

0 0 Puerto Normal, OCxA desconectado

0 1 Inversión del OCxA al alcanzar el valor

1 0 Poner a zero elOCxA al alcanzar el valor

1 1 Poner a uno el OCxA al alcanzar el valor

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.

Page 71: Ejemplo de aplicación con Arduino: medida de caudal

71

Ilustración 49: Ejemplo de uso del temporizador en modo CTC

4.2.3.6.3 Generación de PWMs

Existe la posibilidad de generar dos tipos de PWM para los temporizadores de 8bits,

el “Fast PWM” y el “Phase Correct PWM”; y el de 16bits adicionalmente puede generar

“Phase and Frequency Correct PWM”. La diferencia entre ambos es muy sutil y es muy

particular para cada aplicación.

El comportamiento de los distintos modos se podría resumir como:

“Fast” aplica el nuevo periodo, ciclo de trabajo (duty) y/o frecuencia a

continuación del periodo en curso.

“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.

“Phase and Frequency Correct”. Este modo es igual al anterior pero

garantizando que el pulso siempre es correcto incluso cuando la frecuencia

va variando. Este uso es muy particular y solo está disponible en el

temporizador de 16bits.

Aquí se puede ver el comportamiento de los tres modos.

Page 72: Ejemplo de aplicación con Arduino: medida de caudal

72

Ilustración 50: Generación PWM en modo “Fast PWM”

Ilustración 51: Generación PWM en modo “Phase Correct PWM”

Page 73: Ejemplo de aplicación con Arduino: medida de caudal

73

Ilustración 52: Generación PWM en modo “Phase and Frequency Correct PWM”

Como norma general el modo “Fast PWM” es suficiente para la mayoría de

aplicaciones como regulación de potencia, rectificación,…

4.2.3.6.4 Uso del Input capture

El temporizador de 16bits también incorpora una unidad de “input capture” que

permite capturar eventos externos asociados a cambios en el pin ICP1 y ofrecer una marca

temporal de frecuencia de ejecución.

Típicamente esta funcionalidad se utiliza para calcular la frecuencia y/o el ciclo de

trabajo (duty cycle) de una señal.

Ilustración 53: Uso del temporizador como “Input capture”

Page 74: Ejemplo de aplicación con Arduino: medida de caudal

74

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) {

ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //Divisor a 128 frec.

del ADC a 125Khz

ADMUX |= (1<<REFS0);

ADMUX &= ~(1<<REFS1); //Avcc(+5v) como tensión de referencia

ADCSRA |= (1<<ADEN); //Alimentamos el ADC

ADCSRA |= (1<<ADSC); //Empezamos la conversión

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;

}

Page 75: Ejemplo de aplicación con Arduino: medida de caudal

75

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).

Page 76: Ejemplo de aplicación con Arduino: medida de caudal

76

Ilustración 54: Configuración opciones de optimización del compilador

Ilustración 55: Configuración opciones de optimización del linker

Una vez configurado el compilador y el enlazador (linker) construimos el proyecto.

En el menú “Build” seleccionamos la opción “Rebuil Solution”.

Como resultado veremos en la ventana “Output” que todo ha ido bien. Así como el

resumen de memoria necesaria en el microcontrolador.

Page 77: Ejemplo de aplicación con Arduino: medida de caudal

77

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

Program: 7380 bytes (22.5% Full)

(.text + .data + .bootloader)

Data: 1070 bytes (52.2% Full)

(.data + .bss + .noinit)

Si la misma herramienta la ejecutamos sobre el fichero resultado del proyecto en el

entorno Arduino, obtenemos lo siguiente:

avr-size.exe -C --mcu=atmega328p medidorCaudal_Arduino.cpp.elf

AVR Memory Usage

----------------

Device: atmega328p

Program: 10390 bytes (31.7% Full)

(.text + .data + .bootloader)

Data: 1269 bytes (62.0% Full)

(.data + .bss + .noinit)

Page 78: Ejemplo de aplicación con Arduino: medida de caudal

78

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.

5.1 Precios unitarios

CÓDIGO UD DESCRIPCIÓN PRECIO

IT001 h Ingeniero Técnico Industrial 25,00 VEINTICINCO EUROS

HW001 u Arduino UNO con ATMega328 21,90 VENTIÚN EUROS con NOVENTA céntimos

HW002 u Arduino Shield LCD Color Sparkfun

32,90 TRENTIDÓS EUROS con NOVENTA céntimos

HW003 u Koolance INS-FM17N Coolant Flow Meter for LCS

25,87 VEINTICINCO EUROS con OCHENTA Y SIETE céntimos

HW004 u Tira de pines macho 40 pines paso 2,54 mm

0,53 CINCUENTA Y TRES céntimos

HW005 u Rollo de cable de 10Mts sección 0,5 mm2

2,70 DOS EUROS con SETENTA céntimos

5.2 Precios descompuestos

5.2.1 Capítulo 1: Estudios previos

CÓDIGO UD DESCRIPCIÓN CANTIDAD PRECIO SUBTOTAL

IT001 h Ingeniero Técnico Industrial recopilando información acerca de Arduino y su entorno de programación

80,00 25,00 2.000,00

IT001 h Ingeniero Técnico Industrial recopilando información acerca de ATmega328P y AVRStudio

220,00 25,00 5.500,00

Suma de la Partida 7.500,00

2,00 % Costes Indirectos 150,00

TOTAL PARTIDA 7.650,00

Page 79: Ejemplo de aplicación con Arduino: medida de caudal

79

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 Flow Meter for LCS

1,00 25,87 25,87

HW004 u Tira de pines macho 40 pines paso 2,54 mm

0,25 0,53 0,13

HW005 u Rollo de cable de 10Mts sección 0,5 mm2

0,25 2,70 0.68

Suma de la Partida 581,48

Envío y manipulación 10,00

TOTAL PARTIDA 591,48

5.2.3 Capítulo 3: Diseño del firmware

CÓDIGO UD DESCRIPCIÓN CANTIDAD PRECIO SUBTOTAL

IT001 h Ingeniero Técnico Industrial.

Diseño en entorno y lenguaje “Arduino”

10,00 25,00 250,00

IT001 h Ingeniero Técnico Industrial.

Testeo y corrección de errores en entorno “Arduino”

25,00 25,00 625,00

IT001 h Ingeniero Técnico Industrial.

Diseño en entorno AVRStudio y C

15,00 25,00 375,00

IT001 h Ingeniero Técnico Industrial.

Testeo y corrección de errores en entorno AVRStudio

20,00 25,00 500,00

Suma de la Partida 1.750,00

2,00 % Costes Indirectos 35,00

TOTAL PARTIDA 1.785,00

5.2.4 Capítulo 4: Diseño del software de PC

CÓDIGO UD DESCRIPCIÓN CANTIDAD PRECIO SUBTOTAL

IT001 h Ingeniero Técnico Industrial. 12,00 25,00 300,00

Page 80: Ejemplo de aplicación con Arduino: medida de caudal

80

Implementación de aplicación en Python

IT001 h Ingeniero Técnico Industrial.

Testeo y corrección de errores

25,00 25,00 625,00

Suma de la Partida 925,00

2,00 % Costes Indirectos 18,50

TOTAL PARTIDA 943,50

5.2.5 Capítulo 5: Documentación

CÓDIGO UD DESCRIPCIÓN CANTIDAD PRECIO SUBTOTAL

IT001 h Ingeniero Técnico Industrial

Documentación de todo el proceso de estudio.

80,00 25,00 2.000,00

Suma de la Partida 2.000,00

2,00 % Costes Indirectos 40,00

TOTAL PARTIDA 2.040,00

5.3 Resumen del presupuesto

CAPÍTULO RESUMEN IMPORTE

Capítulo 1 Estudios previos 7.650,00

Capítulo 2 Diseño y montaje del hardware 591,48

Capítulo 3 Diseño del firmware 1.785,00

Capítulo 4 Diseño del software de PC 943,50

Capítulo 5 Documentación 2.040,00

TOTAL EJECUCIÓN MATERIAL 13.009,98

13,00 % Gastos Generales 1,691,30

6,00 % Beneficio Industrial 780,60

TOTAL EJECUCIÓN POR CONTRATO 15.481,87

18,00 % IVA 2.786,74

TOTAL PRESUPUESTO LICITACIÓN 18.268,61

Page 81: Ejemplo de aplicación con Arduino: medida de caudal

81

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.

Page 82: Ejemplo de aplicación con Arduino: medida de caudal

82

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!!!

Page 83: Ejemplo de aplicación con Arduino: medida de caudal

83

ANEXOS

ANEXO 1: Información uso librería LCD

************************************

* *

* ColorLCDShield *

* *

* an Arduino Library *

* *

* by Jim Lindblom *

* SparkFun Electronics *

* *

************************************

License: CC-BY SA 3.0 - Creative commons share-alike 3.0 use this code

however you'd like, just keep this license and attribute. Let me know if you

make hugely, awesome, great changes.

Huge thanks to Jim Lynch, Mark Sproul, and Peter Davenport. If I'm missing

anyone, I apologize, all of this code's been through the ringer more than a

few times.

This is a (hopefully) simple Arduino library for use specifically with

SparkFun Electronics' Color LCD Shield

(http://www.sparkfun.com/products/9363). It'll no doubt work with other

incarnations of LCD breakouts and what not, you just might have to do some

modifying of the pin defintions.

The code gives you access to the following LCD functions:

LCDShield(); - The library's constructor. An instance of the lcd must be

created at the beginning of any code. e.g:

LCDShield lcd;

void init(int type); - This initializes an LCD. Either EPSON or PHILLIPS

should be passed as the type variable. This function should be called near

the beginning of any function (setup()!). Turns on the display, sets the

contrast and uinitializes the LCD into 12-bit RGB color mode.

void clear(int color); - Clears the entire screen, filling it with the 12-

bit RGB color passed to it. There are a number of predefined colors in

ColorLCDShield.h

void contrast(char setting); - Manually adjusts the contrast. A value

between 0 and 60 should be passed. 40 works pretty well for me.

void setPixel(int color, unsigned char x, unsigned char y); - Draws a single

pixel at the specified x, y location. Color is a 12-bit RGB value.

void setCircle (int x0, int y0, int radius, int color); - Draws a circle

centered around x0, y0, of the specified radius and color. Radius is in

pixels, color is a 12-bit RGB value.

void setChar(char c, int x, int y, int fColor, int bColor); - Sets a single

character down at the specified x/y coordinate. You can pick both the

foreground and background color, they're 12-bit RGB values. Only one font is

Page 84: Ejemplo de aplicación con Arduino: medida de caudal

84

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 printLogo(void); - One trick pony. Prints the SparkFun logo.

void on(void); - Turns the display on.

void off(void); - Turns the display off. You'll still see the backlight on!

Modificaciones sobre la librería

En el fichero de librería ColorLCDShield.cpp se han modificado las siguientes líneas

para poder utilizar un tipo de fuente que requiera menos RAM. Se ha pasado de utilizar

una tipografía de 8x16 puntos a otra de 8x8.

Ilustración 57: Modificación del fichero ColorLCDShield.cpp. 1era parte

Page 85: Ejemplo de aplicación con Arduino: medida de caudal

85

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

Page 86: Ejemplo de aplicación con Arduino: medida de caudal

86

{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} // ~

};

ANEXO 2: Programa de control de Arduino.

/*

* Medidor de caudal

*

* Recibe una serie de pulsos proporcionales al caudal detectado por un

caudalimetro

Page 87: Ejemplo de aplicación con Arduino: medida de caudal

87

* 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

/*

Page 88: Ejemplo de aplicación con Arduino: medida de caudal

88

* Funcion de inicializacion del sistema

*/

void setup()

{

/* Configuracion puerto serie (USB) */

Serial.begin(9600);

Serial.println("Empecemos...");

/* Configuracion del LCD */

lcd.init(EPSON); // Inicializa el LCD, utilizar PHILLIPS si no funciona

lcd.contrast(lcdContraste); // Inicializamos el contraste

lcd.clear(WHITE); // Fondo de pantalla en blanco (sin color)

/* Configuracion del sensor */

/* Configuramos el pin de entrada del sensor como entrada con un pullUp

*/

pinMode(caudalPin, INPUT); // Configuramos como entrada

digitalWrite(caudalPin, HIGH); // Activamos pullUp

pinMode(caudalGNDPin, OUTPUT); // Configuramos como salida

digitalWrite(caudalGNDPin, LOW); // Le damos GND al sensor

/* La linea del interruptor del caudalimetro esta conectada al pin 2 que

utiliza la intterupcion 0.

Configuramos para capturar los flancos de bajada (transicion de HIGH a

LOW) */

attachInterrupt(caudalInt, isr_caudalimetro, FALLING);

contadorPulsos = 0;

}

/*

* 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;

/* Para ser usado como test. Remplazamos el caudalimetro por un corto

circuito

entre las lineas del Arduino. Pin2 y Pin6.

Esto equivaldria a que el sensor nos entrega una seoal de 31Hz */

// tone(caudalGNDPin,31); // Al utilizar contadores de 8 bits, 31Hz es la

menor freq que nos permite esta funcion directamente.

/* Acciones a realizar cada segundo */

if (currentMillis - previoMilis > intervalo_1000ms) {

previoMilis = currentMillis;

task_1000ms();

}

/* Lectura continua sobre los pulsadores con debouncing */

if (!digitalRead(lcdBotones[0])){ // Pulsado

if (boton0 < 255){ // Control de rangos

boton0++;

}

}else{ // No pulsado

if (boton0 > botonAntirebote){ // Ha estado pulsado al menos

"botonAntirebote" veces

/* Ponemos a zero el contador parcial 2 */

contadorSegundosParcial_2 = 0;

litrosParcial_2 = 0.0;

}

boton0 = 0;

}

if (!digitalRead(lcdBotones[1])){ // Pulsado

Page 89: Ejemplo de aplicación con Arduino: medida de caudal

89

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 */

Serial.println(contadorPulsosLocal); // Mandamos los pulsos x segundo a

la linea serie

/* Convertimos los pulsos a litros por minuto y acumulamos los totales

*/

litrosMinuto = contadorPulsosLocal * contadorRelacion;

litrosUltimoMinuto = (litrosMinuto / 60);

litrosTotales += litrosUltimoMinuto;

litrosParcial_1 += litrosUltimoMinuto;

litrosParcial_2 += litrosUltimoMinuto;

/* Incrementamos los contadores de tiempo */

contadorSegundos++;

contadorSegundosParcial_1++;

contadorSegundosParcial_2++;

/* Mostramos la pantalla que corresponda */

switch (pantalla){

case 0:

pantalla_principal();

Page 90: Ejemplo de aplicación con Arduino: medida de caudal

90

break;

case 1:

pantalla_parcial_1();

break;

case 2:

pantalla_parcial_2();

break;

default:

break;

}

}

/*

* Pantalla principal a mostrar

*/

void pantalla_principal()

{

lcd.setStr("Tiempo total", 3, 3, BLACK, WHITE);

lcd.setStr(" segundos", 19, 3, BLACK, WHITE);

itoa(contadorSegundos,lcdStr,10);

lcd.setStr(lcdStr, 19, 11, BLACK, WHITE);

lcd.setStr("Consumo actual", 35, 3, BLACK, WHITE);

lcd.setStr(" l x min", 48, 3, BLACK, WHITE);

dtostrf(litrosMinuto, 4, 2, lcdStr);

lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);

lcd.setStr("Litros totales ", 64, 3, BLACK, WHITE);

lcd.setStr(" ", 80, 3, BLACK, WHITE);

dtostrf(litrosTotales, 6, 2, lcdStr);

lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);

lcd.setStr("Cont.1 Cont.2 ", 96, 3, BLACK, WHITE);

lcd.setStr(" ", 112, 3, BLACK, WHITE);

dtostrf(litrosParcial_1, 4, 2, lcdStr);

lcd.setStr(lcdStr, 112, 3, BLACK, WHITE);

dtostrf(litrosParcial_2, 4, 2, lcdStr);

lcd.setStr(lcdStr, 112, 75, BLACK, WHITE);

}

/*

* Pantalla contadores parciales 1

*/

void pantalla_parcial_1()

{

lcd.setStr("Tiempo parcial 1", 0, 3, BLACK, WHITE);

lcd.setStr(" segundos ", 16, 3, BLACK, WHITE);

itoa(contadorSegundosParcial_1,lcdStr,10);

lcd.setStr(lcdStr, 16, 11, BLACK, WHITE);

lcd.setStr("Consumo actual ", 32, 3, BLACK, WHITE);

lcd.setStr(" l x min", 48, 3, BLACK, WHITE);

dtostrf(litrosMinuto, 4, 2, lcdStr);

lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);

lcd.setStr("Litros parcial 1", 64, 3, BLACK, WHITE);

lcd.setStr(" ", 80, 3, BLACK, WHITE);

dtostrf(litrosParcial_1, 4, 2, lcdStr);

lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);

lcd.setStr(" Totales ", 96, 3, BLACK, WHITE);

lcd.setStr(" ", 112, 3, BLACK, WHITE);

dtostrf(litrosTotales, 6, 2, lcdStr);

lcd.setStr(lcdStr, 112, 59, BLACK, WHITE);

}

/*

Page 91: Ejemplo de aplicación con Arduino: medida de caudal

91

* 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);

lcd.setStr("Consumo actual ", 32, 3, BLACK, WHITE);

lcd.setStr(" l x min", 48, 3, BLACK, WHITE);

dtostrf(litrosMinuto, 4, 2, lcdStr);

lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);

lcd.setStr("Litros parcial 2", 64, 3, BLACK, WHITE);

lcd.setStr(" ", 80, 3, BLACK, WHITE);

dtostrf(litrosParcial_2, 4, 2, lcdStr);

lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);

lcd.setStr(" Totales ", 96, 3, BLACK, WHITE);

lcd.setStr(" ", 112, 3, BLACK, WHITE);

dtostrf(litrosTotales, 6, 2, lcdStr);

lcd.setStr(lcdStr, 112, 59, BLACK, WHITE);

}

/*

* Funcion llamada por la interrupcion 0 a cada deteccion de flanco de

bajada

* del caudalimetro.

*/

void isr_caudalimetro()

{

contadorPulsos++; // Incrementamos el contador de pulsos

}

ANEXO 3: Programa de control del PC.

"""

This demo demonstrates how to draw a dynamic mpl (matplotlib)

plot in a wxPython application.

It allows "live" plotting as well as manual zooming to specific

regions.

Both X and Y axes allow "auto" or "manual" settings. For Y, auto

mode sets the scaling of the graph to see all the data points.

For X, auto mode makes the graph "follow" the data. Set it X min

to manual 0 to always see the whole data from the beginning.

Note: press Enter in the 'manual' text box to make a new value

affect the plot.

Eli Bendersky ([email protected])

License: this code is in the public domain

Last modified: 31.07.2008

"""

import os

import pprint

import random

import sys

import wx

Page 92: Ejemplo de aplicación con Arduino: medida de caudal

92

import serial

# The recommended way to use wx with mpl is with the WXAgg

# backend.

#

import matplotlib

matplotlib.use('WXAgg')

from matplotlib.figure import Figure

from matplotlib.backends.backend_wxagg import \

FigureCanvasWxAgg as FigCanvas, \

NavigationToolbar2WxAgg as NavigationToolbar

import numpy as np

import pylab

class DataGet(object):

""" Get the number of pulses received from serial port

"""

def __init__(self, init=0):

self.data = self.init = init

self.ser = serial.Serial(

port='\\.\COM3',

baudrate=9600,

bytesize=serial.EIGHTBITS,

parity=serial.PARITY_NONE,

stopbits=serial.STOPBITS_ONE,

timeout=1

)

def next(self):

test = self.ser.readline()

if (test != '') and (test[0].isdigit()):

self.data = int(test,10)*0.307

return self.data

class BoundControlBox(wx.Panel):

""" A static box with a couple of radio buttons and a text

box. Allows to switch between an automatic mode and a

manual mode with an associated value.

"""

def __init__(self, parent, ID, label, initval):

wx.Panel.__init__(self, parent, ID)

self.value = initval

box = wx.StaticBox(self, -1, label)

sizer = wx.StaticBoxSizer(box, wx.VERTICAL)

self.radio_auto = wx.RadioButton(self, -1,

label="Auto", style=wx.RB_GROUP)

self.radio_manual = wx.RadioButton(self, -1,

label="Manual")

self.manual_text = wx.TextCtrl(self, -1,

size=(35,-1),

value=str(initval),

Page 93: Ejemplo de aplicación con Arduino: medida de caudal

93

style=wx.TE_PROCESS_ENTER)

self.Bind(wx.EVT_UPDATE_UI, self.on_update_manual_text,

self.manual_text)

self.Bind(wx.EVT_TEXT_ENTER, self.on_text_enter, self.manual_text)

manual_box = wx.BoxSizer(wx.HORIZONTAL)

manual_box.Add(self.radio_manual, flag=wx.ALIGN_CENTER_VERTICAL)

manual_box.Add(self.manual_text, flag=wx.ALIGN_CENTER_VERTICAL)

sizer.Add(self.radio_auto, 0, wx.ALL, 10)

sizer.Add(manual_box, 0, wx.ALL, 10)

self.SetSizer(sizer)

sizer.Fit(self)

def on_update_manual_text(self, event):

self.manual_text.Enable(self.radio_manual.GetValue())

def on_text_enter(self, event):

self.value = self.manual_text.GetValue()

def is_auto(self):

return self.radio_auto.GetValue()

def manual_value(self):

return self.value

class GraphFrame(wx.Frame):

""" The main frame of the application

"""

title = 'Demo: dynamic matplotlib graph'

def __init__(self):

wx.Frame.__init__(self, None, -1, self.title)

self.dataget = DataGet()

self.data = [self.dataget.next()]

self.paused = False

self.create_menu()

self.create_status_bar()

self.create_main_panel()

self.redraw_timer = wx.Timer(self)

self.Bind(wx.EVT_TIMER, self.on_redraw_timer, self.redraw_timer)

self.redraw_timer.Start(100)

def create_menu(self):

self.menubar = wx.MenuBar()

menu_file = wx.Menu()

m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S", "Save plot to

file")

self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)

menu_file.AppendSeparator()

Page 94: Ejemplo de aplicación con Arduino: medida de caudal

94

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.xmin_control = BoundControlBox(self.panel, -1, "X min", 0)

self.xmax_control = BoundControlBox(self.panel, -1, "X max", 50)

self.ymin_control = BoundControlBox(self.panel, -1, "Y min", 0)

self.ymax_control = BoundControlBox(self.panel, -1, "Y max", 100)

self.pause_button = wx.Button(self.panel, -1, "Pause")

self.Bind(wx.EVT_BUTTON, self.on_pause_button, self.pause_button)

self.Bind(wx.EVT_UPDATE_UI, self.on_update_pause_button,

self.pause_button)

self.cb_grid = wx.CheckBox(self.panel, -1,

"Show Grid",

style=wx.ALIGN_RIGHT)

self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid)

self.cb_grid.SetValue(True)

self.cb_xlab = wx.CheckBox(self.panel, -1,

"Show X labels",

style=wx.ALIGN_RIGHT)

self.Bind(wx.EVT_CHECKBOX, self.on_cb_xlab, self.cb_xlab)

self.cb_xlab.SetValue(True)

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)

Page 95: Ejemplo de aplicación con Arduino: medida de caudal

95

self.vbox.Fit(self)

def create_status_bar(self):

self.statusbar = self.CreateStatusBar()

def init_plot(self):

self.dpi = 100

self.fig = Figure((3.0, 3.0), dpi=self.dpi)

self.axes = self.fig.add_subplot(111)

self.axes.set_axis_bgcolor('black')

self.axes.set_title('Liters per minute', size=12)

pylab.setp(self.axes.get_xticklabels(), fontsize=8)

pylab.setp(self.axes.get_yticklabels(), fontsize=8)

# plot the data as a line series, and save the reference

# to the plotted line series

#

self.plot_data = self.axes.plot(

self.data,

linewidth=1,

color=(1, 1, 0),

)[0]

def draw_plot(self):

""" Redraws the plot

"""

# when xmin is on auto, it "follows" xmax to produce a

# sliding window effect. therefore, xmin is assigned after

# xmax.

#

if self.xmax_control.is_auto():

xmax = len(self.data) if len(self.data) > 50 else 50

else:

xmax = int(self.xmax_control.manual_value())

if self.xmin_control.is_auto():

xmin = xmax - 50

else:

xmin = int(self.xmin_control.manual_value())

# for ymin and ymax, find the minimal and maximal values

# in the data set and add a mininal margin.

#

# note that it's easy to change this scheme to the

# minimal/maximal value in the current display, and not

# the whole data set.

#

if self.ymin_control.is_auto():

ymin = round(min(self.data), 0) - 1

else:

ymin = int(self.ymin_control.manual_value())

if self.ymax_control.is_auto():

ymax = round(max(self.data), 0) + 1

Page 96: Ejemplo de aplicación con Arduino: medida de caudal

96

else:

ymax = int(self.ymax_control.manual_value())

self.axes.set_xbound(lower=xmin, upper=xmax)

self.axes.set_ybound(lower=ymin, upper=ymax)

# anecdote: axes.grid assumes b=True if any other flag is

# given even if b is set to False.

# so just passing the flag into the first statement won't

# work.

#

if self.cb_grid.IsChecked():

self.axes.grid(True, color='gray')

else:

self.axes.grid(False)

# Using setp here is convenient, because get_xticklabels

# returns a list over which one needs to explicitly

# iterate, and setp already handles this.

#

pylab.setp(self.axes.get_xticklabels(),

visible=self.cb_xlab.IsChecked())

self.plot_data.set_xdata(np.arange(len(self.data)))

self.plot_data.set_ydata(np.array(self.data))

self.canvas.draw()

def on_pause_button(self, event):

self.paused = not self.paused

def on_update_pause_button(self, event):

label = "Resume" if self.paused else "Pause"

self.pause_button.SetLabel(label)

def on_cb_grid(self, event):

self.draw_plot()

def on_cb_xlab(self, event):

self.draw_plot()

def on_save_plot(self, event):

file_choices = "PNG (*.png)|*.png"

dlg = wx.FileDialog(

self,

message="Save plot as...",

defaultDir=os.getcwd(),

defaultFile="plot.png",

wildcard=file_choices,

style=wx.SAVE)

if dlg.ShowModal() == wx.ID_OK:

path = dlg.GetPath()

self.canvas.print_figure(path, dpi=self.dpi)

self.flash_status_message("Saved to %s" % path)

Page 97: Ejemplo de aplicación con Arduino: medida de caudal

97

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()

def on_exit(self, event):

self.Destroy()

def flash_status_message(self, msg, flash_len_ms=1500):

self.statusbar.SetStatusText(msg)

self.timeroff = wx.Timer(self)

self.Bind(

wx.EVT_TIMER,

self.on_flash_status_off,

self.timeroff)

self.timeroff.Start(flash_len_ms, oneShot=True)

def on_flash_status_off(self, event):

self.statusbar.SetStatusText('')

if __name__ == '__main__':

app = wx.PySimpleApp()

app.frame = GraphFrame()

app.frame.Show()

app.MainLoop()

ANEXO 4: Configuración del AVRStudio para descargar el código en Arduino.

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

Page 98: Ejemplo de aplicación con Arduino: medida de caudal

98

: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"

Uso de herramientas externas en AVRStudio

Para la creación de una herramienta externa y su correspondiente botón en la barra de

herramientas en el AVRStudio, debemos definirlas en el menú “Tools”, “External

Tools…”

Page 99: Ejemplo de aplicación con Arduino: medida de caudal

99

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…”

Page 100: Ejemplo de aplicación con Arduino: medida de caudal

100

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”.

Ilustración 61: Cuadro de opciones para botón en la barra de herramientas. I

Page 101: Ejemplo de aplicación con Arduino: medida de caudal

101

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.

Ilustración 63: Vista del botón en la barra de herramientas

ANEXO 5: Librería de uso de la comunicación serie en 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

*/

#define SERIAL_BAUDRATE (9600U)

#define F_CPU (16000000UL)

/* Inicialización de la comunicación serie */

void SERIAL_Init( void );

/* Función de transmisión de un caracter */

void SERIAL_Transmit( unsigned char data );

/* Función de recepción de un caracter */

unsigned char SERIAL_Receive( void );

/* Función de transmisión de una cadena de caracteres */

void SERIAL_PutString(char* StringPtr);

Page 102: Ejemplo de aplicación con Arduino: medida de caudal

102

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"

#define BAUD_RATE_REGISTER ((F_CPU / (SERIAL_BAUDRATE * 16ul)) - 1u) /*

Datasheet. Tabla 20-1. Equations for Calculating Baud Rate Register Setting

*/

/* Inicialización de la comunicación serie */

void SERIAL_Init( void ) {

/* Configuramos la velocidad de la comunicación (baud rate) */

UBRR0H = (unsigned char)(BAUD_RATE_REGISTER>>8);

UBRR0L = (unsigned char)BAUD_RATE_REGISTER;

/* Valores por defecto después de reset en el registre USCR0A.

Esta escritura no esta definida en el datasheet, pero parece

necesaria ya que de lo contrario el bit de "Double USART

Transmission Speed" parece activo, de modo que no configura

el baud rate como esperamos.

Posiblemente el bootloader de Arduino está configurando este

bit, ya que usa el periférico para descargar el código. */

UCSR0A = (1<<TXC0);

/* Activar la recepción y la transmisión */

UCSR0B = (1<<RXEN0)|(1<<TXEN0);

/* Configuramos el formato de la trama: 8data, 2stop bit */

UCSR0C = (1<<USBS0)|(3<<UCSZ00);

}

/* Función de transmisión de un caracter */

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;

}

/* Función de recepción de un caracter */

unsigned char SERIAL_Receive( void ) {

/* Esperamos a recibir todo el dato */

while ( !(UCSR0A & (1<<RXC0) ) );

/* Devolvemos el dato del buffer */

return UDR0;

}

/* Función de transmisión de una cadena de caracteres */

void SERIAL_PutString(char* StringPtr){

while(*StringPtr != 0x00){ /* Mientras la cadena no esta vacia transmite

*/

SERIAL_Transmit(*StringPtr);

StringPtr++;

}

/* Añadimos salto de linea y retorno de carro al final de la cadena */ SERIAL_Transmit(0x0Du);

SERIAL_Transmit(0x0Au);

}

Page 103: Ejemplo de aplicación con Arduino: medida de caudal

103

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>

#define SERIAL_BAUDRATE (9600U)

#define F_CPU (16000000UL)

/* Inicialización de la comunicación serie */

void SERIAL_Init( void );

/* Función de transmisión de un caracter */

void SERIAL_Transmit( unsigned char data );

/* Función de recepción de un caracter */

unsigned char SERIAL_Receive( void );

/* Función de transmisión de una cadena de caracteres */

void SERIAL_PutString(char* StringPtr);

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"

#define BAUD_RATE_REGISTER ((F_CPU / (SERIAL_BAUDRATE * 16ul)) - 1u) /*

Datasheet. Tabla 20-1. Equations for Calculating Baud Rate Register Setting

*/

/* Inicialización de la comunicación serie */

void SERIAL_Init( void ) {

/* Configuramos la velocidad de la comunicación (baud rate) */

UBRR0H = (unsigned char)(BAUD_RATE_REGISTER>>8);

UBRR0L = (unsigned char)BAUD_RATE_REGISTER;

/* Valores por defecto después de reset en el registre USCR0A.

Esta escritura no esta definida en el datasheet, pero parece

necesaria ya que de lo contrario el bit de "Double USART

Transmission Speed" parece activo, de modo que no configura

el baud rate como esperamos.

Posiblemente el bootloader de Arduino está configurando este

bit, ya que usa el periférico para descargar el código. */

UCSR0A = (1<<TXC0);

/* Activar la recepción y la transmisión */

UCSR0B = (1<<RXEN0)|(1<<TXEN0);

/* Configuramos el formato de la trama: 8data, 2stop bit */

UCSR0C = (1<<USBS0)|(3<<UCSZ00);

/* Activar la interrupción del puerto serie */

UCSR0B |= (1<<RXCIE0);

/* Activar interrupciones generales */

sei();

}

/* Función de transmisión de un caracter */

Page 104: Ejemplo de aplicación con Arduino: medida de caudal

104

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;

}

/* Función de recepción de un caracter */

unsigned char SERIAL_Receive( void ) {

/* Esperamos a recibir todo el dato */

while ( !(UCSR0A & (1<<RXC0) ) );

/* Devolvemos el dato del buffer */

return UDR0;

}

/* Función de transmisión de una cadena de caracteres */

void SERIAL_PutString(char* StringPtr){

while(*StringPtr != 0x00){ /* Mientras la cadena no esta vacia transmite

*/

SERIAL_Transmit(*StringPtr);

StringPtr++;

}

}

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

*/

#include "Arduino_SERIAL_INTRx_Api.h" /* Contiene funciones para trbajar con

la comunicación serie */

volatile unsigned char read;

int main( void ) {

int index = 0;

char indexCh[2];

SERIAL_Init(); /* Inicializamos la comunicación */

/* Ejemplo de como escribir enteros en el terminal a modo de cuenta

atras */

for(index=3;index>0;index--){

itoa(index,indexCh,10);

SERIAL_PutString(indexCh);

SERIAL_PutString("\r\n");

_delay_ms(500);

}

SERIAL_PutString("Empieza a escribir en el terminal. \r\n");

read = 0;

while(read != 0x18){ /* Para salir Ctr + x */

/* Solo romperemos este bucle des de la interrupción de recepción */

}

SERIAL_PutString("\r\n Buen trabajo !!!");

return 0;

}

Page 105: Ejemplo de aplicación con Arduino: medida de caudal

105

ISR(USART_RX_vect)

{

read = SERIAL_Receive();

SERIAL_Transmit(read); /* Mandamos lo que recivimos a modo de eco */

}

ANEXO 7: Medidor de caudal implementado con AVRStudio

Este es el programa de control del Arduino codificado en C++ y compilado por el

AVRStudio. El proyecto completo se puede encontrar en el soporte digital de este PFC.

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) */

Page 106: Ejemplo de aplicación con Arduino: medida de caudal

106

#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;

}

Page 107: Ejemplo de aplicación con Arduino: medida de caudal

107

/*

* Inicialización de periféricos (puerto serie, timer, LCD e

interrupciones)

*/

void inicializacion(void){

/* Configuramos la comunicación serie */

SERIAL_Init();

SERIAL_PutString("Empecemos...");

/* Configuracion del LCD */

lcd.init(EPSON); // Inicializa el LCD, utilizar PHILLIPS si no

funciona

lcd.contrast(LCD_CONTRASTE); // Inicializamos el contraste

lcd.clear(WHITE); // Fondo de pantalla en blanco (sin color)

/* Configuración del sensor */

DDRD = (1<<PORTD6); // Pin digital 6 - PD6 como salida las demas

como entrada

PORTD = ((1<<PORTD2) | (1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5)); //

PullUp en las entradas

contadorPulsos = 0;

/* Configuramos interrupciones del pin INT 0 */

EIMSK = (1<<INT0); // INT 0

EICRA = (1<<ISC01); // Flanco de bajada

/* Configuramos el timer en modo CTC y el divisor del timer.

El timer empieza a contar */

TCCR1B = ((1<<WGM12)|(1<<CS12)); // CTC y 1:256

OCR1A = TIEMPO_A_ESPERAR; // Cargamos el valor a contar

TIMSK1 = (1<<OCIE1A); // Habilitamos las interrupciones del timer

sei(); // Habilitamos las interrupciones generales

}

/*

* Chequea el estado de los switches del LCD

*/

void lecturaPulsadorLCD(void){

/* Variables para gestion del anti rebote (debouncing) de los

botones */

static unsigned char boton0 = 0;

static unsigned char boton1 = 0;

static unsigned char boton2 = 0;

/* Lectura continua sobre los pulsadores con debouncing */

if ((PIND & (1<<PORTD3)) == 0){ // Pulsado

if (boton0 < 255){ // Control de rangos

boton0++;

}

}else{ // No pulsado

if (boton0 > LIMITE_ANTIRREBOTE){ // Ha estado pulsado al menos

"LIMITE_ANTIRREBOTE" veces

/* Ponemos a zero el contador parcial 2 */

contadorSegundosParcial_2 = 0;

litrosParcial_2 = 0.0;

}

boton0 = 0;

}

if ((PIND & (1<<PORTD4)) == 0){ // Pulsado

if (boton1 < 255){ // Control de rangos

boton1++;

}

}else{ // No pulsado

if (boton1 > LIMITE_ANTIRREBOTE){ // Ha estado pulsado al menos

"LIMITE_ANTIRREBOTE" veces

/* Ponemos a zero el contador parcial 1 */

contadorSegundosParcial_1 = 0;

Page 108: Ejemplo de aplicación con Arduino: medida de caudal

108

litrosParcial_1 = 0.0;

}

boton1 = 0;

}

if ((PIND & (1<<PORTD5)) == 0){ // Pulsado

if (boton2 < 255){ // Control de rangos

boton2++;

}

}else{ // No pulsado

if (boton2 > LIMITE_ANTIRREBOTE){ // Ha estado pulsado al menos

"LIMITE_ANTIRREBOTE" veces

lcd.clear(WHITE); // Limpiamos la pantalla

pantalla++; // Cambiamos la pantalla a mostrar

if (pantalla >= NUMERO_PANTALLAS){

pantalla = 0;

}

}

boton2 = 0;

}

}

/*

* Funcion periodica cada 1 segundo.

* Cada segundo leemos los pulsos recibidos por el cuadalimetro,

* actualizamos los contadores de volumen acumulado e instantaneo,

* mandamos por la linea serie los pulsos detectados

* y refrescamos la pantalla a mostrar

*/

void task_1000ms(void){

float litrosUltimoMinuto;

/* Inicio zona segura intercambio de datos. No hay interrupciones */

cli(); // DesHabilitamos las interrupciones generales

contadorPulsosLocal = contadorPulsos;

contadorPulsos = 0; // Se escribe el la interrupcion y se limpia una

vez leido

sei(); // Habilitamos las interrupciones generales

/* Fin zona segura intercambio de datos */

itoa(contadorPulsosLocal,lcdStr,10);

SERIAL_PutString(lcdStr); // Mandamos los pulsos x segundo a la

linea serie

/* Convertimos los pulsos a litros por minuto y acumulamos los

totales */

litrosMinuto = contadorPulsosLocal * CONTADOR_RELACION;

litrosUltimoMinuto = (litrosMinuto / 60);

litrosTotales += litrosUltimoMinuto;

litrosParcial_1 += litrosUltimoMinuto;

litrosParcial_2 += litrosUltimoMinuto;

/* Incrementamos los contadores de tiempo */

contadorSegundos++;

contadorSegundosParcial_1++;

contadorSegundosParcial_2++;

/* Mostramos la pantalla que corresponda */

switch (pantalla){

case 0:

pantalla_principal();

break;

case 1:

pantalla_parcial_1();

break;

case 2:

pantalla_parcial_2();

break;

default:

Page 109: Ejemplo de aplicación con Arduino: medida de caudal

109

break;

}

}

/*

* Pantalla principal a mostrar

*/

void pantalla_principal(void)

{

lcd.setStr("Tiempo total", 3, 3, BLACK, WHITE);

lcd.setStr(" segundos", 19, 3, BLACK, WHITE);

itoa(contadorSegundos,lcdStr,10);

lcd.setStr(lcdStr, 19, 11, BLACK, WHITE);

lcd.setStr("Consumo actual", 35, 3, BLACK, WHITE);

lcd.setStr(" l x min", 48, 3, BLACK, WHITE);

dtostrf(litrosMinuto, 4, 2, lcdStr);

lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);

lcd.setStr("Litros totales ", 64, 3, BLACK, WHITE);

lcd.setStr(" ", 80, 3, BLACK, WHITE);

dtostrf(litrosTotales, 6, 2, lcdStr);

lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);

lcd.setStr("Cont.1 Cont.2 ", 96, 3, BLACK, WHITE);

lcd.setStr(" ", 112, 3, BLACK, WHITE);

dtostrf(litrosParcial_1, 4, 2, lcdStr);

lcd.setStr(lcdStr, 112, 3, BLACK, WHITE);

dtostrf(litrosParcial_2, 4, 2, lcdStr);

lcd.setStr(lcdStr, 112, 75, BLACK, WHITE);

}

/*

* Pantalla contadores parciales 1

*/

void pantalla_parcial_1(void)

{

lcd.setStr("Tiempo parcial 1", 0, 3, BLACK, WHITE);

lcd.setStr(" segundos ", 16, 3, BLACK, WHITE);

itoa(contadorSegundosParcial_1,lcdStr,10);

lcd.setStr(lcdStr, 16, 11, BLACK, WHITE);

lcd.setStr("Consumo actual ", 32, 3, BLACK, WHITE);

lcd.setStr(" l x min", 48, 3, BLACK, WHITE);

dtostrf(litrosMinuto, 4, 2, lcdStr);

lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);

lcd.setStr("Litros parcial 1", 64, 3, BLACK, WHITE);

lcd.setStr(" ", 80, 3, BLACK, WHITE);

dtostrf(litrosParcial_1, 4, 2, lcdStr);

lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);

lcd.setStr(" Totales ", 96, 3, BLACK, WHITE);

lcd.setStr(" ", 112, 3, BLACK, WHITE);

dtostrf(litrosTotales, 6, 2, lcdStr);

lcd.setStr(lcdStr, 112, 59, BLACK, WHITE);

}

/*

* Pantalla contadores parciales 2

*/

void pantalla_parcial_2(void)

{

lcd.setStr("Tiempo parcial 2", 0, 3, BLACK, WHITE);

lcd.setStr(" segundos ", 16, 3, BLACK, WHITE);

itoa(contadorSegundosParcial_2,lcdStr,10);

lcd.setStr(lcdStr, 16, 11, BLACK, WHITE);

Page 110: Ejemplo de aplicación con Arduino: medida de caudal

110

lcd.setStr("Consumo actual ", 32, 3, BLACK, WHITE);

lcd.setStr(" l x min", 48, 3, BLACK, WHITE);

dtostrf(litrosMinuto, 4, 2, lcdStr);

lcd.setStr(lcdStr, 48, 11, BLACK, WHITE);

lcd.setStr("Litros parcial 2", 64, 3, BLACK, WHITE);

lcd.setStr(" ", 80, 3, BLACK, WHITE);

dtostrf(litrosParcial_2, 4, 2, lcdStr);

lcd.setStr(lcdStr, 80, 19, BLACK, WHITE);

lcd.setStr(" Totales ", 96, 3, BLACK, WHITE);

lcd.setStr(" ", 112, 3, BLACK, WHITE);

dtostrf(litrosTotales, 6, 2, lcdStr);

lcd.setStr(lcdStr, 112, 59, BLACK, WHITE);

}

/*

* Incrementa el contador de segundos

*/

ISR(TIMER1_COMPA_vect){

segundos++;

}

/*

* Incrementa el contador de pulsos

*/

ISR(INT0_vect){

contadorPulsos++;

}

Parte del contenido modificado de “ColorLCDShield.h”

Para compilar la librería sin depender del entorno Arduino, se han modificado los

ficheros a incluir, y se ha redefinido las librerías de delay para que utilice las del

AVRStudio.

/*

ColorLCDShield.h - Arduino Library to control a Nokia 6100 LCD,

specifically that found on SparkFun's Color LCD Shield.

This code should work for both Epson and Phillips display drivers

normally found on the Color LCD Shield.

License: CC BY-SA 3.0: Creative Commons Share-alike 3.0. Feel free

to use and abuse this code however you'd like. If you find it useful

please attribute, and SHARE-ALIKE!

This is based on code by Mark Sproul, and Peter Davenport.

*/

#ifndef ColorLCDShield_H

#define ColorLCDShield_H

#define PHILLIPS 0

#define EPSON 1

/* The content of this include had been joined at "Arduino.h" */

/* #include <WProgram.h> */

//#include "Arduino.h"

#include "pins_arduino.h"

#include <inttypes.h>

/* Para aseguranos que trabajamos con la frequencia correcta para nuestro

Arduino */

#ifdef F_CPU

Page 111: Ejemplo de aplicación con Arduino: medida de caudal

111

#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)

A partir de este punto se ha mantenido el contenido del fichero utilizado en el

entorno Arduino.

ANEXO 8: Contenido del soporte digital del PFC

En el soporte digital del PFC se ha añadido el código fuente, los programas a instalar

y la documentación técnica referente a los componentes.

El objetivo es poder configurar un PC de manera que pueda reproducirse cualquier

punto del PFC con las versiones de las aplicaciones aquí descritas.

En la raíz del soporte digital podemos encontrar el documento del PFC, su resumen y

tres carpetas.

La primera carpeta contiene el código fuente del PFC para ser ejecutado en entorno

Arduino, AVRStudio y la aplicación python para el PC. También contiene una serie de

ejemplos y librerías para el AVRStudio. Y utilidades para programar directamente el

Arduino des del AVRStudio, calcular el tamaño en RAM y FLASH de un binario y un

monitor serie para Windows que no necesita ser instalado.

La segunda contiene los instaladores y programas para Windows necesarios para

poder compilar y ejecutar el código del proyecto, tanto en Arduino, como AVRStudio

como en python. El entorno Arduino se ha entregado con las librerías del PFC

configuradas, y listo para ser ejecutado y lanzar el proyecto Arduino sin necesidad de ser

instalado. El AVRStudio es un paquete que contiene todas las dependencias necesarias

para poder ser instalado sin necesidad de conexión a internet. La carpeta python contiene el

aplicativo python para ser instalado y librerías adicionales que se deben instalar para poder

ejecutar la aplicación de PC.

La tercera carpeta contiene la documentación técnica referente al microcontrolador,

el LCD y caudalímetro utilizada durante el desarrollo del proyecto.

Esta es la estructura de carpetas del soporte digital:

Page 112: Ejemplo de aplicación con Arduino: medida de caudal

112

Ilustración 64: Estructura de carpetas del soporte digital

Page 113: Ejemplo de aplicación con Arduino: medida de caudal

113

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>

Page 114: Ejemplo de aplicación con Arduino: medida de caudal

114

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/>

Page 115: Ejemplo de aplicación con Arduino: medida de caudal

115

[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>

Page 116: Ejemplo de aplicación con Arduino: medida de caudal

116

[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>