HOJA DE RUTA
FINALIZADO
CODIGOS AQUI:
http://spainlabs.com/foro/viewtopic.php?...537#p10783
Ultimando Detalles y Peparando Carcasas:
Fotos con la placa propia ya acabada:
Caracteristicas finales de la estacion interior (Ya finalizada en cuanto a programacion)
-Reloj
-Fecha (Con dia de la semana)
-Alarma diaria
-Iconos de alarma activada y alarma sonando en todos los menus (Excepto estando en ajustes)
-Temperatura y Humedad (Exterior Interior)
-Presion (Exterior)
-Luminosidad (Exterior)
-Maximos y minimos de los parametros anteriores
-Posibilidad de resetear estos valores
-Prediccion estadistica de Borrasca/Anticiclon
-Deteccion de fallas en sensores externos
-Auto apagado de luz del LCD (Tiempo de 1min a 15min, ajustable en menu opciones)
-Apagado de luz a traves de pulsacion en encoder
-Imposiblidad de dejar cursor en menu de ajustes, retorno automatico a pantalla principal
-Ajuste de fecha-hora-alarma
-Comunicacion Inalambrica
-Unica interface con usuario a traves de encoder
DESCRIPCION:
El proyecto, consistira en realizar dos estaciones, una externa y una interna, conectadas de forma inalambrica, la estacion externa enviara los datos atmosfericos a la estacion interna, la cual los representara a traves de una pantalla LCD 20x4. La estacion interna la controlaremos a traves de un encoder rotativo, evitando el uso de botones.
La distribucion sera por menus, por los cuales nos iremos desplazando con el encoder, pudiendo mostrar los diferentes datos, atmosfericos, minimos, maximos, interiores, exteriores, el reloj, las opciones, y todo lo que vayamos implementando.
La estacion externa funcionara con una bateria y un panel solar, aun se esta viendo la viabilidad de este metodo. Pero esperemos que funcione ya que no nos interesa tener cables a la estacion exterior que sera totalmente inalambrica.
Tendremos datos de temperatura, humedad, presion y luminosidad en la estacion exterior, y de temperatura y humedad en la interior. Registrando de igual modo valores maximos y minimos. Puediendo reinicializarlos cuando se quiera.
Sensores Utilizados:
-DHT22 (Temperatura Humedad)
-BH1750 (Sensor Luminosidad)
-BMP180 (Sensor de Presion)
-DS3231 (Real Time)
Comunicacion
-Modulos NRF24L01
Control
-Arduino NANO
-Encoder Rotativo
-12F508 (Melodia de Alarma)
EXPLICACIONES
ENCODER
BH1750 (Sensor de Luz)
BMP180 (Sensor de Presion)
DHT22 (Sensor Temp y Humedad)
OBSERVACIONES
- Sustitui el modulo de reloj DS1307 por el actual, debido a que era bastante poco preciso. Con el que tengo ahora por ahora no tengo problemas, ademas que tiene mas funcionalidades, aunque en mi caso no las use
-Estoy a la espera de recibir el paner solar para ver si es viable para el proyecto.
VIDEOS
[spoiler]
[/spoiler]
Giltesa se ha hecho una muy recientemente, podria servirte para empezar
La estación meteorológica siempre fue un proyecto muy interesante para hacer con arduino. Giltesa sabe de ello, revisa su blog.
Lo mejor que puedes hacer es lo que comentas, ir pidiendo los módulos poco a poco e ir probando. Así es como voy haciendo yo con mi proyecto. El único módulo del que no he leído nada es del detector de lluvia ese, no lo conocía.
Si vas sobrado de conexiones, puedes añadirle algún sensor para medir la calidad del aire. Y ya si montas un LCD a color la lías parda is1:
El arduino normal creo que te llega para todo
CODIGO
Estacion Interior
[spoiler] Código: //Librerias
#include <dht.h>
#include <DS3231.h>
#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
//Inicializacion LCD
LiquidCrystal_I2C lcd(0x20,20,4); //Direccion y tamaño
//Inicializacion del DS3231
DS3231 RTC; //Creamos el objeto
//Inicializacion DHT22
dht DHT; //Creamos la clase
#define DHT22_PIN 7 //Asignamos al pin 7
//Inicializacion Inalambrica
#define CE_PIN 9 //Definicion de pines
#define CSN_PIN 10
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; //Definicion de canales
RF24 radio(CE_PIN, CSN_PIN); // Creamos Radio
//Estructura (Payload del NRF)
struct estacion {
//Prediccion
byte pred;
//Error
byte error;
//Datos
int temp;
int rh;
int lux;
int32_t pa;
//Maximos
int maxtemp;
int maxrh;
int maxlux;
int32_t maxpa;
//Minimos
int mintemp;
int minrh;
int minlux;
int32_t minpa;
}Datos;
//Temporales para conversion
float temp;
float rh;
float maxtemp;
float mintemp;
float maxrh;
float minrh;
float pa;
float maxpa;
float minpa;
//Variables DHT22 Interior
float tempin;
float rhin;
//Caracteres
byte flecha_dech[8] = { 0x0,0x8,0xc,0xe,0xc,0x8,0x0,0x0 }; //Flecha derecha
byte alarma[8] = { 0x4,0xe,0xe,0xe,0x1f,0x0,0x4,0x0 }; //Señal Alarma
byte altavoz_1[8] = { 0x1,0x3,0xf,0xf,0xf,0x3,0x1,0x0 }; //Altavoz1
byte altavoz_2[8] = { 0x8,0x10,0x0,0x18,0x0,0x10,0x8,0x0 }; //Altavoz2
byte linea_inf[8] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f }; //Linea Inferior
byte cir_vacio[8] = { 0x0,0xe,0x11,0x11,0x11,0xe,0x0,0x0 }; //Circulo Vacio
byte cir_lleno[8] = { 0x0,0xe,0x1f,0x1f,0x1f,0xe,0x0,0x0 }; //Circulo Lleno
byte flecha_aba[8] = { 0x0,0x0,0x0,0x0,0x0,0x1f,0xe,0x4 }; //Flecha abajo
byte barra_sup[8] = { 0x1f,0x1f,0x1f,0x1f,0x0,0x0,0x0,0x0 }; //Barra arriba
byte barra_inf[8] = { 0x0,0x0,0x0,0x0,0x1f,0x1f,0x1f,0x1f }; //Barra abajo
byte barra_llena[8] = { 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f };//Barra llena
//Pines del encoder
enum PinAssignments {
encoderPinA = 2, // right (DT)
encoderPinB = 3, // left (CLK)
};
//Asignacion de pines
const int encoderSW = 8; //Pin 8 para pulsador del encoder
const int pin_alarma = 5; //Pin 5 para activacion alarma
const int pulsador = 4; //Pin 4 para detener alarma
Bounce encoderSW_bounce = Bounce(8,10); //Asignamos el debounce
Bounce pulsador_bounce = Bounce(4,10); //Asignamos el debounce
//Variables del encoder
volatile int menu = 1; //Contador para el encoder
int lastmenu = 0; //Ultima posicion del encoder
static boolean rotating=false; //Debounce
boolean A_set = false; //Variables de seteo
boolean B_set = false;
//Dias de la semana
char *diasemana[] = {"Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"};
//VARIABLES
//Variables temporales para ajuste de hora
int fut_hora = 0;
int fut_min = 0;
int fut_seg = 0;
//Variables temporales para ajuste de fecha
int fut_ano = 0;
int fut_mes = 0;
int fut_dia = 0;
int fut_diaw = 0;
//Variables alarma
int hora_alarma = 0;
int min_alarma = 0;
int seg_alarma = 0;
int alarma_on = 0;
int fut_hora_alarma = 0;
int fut_min_alarma = 0;
int fut_seg_alarma = 0;
int fut_alarma_on = 0; //Variable de activacion
boolean ok_alarma = false; //Si llegamos a la hora activamos esta variable
unsigned long off_alarma; //Variable de tiempo para apagado de alarma
//Variables para los menus
boolean menu_ajustes =false;
boolean salir = false;
boolean cambio = false;
int maxmin = 0;
//Variables
int dia_semana = 10; //Variable para dia de la semana
boolean back = true; //Variable de retroiluminacion activa
//Variables de cuenta de tiempo
unsigned long temp_past;
unsigned long tiempo_res;
unsigned long time_past;
//Variable reinicio de maximos y minimos
boolean reinicio = true;
//Variable para primer inicio
boolean inicio = false;
//Variables timeout del menu
boolean datos_ok = true;
boolean time_out = false;
unsigned long temp_out;
//Variable timeout de backlight
unsigned long temp_margen;
unsigned long fut_luz;
boolean luz_activated = false;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void setup() {
lcd.init(); //Iniciamos el LCD
lcd.backlight(); //Iniciamos la retroiluminacion
//ASIGNACION DE TIPO DE PINES
pinMode(encoderPinA, INPUT_PULLUP); //Pines del encoder
pinMode(encoderPinB, INPUT_PULLUP);
pinMode(encoderSW, INPUT_PULLUP); //Interruptor del encoder
pinMode(pin_alarma, OUTPUT); //Salida de la alarma activa
pinMode(pulsador, INPUT); //Entrada detener alarma
//Configuracion inicial de pin
digitalWrite(pin_alarma,LOW);
//ASIGNACION DE INTERRUPCIONES
attachInterrupt(0, doEncoderA, CHANGE); //Interrupcion 0 para el pin 2
attachInterrupt(1, doEncoderB, CHANGE); //Interrupcion 1 para el pin 3
//CREACION CARACTERES
lcd.createChar(1,flecha_dech); // 1 -> Flecha Derecha
lcd.createChar(2,alarma); // 2 -> Alarma
lcd.createChar(3,altavoz_1); // 3 -> Altavoz1
lcd.createChar(4,linea_inf); // 4 -> Linea Inferior
lcd.createChar(5,altavoz_2); // 5 -> Altavoz2
lcd.createChar(6,cir_vacio); // 6 -> Circulo Vacio
lcd.createChar(7,cir_lleno); // 7 -> Circulo Vacio
lcd.createChar(8,flecha_aba); // 8 -> Flecha abajo
//Leemos valores de la alarma
hora_alarma=EEPROM.read(1);
min_alarma=EEPROM.read(2);
seg_alarma=EEPROM.read(3);
alarma_on=EEPROM.read(4);
//Comunicacion
radio.begin();
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening();
//Reloj
RTC.begin();
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void loop() {
if(menu != lastmenu){ //Si la variable menu cambia
menu = menu > 5 ? 1 : menu ; //Si menu es mayor que 5, volvemos a la posicion 1
menu = menu < 1 ? 5 : menu ; //Si menu es menor que 1, volvemos a la posicion 5
lastmenu=menu; //Igualamos situamos lastmenu como actual
lcd.backlight();
lcd.clear(); //Limpiamos pantalla
print_margen(); //Dibujamos el margen superior
back=true;
cambio = true;
maxmin = 0;
}
switch (menu) { //Switch para mostrar menus
case 1: //Opcion 1 RELOJ
lcd.setCursor(7,0);
lcd.print("Reloj");
lcd.setCursor(9,0);
printhour(); //Imprimimos la hora
fun_alarma(); //Comprobamos alarma
onbacklight(); //Apagar luz LCD
func_time_out(); //Temporizacion luz LCD
break;
case 2: //Opcion 2 TIEMPO
lcd.setCursor(6,0);
lcd.print("Tiempo");
fun_alarma(); //Comprobamos alarma
comunicacion(); //Recibimos datos
adaptacion(); //Adaptamos los datos
//Representamos los datos por pantalla
lcd.setCursor(0,1);
lcd.print("Ext:");
lcd.print(temp,1);
lcd.print("C - ");
lcd.print(rh,1);
lcd.print("%");
lcd.setCursor(0,2);
lcd.print("Presion:");
lcd.print(pa);
lcd.print(" mbar");
lcd.setCursor(0,3);
lcd.print("Luz: ");
lcd.print(Datos.lux);
lcd.print(" Lux ");
onbacklight(); //Apagar luz LCD
func_time_out(); //Temporizacion luz LCD
break;
case 3: //Opcion 3 MAXIMOS
fun_alarma(); //Comprobamos alarma
comunicacion(); //Recibimos datos
adaptacion(); //Adaptamos los datos
func_time_out();//Temporizacion luz LCD
switch (maxmin) {
case 0: //MENU DE MAXIMOS
lcd.setCursor(6,0);
lcd.print("Maximos");
lcd.setCursor(0,1);
lcd.print("Ext:");
lcd.print(maxtemp,1);
lcd.print("C - ");
lcd.print(maxrh,1);
lcd.print("%");
lcd.setCursor(0,2);
lcd.print("Presion:");
lcd.print(maxpa);
lcd.print(" mbar");
lcd.setCursor(0,3);
lcd.print("Luz: ");
lcd.print(Datos.maxlux);
lcd.print(" Lux ");
break;
case 1: //MENU DE MINIMOS
lcd.setCursor(6,0);
lcd.print("Minimos");
lcd.setCursor(0,1);
lcd.print("Ext:");
lcd.print(mintemp,1);
lcd.print("C - ");
lcd.print(minrh,1);
lcd.print("%");
lcd.setCursor(0,2);
lcd.print("Presion:");
lcd.print(minpa);
lcd.print(" mbar");
lcd.setCursor(0,3);
lcd.print("Luz: ");
lcd.print(Datos.minlux);
lcd.print(" Lux ");
break;
}
//Si pulsamos alternamos entre menu maximos o minimos (Ampliable)
encoderSW_bounce.update();
if (encoderSW_bounce.fallingEdge()){
temp_out = millis();
lcd.backlight();
back = true;
maxmin=maxmin++;
maxmin = maxmin > 1 ? 0 : maxmin ;
maxmin = maxmin < 0 ? 1 : maxmin ;
lcd.clear();
print_margen();
}
break;
case 5: //Opcion 5 OPCIONES
lcd.setCursor(6,0);
lcd.print("Opciones");
lcd.setCursor(1,1);
lcd.print("Ajustar Hora");
lcd.setCursor(1,2);
lcd.print("Ajustar Fecha");
lcd.setCursor(1,3);
lcd.print("Ajustar Alarma");
encoderSW_bounce.update(); //Actualizamos situacion del pulsador
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos entramos en opciones
temp_out = millis();
datos_ok = true; //Reiniciamos variable de sobrepaso de tiempo
salir = false ; //Seteamos la variable de salida a false
menu= 1 ; //Reinicializamos las variables del encoder
lastmenu = 1;
while ( salir == false ){ //Mientras salir sea FALSE, mantenemos el menu
rotating = true; //Establecemos el debounce
if(menu != lastmenu){ //Si menu ha cambiado
menu=constrain(menu,1,6); //Establecemos los limites del menu
delete_cursor(lastmenu); //Borramos el cursor anterior al cambiar el valor de menu
lastmenu=menu; //Seteamos como actual lastmenu
}
if (menu > 3 && !menu_ajustes){ //Si sobrepasamos por debajo
menu_ajustes=!menu_ajustes; //Seteamos que ya hemos limpiado pantalla
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Reset Max-Min");
lcd.setCursor(1,1);
lcd.print("Tiempo LUZ");
lcd.setCursor(1,2);
lcd.print("Salir");
}
if (menu < 4 && menu_ajustes){ //Si volvemos al menu anterior
menu_ajustes=!menu_ajustes; //Seteamos que ya hemos limpiado pantalla
lcd.clear();
print_margen(); //Dibujamos el margen superior
lcd.setCursor(6,0);
lcd.print("Opciones");
lcd.setCursor(1,1);
lcd.print("Ajustar Hora");
lcd.setCursor(1,2);
lcd.print("Ajustar Fecha");
lcd.setCursor(1,3);
lcd.print("Ajustar Alarma");
}
switch (menu) { //Switch para el menu de ajustes
case 1: //Ajuste de HORA
lcd.setCursor(0,1); //Situamos el indicador en la linea 1
lcd.write(1);
encoderSW_bounce.update(); //Actualizamos pulsador
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos entramos a ajustar la hora
set_hour(); //Funcion ajustar hora
salir = true ; //Una vez ajustada salimos
lcd.clear();
menu=1; //Volvemos al menu RELOJ
lastmenu = 0;
}
break;
case 2: //Ajuste de FECHA
lcd.setCursor(0,2); //Situamos el indicador en la linea 2
lcd.write(1);
encoderSW_bounce.update(); //Actualizamos pulsador
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos entramos a ajustar la hora
set_date(); //Funcion para ajustar la fecha
salir = true ; //Una vez ajustada salimos del menu
lcd.clear();
menu=1; //Volvemos al menu reloj
lastmenu = 0;
}
break;
case 3: //Ajuste ALARMA
lcd.setCursor(0,3); //Situamos el indicador en la linea 3
lcd.write(1);
encoderSW_bounce.update(); //Actualizamos pulsador
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos entramos a ajustar la hora
set_alarma(); //Funcion de ajuste de alarma
salir = true ; //Una vez ajustada salimos del menu
lcd.clear();
menu=1; //Volvemos al menu RELOJ
lastmenu = 0;
}
break;
case 4: //Reiniciar Maximo Minimos
lcd.setCursor(0,0); //Situamos el indicador en la linea 0
lcd.write(1);
encoderSW_bounce.update(); //Actualizamos pulsador
if (encoderSW_bounce.risingEdge()){ //Si reiniciamos valores
lcd.clear();
lcd.setCursor(6,2);
lcd.print("BORRANDO");
reset(); //Reiniciamos valores
lcd.clear();
lcd.setCursor(4,2);
lcd.print("ACTUALIZANDO"); //Esperamos hasta recibir nuevos valores
tiempo_res=millis();
while (tiempo_res+5000 > millis() )
comunicacion();
salir = true; //Seteamos variable salir a TRUE (Salimos del while)
lcd.clear(); //Limpiamos pantalla
menu=1; //Seteamos menu a 1 (Volvemos a la pantalla reloj)
lastmenu = 0;
}
break;
case 5: //Ajustar tiempo de pantalla encendida
lcd.setCursor(0,1); //Situamos el indicador en la linea 1
lcd.write(1);
encoderSW_bounce.update(); //Actualizamos pulsador
if (encoderSW_bounce.risingEdge()){ //Si pulsamos salimos de los menus
time_lcd_on();
salir = true ; //Una vez ajustada salimos del menu
lcd.clear();
menu=1; //Volvemos al menu RELOJ
lastmenu = 0;
}
break;
case 6: //SALIR
lcd.setCursor(0,2); //Situamos el indicador en la linea 1
lcd.write(1);
encoderSW_bounce.update(); //Actualizamos pulsador
if (encoderSW_bounce.risingEdge()){ //Si pulsamos salimos de los menus
salir = true; //Seteamos variable salir a TRUE (Salimos del while)
lcd.clear(); //Limpiamos pantalla
menu=1; //Seteamos menu a 1 (Volvemos a la pantalla reloj)
lastmenu = 0;
}
break;
}
func_time_out();
if (datos_ok == false){
salir = true; //Si para el tiempo sin setear salimos
datos_ok = true;
lcd.clear(); //Limpiamos pantalla
menu=1; //Seteamos menu a 1 (Volvemos a la pantalla reloj)
lastmenu = 0;
}
}
}
break;
case 4: //Opcion 4 INFORMACION
lcd.setCursor(4,0);
lcd.print("Informacion");
comunicacion(); //Recibimos datos
fun_alarma(); //Comprobamos alarma
temp_rh(); //Leemos temperatura interior
error(); //Comprobamos si hay errores
prediccion(); //Mostramos la prediccion
//Imprimimos los datos
if (tempin < -300 || rhin < -300){ //Si detectamos que los valores no son correctos mostramos error
lcd.setCursor(0,1);
lcd.print("ERR DHT");
borrar(7,19,1); //Limpiamos pantalla
}else{ //Si todo esta OK, mostramos la informacion
lcd.setCursor(0,1);
lcd.print("Int:");
lcd.print(tempin,1);
lcd.print("C - ");
lcd.print(rhin,1);
lcd.print("%");
borrar(17,19,1);
}
onbacklight();
func_time_out(); //Temporizacion luz LCD
break;
}
}
//FUNCIONES+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Interrupcion al cambio de A---------------------------------------------------------------------------------------------------------------
void doEncoderA(){
//Comprobamos que haya cambiado
if( digitalRead(encoderPinA) != A_set ) {
A_set = !A_set;
// adjust counter + if A leads B
if ( A_set && !B_set ){
time_out = false;
menu ++;
}
rotating = false; //Suprimible
}
}
//Interrupcion al cambio de B---------------------------------------------------------------------------------------------------------------
void doEncoderB(){
if( digitalRead(encoderPinB) != B_set ) {
B_set = !B_set;
// adjust counter - 1 if B leads A
if( B_set && !A_set ){
time_out = false;
menu --;
}
rotating = false; //Suprimible
}
}
//Impresion de menu RELOJ-------------------------------------------------------------------------------------------------------------------
void printhour(){
DateTime now = RTC.now();
//Establecemos la hora
lcd.setCursor(6,1);
if(now.hour() >= 0 && now.hour() < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(now.hour());
lcd.print(':');
if(now.minute() >= 0 && now.minute() < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(now.minute());
lcd.print(':');
if(now.second() >= 0 && now.second() < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(now.second());
//Establecemos la fecha (Solo en caso de cambio del dia de la semana o cambio de menu)
if (dia_semana != now.dayOfWeek() || cambio == true){
cambio = false;
dia_semana = now.dayOfWeek();
//Imprimimos la fecha
lcd.setCursor(10,2);
if (now.date()<10) lcd.print('0'); //Si el dia es menor de 10 imprimimos cero a la izquierda
lcd.print(now.date());
lcd.print('/');
if (now.month()<10) lcd.print('0'); //Si el mes es menor de 10 imprimimos cero a la izquierda
lcd.print(now.month());
lcd.print('/');
lcd.print(now.year());
lcd.setCursor(0,2);
borrar(0,9,2);
lcd.setCursor(0,2);
lcd.print(diasemana[(now.dayOfWeek()-1)]);
//Mostramos la posicion de la alarma
lcd.setCursor(0,3);
lcd.print("Alarma: ");
if(hora_alarma >= 0 && hora_alarma < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(hora_alarma);
lcd.print(':');
if(min_alarma >= 0 && min_alarma < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(min_alarma);
lcd.print(':');
if(seg_alarma >= 0 && seg_alarma < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(seg_alarma);
}
}
//Imprimir hora al ajustarla----------------------------------------------------------------------------------------------------------------
void adj_print_hora(int fut_hora,int fut_min, int fut_seg){
lcd.setCursor(0,3);
if(fut_hora >= 0 && fut_hora < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(fut_hora);
lcd.print(':');
if(fut_min >= 0 && fut_min < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(fut_min);
lcd.print(':');
if(fut_seg >= 0 && fut_seg < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
lcd.print('0');
}
lcd.print(fut_seg);
}
//Imprimir fecha al ajustarla---------------------------------------------------------------------------------------------------------------
void adj_print_date(int fut_dia, int fut_mes, int fut_ano, int fut_diaw){
lcd.setCursor(0,3);
if(fut_dia < 10){ //Si el dia es menor que 10, ponemos 0 a la izquierda
lcd.print('0');
}
lcd.print(fut_dia);
lcd.print('/');
if(fut_mes < 10){ //Si el mes es menor que 10 ponemos 0 a la izquierda
lcd.print('0');
}
lcd.print(fut_mes);
lcd.print('/');
lcd.print(fut_ano);
lcd.setCursor(11,3);
lcd.print(diasemana[fut_diaw]);
}
//Establecer la hora------------------------------------------------------------------------------------------------------------------------
void set_hour(){
DateTime now = RTC.now();
//Variables para los menus
boolean set_hora = false;
boolean set_min = false;
boolean set_seg = false;
//Variables de seteo
fut_hora = now.hour();
fut_min = now.minute();
fut_seg = now.second();
//Variables de sobrepaso de tiempo
temp_out=millis();
datos_ok = true;
//Menu ajustes de hora
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Set Hora:");
adj_print_hora(fut_hora,fut_min,fut_seg); //Dibujamos la hora
menu= 0 ; //Inicializamos variables para ENCODER
lastmenu = 0;
while (set_hora == false){ //Mientras no pulsemos ajustamos la hora
lcd.setCursor(0,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_hora = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que last menu sumamos valor
fut_hora++;
fut_hora=constrain(fut_hora,0,23); //Limite de variable 0-23
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que last menu restamos valor
fut_hora--;
fut_hora=constrain(fut_hora,0,23); //Limite de variable 0-23
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_hora=fut_hora;
}
adj_print_hora(fut_hora,fut_min,fut_seg); //Dibujamos nuevo valor de hora
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos el boton salimos de ajustar hora y pasamos a minutos
set_hora = true ;
borrar(0,2,2); //Borramos apuntador
}
}
menu= 0 ; //Inicializamos variables ENCODER
lastmenu = 0;
while (set_min == false){ //Mientras no pulsemos mantenemos en menu minutos
lcd.setCursor(3,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_min = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_min++;
fut_min=constrain(fut_min,0,59); //Limite variable 0-59
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_min--;
fut_min=constrain(fut_min,0,59); //Limite variable 0-59
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_min=fut_min;
}
adj_print_hora(fut_hora,fut_min,fut_seg); //Dibujamos nuevo valor de minutos
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos el boton salimos de ajustar minutos y pasamos a segundos
set_min = true ;
borrar(3,4,2); //Borramos apuntador
}
}
menu= 0 ; //Inicializamos variables ENCODER
lastmenu = 0;
while (set_seg == false){ //Mientras no pulsemos mantenemos en menu segundos
lcd.setCursor(6,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_seg = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_seg++;
fut_seg=constrain(fut_seg,0,59); //Limite variable 0-59
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_seg--;
fut_seg=constrain(fut_seg,0,59); //Limite variable 0-59
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_seg=fut_seg;
}
adj_print_hora(fut_hora,fut_min,fut_seg); //Dibujamos nuevo valor de segundos
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos el boton salimos de ajustar segundos
set_seg = true ;
}
}
if (datos_ok == true){
RTC.adjust(DateTime(now.year(),now.month(), now.date(), fut_hora, fut_min, fut_seg, now.dayOfWeek())); //Introducimos la hora en el DS3231
}else{
datos_ok = true;
}
}
//Funcion Ajustar Fecha---------------------------------------------------------------------------------------------------------------------
void set_date(){
DateTime now = RTC.now();
//Variables para los menus
boolean set_ano = false;
boolean set_mes = false;
boolean set_dia = false;
boolean set_diaw = false;
//Variables de seteo
fut_ano = now.year();
fut_mes = now.month();
fut_dia = now.date();
fut_diaw= (now.dayOfWeek()-1);
//Reiniciamos variables sobrepaso de tiempo
temp_out=millis();
datos_ok = true;
//Menu ajustes de hora
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Set Fecha:");
adj_print_date(fut_dia,fut_mes,fut_ano, fut_diaw); //Dibujamos la fecha
menu= 0 ; //Inicializamos variables para ENCODER
lastmenu = 0;
while (set_dia == false){ //Mientras no pulsemos mantenemos en menu ajustar dia
lcd.setCursor(0,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_dia = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_dia++;
fut_dia=constrain(fut_dia,1,31); //Limite variable 1-31
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_dia--;
fut_dia=constrain(fut_dia,1,31); //Limite variable 1-31
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_dia=fut_dia;
}
adj_print_date(fut_dia,fut_mes,fut_ano,fut_diaw); //Dibujamos nuevo valor de dia
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos pasamos a ajustar los meses
set_dia = true;
borrar(0,2,2);
}
}
menu= 0 ; //Inicializamos variables para encoder
lastmenu = 0;
while (set_mes == false){ //Mientras no pulsemos mantenemos ajustando mes
lcd.setCursor(3,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_mes = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_mes++;
fut_mes=constrain(fut_mes,1,12); //Limite variable 1-12
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_mes--;
fut_mes=constrain(fut_mes,1,12); //Limite variable 1-12
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_mes=fut_mes;
}
adj_print_date(fut_dia,fut_mes,fut_ano,fut_diaw); //Imprimos nuevo valor de mes
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos pasamos a ajustar el año
set_mes = true ;
borrar(3,4,2); //Borramos apuntador
}
}
menu= 0 ; //Incializamos variables para encoder
lastmenu = 0;
while (set_ano == false){ //Mientras no pulsemos mantenemos ajustando año
lcd.setCursor(6,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_ano = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_ano++;
fut_ano=constrain(fut_ano,2000,2099); //Limitamos variable 2000-2099
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_ano--;
fut_ano=constrain(fut_ano,2000,2099); //Limitamos variable 2000-2099
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_ano=fut_ano;
}
adj_print_date(fut_dia,fut_mes,fut_ano,fut_diaw); //Imprimimos nuevo valor de año
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si hemos pulsado salirmos de ajustar año
set_ano = true;
borrar(6,9,2); //Borramos apuntador
}
}
menu= 0 ; //Incializamos variables para encoder
lastmenu = 0;
while (set_diaw == false){ //Mientras no pulsemos mantenemos ajustando año
lcd.setCursor(11,2); //Apuntamos para saber que cambiamos
lcd.write(8);
func_time_out();
if (datos_ok == false) set_diaw = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_diaw++;
fut_diaw=constrain(fut_diaw,0,6); //Limitamos variable 0-6
lastmenu=menu;
lcd.setCursor(11,3); //Limpiamos para evitar superponer letras en los dias de la semana
lcd.print(" ");
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_diaw--;
fut_diaw=constrain(fut_diaw,0,6); //Limitamos variable 0-6
lastmenu=menu;
lcd.setCursor(11,3); //Limpiamos para evitar superponer letras en los dias de la semana
lcd.print(" ");
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_diaw=fut_diaw;
}
adj_print_date(fut_dia,fut_mes,fut_ano,fut_diaw); //Imprimimos nuevo valor de año
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si hemos pulsado salirmos de ajustar año
set_diaw = true;
}
}
fut_diaw=fut_diaw+1;
if (datos_ok == true){
RTC.adjust(DateTime(fut_ano, fut_mes, fut_dia, now.hour(), now.minute(), now.second(), fut_diaw)); //Introducimos fecha en DS1307
}else{
datos_ok = true;
}
}
//Funcion Guardar Alarma (EEPROM)----------------------------------------------------------------------------------------------------------
void save_alarma(int fut_hora_alarma,int fut_min_alarma,int fut_seg_alarma, int alarma_on){
//Leemos los valores guardados
int savehora=EEPROM.read(1);
int savemin=EEPROM.read(2);
int saveseg=EEPROM.read(3);
int saveseton=EEPROM.read(4);
if (savehora!=hora_alarma) //Si las horas guardadas no coinciden con las nuevas volvemos a guardar
{
EEPROM.write(1,hora_alarma); //Guardamos
}
if (savemin!=min_alarma) //Si los minutos guardados no coinciden con los nuevos volvemos a guardar
{
EEPROM.write(2,min_alarma); //Guardamos
}
if (saveseg!=seg_alarma) //Si los segundos guardados no coinciden con los nuevos volvemos a guardar
{
EEPROM.write(3,seg_alarma); //Guardamos
}
if (saveseton!=alarma_on) //SI cambia el estado de la alarma guardamos
{
EEPROM.write(4,alarma_on); //Guardamos
}
}
//Funcion Setear Alarma--------------------------------------------------------------------------------------------------------------------
void set_alarma(){
//Variables para los menus
boolean set_hora_alarma = false;
boolean set_min_alarma = false;
boolean set_seg_alarma = false;
boolean set_alarma_on = false;
//Seteamos variables futuras
fut_hora_alarma = hora_alarma;
fut_min_alarma = min_alarma;
fut_seg_alarma = seg_alarma;
fut_alarma_on = alarma_on;
//Seteamos variables sobrepaso de tiempo
temp_out=millis();
datos_ok = true;
//Menu ajustes de hora
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Set Alarma:");
adj_print_hora(fut_hora_alarma,fut_min_alarma,fut_seg_alarma); //Dibujamos los valores que tengamos guardados
if (fut_alarma_on == 1){ //Dibujamos el estado actual de la alarma, ACTIVADA
lcd.setCursor(15,3);
lcd.print("ON ");
}else{ //DESACTIVADA
lcd.setCursor(15,3);
lcd.print("OFF");
}
menu= 0 ; //Inicializamos variables ENCODER
lastmenu = 0;
while (set_hora_alarma == false){ //Mientras no pulsemos mantenemos en ajustar hora
lcd.setCursor(0,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_hora_alarma = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor a la variable
fut_hora_alarma++;
fut_hora_alarma=constrain(fut_hora_alarma,0,23); //Limite variable 0-23
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor a la variable
fut_hora_alarma--;
fut_hora_alarma=constrain(fut_hora_alarma,0,23); //Limite variable 0-23
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_hora_alarma=fut_hora_alarma;
}
adj_print_hora(fut_hora_alarma,fut_min_alarma,fut_seg_alarma); //Dibujamos el nuevo valor de la hora
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si hemos pulsado pasamos a menu ajuste minutos
set_hora_alarma = true ;
borrar(0,2,2); //Borramos apuntador
}
}
menu= 0 ; //Inicializamos variables ENCODER
lastmenu = 0;
while (set_min_alarma == false){ //Mientras no pulsemos mantenemos en ajustar hora
lcd.setCursor(3,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_min_alarma = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_min_alarma++;
fut_min_alarma=constrain(fut_min_alarma,0,59); //Limite varianle 0-59
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_min_alarma--;
fut_min_alarma=constrain(fut_min_alarma,0,59); //Limite variable 0-59
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_min_alarma=fut_min_alarma;
}
adj_print_hora(fut_hora_alarma,fut_min_alarma,fut_seg_alarma); //Dibujamos nuevo valor de minutos
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si hemos pulsado pasamos a menu ajuste segundos
set_min_alarma = true ;
borrar(3,4,2); //Borramos apuntador
}
}
menu= 0 ; //Inicializamos variables ENCODER
lastmenu = 0;
while (set_seg_alarma == false){ //Mientras no pulsemos mantenemos en ajustar segundos
lcd.setCursor(6,2); //Apuntamos para saber que cambiamos
lcd.write(8);
lcd.write(8);
func_time_out();
if (datos_ok == false) set_seg_alarma = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_seg_alarma++;
fut_seg_alarma=constrain(fut_seg_alarma,0,59); //Limite variable 0-59
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_seg_alarma--;
fut_seg_alarma=constrain(fut_seg_alarma,0,59); //Limite variable 0-59
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_seg_alarma=fut_seg_alarma;
}
adj_print_hora(fut_hora_alarma,fut_min_alarma,fut_seg_alarma); //Dibujamos nuevo valor de segundos
encoderSW_bounce.update(); //COnsultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si hemos pulsado, pasamos a menu activar/descativar alarma
set_seg_alarma = true ;
borrar(6,8,2);
}
}
menu= 0 ; //Inicializamos variables ENCODER
lastmenu = 0;
while ( set_alarma_on == false){ //Mientras no pulsemos mantenemos en el menu de activacion
func_time_out();
if (datos_ok == false) set_alarma_on = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu mayor que lastmenu sumamos valor
fut_alarma_on++;
fut_alarma_on=constrain(fut_alarma_on,0,1); //Limite 0-1
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_alarma_on--;
fut_alarma_on=constrain(fut_alarma_on,0,1); //Limite 0-1
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_alarma_on=fut_alarma_on;
}
//Si alarma_ON es 1 dibujamos ON, de lo contrario dibujamos OFF
if (fut_alarma_on == 1){
lcd.setCursor(15,3);
lcd.print("ON ");
}else{
lcd.setCursor(15,3);
lcd.print("OFF");
}
encoderSW_bounce.update();
if (encoderSW_bounce.fallingEdge()){
set_alarma_on = true ;
}
}
if (datos_ok == true){ //Si todo esta correcto, guardamos
hora_alarma = fut_hora_alarma;
min_alarma = fut_min_alarma;
seg_alarma = fut_seg_alarma;
alarma_on = fut_alarma_on;
save_alarma(hora_alarma,min_alarma,seg_alarma,alarma_on); //Llamamos a la funcion para guardar en la EEPROM
}else{
datos_ok = true;
}
}
//Borrar cursores--------------------------------------------------------------------------------------------------------------------------
//Cada vez que cambia el cursor de posicion en el menu de opciones, limpiamos el anterior
void delete_cursor(int posicion){
if (posicion < 3){
lcd.setCursor(0,posicion);
lcd.print(" ");
}else{
lcd.setCursor(0,posicion-4);
lcd.print(" ");
}
}
//Dibujar margen menu----------------------------------------------------------------------------------------------------------------------
//Cada vez que cambiamos de menu, volvemos a dibujar la linea de margen superior
void print_margen(){
lcd.setCursor(0,0);
for (int x = 0; x<=19; x++){
lcd.write(4);
}
}
//Funcion para alarma----------------------------------------------------------------------------------------------------------------------
void fun_alarma(){
DateTime now = RTC.now();
//Si coinciden horas minutos y segundos, a su vez que alarma_on esta TRUE, activamos la alarma
if (hora_alarma == now.hour() && min_alarma == now.minute() && seg_alarma == now.second() && alarma_on == 1){
ok_alarma = true; //Alarma encendida
temp_out = millis();
lcd.backlight(); //Encendemos la luz
back = true;
digitalWrite(pin_alarma, HIGH); //Activamos pin de alarma
off_alarma = millis();
}
if (off_alarma+120000 < millis() && ok_alarma == true){
ok_alarma = false; //Si lleva sonando la alarma mas de 2 minutos paramos automaticamente
digitalWrite(pin_alarma, LOW);
}
pulsador_bounce.update(); //Comprobamos si hemos pulsado el boton
if (pulsador_bounce.risingEdge()){ //Si hemos pulsado paramos la alarma
temp_out = millis();
lcd.backlight();
back = true;
ok_alarma = false;
digitalWrite(pin_alarma, LOW);
}
if (ok_alarma){ //Si tenemos sonando la alarma mostramos un icono
lcd.setCursor(18,0);
lcd.write(3);
lcd.write(5);
}else{ //Sino dibujamos el guion
lcd.setCursor(18,0);
lcd.write(4);
lcd.write(4);
}
if (alarma_on == 1){ //Si tenemos la alarma activa mostramos un icono
lcd.setCursor(17,0);
lcd.write(2);
}else{ //Sino dibujamos el guion
lcd.setCursor(17,0);
lcd.write(4);
}
}
//Funcion de comunicacion------------------------------------------------------------------------------------------------------------------
void comunicacion(){
//Si tenemos radio aviable, leemos los datos
if (radio.available()){
radio.read( &Datos, sizeof(Datos) );
}
}
//Funcion reset de valores MAX/MIN---------------------------------------------------------------------------------------------------------
void reset(){
//Mandamos los datos durante 3 segundos, para asegurar su correcta recepcion
tiempo_res=millis();
radio.stopListening();
while (tiempo_res+3000 > millis())
radio.write( &reinicio, sizeof(reinicio) );
radio.startListening(); //Volvemos a ponernos en modo escucha
}
//Funcion de adaptacion de valores---------------------------------------------------------------------------------------------------------
void adaptacion(){
//Dada la necesidad de marcar un limite de payload de 32 bits, nos vemos obligados a mandar los datos "codificados", en esta funcion los descodificamos
temp = Datos.temp;
rh = Datos.rh;
maxtemp = Datos.maxtemp;
maxrh = Datos.maxrh;
mintemp = Datos.mintemp;
minrh = Datos.minrh;
pa = Datos.pa;
maxpa = Datos.maxpa;
minpa = Datos.minpa;
temp /=10;
rh /=10;
maxtemp /=10;
maxrh /=10;
mintemp /=10;
minrh /=10;
pa *=0.01;
maxpa *= 0.01;
minpa *= 0.01;
}
//Funcion de lectura temperatura interior--------------------------------------------------------------------------------------------------
void temp_rh(){
if (inicio == true){ //En caso de primer inicio, ponemos a cero el contador de tiempo
time_past = millis();
inicio = false;
}
if (time_past + 5000 < millis()){ //Leemos cada cinco segundos
DHT.read22(DHT22_PIN);
time_past = millis();
}
tempin = DHT.temperature;
rhin = DHT.humidity;
}
//Funcion de errores-----------------------------------------------------------------------------------------------------------------------
void error(){
switch (Datos.error){
case 0: //Todo correcto
lcd.setCursor(0,3);
lcd.print("Running");
break;
case 1: //Error de sensor luz
lcd.setCursor(0,3);
lcd.print("Err L ");
break;
case 2: //Error sensor presion
lcd.setCursor(0,3);
lcd.print("Err P ");
break;
case 3: //Error sensor temperatura
lcd.setCursor(0,3);
lcd.print("Err T ");
break;
case 4: //Error sensores luz y presion
lcd.setCursor(0,3);
lcd.print("Err L/P");
break;
case 5: //Error sensores luz y temperatura
lcd.setCursor(0,3);
lcd.print("Err L/T");
break;
case 6: //Error sensores presion y temperatura
lcd.setCursor(0,3);
lcd.print("Err P/T");
break;
case 7: //Error total
lcd.setCursor(0,3);
lcd.print("ERR ALL");
break;
}
}
//Funcion de Prediccion--------------------------------------------------------------------------------------------------------------------
void prediccion(){
switch (Datos.pred){
case 0: //A la espera de tener datos para el calculo
lcd.setCursor(0,2);
lcd.print("Datos-");
lcd.write(6);
lcd.write(6);
lcd.write(6);
lcd.write(6);
lcd.write(6);
lcd.write(6);
break;
case 1:
lcd.setCursor(0,2);
lcd.print("Datos-");
lcd.write(7);
lcd.write(6);
lcd.write(6);
lcd.write(6);
lcd.write(6);
lcd.write(6);
break;
case 2:
lcd.setCursor(0,2);
lcd.print("Datos-");
lcd.write(7);
lcd.write(7);
lcd.write(6);
lcd.write(6);
lcd.write(6);
lcd.write(6);
break;
case 3:
lcd.setCursor(0,2);
lcd.print("Datos-");
lcd.write(7);
lcd.write(7);
lcd.write(7);
lcd.write(6);
lcd.write(6);
lcd.write(6);
break;
case 4:
lcd.setCursor(0,2);
lcd.print("Datos-");
lcd.write(7);
lcd.write(7);
lcd.write(7);
lcd.write(7);
lcd.write(6);
lcd.write(6);
break;
case 5:
lcd.setCursor(0,2);
lcd.print("Datos-");
lcd.write(7);
lcd.write(7);
lcd.write(7);
lcd.write(7);
lcd.write(7);
lcd.write(6);
break;
case 6: //Si la pendiente es negativa prediccion de borrasca
lcd.setCursor(0,2);
borrar(8,15,2);
lcd.setCursor(0,2);
lcd.print("Borrasca");
break;
case 7: //Si la pendiente es positiva prediccion de anticiclon
lcd.setCursor(0,2);
borrar(10,15,2);
lcd.setCursor(0,2);
lcd.print("Anticiclon");
}
}
//Funcion apagar retroiluminacion----------------------------------------------------------------------------------------------------------
void onbacklight(){
encoderSW_bounce.update(); //Actualizamos situacion del pulsador
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos apagamos retroiluminacion
temp_out = millis();
if (back==true){
lcd.noBacklight();
back=false;
}else{
lcd.backlight();
back=true;
}
}
}
//Funcion borrado Caracteres---------------------------------------------------------------------------------------------------------------
void borrar(int first, int last, int row){
for (first ; first < last+1 ; first++){
lcd.setCursor(first,row);
lcd.print(" ");
}
}
//Funcion para la inactividad--------------------------------------------------------------------------------------------------------------
void func_time_out(){
if (time_out == false){ //Comprobamos si hemos movido el encoder
temp_out = millis(); //Reiniciamos la variable de tiempo
time_out = true;
}
if ((temp_out+10000) < millis()){ //Esperamos 10 segundos de inactividad
datos_ok = false; //Seteamos para salir
}
if (luz_activated == true){ //En caso de tener activada la temporizacion
if ((temp_out+temp_margen) < millis() ){ //Esperamos el tiempo seteado
lcd.noBacklight(); //Apagamos la iluminacion
back = false; //Seteamos como apagada
}
}
}
//Funcion para setear el tiempo de luz encendida-------------------------------------------------------------------------------------------
void time_lcd_on(){
//Variable seteo menu
boolean set_luz = false;
//Mostramos info en el menu
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Tiempo:");
menu= 0 ; //Inicializamos variables para ENCODER
lastmenu = 0;
while (set_luz == false){ //Mientras no pulsemos mantenemos en menu ajustar tiempo
func_time_out();
if (datos_ok == false) set_luz = true; //Si para el tiempo sin setear salimos
if(menu > lastmenu){ //Si menu es mayor que lastmenu sumamos valor
fut_luz++;
fut_luz=constrain(fut_luz,0,15); //Limite variable 0-15
lastmenu=menu;
}else if (menu < lastmenu){ //Si menu es menor que lastmenu restamos valor
fut_luz--;
fut_luz=constrain(fut_luz,0,15); //Limite variable 0-15
lastmenu=menu;
}else if (menu == lastmenu){ //Si nada cambia mantenemos
fut_luz=fut_luz;
}
if (fut_luz == 0){ //Si el tiempo es 0, tenemos que no se apaga nunca, siempre ON
borrar(14,17,1);
lcd.setCursor(12,1);
lcd.print("ON"); //Mostramos ON
}else{ //Si el tiempo no es 0, mostramos que tiempo tenemos
lcd.setCursor(12,1);
if (fut_luz < 10) lcd.print("0"); //Si es menor de 10, ponemos un 0 a la izquierda
lcd.print(fut_luz);
lcd.print("min");
}
encoderSW_bounce.update(); //Consultamos si hemos pulsado
if (encoderSW_bounce.fallingEdge()){ //Si pulsamos el boton salimos de ajustar luz
set_luz = true ; //Seteamos para finalizar
}
}
if (datos_ok == true){ //Si no pasamos del tiempo de inactividad
temp_margen = fut_luz*60000; //Pasamos el tiempo a milisegundos
if (fut_luz > 0){ //Si es mayor que 0, tenemos que esta activado
luz_activated = true;
}else{ //Si es menor que 0, tenemos que esta desactivado
luz_activated = false;
}
}else{
datos_ok = true;
}
set_luz = false;
}
[/spoiler]
Estacion Exterior
[spoiler] Código: //Librerias
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <BH1750.h>
#include <dht.h>
//Inicializacion DHT22
dht DHT; //Declaracion del objeto
#define DHT22_PIN 5 //Configuracion de pin
//Inicializacion Inalambrica
#define CE_PIN 9 //Configuracion de pines
#define CSN_PIN 10
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; //Canales de transmision
RF24 radio(CE_PIN, CSN_PIN); // Creando la radio
//Inicializacion sensor LUZ
BH1750 lightMeter;
//Inicializacion sensor PRESION
Adafruit_BMP085 bmp;
uint8_t mode = BMP085_ULTRALOWPOWER;
//Estructura (Payload del NRF)
struct estacion {
//Prediccion
byte pred;
//Error
byte error;
//Datos
int temp;
int rh;
int lux;
int32_t pa;
//Maximos
int maxtemp;
int maxrh;
int maxlux;
int32_t maxpa;
//Minimos
int mintemp;
int minrh;
int minlux;
int32_t minpa;
}Datos;
//Temporales de operacion
float temp = 0;
float rh = 0;
float maxtemp = 0;
float mintemp = 0;
float maxrh = 0;
float minrh = 0;
//Errores
boolean error_luz = false;
boolean error_presion = false;
boolean error_temprh = false;
int chk;
//Prediccion
int32_t presure[5]; //Array para los valores
unsigned long time_pred = 0;
boolean first_pred = true;
byte i = 0;
//Variables conteo de tiempo e inicializacion
unsigned long time_past;
unsigned long tiempo_pas = 0;
unsigned long tiempo_envio = 0;
boolean reinicio = true;
boolean inicio = true;
boolean initiatemaxmin = false;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void setup() {
//Iniciamos los sensores y comunicacion
lightMeter.begin();
bmp.begin(mode);
radio.begin();
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.startListening(); //Comenzamos a escuchar
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void loop() {
temp_rh(); //Medimos la temperatura
luz(); //Medimos la luz
presion(); //Medimos la presion
prediccion(); //Calculamos para la prediccion
reset(); //Consultamos si debemos reiniciar datos
maxmin(); //Calculamos maximos y minimos
error(); //Comprobamos si tenemos algun error en los sensores
if (inicio == true){ //Si es la primera vez que iniciamos
tiempo_envio = millis();
inicio = false;
}
if (tiempo_envio+10000 < millis()){ //Enviamos cada 10 segundos (MODIFICABLE)
comunicacion();
tiempo_envio = millis();
}
}
//FUNCIONES+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Funcion leer temperatura y humedad--------------------------------------------------------------------------------------------------------
void temp_rh(){
if (inicio == true){
time_past = millis();
}
Serial.print("DHT22, \t");
if (time_past + 5000 < millis()){
chk =DHT.read22(DHT22_PIN);
time_past = millis();
error_temprh = chk /= 0 ? true : false ;
}
Datos.rh = DHT.humidity*10;
Datos.temp = DHT.temperature*10;
//Variables de operacion
temp = DHT.temperature;
rh = DHT.humidity;
}
//Funcion leer luz--------------------------------------------------------------------------------------------------------------------------
void luz(){
Datos.lux=lightMeter.readLightLevel(); //Leemos el valor del sensor de luz
error_luz = Datos.lux < 0 ? true : false ; //Comprobamos si la medida es correcta
}
//Funcion leer presion----------------------------------------------------------------------------------------------------------------------
void presion(){
Datos.pa=bmp.readPressure(); //Leemos el sensor de presion
error_presion = Datos.pa < 50000 ? true : false; //Comprobamos si la medida es correcta
}
//Funcion comunicacion----------------------------------------------------------------------------------------------------------------------
void comunicacion(void){
tiempo_pas=millis();
radio.stopListening(); //Paramos de escuchar para pasar a emitir
while (tiempo_pas+500 > millis()) //Enviamos durante 1.5seg para asegurar la recepcion correcta
radio.write( &Datos, sizeof(Datos) );
radio.startListening(); //Pasamos a escuchar
}
//Funcion maximos/minimos-------------------------------------------------------------------------------------------------------------------
void maxmin(){
//Inicializacion (Seteamos los valores sobre los que operaremos)
if (reinicio == true && (temp != 0 && rh != 0)){
maxtemp=temp;
maxrh=rh;
Datos.maxlux=Datos.lux;
Datos.maxpa=Datos.pa;
mintemp=temp;
minrh=rh;
Datos.minlux=Datos.lux;
Datos.minpa=Datos.pa;
reinicio = false;
initiatemaxmin = true;
}
//Una vez inicializamos, calculamos
if (initiatemaxmin == true){
//Maximos
if (maxtemp < temp) maxtemp=temp;
if (maxrh < rh) maxrh=rh;
if (Datos.maxlux < Datos.lux) Datos.maxlux=Datos.lux;
if (Datos.maxpa < Datos.pa) Datos.maxpa=Datos.pa;
//Minimos
if (mintemp > temp) mintemp=temp;
if (minrh > rh) minrh=rh;
if (Datos.minlux > Datos.lux) Datos.minlux=Datos.lux;
if (Datos.minpa > Datos.pa) Datos.minpa=Datos.pa;
}
//Convertimos a INT
Datos.maxtemp = maxtemp*10;
Datos.maxrh = maxrh*10;
Datos.mintemp = mintemp*10;
Datos.minrh = minrh*10;
}
//Funcion reinicio max/min-----------------------------------------------------------------------------------------------------------------
void reset(){
if (radio.available()){
radio.read( &reinicio, sizeof(reinicio) );
}
}
//Funcion comprobacion de errores----------------------------------------------------------------------------------------------------------
void error(){
// 0: Sin errores
Datos.error = error_luz == false && error_presion == false && error_temprh == false ? 0 : Datos.error ;
// 1: Error Sensor Luz
Datos.error = error_luz == true ? 1 : Datos.error ;
// 2: Error Sensor Presion
Datos.error = error_presion == true ? 2 : Datos.error ;
// 3: Error temp/rh
Datos.error = error_temprh == true ? 3 : Datos.error ;
// 4: Error Sensor Luz && Presion
Datos.error = error_luz == true && error_presion == true ? 4 : Datos.error;
// 5: Error Sensor Luz && Temp/rh
Datos.error = error_luz == true && error_temprh == true ? 5 : Datos.error;
// 6: Error sensor Pesion && Temp/rh
Datos.error = error_temprh == true && error_presion == true ? 6 : Datos.error;
// 7: Error todos sensores
Datos.error = error_temprh == true && error_presion == true && error_luz == true ? 7 : Datos.error;
}
//Funcion prediccion-----------------------------------------------------------------------------------------------------------------------
void prediccion(){
float a,b,c,d,m; //Variables de calculo
if (inicio == true){
presure[i]=Datos.pa;
i=i+1;
time_pred = millis();
}
if (time_pred+1800000 < millis()){ //Registramos datos cada media hora
presure[i]=Datos.pa;
i=i+1;
time_pred = millis();
}
if (i == 6){ //Cuando tenemos 6 datos, calculamos
a = 6*((1*presure[0])+(2*presure[1])+(3*presure[2])+(4*presure[3])+(5*presure[4])+(6*presure[5]));
b = (720)*(presure[0]+presure[1]+presure[2]+presure[3]+presure[4]+presure[5]);
c = 546;
d = 441;
m = (a-b)/(c-d);
if (m < 0){
Datos.pred = 6; //Si m menor que cero, BORRASCA
}else{
Datos.pred = 7; //Si m mayor que cero, ANTICICLON
}
i = 0; //Reiniciamos cuenta de datos
first_pred = false;
}
if (first_pred == true) Datos.pred = i; //Si es la primera vez que iniciamos la estacion, esperamos hasta tener los 6 datos.
}
[/spoiler]
ME acaba de llegar el DHT11 y me queda comparar temperaturas con uno que sea comercial pero de momento no iba mal
cansi22 escribió:ME acaba de llegar el DHT11 y me queda comparar temperaturas con uno que sea comercial pero de momento no iba mal
Espero esos resultados
Todo mola más con GPS. Ponle un módulo GPS para tiempo de alta precisión y un ethernet shield para dar los datos por red (y ya que estás, un servidor NTP )
Los u-blox de portátil en formato mini-pcie son muy baratos y tienen salida serie en unos pads bastante accesibles.
n0p escribió:Todo mola más con GPS. Ponle un módulo GPS para tiempo de alta precisión y un ethernet shield para dar los datos por red (y ya que estás, un servidor NTP )
Los u-blox de portátil en formato mini-pcie son muy baratos y tienen salida serie en unos pads bastante accesibles.
Para el nivel actual que controlo de arduino (Segundo Proyecto) Se me escapa un poco de las manos ese nivel jajajaja.
Por ahora ire probando los sensores y la comunicacion con los mismos, e ire poniendo los resultados por aqui
La tasa de refresco no es algo que te vaya a importar mucho. No tienes que llevar un seguimiento muy continuo. Y por el rango tres cuartos de lo mismo, podrías usar hasta un LM35 o un DS18B20, ya que no vas a tener temperaturas muy extremas y su funcionamiento es más que bueno en ambos casos, quizás algo mejor el DS, pero para lo que es... Ahora ya la precisión que tu quieras será la que decida qué componentes pilar.
Si investigas algo sobres los sensores de gases, calidad del aire o similares, postealo, que yo tengo mis dudas con los MQ, xD.
n0p escribió:Todo mola más con GPS. Ponle un módulo GPS para tiempo de alta precisión y un ethernet shield para dar los datos por red (y ya que estás, un servidor NTP )
Los u-blox de portátil en formato mini-pcie son muy baratos y tienen salida serie en unos pads bastante accesibles.
Eso ya es pasarse :elrisas: Hay que saber hasta donde llegar
Grafi, ya sabes que aquí a la gente se le va de las manos rápidamente, xDDD.
Otra cosa, lo de conectarlo al móvil quizás puedas apañar algo con la app del compañero r0bert0: http://www.spainlabs.com/foro/viewtopic.php?f=9&t=505
El de casa se actualiza cada minuto y este en el ejemplo cada medio segundo. No creo que cambie mucho la tempera tuda en 1 minuto
jajajaaj
Lo que tengo en el blog es algo antiguo, un año ya, así que aunque esta bien se puede mejorar y mucho. Hace poco tenia intención de montar una estación 2.0 pero al final la he dejado estar por el momento ya que no he encontrado solución a los cuelgues de la shield de ethernet.
El caso es que los sensores ya los pille y he probado bastantes...
Para la humedad y la temperatura te recomiendo un DHT22, va muy bien y con un solo sensor ya tienes los dos datos. El DHT11 es muy rancio, el LM35 es rancio también, el DS18B20 esta bien pero con el DHT22 sobra.
Para la presión atmosférica yo he probado un BMP180 que es el modelo siguiente al que has puesto y se supone que es mejor, el problema es que se alimenta a 3.3V, el tuyo puedes elegir a 5V y 3.3V.
Lo he probado con una librería (creo que solo hay una para el mio) y te saca la presión, altitud y temperatura, aunque no sé si va muy bien porque la presión no coincide para nada con la del reloj (un casio de montañismo), y la altitud ni con la del reloj ni con la que hay en mi ciudad... eso lo tengo que investigar mas.
Para el sensor de luz tengo ese mismo que has puesto, parece ir bien aunque no tengo con que comparar xD
Los transmisores RF también van muy bien aunque es un coñazo realizar las conexiones ya que no puedes pincharlo directamente en la protoboard.
En vez del arduino nano yo quizás pondría mejor un arduino pro micro, tendrás mas memoria sram y es mas actual:
http://www.ebay.es/itm/Leonardo-Pro-Micr...232f240fb6
El sensor de dióxido de carbono aun no lo he probado.
El sensor de lluvia no sé como de bien ira, imagino que las gotas harán "corto" y según cuantas gotas haya y como tengas regulado la sensibilidad pues te dirá que esta lloviendo o no. La gracia si tienes espacio seria que te midiera la cantidad de lluvia pero es mas caro claro.
Si lo quieres complicar un poco mas puedes poner un lector de tarjetas SD y guardar los datos por si un dia quieres hacerte gráficas con el excel is1:
PD: Te dejo una lista de la compra que hice aunque básicamente son los componentes que has puesto ya http://goo.gl/InOAh5
giltesa.com Mi blog personal sobre informática, electrónica, Arduino, bricolaje, etc.
Si sin duda, empleare el DHT22, luego el de presion sera probar...aver que resultados da, ya lo comentare por aqui, el tema es que la presion la da en Hectopascales, por tanto habra que pasarla a bares.
Los NRF funcionan a 3,3V tambien
El sensor de gases efectivamente seria el MQ7, que mide dioxido de carbono...etc etc que es lo que nos interesa
Y el sensor de lluvia, lo mismo todo sera cuestion de probarlo, estaria bien saber que cantidad de agua ha llovido, pero me parece mucho armatroste....
El que es majo es este, pero no tengo sitio para montarlo al aire libre :/
https://www.sparkfun.com/products/8942
giltesa.com Mi blog personal sobre informática, electrónica, Arduino, bricolaje, etc.
giltesa escribió:El que es majo es este, pero no tengo sitio para montarlo al aire libre :/
https://www.sparkfun.com/products/8942
Bufff, yo tampoco, mi idea es una cajita como la tuya nomas. Vivo en un piso y es lo que hay....jajajaj
Tendre problemas con el rango de los NRF? dentro de una caja pasando una ventana a unos 5 metros?
Estaba mirando sensores de Gases, hay de muchos tipos, todos con la denominacion MQ, creo que el mas adecuado para mirar la calidad del aire es:
http://www.futurlec.com/Datasheet/Sensor/MQ-135.pdf
Ya que el MQ7 solo mide CO.
Echarle un ojo a :
http://playground.arduino.cc/Main/MQGasSensors
Buena lista la del playground, no la había visto. Me la apunto.
|