ÍNDICE 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. La ventaja de los registradores de datos es que pueden operar independientemente de una computadora, a diferencia de muchos otros tipos de dispositivos de adquisición de datos. Los registradores de datos están disponibles en varias formas y tamaños. La gama incluye registradores de función fijos económicos simples de un solo canal a dispositivos programables más potentes capaces de manejar cientos de entradas. El datalogger, conocido también como sistema de adquisición de datos y control, o micrologger, es el corazón de una estación de medida. Mide las señales eléctricas de sensores a una velocidad de muestreo determinada, procesa y almacena los datos, y dispone de comunicación capaz de hacer la transferencia de los datos hacia una PC
Parámetros de un DataLogger 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). Operación en tiempo real 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.1 Placa Arduino Uno
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. 2.1.3 Características generales de la placa Arduino
Opera con el microprocesador ATmega328
13 pines para entradas/salidas digitales (programables) de los cuales 6 pueden operarse como salidas analógicas del tipo PWM
6 pines para entradas analógicas
Voltaje de operación 5V 3
Voltaje de entrada (recomendado) 7-12 V
Voltaje de entrada (limite) 6-20 V
Corriente DC I/O Pin 40 mA
Corriente DC 3.3V Pin 50 mA
Memoria Flash 32 KB (2 KB para el bootloader)
SRAM 1 KB
EEPROM 512 byte
Velocidad de reloj 16 MHz
Lenguaje Wiring
3.- Conexión del Sensor de Temperatura CI LM35 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.
Se conecta el sensor al Arduino al puerto análogo 0 (a0)
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á: Vout = Vo reemplazndo los terminos equivalentes:
5.𝑉𝑙𝑒𝑖𝑑𝑜 1023
=10mV.T
Despejamos T: 5.𝑉𝑙𝑒𝑖𝑑𝑜
𝑇 = (1023)(10𝑥10−3 𝑉) luego
𝑇=
𝑇=
5(0,1𝑥103 𝑉)𝑉𝑙𝑒𝑖𝑑𝑜 (1023)(10𝑥10−3 𝑉)
500𝑉𝑙𝑒𝑖𝑑𝑜 1023
En wiring al pasarlo al Arduino IDE queda así: 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
Voltaje de Alimentación: 3V-5.5V Corriente de Alimentación: en medición de 0.5mA-2.5mA Stand by: 100uA-150uA Alcance de medición: 20-90% humedad/ 0-50°C Temperatura de precisión: ±2°C
Protocolo de transmisión digital del DHT11 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 Conexión del DHT11 a Arduino
Conexionado DHT11 sin PCB 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. El esquema eléctrico del DHT11 sería el siguiente:
Conexionado DHT11 con PCB 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
Instalación de librerias para el DHT11 hacia el IDE de Arduino 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. En este caso se va a utilizar la que proporciona Adafruit. El procedimiento es simple: 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 4.- Ir al enlace y y ahí seleccionar Clone or Download y luego Download ZIP 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 3.- Ir al Arduino IDE y luego:
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.
Programación del DHT11 en el IDE de Arduino En este ejemplo, se va a obtener 3 valores del DHT11:
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. Código completo del programa sensor de temperatura y humedad DHT11 (y LM35) #include // Incluimos librería #define DHTPIN 2 // Definimos el pin digital donde se conecta el sensor #define DHTTYPE DHT11 // Dependiendo del tipo de sensor DHT dht(DHTPIN, DHTTYPE); // Inicializamos el sensor DHT11 void setup() { Serial.begin(9600); // Inicializamos comunicación serie dht.begin(); // Comenzamos el sensor DHT } void loop() { if (millis() % 5000 == 0) // Esperamos 5 segundos entre medidas { int h = dht.readHumidity(); // Leemos la humedad relativa int 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; } int hic = dht.computeHeatIndex(t, h, false); // Calcular el índice de calor en grados centígrados int temp = ((analogRead(0)*500)/1023); // programa para el LM35 Serial.print("Humedad: "); Serial.print(h); Serial.print("% "); Serial.print("Temperatura: "); Serial.print(t); Serial.print("C "); 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.print("promedio: "); Serial.print((t+temp)/2); Serial.println("C"); } }
Nota: Programa anterior es Datalogger3 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
5.- Almacenamiento en memoria de los datos leidos 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. Capacidad de la memoria EEPROM de Arduino 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. Se necesita un programa entonces que actue bajo la siguiente lógica:
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 En la segunda parte del diagrama de flujo se realiza la lectura de la memoria EEPROM y se recompone el dato que habia sido particionado para poder ser almacenado en memoria
14
Ejemplo: Programa funcion que restaura un dato int a partir de 2 bytes alto y bajo grabados en memoria EEPROM del Arduino int ensamblardato(int direc) { byte H; byte L; H=EEPROM.read(direc); //Se leen los bytes en direcciones de memoria contiguas. L=EEPROM.read(direc + 1); int ensamblar; ensamblar = H; ensamblar = ensamblar*256; ensamblar |= L; se realiza la operación OR lógica return ensamblar; }
15
Aquí se puede exponer el programa de acuerdo a sus diferentes partes: #include // 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 int pulsador = 12; int led= 13; DHT dht(DHTPIN, DHTTYPE); // Inicializamos el sensor DHT11 void setup() { Serial.begin(9600); // Inicializamos comunicación serie dht.begin(); // Comenzamos el sensor DHT pinMode(pulsador, INPUT); pinMode(led, OUTPUT); } void grabar(int data, int 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); } void loop() { int direccion=0; int dato; for (int i = 0; i<=4; i++) { digitalWrite(led, HIGH); int h = dht.readHumidity(); // Leemos la humedad relativa int 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; } int hic = dht.computeHeatIndex(t, h, false); // Calcular el índice de calor en grados centígrados int temp = ((analogRead(0)*500)/1023); // programa para el LM35 grabar (h,direccion); direccion= direccion+2; grabar (hic,direccion); direccion= direccion+2; grabar (temp,direccion); direccion= direccion+2; delay(100); digitalWrite(led, LOW); delay(10000); } direccion=0; for (int i = 0; i<=4; i++) { int h=ensamblardato(direccion); direccion=direccion+2; int hic=ensamblardato(direccion); direccion=direccion+2; int temp=ensamblardato(direccion); direccion=direccion+2; Serial.print("Humedad: "); Serial.print(h); Serial.print("% ");
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"); } } int ensamblardato(int direc) { byte H; byte L; H=EEPROM.read(direc); //Se leen los bytes en direcciones de memoria contiguas. L=EEPROM.read(direc + 1); int ensamblar; ensamblar = H; ensamblar = ensamblar*256; ensamblar |= L; return ensamblar; }
Nota: Programa anterior es Datalogger4
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. Escribe una variable en la dirección address:
EEPROM.Put(address, variable)
Lee una variable en la dirección address:
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. A continuación tenemos un programa que graba datos float en la memoria eeprom
#include <EEPROM.h> float sensorValue; int direccion = 0; //Funcion que simula la lectura de un sensor float ReadSensor() { return 10.0f; } void setup() { } void loop() { sensorValue = ReadSensor(); //Lectura simulada del sensor EEPROM.put( direccion, sensorValue ); //Grabamos el valor direccion += 4; //Obtener la siguiente posicion para escribir if(direccion >= EEPROM.length()) direccion = 0; //Comprobar que no hay desbordamiento delay(30000); //espera 30 segunos }
Ahora se puede incluir esta forma de leer el dato float en el programa del Datalogger: #include // 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 int pulsador = 12; int led= 13; DHT dht(DHTPIN, DHTTYPE); // Inicializamos el sensor DHT11 void setup() { Serial.begin(9600); // Inicializamos comunicación serie dht.begin(); // Comenzamos el sensor DHT pinMode(pulsador, INPUT); pinMode(led, OUTPUT); } void loop() { int direccion=0; float dato; for (int i = 0; i<=4; i++) { digitalWrite(led, 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;
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"); } }
Nota: Programa anterior es Datalogger5
6.- Tiempo de muestreo 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𝑚𝑖𝑛 Se elegirá un tiempo de muestreo de 10 minutos
7.- Ahorro de energía 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); }
En este programa la línea que realiza el trabajo de dormir al arduino es: 20
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); El comando LowPower.powerDown utiliza la función sleep en el modo Power Down, de hecho tenemos en el Atmega328p seis modos de Sleep:
Idle ADC Noise Reduction Power-save Power-down Standby Extended Standby
El consumo para cada modo es:
Sleep modo IDLE: 15 mA Sleep modo ADC: 6.5 mA Sleep modo POWER SAVE: 1.62 mA Sleep modo EXT STANDBY: 1.62 mA Sleep modo STANDBY : 0.84 mA Sleep modo POWER DOWN : 0.36 mA
Entonces estamos consumiendo con el modo utilizado sólo 0,36 mA. 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. Este tiempo puede variar de acuerdo a la tabla siguiente:
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: for (int i = 0 ; i < 76 ; i++) LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
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. Con respecto a los otros datos: ADC_OFF: Apaga los convertidores Analógico a digital 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. 8.- Inicio y fin de operación de muestreo e inicio y fin de transmisión de datos 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 Que se puede encontrar en el enlace: https://github.com/PaulStoffregen/Time La librería descargada renombrarla como Time.ZIP se añade al Arduino IDE de la forma ya especificada dentro de directorio Mis Documentos/Arduino/libraries/libraries, una vez alli se añade desde Arduino IDE: Programa -> Incluir Librería -> Añadir Librería ZIP -> especificar la ruta donde se ha depositado el ZIP Siempre es aconsejable verificar que la librería ha sido añadida en Arduino IDE:
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 //Imprimimos la fecha y la hora Serial.print(day(t)); Serial.print(+ "/") ; Serial.print(month(t)); Serial.print(+ "/") ; Serial.print(year(t)); Serial.print( " ") ; Serial.print(hour(t)); Serial.print(+ ":") ; Serial.print(minute(t)); Serial.print(":") ; Serial.println(second(t)); delay(3000);//Esperamos 3 segundos }
Los resultados se observan en monitor serial
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. Una interrupción se puede llamar de varias formas:
Un Timer ( Un Watch Dog, es un caso particular de Timer) Una interrupción hardware. Una señal UART
Un ejemplo de interrupción por hardware lo implementamos a continuación:
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: Placa Arduino
INT.0
INT.1
INT.2
INT.3
INT.4
Uno, nano, mini, Ethernet
2
3
Mega, mega2560, megaADK
2
3
21
20
19
Basados en el 32u4 (ej.Leonardo, Micro)
3
2
0
1
7
INT.5
18
Número del pin de la placa
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: attachInterrupt(pin, ISR, modo) 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:
LOW: se lanzará la interrupción cuando el pin esté en estado bajo. CHANGE: se lanzará la interrupción cuando el pin cambie de valor de alto a bajo, o de bajo a alto. 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) Si attachInterrupt() nos permite configurar un pin como interrupción, el método detachInterrupt() anula esa configuración. Como parámetro le pasamos el pin y lo podemos hacer con la función digitalPinToInterrupt(número de pin) que nos devolverá el ordinal del pin del que queremos anular la configuración. 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: a) En el programa ya se fija 2 datos importantes que necesita el Datalogger: Sample Rate: que es el periodo de tiempo entre las muestras, este será preconfigurado a un valor de 8 segundos Sample points: que es la cantidad de muestras que seràn tomadas por el Datalogger, este será preconfigurado a 10 muestras b) Al colocar el interruptor de encendido a ON el Datalogger entra inmediatamente en modo sleep c) Cuando el usuario lo determine, para iniciar el proceso de muestreo debe de presionar el pulsador de habilitación Enable d) El Datalogger realizara la toma de muestras de acuerdo a la cantidad especificada por Sample Points y de acuerdo al periodo fijado por Sample Rate e) Durante el proceso de muestreo se activará un led Rojo indicando este modo f) Luego de terminar el proceso de muestreo el Datalogger pasa inmediatamente al modo sleep g) Cuando el usuario lo determine, para iniciar el proceso de transferencia de datos a la PC, debe de presionar el pulsador de habilitación Enable h) El Datalogger realizará la transferencia de la data a la PC, en este modo será indicado por un LED Verde i) Al término de este proceso el Datalogger pasa a repetir su operación especificada desde el item b El diagrama de flujo correspondiente será:
28
El circuito completo tiene 2 sensores, LM35, DHT11, un pulsador y un led bicolor. 29
Luego pasamos a implementar el programa: #include // 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 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 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 }
Nota: Programa anterior es Datalogger6 31
11.- Transmisión de datos por Bluetooth 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. Utilizamos el módulo Bluetooth HC-05
Vcc: Alimentación del módulo entre 3,6V y 6V.
GND: La masa del módulo.
TXD: Transmisión de datos.
RXD: Recepción de datos a un voltaje de 3,3V.
KEY: Poner a nivel alto para entrar en modo configuración del módulo (solo el modelo HC05)
STATE: Para conectar un led de salida para visualizar cuando se comuniquen datos.
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 Que se puede descargar de este enlace: 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
Programa para que el módulo Bluetooth envíe datos a la PC #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 a) Emparejar el módulo bluetooth 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.
Es el puerto COM27 en este caso particular.
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 c) Control desde la PC con Hyperterminal Hyperterminal es una herramienta para hacer conexiones de la PC a través de sus puertos COM, con dispositivos externos, normalmente viene instalado en el sistema operativo de Windows, pero a partir de windows 7 ya no lo incorpora por defecto, si que si ese es el caso puede utilizar el archivo descargado de internet y simplemente instalarlo. Correr Hyperterminal, aparece la ventana para una nueva conexión, colocar cualquier nombre
Luego especificar el puerto COM27 para el enlace
36
Y listo,
d) Control desde la PC con PUTTY activar Putty elegir el campo Serial y colocar el puerto COM 27 en este caso y la velocidad de transmisión que será igual a la que ha sido configurado el módulo BT, esto es 9600
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
e) Control desde la PC via bluetooth
#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 ) ; } } String GetLineBT() // Devuelve lo tecleado en la PC y enviado por Putty via bluetooth { String S = "" ; if (BT1.available()) { char c = BT1.read(); ; while ( c != '\r' ) //Hasta que el caracter sea intro { S=S+c;
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 // 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