Diseño, Construcción y Puesta A Punto de Un Teslámetro Mediante El Sistema Arduino
Diseño, Construcción y Puesta A Punto de Un Teslámetro Mediante El Sistema Arduino
Diseño, Construcción y Puesta A Punto de Un Teslámetro Mediante El Sistema Arduino
2016/2017
Resumen
Este proyecto pretende obtener un Teslametro de bajo coste, elaborado a partir de hardware y
software libre, escogiendo como plataforma abierta Arduino junto con otros dispositivos y intentado
reutilizar objetos desechados en casa. Todo ello para poder disponer de un dispositivo para el
laboratorio de física Nikkola Tesla de la ETSINF; elaborado desde la misma universidad para el
desarrollo de la universidad.
Resum
Aquest proyecte preten obtindre un Teslametre de baix cost, elaborat a partir de hardware y software
lliure, escollint com a plataforma oberta Arduino junt amb altres dispositius i intentant reutilitzar
objectes en des ús de casa. Tot açó per poder disposar d'un dispositiu per al laboratori de fisiaca
Nikkola Tesla de la ESTINF elaborat desde la mateixa universitat y per al desenvolupament de la
universitat.
Abstract
The objective of this project is to obtain a low cost Teslameter, made with free hardware and free
software. Arduino has been chosen as an open platform along with other devices, and we have tried
the recycling of discarded items at home. All this in order to have a device for the Nikkola Tesla
Physics laboratory at ETSINF: created from university for the development of the University.
We have developed the analysis, design, implementation and testing of the resulting device, putting
into practice different techniques learned during the degree on computer engineering. Moreover we
have used different buses of communication and we have corrected the rebound effect of electrical
signals. In conclusion, this work involves a complete resolution on an engineering project.
Capítulo 2: Análisis................................................................................................3-14
2.1: Introducción a los Teslámetros............................................................3-5
2.2: Requerimientos del dispositivo...............................................................5
2.3: Selección de los dispositivos...............................................................6-9
2.3.1: Comparativa Arduinos............................................................................7
2.3.2: Comparativa sensores Hall..................................................................7-8
2.3.3: Comparativa SD/microSD...................................................................8-9
2.4: Introducción a Arduino Due y los módulos seleccionados................9-14
2.4.1: Arduino Due......................................................................................9-10
2.4.2: Display LCD....................................................................................11-12
2.4.3: Reloj RTC Adalloger.......................................................................12-13
2.4.4: Lector tarjetas microSD Adalloger.......................................................13
2.4.5: Sensor Hall A1318...........................................................................13-14
2.4.6: Botonera interfaz de usuario.................................................................14
Capítulo 3: Diseño................................................................................................15-24
3.1: Diagramas de flujo...........................................................................15-21
3.1.1: Diagramas de flujo principal.................................................................15
3.1.2: Diagramas de flujo tratamiento de las muestras...................................16
3.1.3: Diagramas de flujo impresión de las muestras por el display...............17
3.1.4: Diagramas de flujo guardado de las muestras en la microSD...............18
3.1.5: Diagramas de flujo de la lectura de una muestras.................................19
3.1.6: Diagramas de flujo de la adecuación del valor captado.............................19-20
3.1.7: Diagramas de flujo de representación de la magnitud medida.............21
3.2: Conexionado de los componentes.....................................................22-24
3.3: Revestimiento y alimentación del dispositivo........................................24
Capítulo 4: Implementación.................................................................................25-37
4.1: Estructura de la lectura de muestras.......................................................25
4.2: Librerías utilizadas............................................................................26-27
4.2.1: LiquidCrystal..........................................................................................26
4.2.2: SPI y SD.................................................................................................26
4.2.3: Wire y RTClib........................................................................................27
4.3: Funciones..........................................................................................27-34
4.3.1: setup()................................................................................................27-28
4.3.1.1: inicializaPantalla()...................................................................28
4.3.1.2: inicializaSD()...........................................................................28
4.3.1.3: creaFichero().............................................................................28
1
4.3.2: loop()................................................................................................28-34
4.3.2.1: tratamientoMuestra()..............................................................29
4.3.2.2: impresionMuestra(lecturaSensor)......................................29-30
4.3.2.3: guardarMuestra(lecturaSensor)...............................................30
4.3.2.4: leeValorSensor().................................................................30-31
4.3.2.5: convertirValor(int)...................................................................31
4.3.2.6: magnitud(lecturaSensor)..........................................................31
4.3.2.7: Tratamiento de interrupciones............................................31-34
4.3.2.7.1: mantener()..........................................................................32
4.3.2.7.2: unidades()..........................................................................32
4.3.2.7.3: iluminacion()................................................................32-33
4.3.2.7.4: rangos()..............................................................................33
4.3.2.7.5: maximominimo()...............................................................33
4.3.2.7.6: extraerConSeguridad().......................................................33
4.3.2.7.7: borrado()............................................................................34
4.3.2.7.8: borradoInformacion()........................................................34
4.4: Montaje del dispositivo....................................................................34-37
4.4.1: Preparativos para el montaje del dispositivo...................................34-36
4.4.1.1: Realizar perforaciones............................................................35
4.4.1.2: Soldado de la botonera, pines extra y sensor hall A1318........35
4.4.2: Colocación y conexionado de los componentes....................................36
4.4.3: Cierre y comprobación del acabado.................................................36-37
4.4.4: Carga del archivo fuente a la placa Arduino Due..................................37
Capítulo 5: Comprobación.................................................................................38-39
5.1: Pruebas caja blanca y caja negra...........................................................38
5.2: Comprobación con otro Teslametro.................................................38-39
Capítulo 6: Presupuesto......................................................................................40-43
6.1: Diagrama de Gannt................................................................................40
6.2: Presupuesto del hardware......................................................................41
6.3: Presupuesto del software.......................................................................42
6.4: Comparación con un Teslámetro comercial..........................................43
Bibliografía..........................................................................................................47-49
Apéndice..............................................................................................................50-61
Código fuente........................................................................................50-61
2
Índice de figuras
1
Figuras del capítulo 5 .
Figura 5.1: Gráfica comparativa teslametros midiendo una bobina.......39
Figura 5.2: Gráfica comparativa teslametros midiendo un imán............39
2
Índice de tablas
1
Capitulo 1 : Introducción
En este trabajo vamos a aproximarnos a la fabricación de un Teslámetro. Intentado que
sea fácil de montar, programar y reparar, destinado al uso educativo en los laboratorios
de física de la ETSINF.
1.1 Motivación
Con la aparición del hardware libre o hardware abierto, se ha dado una puerta al
desarrollo de instrumentación de laboratorio. Donde a partir de diseños libres, se puede
ir creando distintos aparatos como Teslametros, Voltímetros, Amperímetros, Generador
de señales, Osciloscopios, Brazos robots, Impresoras 3D... con los cuales promulgar la
investigación científica de un coste mucho más asequible para estudiantes y
emprendedores. Como al mismo tiempo aporta una capacidad creativa de adaptación de
los instrumentos elaborados a las necesidades particulares de cada persona.
1.2 Objetivos
laboratorio de física.
1
1.3 Estructura de la memoria
Con un total de siete capítulos, nos adentramos en el diseño e implementación de un
Magnetómetro. En este apartado se comentara brevemente el contenido de cada
capítulo.
2
1.4 Uso bibliográfico
En este apartado vamos a explicar del material bibliográfico utilizado para elaborar el
proyecto.
• En primera instancia empleamos los recursos de la Efecto Hall [13], RAE [14],
Magnetómetro [16] y Wikipedia [17] para introducirnos en los Teslámetro, y así
poder analizarlos.
• Una vez clara la idea de los magnetómetros, procederemos a buscar dispositivos con
los que confeccionar el proyecto. Para ello empleamos los recursos Arduino [7] y
RsComponentes [15].
• Por último, para dar precio a las horas dedicadas al trabajo y aproximarnos al
mundo laboral, damos uso al recurso del Boletín oficial del estado [11]. En el
documento oficial del estado queda declarado el sueldo mínimo correspondiente con
los distintos trabajos relacionados con la consultoría informática.
3
Capitulo 2 : Análisis
Durante el segundo capitulo se va a proceder a investigar y analizar el funcionamiento
de un Teslámetro. Procederemos a buscar los Teslametros existentes en el mercado,
extraeremos los requerimientos hardware, y procederemos a buscar y seleccionar los
componentes necesarios para el desarrollo del dispositivo.
4
Magnetómetro:
Aparato que mide la inducción de un campo magnético en una dirección determinada
Un magnetómetro básico como el de la Figura 2.2, dispone de una display LCD, una
interfaz de usuario, y una sonda de medición o sensor.
1 El efecto Hall se produce cuando se ejerce un campo magnético transversal sobre un cable por el
que circulan cargas. Como la fuerza magnética ejercida sobre ellas es perpendicular al campo
magnético y a su velocidad según la ley de Lorentz, las cargas son impulsadas hacia un lado del
conductor y se genera en él un voltaje transversal o voltaje Hall.
5
Entre ellos podemos destacar los escalares que miden la fuerza en una única dirección
del vector B de campo magnético al que son sometidos; y los vectoriales que tienen la
capacidad de medir todas las componentes del vector del campo, concretamente las
componentes (X,Y, Z).
Leyendo un poco sobre el tema, podemos definir como común; una pantalla por la que
imprimir la información, una botonera de interfaz de usuario y un sensor Hall.
6
2.3 Selección dispositivos
Sabiendo nuestras necesidades, es momento de tomar decisiones respecto a como
plantearnos el dispositivo.
Primera decisión a tomar es la forma que utilizamos para imprimir la información. Para
ello podemos disponer de la comunicación con un PC y aprovechar su pantalla; o
integrar una pantalla ligera en el dispositivo. La ausencia de una pantalla integrada en el
dispositivo impide que este dispositivo sea portátil, mientras que con una pantalla
integrada nos permite desplazarnos donde queramos fácilmente y sin necesidad de un
PC.
Definitivamente optamos por integrar una pantalla en el dispositivo. Ahora hay que
decidir que tipo de pantalla integramos. En este caso, vamos a considerar cuanta
información disponemos para imprimir. Donde recae otra decisión, que sensor Hall
vamos a escoger, decidimos utilizar un sensor Hall escalar o lineal con una única
medida, esta decisión se comenta más a fondo en el Capitulo 2.3.3.
Otra decisión a tener en cuenta es como implementar la interfaz de usuario. Esta viene
condicionada por la primera decisión de como imprimir la información, por el hecho de
que en esa decisión escogimos integrar la pantalla para poder prescindir de un PC o
otros.
Por ello, siguiendo con el mismo razonamiento, nos vemos obligados a escoger una
botonera física integrada en el dispositivo, más adelante explicaremos con más
detenimiento las distintas tomas de decisión que surgen a consecuencia de esta última,
concretamente en el Capitulo 2.4.6
7
la interfaz y su lenguaje de programación, utilizando por tanto C++ y aumentado la
dificultad al uso pero ampliando la profundidad de comprensión en su funcionamiento.
Con una breve historia, dispone de una larga documentación y módulos compatibles,
una gran parte contribuyen con la fundación Arduino, aunque hay muchos otros que
son compatibles que no lo hacen, con esta historia hay mucha controversia en la cual
no nos inmiscuiremos, aunque en este proyecto tendremos en cuenta a aquellos que si
contribuyen con la fundación Arduino. Seguidamente analizaremos brevemente las
placas existentes de Arduino y seleccionaremos aquella que más se adecue al proyecto.
Existen varias placas con distintas prestaciones, intentando adaptarse a cierto tipo de
aplicaciones. Las más comunes son Arduino UNO, Arduino Mega, Arduino Mini,
Arduino Nano, Arduino Leonardo,Arduino Due. Existen otras menos comunes como
Arduino Lili, Arduino Fio o Arduino Pro Mini.
De entre los más comunes, muchos de ellos tienen un número bajo de pines como
Arduino Uno, Arduino Leonardo, Arduino Mini, Arduino Nano, los cuales nos sirven
para este proyecto, pero están un poco limitadas para hacer ampliaciones y además nos
quedamos un poco cortos con las capacidades de interrupciones hardware, que solo
dispone de 2. Mientras que Arduino Mega y Arduino Due dispone de 6 con los pines
fijos para la Mega, pero para la Due cualquier pin Digital puede ser configurado como
interrupción. Todo esto podemos observarlo en la Tabla 2.3.1
Así que tenemos como posible candidatas Arduino Mega y Arduino Due, ambas sirven
para nuestro propósito. Para este proyecto hemos decidido usar Arduino Due, porque
dispone de más frecuencia de reloj, de una resolución de 12 bits en sus conversores
analógico-digital, permitiéndonos una mejor precisión de medida del campo.
Aunque nos plateemos usar Arduino Due por posibles ampliaciones, debemos tener en
cuenta que Arduino Mega también se puede usar y se programara el código de
funcionamiento para que sea compatible con ella.
Hemos de tener en cuenta, que este sensor va a ser el encargado de percibir el campo
magnético. Por tanto cuanto mas sensibilidad posea el sensor más precisas serán las
muestras obtenidas en las unidades estándares de medición (Tesla y Gauss), pero
también nos interesa tener un rango de medida de al menos 200 mT [-100 mT, 100
mT].
Existen distintos tipos de sensores Hall (escalares, vectoriales). Para una primera
aproximación a los Magnetómetros básicos, nos centraremos en escoger sensores
escalares, son económicos y simples, miden en un eje pudiendo llegar a medir una de
las componentes del vector B de campo magnético al que es sometidos dependiendo
8
del ángulo en el cual se realice la medida. Los sensores Hall vectoriales también son
económicos, sencillos, y miden los tres ejes. A pesar de ello es más conveniente
emplearlos en futuras ampliaciones del Magnetómetro y así desarrollar uno avanzado.
Teniendo en cuenta que vamos a utilizar una Arduino Due que funciona a 3,3V
necesitamos un sensor que trabaje a esa tensión. Muchos trabajan por encima de los 3
V, así que estamos un poco limitados. Aunque en el caso de usar Arduino Mega
tendríamos bastante más gama a elegir.
Hay más opciones a escoger, pero estos tres modelos son los que ofrecían una
sensibilidad adecuada para nuestro proyecto. Y como elección final tomamos el A1318
que dispone un voltaje máximo más próximo al máximo de los pines de Arduino Due,
de este modo aseguramos el correcto funcionamiento del sensor, ja que los otros dos
necesitan el doble de la proporcionada por los pines de Arduino Due.
Por lo tanto con el sensor Hall A1318, tenemos un rango entre [-128 mT, 128 mT], con
una sensibilidad de 0,5 mT / b. Mientras que el AH49E tiene [-103,25 mT, 103,25 mT],
con un sensibilidad de 0,4 mT / b. Y TSH481 tiene [9-1 mT, 91 mT] con 0,35 mT/b.
Para finalizar las comparativas, hablaremos un poco sobre las tarjetas SD y las
microSD. Aunque a primera vista parezcan iguales pero distintas en tamaño, ocultan
otras pequeñas diferencias. Existen distintos tipos de estas tarjetas, SD, SDHC y las
SDXC. Además de distintas clases (2, 4, 6 y 10). Cada una tiene unas propiedades
distintas de capacidad y velocidad de transmisión.
Arduino accede a las tarjetas utilizando el bus SPI a una velocidad máxima de 8 MHz
sin acceso dinámico de memoria (DMA), por lo que nunca obtendrá una velocidad de
transferencia superior a unos 500 KB/seg, aproximadamente la mitad de la velocidad
9
del bus estándar. En la práctica la velocidad de lectura máxima de un archivo es de
aproximadamente de 300 KB/ seg.
La mayoría de PC's, Macs o otros dispositivos acceden a las tarjetas usando el bus a
una frecuencia de reloj de hasta 50 MHz y el bus es de 4 bits de ancho de banda por lo
que es posible una tasa de lectura de 25 MB/seg. Las tarjetas nuevas utilizan el bus
UHS-1 que alcanza los 104MB/seg.
Arduino Due es una variante de Arduino con un procesador ARM CortexM3 de 32 bits,
programables desde la interfaz de Arduino, con una frecuencia de funcionamiento de
84MHz, a 3,3V de tensión de funcionamiento.
10
Figura 2.4: Arduino Due
11
2.4.2 Display LCD
Se va a conectar mediante el modo 4 pines, donde los pines 11, 12, 13 y 14 van a
transmitir datos. Esta forma de funcionamiento es muy rápida y nos permite poder
tener una alta tasa de refresco del display. Se podrían usar otros buses, como por
ejemplo con un bus I2C con el que tendríamos una sensación de retardo para tan solo
dos conexiones menos, mientras que con el modo 8 pines, duplicaríamos el cableado
para la transmisión pero no mejoraríamos las prestaciones ya que no necesitamos tanto
ni tampoco disponemos de un display muy grande.
12
Figura 2.7: Display LCD
Echando una ojeada en las tiendas on-line de los productores oficiales de hardware
compatible con la fundación Arduino, encontramos un módulo de Adaloger Feather
RTC y microSD, integrados en la misma placa; nos proporciona una doble solución a
nuestro proyecto.
El reloj RTC funciona a 3V y utiliza el bus I2C para comunicarse con la placa Arduino.
Se utiliza la librería RTClib para su programación.
13
Figura 2.8: Adalloger Feathuring
Definitivamente se escoge el sensor Hall A1318 lineal de 1.3 mV/Gauss con conexión
One-Wire; de los cuales hay muchos fabricantes y se puede elegir cualquiera de ellos
que cumpla esas condiciones y sea compatible con Arduino Due.
14
Figura 2.9: Sensor Hall A1318
Para ello con unos botones para circuitos impresos, unas resistencias de 10k Ohmios,
un condensador de 6 uF, una PCB perforadora en matriz, para que con un poco de
estaño y un soldador poder disponer de nuestra interfaz de usuario para utilizar el
Magnetómetro.
Con todo esto conseguimos solucionarlo de una forma muy económica y sencilla de
reparar. No dispondrá de unos acabados perfectos para su venta, pero si suficientes para
fomentar el aprendizaje y auto-construcción de prototipos.
Además configuraremos los pines correspondientes para que detecten los flancos de
bajada de los botones y activen cada uno su interrupción correspondiente. Además de la
incorporación de un condensador para anular el efecto rebote o debounce de los
pulsadores, también se programara un sistema de control mediante la medición
temporal entre flancos de activación de las interrupciones.
15
Capitulo 3 : Diseño
Durante este capitulo vamos a elaborar el diseño del dispositivo, para ello
confeccionamos un flujo de los datos para orientarnos luego en la implementación del
código. También seleccionaremos los pines a los que se conectará cada componente al
Arduino Due, y por último diseñaremos dentro de la caja la colocación de los
componentes y comentaremos la alimentación del dispositivo.
Seguido del método principal que siempre se repite, loop(). Donde se realiza una
limpieza del display lcd y se invoca a la función tratamientoMuestra, que gestiona toda
la toma de información, impresión y almacenado de cada muestra tomada.
16
3.1.2 Función tratamientoMuestra
Como se puede observar en la Figura 3.2 primero se lee una muestra, luego se examina
por si es máximo o mínimo. Seguidamente dependiendo de la interacción del usuario,
se realizara una gestión distinta, si el usuario deseaba mantener la imagen congelada en
el display LCD se invocara la función impresionMuestra pasándole como parámetro el
valor a mantener almacenado en la variable correspondiente; por otra parte se invocaría
la misma función pero como parámetro la muestra tomada en esa misma iteración del
programa.
17
Hay que observar que se utiliza un tipo de datos llamado lecturaSensor, el cual es una
estructura conformada por 7 elementos significativos de la representación de
información perteneciente a una lectura del sensor Hall.
18
3.1.4 Función guardarMuestra
19
3.1.5 Función leeValorSensor
Esta función necesita un entero como parámetro de entrada, que es la lectura del pin
analógico al que esta conectado el sensor Hall. Además devuelve un double resultado
de aplicar una ecuación de acondicionamiento de la señal proporcionada.
Como se observa en Figura 3.7, diferenciamos entre las muestras tomadas en Tesla o en
Gauss, permitiendo poder tener mayor versatilidad de magnitudes, consiguiendo así T,
mT, uT, kG, G y mG.
20
1G 1 mT 3300 mT
3300 mV × × = =253,846 mT
1,3 mV 10 G 1,3⋅10
Figura 3.6.1: Máximo rango de medida
Sabiendo que el valor 0 del campo magnético corresponde a una tensión de 1,62 V,
sabemos que los valores negativos del campo magnético oscilaran entre 0 V a 1,62V y
los valores positivos de 1,62 V a 3,3 V. Habiendo calculado el valor máximo que
podemos captar con el sensor, si este resultado le una ecuación de adaptación para el
rango de medida de [-126,923 mT, 126,923 mT]. Observamos que el valor captado en
la entrada analógica de Arduino Due varia entre [0, 1024], este valor hay que adaptarlo
al rango de [-126,923 mT, 126,923 mT]. Para ello operamos y al generalizar
obtenemos:
Vmax×1 G×1 mT
( )
Vsensor×10 G Vmax×1G×1 mT
valor×( )−
resolucion Vsensor×10 G×2
Figura 3.6.2: Ecuación de adecuación de la señal
Donde valor es la lectura de la entrada analógica de la placa Arduino Due, Vmax es la tensión
máxima de la placa Arduino Due (3300 mV), Vsensor es la tensión por cada Gauss dada de cada
sensor hall; en nuestro caso el sensor hall A1318 tiene 1,3 mV/G. Resolución es el total de bits
utilizados por el sensor y la placa Arduino Due para la representación de la señal analógica
transmitida.
21
En la figura 3.7, vemos el procedimiento seguido para convertir el valor leído al rango
de medida adecuado. Además teniendo en cuenta en la unidad de medida en la cual se
esta solicitando las muestras por parte del usuario.
22
3.2 Conexionado de los componentes
En este apartado plantaremos la interconexión de componentes y definiremos los pines
de la placa de Arduino Due que tendrán los correspondientes buses de comunicación
con los periféricos. Y al mismo tiempo definir en cada periférico en que pines se
conecta a la placa.
Algunos de los módulos representados no son los mismos que el montaje final, pero
cumplen sus misma características de funcionamiento e interconexión.
Utiliza los pines 8(pin 4 del display),9(pin 6 del display), 4-7(pines 11-13 del
display); de la placa de Arduino Due.
23
● Reloj RTC I2C
Al utilizar el bus I2C, utiliza un pin para reloj(SCL) y otro para datos(SDA). Se
ha decidido utilizar los puertos de la placa Arduino dedicados al segundo bus
I2C implementado, SCL1 y SDA1; el resto de conexiones son simplemente la
alimentación del modulo como queda reflejado en la Figura 2.4.
24
y 3,3V, pudiendo activar nuevas interrupciones sin que sean realmente
solicitadas por el usuario.
A lo que la caja respecta hemos decidido construir nosotros mismo la caja donde
montar el dispositivo. Reutilizaremos algún tupper-ware o caja de plástico, que
vallamos a desechar, suficientemente grande para abarcar nuestros dispositivos y
cableado. De esta manera fomentamos la creación de prototipos caseros y una toma de
contacto con la reutilización de los desechos plásticos en nuestros proyectos,
consiguiendo darle uso a muchos desechos que se generan en el día a día en los hogares
y que acaban en vertederos, así conseguimos alargar la vida útil de ciertos desechos y
incentivando el reciclaje y la reutilización.
25
Capitulo 4 : Implementación
En este cuarto capitulo vamos a implementar los diseños realizados en el capitulo anterior.
Para ello separamos la estructura de datos utilizada para datos del sensor, las librerías
utilizadas, las funciones de flujo de datos y el montaje del dispositivo en la caja.
struct lecturaSensor {
int valorOriginal;
double valor;
String polaridad;
int rango;
boolean unidad;
String magnitud;
DateTime fechaYHora;
};
26
4.2 Librerías utilizadas
Durante el siguiente apartado vamos a presentar a las librerías empleadas en el
desarrollo del software.
4.2.1 LiquidCrytal
Esta librería permite a la placa Arduino Due controlo el diplay LCD. La librería trabaja
en el modo 4 o 8 bit.
Para trabajar con ella se crea una variable global del tipo LiquidCrystal e invocando al
constructor de la clase que nos convenga. Existen 4 que son :
• LiquidCrystal(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7)
• LiquidCrystal(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7)
En ellos podemos observar las variables que guardan relación con los pines del display
planteados en el capitulo 2.4.2. El primero de ellos activa el display en modo 4 bit y
además solo lectura, el segundo es con lectura y escritura. Del mismo modo para el
tercero y cuarto, pero estos para el modo 8 bit.
Además dispone de otras funciones, como begin(), clear(), setCursor(), print(), cursor(),
leftToRight(), entre otros. Todo esto esta disponible en la pagina web de Arduino.
4.2.2 SPI y SD
La librería SPI, consiste en una clase de control del bus SPI (Serial Peripheral
Interface) el cual sigue el protocolo de conexión serie síncrona. Este bus es utilizado
por la tarjeta SD, para comunicarse con la placa Arduino Due. La librería SD habilita el
bus utilizando la librería SPI, y invocando las funciones de la librería SD controlamos
el modulo de la tarjeta micro SD. de esta manera lee y escribimos en los archivos
almacenados en la micro SD.
27
4.2.3 Wire y RtcLib
Estas librerías son utilizadas para el funcionamiento del dispositivo del reloj RTC, en
concreto la librería Wire es utilizada por la librería RTClib para usar el bus I2C o TWI,
al igual como pasa con la librería SPI y SD.
El bus en este caso esta formado por dos conexiones, una de datos(SDA) y otra de
sincronización (SCL). Es un protocolo asíncrono, SCL indica cuando leer los datos.
Cada dispositivo conectado al bus tiene una dirección de 7 bits con lo que se pueden
conectar hasta 128 dispositivos en paralelo (2 ⁷). Entre ellos debe haber uno o más
maestros que controlan el reloj, pudiendo estar solo uno activo a la vez. Y el resto de
dispositivos son esclavos.
4.3 Funciones
A continuación presentaremos la implementación de las funciones pertenecientes a los
diagramas de flujo de datos realizados previamente. Están dividas dentro de donde son
utilizadas, es decir, los programas en Arduino se componen del setup() y del loop(), y
pueden haber más funciones pero solo van a poder ser invocadas dentro de los dos
anteriores .
Por tanto están divididas entre las que son invocadas en el setup() y las que son
invocadas en el loop().
4.3.1 setup()
28
Donde indicamos el pin mediante una conversión a pines de interrupción con
digitalPinToInterrupt() . Luego el nombre de la función de tratamiento donde ejecutara
las acciones previstas para esa interrupción y el flanco de detección de la interrupción.
Luego se invocan 3 funciones escritas fuera del bloque del setup(), para juntar en cada
una los procesos de inicialización de los distintos componentes.
4.3.1.1 inicializaPantalla()
4.3.1.2 inicializaSD()
4.3.1.3 creaFichero()
Para ello instancia una variable del tipo DateTime con valor rtc.now(), de manera que
dispone de la fecha y hora de ese momento. Luego abre un archivo con
SD.open(nombreFichero, FILE_WRITE) con nombre el String almacenado en la
variables nombreFichero y en modo escritura; escribe “Lectura del dd/mm/yyyy a las
hh:mm:ss” en el fichero abierto y por último cierra el fichero.
29
4.3.2 loop()
4.3.2.1 tratamientoMuestra()
4.3.2.2 impresionMuestra()
30
Por contra, si no se solicitan el máximo y el mínimo; el dispositivo imprime las lecturas
tomadas una tras otra. De manera que en la fila 0 del display se imprime la polaridad, el
valor y la unidad del muestreo; y en la fila 1 del display se imprime el estado del
dispositivo.
De manera que si HOLD es true se muestra una “H”, se muestra la unidad utilizada, el
rango aplicado a la unidad, y por ultimo información correspondiente con la tarjeta SD
insertada, si hay tarjeta indica su tipo (SD1, SD2, SDH), y seguido el formato de
archivos de la tarjeta, si existe un problema con el formato de archivos imprime “Fat
E” o si no se puede escribir las muestras imprime “Error W”; por contra en caso de no
haber insertado tarjeta, imprime “Fallo SD”.
4.3.2.3 guardarMuestra()
Para guardar el valor de las distintas variables con información relevante, se invoca la
función guardarMuestra(lecturaSensor) declarada void, necesita como parámetro una
estructura del tipo lecturaSensor almacenada en la variable ls..
4.3.2.4 leeValorSensor()
En esta función se realiza la lectura del sensor en un instante dado. Para ello no
necesita parámetros de entrada, pero si devolver la estructura lecturaSensor creada en
su invocación.
Para tomar la muestra, almacena en la variable valorOriginalNou del tipo int el valor
de la entrada analógica mediante analogRead(SENSOR), además en la variable
valorNou del tipo double almacena el valor devuelto por la invocación a la función
convertirValor(valorOriginalNou).
31
Due. Si el valor es mayor o igual se asigna “S” a la variable polNou del tipo String,
sino asigna “N” a la misma variable.
Crea una struc del tipo lecturaSensor llamada nova a la cual asigna todos los campos
obtenidos. El valorOriginalNou, el valorNou, el polNou, junto al estado de las
variables globales RANGOACTUAL y TESLA. Es asignado espacio nulo (“”) en el
String de la magnitud, y la hora y fecha del relog RTC mediante rtc.now().
4.3.2.5 convertirValor(int)
4.3.2.6 magnitud(lecturaSensor)
La función magnitud(), recibe como parámetro de entrada una estructura del tipo
lecturaSensor, y retorna otra estructura del mismo tipo.
32
Además hay que tener en cuenta que al tratarse de funciones de tratamiento de
interrupciones, se ha pretendido hacerlas lo más simples posibles para conseguir la
mayor eficiencia posible.
4.3.2.7.1 mantener()
Dicha variable cuando su valor es false, el usuario quiere ver por el display el
seguimiento del sensor, además por tiene este valor al iniciarse el dispositivo. Por el
contrario al solicitar congelar la imagen su valor es modificado a true.
4.3.2.7.2 unidades()
Cuando la variable TESLA esta con valor true significa que el usuario quiere
representar la medición en Tesla, además al iniciarse el dispositivo se inicializa a true
por defecto. Mientras que si la variable vale false el usuario quiere representar la
información en Gauss.
4.3.2.7.3 iluminacion()
Esta función tiene asociada la interrupción del pulsador conectado al pin instanciado
con la variable BOTONLLUM, al activarse esta interrupción la función iluminacion()
modifica el valor de la variable global apagada.
33
El valor por defecto al iniciarse el dispositivo es true, esto hace que la función
iluminacion() ejecute la instrucción digitalWrite(LLUM, HIGH), haciendo que el pin
14 del display LCD reciba 5V y encienda la iluminación de la pantalla. Mientras que al
modificar su valor a false, ejecuta digitalWrite(LLUM, LOW), apagando la
iluminación.
4.3.2.7.4 rangos()
4.3.2.7.5 maximoMinimo()
4.3.2.7.6 extraerConSeguridad()
Dicha función examina la variable global extraida del tipo boolean, si su valor es true
modifica a la variable extraida a false y además a otra variable boolean llamada iniSd a
true. Por otra parte al valer extraida false, esta función modifica estas dos mismas
variables a su opuesto, es decir, extraida queda a true y iniSd queda a false.
34
4.3.2.7.7 borrado()
4.3.2.7.8 borradoInformacion()
4.4.1 Preparativos
Para el montaje necesitamos, deformar los cilindros de plástico de manera que dejemos
el orificio al tamaño de nuestros tornillos reciclados.
35
Luego atornillar los porta-tornillos que acabamos de modificar a los orificios
correspondientes de los componentes y soldarlas con termo-silicona o con otro
adhesivo a la caja en la ubicación decidida para ese componente.
Una vez fijadas las bases para el atornillado se puede montar el circuito de la figura
3.3, y verificar la buena colación de los componentes y el cableado de conexión. Una
vez comprobado podemos desconectar el cableado y desatornillar los componentes de
las fijaciones. Previamente marcaremos las zonas a perforar para dejar hueco para
conectores, la pantalla y los botones.
Para perforar las zonas de los conectores, botones y pantalla; utilizaremos un soldador
de estaño o un pirograbador.
Una vez soldado con estaño los componentes y los cables de conexionado con la
Arduino Due se realiza un testeo de la tensión del circuito, comprobando su correcta
implementación.
36
Además en una porción de una PCD se conectan conectores hembra para ampliar los
pines de alimentación de 3.3V y GND. Y en el se coloca el potenciómetro que necesita
el display LCD.
Y el sensor Hall A1318, con tres cables de conexionado, GND, VCC, DATA.
Cuando este todo bien colocado y ninguna conexión se fuerce, el dispositivo esta
preparado para probarlo.
37
Figura 4.5: Teslametro con Arduino y reciclaje de desechos plásticos
38
Capitulo 5 : Comprobación
Durante este capitulo vamos a exponer los pasos seguidos para comprobar el correcto
funcionamiento del dispositivo.
Para ello primero realizamos la prueba de caja blanca que consiste en un seguimiento
en la ejecución del programa. Mediante la impresión de comentarios al comenzar una
función, durante su procedimiento y al salir de la función. De esta manera podemos
observar si el dispositivo ejecuta todo el código. Además se forzara a recorrer todas la
funciones a través de la interacción con la interfaz de usuario. Como resultado
obtendremos un registro detallado de las distintas rutas que sigue la ejecución del
código fuente.
Haciendo uso del Teslametro PHYWE del laboratorio Nikola Tesla de la ETSINF,
hemos contrastado el magnetómetro construido con Arduino. Tras unos cuantos errores,
conseguimos el modelo correcto. Para contrastar que las medidas son correctas,
medimos el campo magnético de una bobina la cual generaba hasta 25mT en su
interior, nosotros pudimos medir el exterior, debido a la ausencia de sonda externa. Y
además medimos el campo magnético de un imán.
39
Comparativa Teslametros
Medida de la parte externa de una bobina
5
4
3
2
1
B (mT)
0
-1 1 2 3 4 5 6 7 8 9 10 11 12 13 14
-2
-3
-4
-5
nº muestras
teslametro_arduino phywe_teslametro
Comparativa Teslametros
Medida de un imán
30,00
25,00
20,00
15,00
10,00
B (mT) 05,00
00,00
-05,00
-10,00
-15,00
-20,00
-25,00
-30,00
1 2 3 4 5 6 7 8 9 10
nº muestras
teslametro_arduino phywe_teslametro
40
Capitulo 6 : Presupuesto
En este capitulo se desglosa la organización temporal seguida para el desarrollo de este
proyecto, como además los presupuesto del hardware usados y del software
desarrollado.
41
6.2 Presupuesto hardware
Los componentes del dispositivo se han comprado en la tienda on-line y en una tienda de
electrónica convencional.
IVA
Total 80,68 €
42
6.3 Presupuesto software
En este último apartado del capitulo 6, vamos a presentar un presupuesto al trabajo
realizado. Según el sueldo marcado por el XVI CONVENIO COLECTIVO
ESTATAL DE EMPRESAS DE CONSULTORÍA Y ESTUDIOS DE
MERCADOS Y DE LA OPINIÓN PÚBLICA, y según el tiempo planificado
en el capitulo 6.1, obtenemos:
Análisis 40 8€ 320 €
Diseño 40 8€ 320 €
Implementación 80 8€ 640 €
Comprobación 20 6€ 120 €
Total 1694 €
43
6.4 Comparación con un Teslametro comercial
44
Capitulo 7 : Resultados y conclusiones
En este ultimo capitulo, vamos a exponer las mayores dificultades encontradas durante
el desarrollo del proyecto, las experiencias del trabajo realizado y posibles ampliaciones
en un futuro.
45
7.2 Experiencias y valoraciones del trabajo realizado
En el transcurso del trabajo, nos hemos aproximado a los Magnetómetros y a la
fabricación de dispositivos de laboratorio, con un precio muy reducido.
Con ello hemos practicado mucho del conocimiento adquirido durante el grado de
informática. Y puesto en practica con un ejemplo real, el cual se va a replicar y utilizar
en los laboratorios de física aporta una gran relevancia a la experiencia obtenida.
7.3 Ampliaciones
Para finalizar, vamos a exponer brevemente alguna de las posibles ampliaciones que da
pie este proyecto. Desde la ampliación del Magnetómetro resultante, como la
modificación del software para hacer que el dispositivo cumpla otro cometido.
• Ampliación del Magnetómetro: modificando el sensor Hall por uno del tipo
vectorial, ampliaríamos nuestras mediciones del campo magnético en los tres
vectores espaciales (X, Y, Z). Por otra parte, se puede modificar el firmware del
puerto USB-Nativo para que se conecte a un PC y desde él puedas acceder a los
datos almacenados en la tarjeta SD. Otra posible ampliación, seria una conexión
bluetooh, para transmisión de datos en tiempo real de forma inalámbrica, o para
acceder a los datos almacenados en la tarjeta SD. Y por supuesto se pueden añadir
canales de medición adicionales, solamente con añadirle sensores; o se podría
extraer el sensor a una sonda.
De esta manera se podría conseguir un dispositivo con una programación a alto nivel
implementada en el IDE de Arduino, fácil de explicar y utilizar como ejemplo en
asignaturas como DIP. Se tendría también el código escrito en C++ formando una
librería, con la que se podría emplear en asignaturas como MEC; y por ultimo el código
46
a bajo nivel útil para asignaturas como AIC, AAV, DSD, IIN. Pudiendo tener un ejemplo
común entre por ejemplo DIP, MEC y IIN las cuales están relacionadas pero sin más
conexión que las temáticas tratadas, es decir, carecen de ejemplos comunes que hagan
fácil visualizar la relación entre los distintos puntos de vista impartidos en cada una de
las ellas.
7.4 Conclusiones
comercial.
47
Bibliografía
[1] Adafruit. RTClib. Consultado el 05/02/2017
https://github.com/adafruit/RTClib/blob/master/RTClib.h
48
[11] Boletin oficial del Estado. XVI CONVENIO COLECTIVO
ESTATAL DE EMPRESAS DE CONSULTORÍA Y ESTUDIOS
DE MERCADOS Y DE LA OPINIÓN PÚBLICA Consultado el
13/02/2017
https://www.boe.es/boe/dias/2009/04/04/pdfs/BOE-A-2009-5688.pdf
DC-magnetic-field-gauss-meter-Tesla-BST-600-0-200mT-
2000mT/1422139_32622700574.html
sa=t&rct=j&q=&esrc=s&source=web&cd=8&ved=0ahUKEwiJl-6z-
8bSAhWpBcAKHUVtB5MQFghEMAc&url=http%3A%2F
%2Fwww.allegromicro.com%2F~%2Fmedia%2FFiles%2FDatasheets
%2FA1318-A1319-
Datasheet.pdf&authuser=1&usg=AFQjCNHQKewhUh9X4PWVjf1DSYEHH
xV0Sw&sig2=OiXHcD2P8VVRrHC8rNQLPA&cad=rja
ectromagnetismo07b.htm
49
[16] RSComponents. Productos. Consultado el 13/01/2017
http://es.rs-online.com/web/
50
Apéndice
Código fuente
0 #include <LiquidCrystal.h>
1 #include <SPI.h>
2 #include <SD.h>
3 #include <Wire.h>
4 #include "RTClib.h"
5
6 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7 /////////////////////////////////////////// Definición de variables ////////////////////////////////////////////////////////
8 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9 //acceso rápido al pin dedicado a botones o pines de actuadores o sensores
10 //botones llamada a ISR
11 #define HOLD 20
12 #define RANGO 3
13 #define UNITS 18
14 #define BOTONLLUM 22
15 #define BORRADOR 19
16 #define MAXMIN 21
17 #define EXTRACT 2
18 //sensor
19 #define SENSOR A0
20 //salida iluminacion pantalla
21 //#define LLUM 10
22 //entrada cs modulo sd
23 #define CS 53
24
25 //el reloj rtc de adaloger usa los puerto SDA1 y SCL1 en Arduino Due. En Arduino Mega usan
26 //SDA y SCL que son el pin 20 y 21, tenemos un conflicto de pines para Arduino Mega, con
27 //Hold y MaxMix
28
29 RTC_Millis rtc;
30
31 //variables para medición tiempo
32 unsigned long currentMillis, previousMillis = 0;
33 const long tiempo = 500, tiempoDisplay = 1000;
34
35 //para anular el debounce de la botonera
36 const int timeThreshold = 150;
37 int counterHold, counterLuz, counterRango, counterUnits, counterMaxMin, counterExtract= 0; int
38 counterBorrado = 0;
39 unsigned long currentHold, currentLuz, currentRango, currentUnits, currentMaxMin, currentExtract,
40 currentBorrado = 0;
51
41
42 //variables volátiles para la gestión de interrupciones
43 volatile boolean HOLDS = false; //botón hold
44 volatile boolean TESLA = true; //botón units
45 volatile boolean MAXIMOMINIMO = false; //botón MAXMIN
46 volatile boolean extraida = false; //botón MAXMIN
47
48 //variables sd
49 boolean iniSd = false;
50 boolean errorWrite = false;
51 unsigned long numMuestra = 0;
52 String nombreFichero = "datos.txt";
53
54 //variables para aplicar a la función hold y maxMin
55 struct lecturaSensor {
56 int valorOriginal;
57 double valor;
58 String polaridad;
59 int rango;
60 boolean unidad;
61 String magnitud;
62 DateTime fechadora;
63 };
64
65 //estructura de datos para almacenar la información acerca de una muestra.
66 DateTime dt0 (0, 0, 0, 0, 0, 0);
67 lecturaSensor muestra, valorMantener, muestraMax = {1000, 0, "", 0, true, "", dt0};
68 lecturaSensor muestraMin = {0, 0, "", 0, true, "", dt0};
69
70 //variables de rangos;
71 double rangoT[3]= {0.001, 1.0, 1000.0};
72 double rangoG[3]= {0.001, 1, 1000};
73 int RANGOACTUAL = constrain (RANGO,ACTUAL, 0, 2);
74
75 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
76 //////////////////////////////////////Variables y métodos Modulo SD//////////////////////////////////////////////////
77 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
78 Sd2Card card;
79 SdVolume volume;
80
81 File archivoDatos;
82
83 void inicializaSD(){
84 //Serial.println("Inicialización del modulo SD:");
85 //intentamos inicializar la tarjeta sd. si no inicializa lo marcamos con la variable iniSd a false
86 //para reintentarlo mas tarde
52
87 if (!SD.begin(CS)) {
88 iniSd = false;
89 }else{
90 iniSd = true;
91 }
92 //habilita la tarjeta de forma que se puede leer su configuración
93 if (!card.init(SPI_HALF_SPEED, CS)) {
94 //Serial.println("Inicializada la tarjeta");
95 }
96 //comprueba si existe el archivo de texto, sino esta lo crea y lo cierra.
97 if(!SD.exists(nombreFichero)){
98 creaFichero();
99 //Serial.println("Inicializado el fichero");
100 }
101 //Serial.println("Completada");
102 }
103
104 //si abre bien el archivo imprime la lectura y el estado de la memoria, sino modifica la variable
105 //errorWrite para mostrar un error en display lcd
106 void guardarMuestra(lecturaSensor ls){
107 //Serial.println("Proceso de guardado:");
108 archivoDatos = SD.open(nombreFichero, FILE_WRITE);
109 //Serial.println(" Se ha abierto el fichero: "+nombreFichero);
110 if (archivoDatos){
111 //Guarda numMuestra ls.polaridad ls.valor magnitud Maximo: muestraMax.polaridad
112 muestraMax.valor magnitud Mínimo: muestraMin.polaridad muestraMin.valor magnitud
113 //archivoDatos.println("N 30 mG; Maximo; Mínimo; Hora ... ");
114 archivoDatos.println(ls.polaridad+" "+ls.valor+" "+ls.magnitud+ “; ”+
115 muestraMax.polaridad+" ” +muestraMax.valor+" "+muestraMax.magnitud+ “; ”+
116 muestraMin.polaridad+" "+muestraMin.valor+" "+muestraMin.magnitud+ “; ”+
117 ls.fechaYHora.day()+"/"+ls.fechaYHora.month()+"/"+ls.fechaYHora.year()+ “; ”+
118 ls.fechaYHora.hour()+":"+ls.fechaYHora.minute()+":"+ls.fechaYHora.second());
119 archivoDatos.close();
120 errorWrite = false;
121 //Serial.println("Se ha guardado la muestra: "+numMuestra);
122 }else{
123 //Error al abrir el archivo
124 errorWrite = true;
125 //Serial.println("Error al guardar la muestra: "+numMuestra);
126 }
127 }
128
129 void borradoInformacion(){
130 archivoDatos = SD.open(nombreFichero, FILE_WRITE);
131 SD.remove(nombreFichero);
132 //Serial.println("Se ha borrado el archivo: "+nombreFichero);
53
133 creaFichero();
134 }
135 void creaFichero(){
136 DateTime ahora = rtc.now();
137 archivoDatos = SD.open(nombreFichero, FILE_WRITE);
138 archivoDatos.print("Lectura del "+ahora.day());
139 archivoDatos.print(+"/"+ahora.month());
140 archivoDatos.print(+"/"+ahora.year());
141 archivoDatos.print(+" a las "+ahora.hour());
142 archivoDatos.print(+":"+ahora.minute());
143 archivoDatos.print(+":"+ahora.second());
144 archivoDatos.println();
145 archivoDatos.close();
146 //Serial.println("Se ha creado el archivo: "+nombreFichero);
147 }
148 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
149 ////////////////////////////////////////////////// variables de pantalla ///////////////////////////////////////////////////////
150 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
151
152 //definición de la pantalla lcd con parámetros RS pin 8, E pin 9, d4-7 pines 4-7
153 LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
154
155 //variable control iluminacion
156 boolean apagada = true;
157
158 //Inicializa la pantalla lcd y muestra el mensaje inicial
159 void inicialicizaPantalla(){
160 //Serial.println("Inicialización del display:");
161 lcd.begin(16, 2); // Inicializar el LCD
162 lcd.clear(); //limpia la pantalla
163 //Serial.println("Completada");
164 }
165
166 void impresionMuestra(lecturaSensor ls){
167
168 if(!MAXIMOMINIMO){
169 //Serial.println("Se imprime en el display la muestra actual:");
170 lcd.setCursor(1,0);
171 //muestra la polaridad de la señal magnética captada.
172 lcd.print(ls.polaridad);
173
174 //imprime en la parte superior de la pantalla el valor obtenido junto con la magnitud en
175 //la que esta expresado
176
177 if(ls.valor<0){
178 lcd.setCursor(3,0);
54
179 lcd.print(ls.valor);
180 lcd.print(ls.magnitud);
181 }else{
182 lcd.setCursor(4,0);
183 lcd.print(ls.valor);
184 lcd.print(ls.magnitud);
185 }
186 //Serial.println(ls.polaridad+" "+ls.valor+" "+ls.magnitud);
187 lcd.setCursor(1,1);
188 if(HOLDS) lcd.print("H");
189 lcd.setCursor(3,1);
190 if(TESLA) lcd.print("T");
191 else lcd.print("G");
192 lcd.setCursor(5,1);
193 lcd.print(RANGOACTUAL);
194 //Serial.print("Mantener: ");
195 //Serial.print(HOLDS);
196 //Serial.print(", Unidades(Tesla = true, Gauss = false): ");
197 //Serial.print(TESLA);
198 //Serial.print(", Rango: ");
199 //Serial.print(RANGOACTUAL);
200 //Serial.print(", ");
201 //muestra información de la sd
202 lcd.setCursor(7,1);
203 if(!extraida){
204 if(!iniSd){ lcd.print("Fallo SD");
205 //Serial.print("Modulo SD: FalloSD ")
206 }else{
207 switch (card.type()) {
208 case SD_CARD_TYPE_SD1:
209 lcd.print("SD1 ");
210 //Serial.print("Modulo SD: SD1 ");
211 break;
212 case SD_CARD_TYPE_SD2:
213 lcd.print("SD2 ");
214 //Serial.print("Modulo SD: SD2 ");
215 break;
216 case SD_CARD_TYPE_SDHC:
217 lcd.print("SDH ");
218 //Serial.print("Modulo SD: SDH ");
219 break;
220 default:
221 lcd.print("NN ");
222 //Serial.print("Modulo SD: ERROR DISK ");
223 }
224 if(!errorWrite){
55
225 lcd.print("FAT");
226 //Serial.print("FAT ");
227 //indica el tipo de formato de fat que tiene la sd
228 if (!volume.init(card)){
229 lcd.print(" ERROR");
230 //Serial.print("ERROR ");
231 SD.begin(CS);
232 }else
233 lcd.print(volume.fatType(),DEC);
234 //Serial.print(volume.fatType(), DEC);
235 }else{
236 lcd.print("ERR W");
237 //Serial.print("Error de escritura");
238 }
239 }
240 }else{
241 lcd.print("Extract");
242 //Serial.println("Tarjeta extraida");
243 }
244 }else{
245 //Serial.println("Se imprime al display las muestras máxima y mínima: ");
246 lcd.setCursor(2,0);
247 //muestra la polaridad de la máxima señal magnética captada.
248 lcd.print(muestraMax.polaridad);
249
250 //imprime en la parte superior de la pantalla el valor obtenido junto con la magnitud en la
251 //que esta expresado
252 lcd.setCursor(4,0);
253 lcd.print(muestraMax.valor);
254 lcd.print(muestraMax.magnitud);
255 //Serial.println("Maximo: "+muestraMax.polaridad+" "+muestraMax.valor+"
256 "+muestraMax.magnitud);
257 lcd.setCursor(2,1);
258 //muestra la polaridad de la señal magnética captada.
259 lcd.print(muestraMin.polaridad);
260
261 //imprime en la parte superior de la pantalla el valor obtenido junto con la magnitud en la
262 //que esta expresado
263 lcd.setCursor(4,1);
264 lcd.print(muestraMin.valor);
265 lcd.print(muestraMin.magnitud);
266 //Serial.println("Mínimo: "+muestraMin.polaridad+" "+muestraMin.valor+"
267 "+muestraMin.magnitud);
268 }
269 }
270 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
56
271 //////////////////////////////////////////////// variables de sensor hall /////////////////////////////////////////////////////
272 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
273
274 //variables para el tratamiento del valor del sensor hall.
275
276 //1.3mV = 1Gauss
277 const double VMax = 3300.0;
278 const double bitsResolucion = 1024;
279 const double VSensor = 1.3;
280
281 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
282 ///////////////////////////////////////////////// métodos sensor hall /////////////////////////////////////////////////////////
283 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
284
285 lecturaSensor leeValorSensor(){
286 //Serial.println("Lectura del Sensor");
287 int valorOriginalNou = analogRead(SENSOR)-18;
288 double valorNou = convertirValor(valorOriginalNou);
289 String polNou = "";
290 if(valorOriginalNou >= bitsResolucion/2)
291 polNou = "S";
292 else
293 polNou = "N";
294
295 lecturaSensor nova ={valorOriginalNou, valorNou , polNou, RANGOACTUAL, TESLA, "", rtc.now()};
296 nova = magnitud(nova);
297 numMuestra++;
298 return nova;
299 }
300
301 //* Método de transformación del valor recogido por el sensor. Dependiendo de la unidad
302 seleccionada, se transformara a Teslas o a Gauss, viene dado por el valor de la variable
303 boleana Tesla, si esta a true, esta seleccionada la magnitud estándar del sistema internacional Tesla,
304 mientras que si esta en false se mostrara en Gauss.
305 Este método retorna un double, con el valor transformado.
306 En definitiva el dispositivo puede medir entre [-128 mT. 128 mT]
307 */
308
309 double convertirValor(int val){
310 //Serial.println("Se procesa el valor captado aplicándole la ecuación de adaptacion: (val*((VMax/
311 (VSensor*10))/(bitsResolucion)))-((VMax/(VSensor*10))/(2))");
312 double res = (val*((VMax/(VSensor*10))/(bitsResolucion)))-((VMax/(VSensor*10))/(2)); //esto
313 calcula el valor en mT
314 if(TESLA){//en tesla
315 res = res * rangoT[RANGOACTUAL];
316 }else{//en gauss
57
317 res = res * rangoG[RANGOACTUAL]*10000;
318 }
319 //Serial.println("Finalizada el calculo de la ecuación de adaptacion de la señal.");
320 return -res;
321 }
322
323 lecturaSensor magnitud(lecturaSensor ls){
324 if(ls.unidad){
325 if(ls.rango==0)
326 ls.magnitud = " T";
327 else if(ls.rango==1)
328 ls.magnitud = " mT";
329 else if(ls.rango==2){
330 ls.magnitud = " uT";
331 }
332 }else{
333 if(ls.rango==0)
334 ls.magnitud = " kG";
335 else if(ls.rango==1)
336 ls.magnitud = " G";
337 else if(ls.rango==2){
338 ls.magnitud = " mG";
339 }
340 }
341 return ls;
342 }
343 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
344 /////////////////////////////////////////////// Tratamiento de interrupciones /////////////////////////////////////////////
345 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
346
347 //interrupción de mantener
348 void mantener(){
349 //Serial.println("Invocación de la rutina mantener()");
350 currentHold = millis();
351 if (currentHold > counterHold + timeThreshold) {
352 HOLDS = !HOLDS;
353 counterHold = millis();
354 }
355 //Serial.println("Finalizada la rutina mantener()");
356 }
357 //interrupción de unidades
358 void unidades() {
359 currentUnits = millis();
360 if (currentUnits > counterUnits + timeThreshold){
361 TESLA = !TESLA;
362 counterUnits = millis();
58
363 }
364 }
365 //interrupción de iluminacion
366 /*void iluminacion(){
367 currentLuz = millis();
368 if (currentLuz > counterLuz + timeThreshold) {
369 if (apagada) {
370 //enchufar la luz
371 digitalWrite(LLUM, HIGH);
372 }
373 else {
374 //apagar la luz
375 digitalWrite(LLUM, LOW);
376 }
377 apagada = !apagada;
378 counterLuz = millis();
379 }
380 }*/
381 //Incrementa el RANGOACTUAL de forma cíclica
382 void rangos(){
383 //Serial.println("Invocación de la rutina rangos()");
384 currentRango = millis();
385 if (currentRango > counterRango + timeThreshold) {
386 if (RANGOACTUAL == 2)
387 RANGOACTUAL = 0;
388 else
389 RANGOACTUAL++;
390 counterRango = millis();
391 }
392 //Serial.println("Finalizada la rutina rangos()");
393 }
394 //interrupción de MAXIMOMINIMO
395 void maximoMinimo(){
396 //Serial.println("Invocación de la rutina maximoMinimo()");
397 currentMaxMin = millis();
398 if (currentMaxMin > counterMaxMin + timeThreshold) {
399 MAXIMOMINIMO = !MAXIMOMINIMO;
400 counterMaxMin = millis();
401 }
402 //Serial.println("Finalizada la rutina maximoMinimo");
403 }
404 //interrupción de EXTRACT
405 void extraerConSeguridad(){
406 //Serial.println("Invocación de la rutina extraerConSeguridad()");
407 currentExtract = millis();
408 if (currentExtract > counterExtract + timeThreshold) {
59
409 if (extraida) {
410 iniSd = true;
411 extraida = false;
412 }
413 else {
414 extraida = true;
415 iniSd = false;
416 }
417 counterExtract = millis();
418 }
419 //Serial.println("Finalizada la rutina extraerConSeguridad()");
420 }
421 //método de borrado del archivo de datos. Al ser invocado se eliminara el archivo de datos dejándolo
422 otra vez vacío
423 void borrado(){
424 //Serial.println("Invocación de la rutina borrado()");
425 currentBorrado = millis();
426 if (currentBorrado > counterBorrado + timeThreshold) {
427 borradoInformacion();
428 counterBorrado = millis();
429 }
430 //Serial.println("Finalizada la rutina borrado()");
431
432 }
433 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
434 //////////////////////////////////////////Tratamiento de la lectura de la muestra///////////////////////////////////////
435 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
436
437 / * Este método toma una lectura del sensor actualizando la struct muestra.
438 * Luego dependiendo de las interrupciones HOLD, UNIT, MAXMIN modifican el comportamiento
439 *
440 * -HOLD: dependiendo de una variable boolean utiliza la struct muestra o valorMantener
441 * -UNIT: varia entre Tesla o Gauss, las unidades de medida de campo magnético.
442 * -RANGO: varia la variable rangoActual entre 0, 1, 2. donde además varia el valor en la
443 * conversión del valor leído del sensor.
444 */
445 void tratarMuestra(){
446 //Serial.println("Inicio de la gestión de la muestra: "+numMuestra);
447 //tomamos una muestra
448 muestra = leeValorSensor();
449 //tratamiento de los máximos y mínimos, queda definir la diferencia entre los rangos
450 if(muestra.valorOriginal>muestraMax.valorOriginal){
451 muestraMax = muestra;
452 //Serial.println("La muestra es maximo");
453 }
454 if(muestra.valorOriginal<muestraMin.valorOriginal){
60
455 muestraMin = muestra;
456 //Serial.println("La muestra es mínimo");
}
457
//tratamiento de hold
458 if(HOLDS){
459 impresionMuestra(valorMantener);
460 //Serial.println("Se congela la muestra a imprimir");
461 }else{
462 impresionMuestra(muestra);
463 valorMantener = muestra;
464 //Serial.println("Se imprime la muestra actual");
465 }
466 if(!extraida){
467 //Serial.println("Tarjeta no extraida, se procede a guardar la muestra: "+numMuestra);
468 guardarMuestra(muestra);
469 }
470 }
471 /*
472 Primero que todo se inicializan los pines para los botones HOLD, UNITS, RANGO, MAXMIN,
473 LLUM, CS, BOTONLLUM
474 luego se inicializan las interrupciones asociadas a cada botón con su respectivo código de
475 tratamiento de interrupciones
476 Posteriormente se calibra el sensor, y se inicializan el resto de módulos (Display LCD, SD, RTC)
477 */
478 void setup() {
479 //Serial.begin(9600);
480 //Serial.println("Inicio del registro prueba caja blanca:");
481 //inicialización de los pines
482 //Serial.println("Inicialización de los pines HOLD, UNITS, RANGO, MAXMIN, CS, EXTRACT,
483 BORRADOR y LED_BUILDIN");
484 pinMode(HOLD, INPUT);
485 analogWrite(HOLD, LOW);
486 pinMode(UNITS, INPUT);
487 analogWrite(UNITS, LOW);
488 pinMode(RANGO, INPUT);
489 analogWrite(RANGO, LOW);
490 pinMode(MAXMIN, INPUT);
491 analogWrite(MAXMIN, LOW);
492 pinMode(CS, INPUT);
493 pinMode(BORRADOR, INPUT);
494 analogWrite(BORRADOR, LOW);
495 pinMode(LED_BUILTIN, OUTPUT);
496 //Serial.println("Inicialización de los pines completada.");
497 //Serial.println("Inicialización de las interrupciones HOLD, UNITS, RANGO, MAXMIN,
498 EXTRACT y BORRADOR");
61
499 //inicialización de las interrupciones
500 attachInterrupt( digitalPinToInterrupt(HOLD), mantener, FALLING );
501 attachInterrupt( digitalPinToInterrupt(UNITS), unidades, FALLING );
502 attachInterrupt( digitalPinToInterrupt(RANGO), rangos, FALLING );
503 attachInterrupt( digitalPinToInterrupt(MAXMIN), maximoMinimo, FALLING );
504 attachInterrupt( digitalPinToInterrupt(EXTRACT), extraerConSeguridad, FALLING );
505 attachInterrupt( digitalPinToInterrupt(BORRADOR), borrado, FALLING );
506 //En Arduino Due los pines digitales funcionan a 3,3V, por lo tanto no se puede usar la iluminación,
507 por contra podemos disponer de un calibrado del sensor por ejemplo.
508 //attachInterrupt( digitalPinToInterrupt(BOTONLLUM), iluminacion, FALLING );
509
510 //invocación de métodos de inicialización del sensor y pantalla
511 calibradoInicial();
512 inicialicizaPantalla();
513 inicializaSD();
514 //inicializando el relog
515 //Serial.println("Inicialización del modulo RTC");
516 rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
517 //Serial.println("Completada");
//Serial.println("Finalizada la inicialización del Teslametro. Activación de su funcionamiento:");
}
/*
El cuerpo principal del magnetómetro, realiza una limpieza de pantalla para posteriormente tomar
una lectura del sensor actualizando el estado de la struct lecturaSensor, mostrando el valor en
pantalla y almacena una linea mas en un txt de la sd. Seguido de un delay, con el tiempo mínimo
para que se guarde y se muestre correctamente
*/
void loop() {
currentMillis = millis();
if(currentMillis - previousMillis > tiempo){
previousMillis = currentMillis;
digitalWrite(LED_BUILTIN, HIGH);
lcd.clear();
//invocación al método principal
tratarMuestra();
}else digitalWrite(LED_BUILTIN, LOW);
//Serial.println("Finaliza la muestra: "+numMuestra);
}
62
63