Escolar Documentos
Profissional Documentos
Cultura Documentos
GLOSARIO
MARCO TEÓRICO
1.- DATALOGGER
Un Datalogger es un registrador de datos que opera en forma independiente y puede leer varios
tipos de señales eléctricas o magnitudes físicas y almacenar los datos en la memoria interna para su
posterior descarga a una computadora.
Señal de entrada
Algunos dataloggers están dedicados a un cierto tipo de entrada mientras otros son programables
para diferentes tipos de entradas. Las magnitudes físicas mas sensadas son temperatura, humedad,
sonido, iluminación, nivel, frecuencia, velocidad del viento, dirección del viento, voltaje o corriente
de paneles solares, etc
Número de entradas
Los dataloggers están disponibles en diseños de un solo canal y multicanal. Algunos dataloggers son
capaces de manejar hasta 32 canales.
Tamaño
En muchas aplicaciones el espacio es una limitante. En esos casos el tamaño del datalogger puede
ser un parámetro de selección crucial. Se espera que un datalogger tenga un montaje
extremadamente compacto.
Velocidad/memoria
En comparación con los sistemas de adquisición de datos en tiempo real, los dataloggers en general
tienen bajas velocidades de muestreo. Esto se debe normalmente a que almacenan datos en
memoria interna, que es limitada. Los datos normalmente se recopilan en memoria no volátil para
descargar posteriormente a un computador. Cuanto más altas son las velocidades de datos más
memoria se requiere. Por lo tanto, al especificar un datalogger es importante determinar la tasa de
muestreo y la duración de la muestra que se puede usar para calcular la memoria requerida. Por
ejemplo, si una aplicación requiere tasas de muestreo de 1 por segundo y la prueba debe durar una
hora, el datalogger debe poder almacenar 3600 muestras (1 muestra/segundo x 1 hora x 3600
segundos/hora).
En algunas aplicaciones puede ser deseable mostrar los datos que se están recopilando en tiempo
real en un ordenador.
Tasa de muestreo
La tasa de muestreo depende del modelo específico. Algunos data loggers ofrecen tasas de hasta
una muestra cada 24 horas en sus valores máximos hasta tasas de más de 100 muestras por
segundo.
Alimentación
1
Casi todos los dataloggers funcionan con baterías aunque algunos ofrecen también una opción para
energía externa
Memoria de datos
Casi todos los dataloggers usan memoria no volátil para el almacenamiento de datos. Esto significa
que los datos no se perderán si la energía falla
Tiempo de registro
La duración del registro depende de la capacidad de memoria del datalogger y la tasa de muestreo
deseada. Para determinar la duración, divida la capacidad de la memoria (número de muestra que
el dispositivo puede registrar) entre la tasa de muestreo. Por ejemplo, supongamos que un
datalogger dado puede almacenar hasta 10,000 muestras. Si se desea registrar 2 muestras cada
minuto, el datalogger puede funcionar durante 10,000/2 o 5,000 minutos (unos 3.5 días). Si la tasa
de muestreo se recortara a la mitad (1 muestra por minuto), el periodo de registro se duplicaría a 7
días.
2.- ARDUINO
Arduino es una plataforma de prototipos electrónica de código abierto (open – source) basada en
hardware y software flexibles y fáciles de usar. Está orientado para un uso en el campo de la
computación o robótica y entornos interactivos. La placa de Arduino es multiplataforma pues su
software funciona en los sistemas operativos Windows, Macintosh OSX y Linux. El software que lo
opera es ampliable y de código abierto, esta publicado bajo una licencia libre y preparado para ser
ampliado por programadores. El lenguaje puede ampliarse a través de librerías de C++, con el
lenguaje AVR C en el que está basado. Por otro lado su hardware también es 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 de Creative Commons, por lo que se puede
realizar versiones propias del módulo, ampliándo u optimizándolo.
2
2.1.1 Hardware
Arduino Uno es una placa electrónica basada en el microcontrolador ATmega328. Cuenta con 13
entradas/salidas digitales, de las cuales 6 se pueden utilizar como salidas PWM (Modulación por
ancho de pulso) y otras 6 son entradas analógicas. Además, incluye un cristal o resonador cerámico
de 16 MHz, un conector USB, un conector de alimentación, una cabecera ICSP y un botón de
reseteado. Se conecta a una PC por medio de un cable USB para alimentación e intercambio de
datos o a la corriente eléctrica a través de un adaptador AC/DC.
2.1.2 Software
Arduino utiliza un lenguaje de programación que sirve para controlar los distintos sensores y
actuadores que se encuentran conectados a la placa. Este lenguaje se llama Wirirng, basado en la
plataforma Processing y primordialmente en el lenguaje de programación C/C++, de este lenguaje
derivan otros más que son muy utilizados en el ámbito de Ingeniería y desarrollo, como C#, Java,
BASIC, Php, Phytom, JavaScript, Perl, entre otros más. Para poder trabajar desde el nivel
programación del procesador, debe descargarse el software que incluye las librerías necesarias para
poder utilizar el lenguaje de manera completa. Una ventaja de este software es que puede
descargarse desde el sitio web oficial de Arduino, pues es open source.
Voltaje de operación 5V
3
Voltaje de entrada (recomendado) 7-12 V
SRAM 1 KB
Lenguaje Wiring
El LM35 es un circuito electrónico sensor que puede medir temperatura. Su salida es analógica, es
decir, proporciona un voltaje proporcional a la temperatura. El sensor tiene un rango desde −55°C
a 150°C.
Para convertir el voltaje a la temperatura, el LM35 proporciona 10mV por cada grado centígrado. Es
decir que si se mide 20mV a la salida, se estara midiendo 2°C.
4
El Arduino leera el puerto A0, este puerto A0 recibe una tensión Vo desde el sensor, pero el Arduino
interpreta la tensión del sensor a través de su convertidor análogo digital de 10 bits
Por lo que una tensión aplicada al puerto analogo que varia entre 0 y 5 voltios se interpreta y se lee
como un valor entre 0 y 1023 (desde que al ser el convertidor A/D de 10 bits hay 210 = 1024 posibles
valores), esto se expresa asi:
5.Vleido
𝑉𝑜 = 1023
Por otro lado el sensor proporciona en su terminal central Vout un valor de 10mV por grado celsius,
entonces Vout que es el voltaje de salida que esta en función de la temperatura se expresa asi:
5
𝑉𝑜𝑢𝑡 = 10𝑚𝑉. 𝑇 ᴼ𝐶
juntando estas 2 relaciones tenemos que el valor de la temperatura en grados Celsius será:
5.𝑉𝑙𝑒𝑖𝑑𝑜
Vout = Vo reemplazndo los terminos equivalentes: 1023
=10mV.T
Despejamos T:
500𝑉𝑙𝑒𝑖𝑑𝑜
𝑇=
1023
void setup()
{
Serial.begin(9600);
}
void loop()
{
Serial.print("LM35 T:");
Serial.print(((analogRead(0)*500)/1023));
Serial.println();
delay(100);
}
Para visualizar resultados activar monitor serial en Herramientas
6
4.- Conexión del Sensor de Temperatura y Humedad DHT11
El DHT11 es un sensor que mide humedad y temperatura. Es ideal para sistemas de medición
climatológicos o para controles de temperatura y humedad. Este sensor además incluye un
transductor interno de temperatura del tipo NTC. También el módulo tiene una gran relación señal
a ruido ante la interferencia. Por ejemplo cada circuito, se calibra estrictamente en el laboratorio.
Esto permite que sea extremadamente preciso en calibración de humedad. Los coeficientes de
calibración se almacenan como programas en la memoria OTP, que son utilizados por el proceso de
detección de la señal interna del sensor.
CARACTERÍSTICAS
El DHT11 es un sensor que presenta una salida digital en forma de un tren de pulsos que se enviará
al microcontrolador. La trama de datos es de 40 bits correspondiente a la información de humedad
y temperatura del DHT11.
El primer grupo de 8-bit es la parte entera de la humedad y el segundo grupo la parte decimal. Lo
mismo ocurre con el tercer y cuarto grupo, la parte entera de la temperatura y la parte decimal. Por
último los bits de paridad para confirmar que no hay datos corruptos.
Estos bits de paridad lo único que hacen es asegurarnos de que la información es correcta, sumando
los 4 primero grupos de 8-bit. Esta suma debe ser igual a los bit de paridad. Si nos centramos en la
imagen anterior y sumamos los bits, comprobamos que todo está correcto.
0011 0101 + 0000 0000 + 0001 1000 + 0000 0000 = 0100 1101
7
Para conectar el circuito con un DHT11, necesitaremos tener una resistencia que ayude a
conformar el nivel alto (pull-up) conectada a la salida digital. La recomendación es utilizar una
resistencia de 5 kΩ. Se dispone de 4 pines el VCC (de 3,5V a 5V), la salida digital I/O, el pin no
conectado NC y la toma de tierra GND.
En este caso el DHT11 esta soldado dentro de un PCB el cual ya viene con la resistencia pull-up
integrada. Este modelo de presentación del DHT11 dispone de 3 pines, la toma de tierra GND, el
terminal para los datos DATA y el pin de la alimentación VCC (de 3,5V a 5V). En la siguiente imagen se
puede ver el esquema de conexión con Arduino.
8
IMPORTANTE: Se debe de tener cuidado pues existen muchas versiones de DHT11 con PCB y
algunos modelos presentan distinto patillaje
Se debe descargar la librería de este sensor, el cual facilita su programación con el Arduino. Hay
varias librerías disponibles en Internet que se puede utilizar para obtener la información de
temperatura y humedad.
1.- Buscar en google con las palabras claves: Adafruit DHT11 library
2.- Se ingresa a la pagina de Adafruit y ahí seleccionar Clone or Download y luego Download ZIP
3.- Luego en esa misma pagina ir al enlace de Adafruit Unified Sensor Library
5.- Con esto se ha descargado 2 librerías que estan comprimidas en formato ZIP
9
Luego es necesario integrar estas librerías al entorno de desarrollo de Arduino IDE, para esto realizar
los siguientes pasos:
1.- Ir a la carpeta de descargas de la PC, y ahí copiar las dos librerías ZIP descargadas
2.- Ir a la carpeta de Arduino en Mis Documentos, ubicar la carpeta de Libraries, entrar a esa carpeta
y ubicar una subcarpeta tambien con el nombre de libraries y depositar los archivos copiados, en
caso no haya subcarpeta copiar los ZIP en la carpeta de libraries
4.- Se elige añadir librería ZIP y se busca la ruta donde esta el DHT Sensor Library y listo, se repite
el procedimiento para el otro ZIP y eso será todo.
Humedad relativa: describe la cantidad de agua que se transporta por el aire, es importante
para determinar el desarrollo de las nubes y el factor precipitación.
Temperatura ambiente: temperatura en un determinado lugar.
Índice de calor: indica cuánto calor hace teniendo en cuenta la humedad relativa y la
temperatura. Nos da una idea de la sensación de calor.
El programa muestrea estos valores cada 5 segundos, para esto se hace uso de la función millis.
La librería de Adafruit para el DHT11 proporciona datos en grados centígrados y Fahrenheit. Para
obtener los dos datos utilizamos la misma función, readTemperature().
10
Si no pasamos ningún parámetro nos devuelve la temperatura en grados centígrados. Si pasamos el
valor true nos devuelve la temperatura en grados Fahrenheit. La humedad se obtiene llamando a la
función readHumidity().
Se utiliza la sentencia isnan para comprobar que la información enviada por el sensor no está
corrupta y que realmente está enviando un número. Esta sentencia nos dará verdadero si no es un
número (isnan, Is Not a Number) y falso en caso contrario.
Se obtiene el índice de calor con la función computeHeatIndex. Esta función puede devolver grados
centígrados o grados Fahrenheit.
El programa tambien muestra la información del anterior sensor de temperatura LM35. Al final del
todo se muestra la información en el monitor serie.
11
Comparando las señales producidas por el LM35 y el DHT11 con respecto a un medidor más preciso
(DS18B20), podemos presentar la tabla a continuación
Vemos que el LM35 presenta mejor aproximación en promedio que el DHT11, por lo que el DHT11
lo usaremos para muestrear humedad y el LM35 para muestrear temperatura
Los datos que se pueden almacenar en una memoria pueden ser de 1 byte u 8 bits, y almacenan
valores entre 0y 255, los datos proporcionados por los sensores son datos que ocupan 2 bytes (16
bits) y se puede almacenar valores entre 0 y 216 – 1.
Cada modelo de placa posee una EEPROM distinta. La tabla a continuación brinda información al
respecto:
12
Para programar la memoria EEPROM se debe utilizar la librería EEPROM.h (Se encuentra por defecto
en la IDE).
En la memoria del Arduino se debe trabajar por direcciones y byte a byte tanto para leer como
para escribir. Esto significa que para una memoria de 1kB se tendrá desde la dirección 0 hasta la
999 y se puede utilizar valores para almacenar desde 0 a 255. En caso de que se requiera guardar
valores mayores como los leidos por los sensores, se tendrá que dividirlos por bytes.
13
En la primera parte se lee el sensor que es un valor int (16 bits), este dato se tiene que guardar en
la memoria EEPROM, pero como los datos que se graban deben ser bytes, el dato del sensor se tiene
que descomponer en 2 mitades, los 8 bits mas significativos o altos, y los 8 bits menos significativos
o bajos.
Ejemplo: Programa que descompone un dato int en 2 bytes alto y bajo y lo graba en la memoria
EEPROM del Arduino en la direccion address
byte L; //Se crean dos variables de tipo byte para almacenar la información.
byte H;
H = highByte(data); //Se almacenan los bytes más y menos significativos.
L = lowByte(data);
EEPROM.write(address, H); //Se escriben los bytes en direcciones de memoria contiguas.
EEPROM.write(address + 1, L);
El retardo que indica el diagrama de flujo sirve para espaciar las muestras en el tiempo, esto se debe
fijar en funcion del tiempo de muestreo mas adelante
14
Ejemplo: Programa funcion que restaura un dato int a partir de 2 bytes alto y bajo grabados en
memoria EEPROM del Arduino
15
Aquí se puede exponer el programa de acuerdo a sus diferentes partes:
16
Serial.print("Indice de calor: ");
Serial.print(hic);
Serial.print("C ");
Serial.print("LM35 T:"); // programa para el LM35
Serial.print(temp); // programa para el LM35
Serial.println("C");
}
}
Datos FLOAT
En el caso que el dato fuera float, se tienen 4 bytes utilizados, en ese caso es mejor emplear las
funciones Put, Get y Update.
EEPROM.Put(address, variable)
EEPROM.Get(address, variable)
Actualiza el valor de una variable, es decir, primero la lee, y sólo la graba si su valor es distinto del
que vamos a guardar. Esto favorece a reducir el número de escrituras, y alargar la vida útil de la
memoria:
EEPROM.Update(address, variable)
Las funciones Put, Get y Update tienen en cuenta el tamaño de la variable, y funcionan incluso con
variables y estructuras definidas por nosotros. Sin embargo, tendremos que tener en cuenta el
17
tamaño de la variable para saber cuál es la siguiente dirección a escribir, y evitar que se “solapen”
las variables.
#include <EEPROM.h>
float sensorValue;
int direccion = 0;
Ahora se puede incluir esta forma de leer el dato float en el programa del Datalogger:
18
}
float hic = dht.computeHeatIndex(t, h, false); // Calcular el índice de calor en grados centígrados
float temp = ((analogRead(0)*500)/1023); // programa para el LM35
EEPROM.put(direccion, h); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
EEPROM.put(direccion, hic); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
EEPROM.put(direccion, temp); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
delay(100);
digitalWrite(led, LOW);
delay(10000);
}
direccion=0;
for (int i = 0; i<=4; i++)
{
float h, hic,temp;
EEPROM.get(direccion, h);
direccion= direccion+4;
EEPROM.get(direccion, hic);
direccion= direccion+4;
EEPROM.get(direccion, temp);
direccion= direccion+4;
Serial.print("Humedad: ");
Serial.print(h);
Serial.print("% ");
Serial.print("Indice de calor: ");
Serial.print(hic);
Serial.print("C ");
Serial.print("LM35 T:"); // programa para el LM35
Serial.print(temp); // programa para el LM35
Serial.println("C");
}
}
Un criterio para elegir el tiempo de muestreo es determinar el tiempo (Te) de respuesta del proceso
para alcanzar el 95% de su valor final, luego el tiempo de muestreo (Tm) debe estar comprendido
entre los valores
1 1
𝑇𝑒 ≤ 𝑇𝑚 ≤ 𝑇𝑒
15 4
Si consideramos un entorno industrial en el que se tiene areas que estan bajo la influencia de
calderos, intercambiadores, hornos industriales, etc, se puede estimar que la temperatura en el
entorno industrial puede cubrir su rango de variación en un lapso de 2 horas de operación contínua,
si se toma como referencia ese tiempo tendremos que:
19
8𝑚𝑖𝑛 ≤ 𝑇𝑚 ≤ 30𝑚𝑖𝑛
El Arduino UNO tiende a consumir uso 45 mA en vacío, mientras que un Arduino Nano llega a los
15 mA, el problema consiste en que una aplicación como Datalogger implica operación
independiente y autónoma por lo que el uso de baterías para alimentar el circuito es obligatorio y
la condición de ahorro de energía es indispensable.
Para lograr este ahorro se utiliza la función sleep, para ello es necesario descargar la librería:
Low-Power-master, ir al enlace:
https://github.com/rocketscream/Low-Power
La función sleep trabaja con el Watchdog Timer del Arduino, el Watchdog Timer no es mas que un
temporizador que cuando se lo utiliza con un valor de tiempo preestablecido, empieza a realizar una
cuenta descendente respecto al tiempo prefijado, al llegar a cero, este Watchdog Timer activa una
interrupción Hardware sobre el Arduino, es decir interrumpe cualquier labor que estuviese haciendo
el Arduino y lo direcciona a realizar una tarea específica. Normalmente el watchdog se utiliza como
una condición de preeemergencia, digamos que se hacen labores repetitivas que “duran” un
periodo de tiempo, se activa el watchdog con cada labor repetitiva con un tiempo prefijado mayor
al periodo que supuestamente demora la labor repetitiva, el objetivo es que Arduino realice una
tarea de emergencia cuando la labor específica dure mas de su tiempo normal, esto es de bastante
utilidad en algunos casos.
Una vez descargada e integrada la nueva librería al Arduino IDE, se puede probar el programa
siguiente:
#include "LowPower.h"
int LED = 13 ;
void setup()
{
pinMode(13, OUTPUT);
}
void loop()
{
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
}
Idle
ADC Noise Reduction
Power-save
Power-down
Standby
Extended Standby
Ahora respecto al dato SLEEP_8S, éste va directo al Watchdog Timer y sera el tiempo que dormira
el arduino hasta que lo despierte la interrupción activada por el watchdog cuando la cuenta
regresiva del tiempo programado (8 segundos) llegue a cero.
SLEEP_15MS
SLEEP_30MS
SLEEP_60MS
SLEEP_120MS
SLEEP_250MS
SLEEP_500MS
SLEEP_1S
SLEEP_2S
SLEEP_4S
SLEEP_8S
SLEEP_FOREVER
Se debe tener cuidado con SLEEP FOREVER pues el Arduino “dormira” por siempre si es que no se
ha establecido el procedimiento de hardware o software para “despertarlo”
Respecto al tiempo, vemos que el mayor disponible es el de 8 segundos, pero esto puede extenderse
realizando bucles anidados que prolongan la cantidad de estos periodos de “sueño”
21
El programa siguiente:
Genera un lapso de 8 segundos x 75 = 600 segundos o 10 minutos, en los que el WDT despierta el
micro lo justo para hacer una tarea especifica , incrementar la variable i, y volver a dormirse. (no
hay ninguna razón para no hacer lo mismo 8 x 75 x 6 = 1 hora (si es lo que se requiere).
Anteriormente se habia previsto un tiempo de muestreo de cada 10 minutos por lo que el programa
del Datalogger incorporara esta linea.
BOD_OFF: Apaga el circuito de Brown Out Detection, que es un circuito para detectar niveles bajos
de tensión. Si no fuera por este detector BOD, cuando las pilas se fueran agotando la tensión podría
descender de un cierto nivel y dañar los circuitos. Apagarlo ayuda a reducir consumo, pero
ciertamente se corre otros peligros.
El Datalogger se debe poner en operación de muestreo de algún modo, sea este manual o
automático. Una forma eficiente y automática sería que inicie sus operaciones de toma de muestras
a una hora en particular esto se puede realizar si utilizamos la librería de manejo de tiempo Time.h
https://github.com/PaulStoffregen/Time
Programa -> Incluir Librería -> Añadir Librería ZIP -> especificar la ruta donde se ha depositado el ZIP
22
Programamos lo siguiente:
#include <Time.h>
#include <TimeLib.h>
#include <Time.h>//Incluimos la librería Time
void setup()
{
Serial.begin(115200);//Inicializamos el puerto serie.
//Anotamos la hora y la fecha desde la que nuestro programa empezará a contar.
//Formato: hora, minutos, segundos, días, mes, año
setTime(14,25,06,04,05,2018);
}
void loop()
{
time_t t = now();//Declaramos la variable time_t t
23
9.- Interrupciones
Las interrupciones son útiles para hacer que las cosas sucedan automáticamente en un programa
de un microcontrolador y pueden ayudar a resolver problemas de tiempo. Una tarea adecuada para
usar una interrupción pueden incluir leer un sensor eventualmente o monitorear algún puerto de
entrada.
Si se desea asegurar de que un programa siempre capte los impulsos proporcionados por el rotor
de una turbina giratoria, para que nunca falle la recepción del pulso se tendría que realizar un
complicado programa para hacer que el microcontrolador haga algo adicional a eso, puesto que el
programa necesitaría sondear constantemente al sensor, procesar la señal obtenida, etc. Otras
situaciones en las que se utilicen sensores también tienen una dinámica de interfaz similar, como
tratar de leer un sensor de sonido que está tratando de captar un clic, o un sensor de ranura
infrarroja (fotointerruptor) que intenta capturar una caída de moneda. En todas estas situaciones,
usar una interrupción puede liberar el microcontrolador para realizar otro trabajo sin perder la
entrada.
24
Primero se tiene que elegir la placa arduino que se utiliza, en el caso que fuese Arduino UNO el pin
digital 2 será por donde se habilite la interrupción 0, y el pin digital 3 será por donde se habilite la
interrupción 1. Para otras placas se puede revisar la tabla siguiente:
Como tenemos en nuestro desarrollo el puerto digital 2 ocupado por el DHT11, utilizamos el pin 3 o
interrupción 1 para la prueba respectiva:
25
Para poder utilizar interrupciones con Arduino no necesitamos incorporar ningún tipo de librería al
programa, únicamente se necesita hacer referencia a las funciones que trabajan con ello:
Esta función nos va a permitir definir o configurar uno de los pines como un puerto de interrupción.
Los tres parámetros que admite son:
pin: debemos llevar especial cuidado con este parámetro, no se refiere al pin utilizado para la
interrupción sino al numero de interrupcion asociado al pin utilizado, (ver la tabla previa).por
ejemplo si trabajamos con Arduino UNO tenemos dos pines para interrupciones el 2 y el 3. Si
queremos utilizar el 2 debemos poner un 0 y si queremos utilizar el 3 debemos poner un 1. Esto se
resuelve muy fácilmente utilizando otra función, digitalPinToInterrupt(pin), que devuelve el ordinal
del pin que queremos utilizar. Por ejemplo, en el caso anterior, si queremos utilizar el pin 2
llamaríamos a la función digitalPinToInterrupt(2). Esto nos devolverá un 0 y es el método
recomendado por Arduino para pasar este parámetro.
ISR: es una abreviatura de Interrupt Service Routine y no es más que la función o método
que se llama cuando se produce la interrupción. Es de un tipo particular ya que no admite
parámetros y tampoco devuelve ningún valor. En general, se debe hacer métodos o
funciones ISR lo más cortas y rápidas posibles. Se puede producir un bloqueo entre los
diferentes ISR. Lo que sucede en estos casos es que solo se ejecuta una a la vez quedando
en cola el resto de interrupciones.
Dentro de las interrupciones no funciona el delay() (retardo) por lo tanto no se debe utilizar.
Si se requiere un retardo dentro de un ISR se puede utilizar la función delayMicrosends(),
que funciona con normalidad. Tambien ocurre que los datos recibidos por el puerto serie
se pueden perder mientras se está en la función llamada por la interrupción.
Las variables que se vayan a utilizar tanto dentro de los métodos ISR como fuera, ya sea en
el loop() o en cualquier otra función, deben ser declararlas como volatile. Esta palabra
reservada le dice al compilador que estas variables pueden cambiar de valor en cualquier
momento y, por lo tanto, el compilador debe volver a cargar la variable cada vez que se
hace referencia en algún sitio a ella. Al contrario que ocurre con otras variables donde el
compilador confía en alguna copia que pueda tener en algún registro del procesador.
modo: define cuando debe ser disparada la interrupción. Puede tomar cuatro valores constantes
dependiendo de lo que se quiera hacer:
26
RISING: se lanzará la interrupción cuando el pin cambie de estado de bajo a alto.
FALLING: se lanzará la interrupción cuando el pin cambie de estado de alto a bajo.
Existe un quinto estado que solo los Arduino Due, Zero y MKR1000 permiten:
HIGH: se lanzará la interrupción cuando el pin esté en estado alto.
detachInterrupt(pin)
A continuación se muestra un programa que maneja interrupcion por hardware para salir de el
modo Sleep forever
#include "LowPower.h"
const int pindisparador = 2; // se utiliza el pin 2 para activar la interrupcion
int contador = 0;
volatile int n = contador ;
void setup()
{
Serial.begin(9600);
pinMode( pindisparador, INPUT);
}
void loop()
{
attachInterrupt(1, subrutina, FALLING); // engancha la int por pulso en pin 3, saldra del sleep y eje subrutina
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // dormira, sale cuando se produce la interrupcion
detachInterrupt(0); // se inhabilita la interrupcion pues pasara a imprimir
if (n != contador) // si n no es igual a contador
{
Serial.println(contador); // envia a la PC el valor del contador
n = contador ; // hace n igual al contador
Serial.flush(); // vaciamos la cola serie
}
}
void subrutina() // subrutina de servicio de la interrupción
{ contador++ ; // incrementa el valor del contador de pulsos
}
27
10.- Incorporamos la funcion sleep y las interrupciones en el programa del datalogger
Para realizar el programa primero trazamos el diagrama de flujo, este se basa en la forma como
operaría el Datalogger, las condiciones serán las siguientes:
28
El circuito completo tiene 2 sensores, LM35, DHT11, un pulsador y un led bicolor.
29
Luego pasamos a implementar el programa:
void setup()
{
Serial.begin(9600); // Inicializamos comunicación serie
dht.begin(); // Comenzamos el sensor DHT
pinMode(pulsador, INPUT);
pinMode(ledm, OUTPUT);
pinMode(ledt, OUTPUT);
pinMode(pindisparador, INPUT);
}
void loop()
{
attachInterrupt( 1, subrutina, FALLING); // engancha interrupción por pin 3, saldra de de sleep y hace la subrutina
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // pasa a dormir, saldra con la interrupcion
detachInterrupt(1); // se inhabilita la interrupcion
int direccion=0;
float dato;
int samplepoints=10;
int samplerate=1;
30
for (int i = 0; i<samplepoints; i++)
{
digitalWrite(ledm, HIGH);
float h = dht.readHumidity(); // Leemos la humedad relativa
float t = dht.readTemperature(); // Leemos la temperatura en grados centígrados
if (isnan(h) || isnan(t)) // Comprobamos si ha habido algún error en la lectura
{
Serial.println("Error obteniendo los datos del sensor DHT11");
return;
}
float hic = dht.computeHeatIndex(t, h, false); // Calcular el índice de calor en grados centígrados
float temp = (((analogRead(0)*500)/1023)+t)/2; // temperatura promedio del LM35 y DHT11
EEPROM.put(direccion, h); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
EEPROM.put(direccion, hic); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
EEPROM.put(direccion, temp); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
delay(100);
digitalWrite(ledm, LOW);
for (int j = 0 ; j < samplerate ; j++)
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
attachInterrupt( 1, subrutina, FALLING); // engancha interrupción por pin 3, saldra de de sleep y hace la subrutina
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // pasa a dormir, saldra con la interrupcion
detachInterrupt(1); // se inhabilita la interrupcion
direccion=0;
digitalWrite(ledt, HIGH);
for (int i = 0; i<samplepoints; i++)
{
float h, hic,temp;
EEPROM.get(direccion, h);
direccion= direccion+4;
EEPROM.get(direccion, hic);
direccion= direccion+4;
EEPROM.get(direccion, temp);
direccion= direccion+4;
Serial.print("Humedad: ");
Serial.print(h);
Serial.print("% ");
Serial.print("Indice de calor: ");
Serial.print(hic);
Serial.print("C ");
Serial.print("LM35 T:"); // programa para el LM35
Serial.print(temp); // programa para el LM35
Serial.print("C");
Serial.println();
}
delay(1000);
digitalWrite(ledt, LOW);
}
void subrutina() // subrutina de servicio de la interrupción
{ contador++ ; // incrementa el valor del contador de pulsos
}
Bluetooth es una especificación industrial para Redes Inalámbricas de Área Personal (WPAN) que
posibilita la transmisión de voz y datos entre diferentes dispositivos mediante un enlace por
radiofrecuencia en la banda ISM (Industrial, Scientific and Medical, reservadas internacionalmente
para uso no comercial de radiofrecuencia electromagnética en dichas área) de los 2.4 GHz.
Este módulo realiza la comunicación por via BT y sus terminales Rx y Tx, estos terminales pueden
conectarse en forma cruzada a los correspondientes del Arduino Rx y Tx que son los pines digitales
0 y 1 respectivamente, pero el problema es que Arduino se enlaza por dicha vía con el puerto serial
USB de la PC, por tanto es conveniente utilizar otros pines digitales del Arduino para que intercambie
datos con este módulo BT, para realizar esto necesitamos una librería denominada softwareserial
32
https://www.robot-r-us.com/e/995-softwareserial.html
Primero instalamos el módulo bluetooth en el circuito del Datalogger, vamos a utilizar para la
comunicación entre Arduino y el BT, los pines del arduino: 6 como Rx y 7 como Tx, se deben conectar
pero en forma cruzada a los pines Rx y Tx del módulo BT
#include <SoftwareSerial.h>
SoftwareSerial BT1(6, 7); // RX | TX
void setup()
{
Serial.begin(9600);
BT1.begin(9600);
}
void loop()
{
if (millis() % 2000 == 0)
{
BT1.println("Analog 0 = " + String(analogRead(A0))) ;
BT1.println("Analog 1 = " + String(analogRead(A1))) ;
BT1.println("Analog 2 = " + String(analogRead(A2))) ;
BT1.println(".................");
}
}
33
Para comprobar su operación primero se debe de emparejar el módulo BT con la PC
Para esto conectar el circuito al puerto USB, esto también conectará el módulo bluetooth. Hacer clic
en el icono de Bluetooth en la bandeja del sistema que normalmente se encuentra en la esquina
inferior derecha de la pantalla de la PC.
Se debe hacer clic y desplegar el menú contextual:
Al hacer clic en el icono debe obtener un menú con "Agregar un dispositivo" en la parte superior del
menú así que seguir adelante y haga clic en él.
puede hacer clic en "Mostrar dispositivos Bluetooth", donde también encontrará un enlace
"Añadir un dispositivo" en la esquina superior izquierda de la ventana que se abre.
Al hacer clic en el vínculo "Añadir un dispositivo", lo llevará a la pantalla "Agregar un
dispositivo" donde su computadora comenzará a buscar dispositivos Bluetooth.
Asegúrese de que su proyecto está encendido en este momento para que su computadora
pueda encontrar el HC-06.
Cuando vea el HC-06 ha sido encontrado y el icono se muestra haga clic en él y verá la
pantalla de vinculación de dispositivos Bluetooth.
Usted debe elegir "Introduzca el código de emparejamiento del dispositivo" y luego haga
clic en "Siguiente" donde puede ingresar el código de emparejamiento, que es "1234" o
"0000".
A continuación, haga clic en "Siguiente" y verá que su dispositivo se ha agregado
correctamente.
34
No olvidarse que el Bluetooth debe ser emparejado con la PC en un momento distinto al de la
programación del arduino, y cuando se programa el arduino, no debe de estar energizado el modulo
bluetooth.
Una vez que esta programado, entrar al icono de bluetooth y ver en que puerto esta
conectado el módulo bluetooth emparejado con la PC
Vuelva a la ventana "Mostrar dispositivos Bluetooth" Haga clic con el botón derecho del
ratón en el nuevo icono HC-05
Luego haga clic en "Propiedades" Cuando aparezca la ventana "Propiedades" aparecerá
cuatro tablas.
Hacer click en la sección "Servicios" y aparece el numero de puerto COM.
35
b) Recepción desde la PC de los datos enviados por el módulo BT
Para que la PC pueda recibir los datos se pueden probar 2 herramientas de software muy utiles,
ambas se descargan gratuitamente de Internet y son:
Hyperterminal
Putty
Correr Hyperterminal, aparece la ventana para una nueva conexión, colocar cualquier nombre
36
Y listo,
37
Luego debajo de Session hacer click en Logging (Registro), aquí se configura que todo lo que
reciba el software Putty se guarde en un archivo (all session output) que será llamado
putty.log, también se selecciona la opción de sobreescribir lo anterior (always overwrite it)
si existe.
38
Si hacemos click ahora en Terminal, se selecciona que fuerce el hecho en lo que se recibe y
también en lo que se envia
Luego se vuelve a session para guardar esta configuración como BtQueen para que sea más facil
entrar las siguientes veces.
39
Luego de ello se procede a hacer click en Open para enlazar el BT que ya esta operando con el
Arduino
#include <SoftwareSerial.h>
SoftwareSerial BT1(6, 7); // RX | TX
void setup()
{
BT1.begin(9600);
}
void loop()
{
pinMode(13, OUTPUT);
String B= "." ;
if (BT1.available())
{ B= GetLineBT();
Serial.write(BT1.read());
}
if (B =="13")
digitalWrite(13, !digitalRead(13));
}
String GetLineBT()
{
String S = "" ;
if (BT1.available())
40
{ char c = BT1.read(); ;
while ( c != '\r' ) //Hasta que el caracter sea intro
{ S=S+c;
delay(25) ;
c = BT1.read();
}
return( S ) ;
}
}
Con este programa se envía data por bluetooth que realiza una acción concreta en la tarjeta
Arduino:
Desde la consola de Putty que ya esta configurada, al pulsar el número 13 el LED embebido en la
placa el pin 13 encenderá, si se vuelve a pulsar 13 este se apagará y asi sucesivamente
Respecto al módulo BT, este tiene leds incorporados que avisan su estado:
El módulo BT en estado de conexión flashea 2 pulsos rápidos de corta duración por cada 2
segundos
Cuando Putty no enlaza aún con el dispositivo BT, este flashea a un periodo de 0,25 s
Antes de emparejarse el módulo BT flashea a un periodo de 0,5 s
41
El software completo que maneja el módulo BT es el siguiente:
#include <SoftwareSerial.h>
SoftwareSerial BT1(6, 8); // RX | TX
void setup()
{
Serial.begin(9600);
BT1.begin(38400); // depende de la velocidad por defecto del módulo BT
pinMode(13, OUTPUT);
}
void loop()
{
String B= "." ;
if (BT1.available()) // lee lo que viene desde la PC por putty via bluetooth
{ B= GetLineBT();
Serial.println(B);
}
if (Serial.available()) // lee lo que viene desde la PC por Monitor serie ("Ambos NL&CR") via USB
{ String S = GetLine();
BT1.println(S);
Serial.println(S);
}
if (B =="3") // en función de lo recibido acciona led pin 13
digitalWrite(13, !digitalRead(13));
if (millis() % 2000 == 0) // envia desde el módulo BT hacia la PC via bluetooth datos de puertos
{
BT1.println("Analog 0 = " + String(analogRead(A0))) ;
BT1.println("Analog 1 = " + String(analogRead(A1))) ;
BT1.println("Analog 2 = " + String(analogRead(A2))) ;
BT1.println(".................");
}
}
String GetLine() // Devuelve lo tecleado en la PC y enviado por Monitor serie via USB
{ String S = "" ;
if (Serial.available())
{ char c = Serial.read(); ;
while ( c != '\n') //Hasta que el caracter sea intro
{ S=S+c;
delay(25) ;
c = Serial.read();
}
return( S ) ;
}
}
42
delay(25) ;
c = BT1.read();
}
return( S ) ;
}
}
NOTA: El módulo BT ya viene con una velocidad por defecto que es de 9600 bps pero esto no es una
constante en todos los casos por lo que si no se obtienen los resultados deseados y se imprime ruido
o barras horizontales, se puede probar con otras velocidades para el módulo BT en el programa (la
parte de color verde en el programa principal)
Lo siguiente es incorporar el enlace bluetooth para enviar los datos del Datalogger a la PC
43
#include <SoftwareSerial.h>
#include <DHT.h> // Incluimos librería
#define DHTPIN 2 // Definimos el pin digital donde se conecta el sensor
#define DHTTYPE DHT11 // Dependiendo del tipo de sensor
#include <EEPROM.h> //Se incluye la librería EEPROM
SoftwareSerial BT1(6, 8); // RX | TX
int pulsador = 12;
int ledm= 10; // led que indica muestreo
int ledt= 11; // led que indica transmisión a la PC
DHT dht(DHTPIN, DHTTYPE); // Inicializamos el sensor DHT11
#include "LowPower.h"
const int pindisparador = 3; // se utiliza el pin 3 para activar la interrupcion
int contador = 0;
volatile int n = contador ;
void setup()
{
Serial.begin(9600); // Inicializamos comunicación serie
BT1.begin(38400); // depende de la velocidad por defecto del módulo BT
dht.begin(); // Comenzamos el sensor DHT
pinMode(pulsador, INPUT);
pinMode(ledm, OUTPUT);
pinMode(ledt, OUTPUT);
pinMode(pindisparador, INPUT);
pinMode(13, OUTPUT);
void loop()
{
attachInterrupt( 1, subrutina, FALLING); // engancha interrupción por pin 3, saldra de de sleep y hace la subrutina
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // pasa a dormir, saldra con la interrupcion
detachInterrupt(1); // se inhabilita la interrupcion
int direccion=0;
float dato;
int samplepoints=10;
int samplerate=1;
for (int i = 0; i<samplepoints; i++)
{
digitalWrite(ledm, HIGH);
float h = dht.readHumidity(); // Leemos la humedad relativa
float t = dht.readTemperature(); // Leemos la temperatura en grados centígrados
if (isnan(h) || isnan(t)) // Comprobamos si ha habido algún error en la lectura
{
Serial.println("Error obteniendo los datos del sensor DHT11");
return;
}
float hic = dht.computeHeatIndex(t, h, false); // Calcular el índice de calor en grados centígrados
float temp = (((analogRead(0)*500)/1023)+t)/2; // temperatura promedio del LM35 y DHT11
EEPROM.put(direccion, h); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
EEPROM.put(direccion, hic); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
44
EEPROM.put(direccion, temp); //Se escriben los bytes en direcciones de memoria contiguas.
direccion= direccion+4;
delay(100);
digitalWrite(ledm, LOW);
for (int j = 0 ; j < samplerate ; j++)
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
attachInterrupt( 1, subrutina, FALLING); // engancha interrupción por pin 3, saldra de de sleep y hace la subrutina
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // pasa a dormir, saldra con la interrupcion
detachInterrupt(1); // se inhabilita la interrupcion
direccion=0;
BT1.begin(38400); // depende de la velocidad por defecto del módulo BT
digitalWrite(ledt, HIGH);
for (int i = 0; i<=samplepoints; i++)
{
float h, hic,temp;
EEPROM.get(direccion, h);
direccion= direccion+4;
EEPROM.get(direccion, hic);
direccion= direccion+4;
EEPROM.get(direccion, temp);
direccion= direccion+4;
// BT1.println("Humedad = " + String(h)) ;
// BT1.println("Indice Calor = " + String(hic)) ;
// BT1.println("Temperatura= " + String(temp)) ;
// BT1.println(".................");
BT1.println(String(h)) ;
BT1.println(String(hic)) ;
BT1.println(String(temp)) ;
Serial.flush(); // para asegurar que se vacia la cola
}
delay(1000);
digitalWrite(ledt, LOW);
}
void subrutina() // subrutina de servicio de la interrupción
{ contador++ ; // incrementa el valor del contador de pulsos
}
45
46
47