// carga de hora y fecha para Anemometro, Compilado con Arduino 1.8.1, 15/03/2019 #include <EEPROM.h> void setup() { Serial.begin(9600); // estos valores deben indicarse solo al cargar el programa por primera vez. Para actualizar la hora y/o minuto hay que comentar el resto de lineas // ya que el programa principal se autogestiona EEPROM.write(0,0);//seg EEPROM.write(1,23);//hora EEPROM.write(2,59);//minuto EEPROM.write(3,31);//dia EEPROM.write(4,12);//mes EEPROM.write(5,19);//any EEPROM.write(6,1);//puntero dia de la Semana /* posicion= 0 1 2 3 4 5 6 para el año 2019 le corresponde 1; ya que el 1/01/2019 fué Martes, y se corresponde con la posision 1 de la tabla tSemana[7]={'L','M','X','J','V','S','D'}; para el año 2020 le corresponde 2; ya que el 1/01/2020 será Miercoles, y se corresponde con la posision 2 de la tabla tSemana[7]={'L','M','X','J','V','S','D'}; y así sucesivamente hasta seis, luego comienza de cero */ Serial.print(EEPROM.read(1));Serial.print(":");Serial.print(EEPROM.read(2));Serial.print(":");Serial.println(EEPROM.read(0));// imprime la hora establecida Serial.print(EEPROM.read(3));Serial.print("/");Serial.print(EEPROM.read(4));Serial.print("/");Serial.println(EEPROM.read(5)+2000);// imprime la fecha establecida Serial.print("Puntero: ");Serial.println(EEPROM.read(6));// imprime el valor de puntero } void loop() {}
Y el Sketch final, fuertemente comentado, es un modelo resultón y muy similar al que estoy empleando en la actualidad, determina la velocidad del viento dado en un minuto, o sea, ofrece las revoluciones por minuto, literalmente hablando. De manera que si un día de viento racheado nuestro anemómetro nos calcula una velocidad de 60km/h., nos esta dando un promedio por minuto ya que ha multiplicado las revoluciones que se han sucedido por la distancia y lo ha dividido entre 60seg.
/* ESQUEMA DE CONEXIONES. Compilado con Arduino 1.8.1 el 15/03/2019 7-14v. +-----+ ____[PWR]___________________| USB |__ | +-----+ | | GND/RST2 [ ][ ] | | MOSI2/SCK2 [ ][ ] A5/SCL[ ] | <-- pin SCL del LCD | 5V/MISO2 [ ][ ] A4/SDA[ ] | <-- pin SDA del LCD | AREF[ ] | | GND[ ] | | [ ]N/C SCK/13[ ] | <-- pin SCK microSD | [ ]IOREF MISO/12[ ] | <-- pin MISO microSD | [ ]RST MOSI/11[ ]~| <-- pin MOSI microSD | [ ]3V3 +---+ 10[ ]~| + Anem,SD,LCD--> | [ ]5v -| A |- 9[ ]~| - Anem,SD,LCD--> | [ ]GND -| R |- 8[ ] | | [ ]GND -| D |- | | [ ]Vin -| U |- 7[ ] | | -| I |- 6[ ]~| | [ ]A0 -| N |- 5[ ]~| | [ ]A1 -| 0 |- 4[ ] |<-- pin CS microSD | [ ]A2 +---+ INT1/3[ ]~| | [ ]A3 INT0/2[ ] |<-- Señal Anemómetro | [ ]A4/SDA RST SCK MISO TX>1[ ] | | [ ]A5/SCL [ ] [ ] [ ] RX<0[ ] | | [ ] [ ] [ ] | | UNO_R3 GND MOSI 5V ____________/ \_______________________/ */ #include <LiquidCrystal_I2C.h>// Incluye la libreria LiquidCrystal_I2C para hacer uso del LCD LiquidCrystal_I2C lcd(0x27,16,2);// declaramos nuestra variable lcd(direccion,nº celdas,nº filas) #include <EEPROM.h>// Incluye la libreria EEPROM para hacer uso de la EEPROM #include <SD.h> // Incluye la libreria para la SD File DatAnem;// creamos un objeto de tipo FILE boolean sh;// Sentecia Anemometro unsigned int rev,kmh;// Sentecia Anemometro float D=1.60,e,v,Cf=(D*PI);// formula del Anemometro const byte sensHall= 7; // pin de la señal sensor hall. long newMilli; // Control de tiempo byte seg=EEPROM.read(0)+2;// cada vez que byte hora=EEPROM.read(1); // se inicie nuestra byte minuto=EEPROM.read(2);// Arduino toma byte dia=EEPROM.read(3);// los datos byte mes=EEPROM.read(4); // de la EEPROM int any=EEPROM.read(5)+2000; // Hay que sumarle 2000 para ver el año en su formato completo //byte puntDiaSemana=EEPROM.read(6); byte Mes[12]={31,28,31,30,31,30,31,31,30,31,30,31}; // Tabla de los dias del mes char tSemana[7]={'L','M','X','J','V','S','D'}; // Tabla de los dias de la semana char dSemana; // Variable que almacena el dia de la semana boolean shAnterior; void setup() { Serial.begin(9600); lcd.init(); // Inicializamos el LCD lcd.backlight(); // Encedemos la iluimnacion del LCD lcd.setCursor(0,0);lcd.print("Iniciando...");lcd.clear(); esbisiesto(any); // determina si el año corriente es o no bisiesto diaSemana(); // determina el dia de la semana InitSD(); // inicializa la SD } void loop() { newMilli=millis()/999; // Asignamos a nuestra varible newMillis() el valor que contiene millis(); contador interno de Arduino while((newMilli+1)>(millis()/999)){ // retenemos el flujo un segundo sh = digitalRead(sensHall);// mientras leemos el valor del sensor y se lo asignamos a nuestra variable sh if(sh){shAnterior=sh;}// si se detecta el paso del iman igualamos las dos variables para determinar si hay movimiento if (!sh && shAnterior){ // si las variables son distintas es que efectivamente hay movimiento rev++;// e incrementamos una revolucion shAnterior=sh;// volvemos a igualar las variables. Si el iman se detiene frente al }// sensor, iria entrando en el if anterior sumando revoluciones falsas a cada segungo } // Cierra While Millis actualiza(); // actualizamos los datos imprimirLCD();// imprime los datos actualizados a la LCD }// Cierra Loop void actualiza(){ seg++;//EEPROM.write(0,seg);// sumamos un segundo. Si guardamos cada segundo en la EEPROM no tardara mucho en quemar esa posicion!!! if (seg > 59){ // al superar los 60 segundos seg=0;EEPROM.write(0,seg);minuto++;EEPROM.write(2,minuto);// Actualizamos seg y minutos y los guardamos en la EEPROM kmh=calcVel(rev);//Llama a la funcion calcVel, enviando las rev registradas en un minuto y asignamos el calculo a nuestra variable kmh rev=0; // ponemos las revoluciones a cero if(minuto<60){Traspas_SD();}// tras cada minuto, exceptuando las :00 salvamos los datos en la SD } if (minuto > 59){// al superar la hora if (hora < 23){// si son menos de las 23 horas minuto=0;EEPROM.write(2,minuto);hora++;EEPROM.write(1,hora);// sumamos una hora y actualizamos la EEPROM Traspas_SD();//salvamos los datos en la SD en cada :00 exceptuando la del fin del año }else{ // en caso contrario es que estamos en el siguiente dia dia++;EEPROM.write(3,dia);minuto=0;EEPROM.write(2,minuto);hora=0;EEPROM.write(1,hora);//incrementamos un dia y lo guardamos en la EEPROM if(dia > Mes[mes-1]){//determinamos en que mes nos encontramos dia=1;EEPROM.write(3,dia);mes++;EEPROM.write(4,mes);// incrementamos un mes y lo guardamos en la EEPROM } if (mes > 12){mes=1;EEPROM.write(4,mes);any++;EEPROM.write(5,any-2000);EEPROM.write(6,EEPROM.read(6)+1);esbisiesto(any);}// cambio de año diaSemana();// actualizamos el dia de la semana Traspas_SD();//salvamos los datos en la SD al cambiar de dia y año } // cierra else } } //------------------------------------------------------------------------------------------------------------------------------- Metodo Calcula Velocidad en Km/h. int calcVel(int z){ // recibe las rev return ((Cf*z)/60)*3.6;// calcula la la velocidad, dados las caracteristicas de nuestro anem, establecidas en la declaracion de variables } //------------------------------------------------------------------------------------------------------------------------------- Metodo Impresion a la LCD void imprimirLCD(){ lcd.clear(); // Limpiamos la LCD if (hora<10){lcd.print("0");} // Añadimos un cero si la hora solo contiene un digito lcd.print(hora); // imprime la hora lcd.print(':'); // imprime pues eso... dos puntos if (minuto<10){lcd.print("0");}// Añadimos un cero si los minutos solo contienen un digito lcd.print(minuto); // imprime el minuto lcd.print(':'); if (seg<10){lcd.print("0");}// Añadimos un cero si los segundos solo contiene un digito lcd.print(seg); // imprime el minuto lcd.print(" "); // imprime la etiqueta para la intensidad lcd.print(kmh);// imprime la intensidad lcd.print("km/h"); lcd.setCursor(0,1);// pasamos a la segunda linea del LCD lcd.print(dSemana);// imprime el char correspondiente al dia de la semana lcd.print(" "); if (dia<10){lcd.print("0");} // añadimos un cero si dia solo contiene un digito lcd.print(dia);// imprime el dia lcd.print('/'); if (mes<10){lcd.print("0");}// añadimos un cero si mes solo contiene un digito lcd.print(mes);// imprime el mes lcd.print('/'); lcd.print(any);// imprime el año lcd.print(" ");lcd.print(rev); } //------------------------------------------------------------------------------------------------------------------------------- Metodo si es bisiesto void esbisiesto(int any){ // Comprueba si el año que recibe es bisiesto if (any %4==0 && (any%100!=0 || any%400==0)){ // en caso de serlo le asigna al mes de febrero 29 dias Mes[1]=29;lcd.print("Bisiesto");lcd.setCursor(0,1);lcd.print("Febrero ");lcd.print(Mes[1]);lcd.print(" dias");//Imprime si es bisiesto el nº de dias de Febrero }else{ // en caso de no ser bisiesto asigna a febrero 28 dias Mes[1]=28;lcd.print("No Bisiesto");lcd.setCursor(0,1);lcd.print("Febrero ");lcd.print(Mes[1]);lcd.print(" dias");//Imprime si no es bisiesto el nº de dias de Febrero } delay(500);lcd.clear();// retiene el flujo 1/2 segundo para poder leer el texto y borra la pantalla } //------------------------------------------------------------------------------------------------------------------------------- Metodo diaSemana void diaSemana(){// Determina el dia de la semana byte puntero=EEPROM.read(6); // sabemos que el 1/1/2019 fue Martes, de ahí que puntero valga 1, que es la posicion de Martes en la tabla tSemana byte d=1; // establecemos una variable dia para ir sumando los dias uno a uno byte m=1; // establecemos una variable mes para ir sumando los meses uno a uno String stfecha=String(dia)+"_"+String(mes);// hacemos un cast y covertimos el d y el m en una string String stF=String(d)+"_"+String(m);// hacemos un cast y covertimos el dia y el mes en una string para ser comparada en el while if(stF.equals(stfecha)){dSemana=tSemana[EEPROM.read(6)];// si la fecha es 1/01 se toma el valor para puntero de la EEPROM que ha sido actualizado al cambio de año }else{ // de lo contrario hay que buscar el dia y reasignarle el nuevo dia de la semana lcd.print("buscando dia ..."); while(!stF.equals(stfecha)){ // mientras la cadena que irá variando el bucle sea distinta a la fecha actual se sumaran dias Serial.print(stF);Serial.print(" ");Serial.print(tSemana[puntero]);Serial.print(" ");Serial.print(stfecha);Serial.print(" ");Serial.println(puntero); if(puntero>5){puntero=0;}else{puntero++;}// controlamos el valor de puntero, éste nos señalará la posicion final d++;// vamos sumando uno a cada iteracion a la variable d if (d > Mes[m-1]){d=1;m++;} // comprobacion para sumar un mes if (m>12){m=1;}// comprobacion para que m no supere el 12 stF=String(d)+"_"+String(m); // a cada iteracion debemos actualizar la string stF para que el bucle la compare con la fecha actual }// cierra while lcd.clear(); dSemana=tSemana[puntero];// establece el dia de la semana en funcion de donde haya quedado el puntero. }//cierra else }// cierra metodo diaSemana //------------------------------------------------------------------------------------------------------------------------------- Metodo conexion SD void InitSD(){ if (!SD.begin(4)){ // si no detecta la SD lcd.setCursor(0,0);lcd.print("SD no conectada");delay(500);lcd.clear();// imprime que no la ha detectado }else{lcd.setCursor(0,0);lcd.print("SD en Conexion ");delay(500);lcd.clear();// en caso contrario imprime lo pertinente } if (!SD.exists("DtAnem")) {//comprueba si el archivo DtAnem existe en la SD lcd.setCursor(0, 0); lcd.print("Archivo NO Existe"); delay(500); lcd.clear();// en caso de no existir imprime lo pertinente } else { lcd.setCursor(0, 0);lcd.print("Archivo OK");// si existe imprime lo propio delay(500); lcd.clear();// Vacia la pantalla } } //------------------------------------------------------------------------------------------------------------------------------- Metodo traspaso a la SD void Traspas_SD(){ SD.begin(4);//cada vez que saquemos la tarjeta se pierde la conexion, al iniciar la SD en cada llamada nos aseguramos que los datos se guardaran DatAnem = SD.open("DtAnem",FILE_WRITE); // Abre el archivo DtAnem en modo lectura-escritura DatAnem.print(dSemana);DatAnem.print(" ");// imprime en el archivo el dia de la semana DatAnem.print(dia);DatAnem.print("/");DatAnem.print(mes);DatAnem.print("/");DatAnem.print(any);DatAnem.print(" ");// seguido de la fecha DatAnem.print(hora);DatAnem.print(":");DatAnem.print(minuto);DatAnem.print(":");DatAnem.print("0");DatAnem.print(seg);DatAnem.print(" ");// la hora DatAnem.println(kmh);// y el dato de velocidad, todo en la misma linea. DatAnem.close();// cierra el archivo lcd.clear();// limpia el LCD }
El valor mas alto que mi anemómetro ha registrado ha sido de 91km/h. ¿Cual habrá sido la racha en ese minuto?
Para que nuestro anemómetro pueda obtener el detalle de las rachas, será necesario realizar alguna modificación, que puede hacer peligrar su fiabilidad. Por si no te has percatado para obtener la medición de la intensidad del viento, el factor tiempo es tan vital como destructivo, el programa debe ser capaz de leer decenas de veces por segundo el tiempo transcurrido entre una revolución y otra, almacenar esa información y procesarla. Esto como digo, va a requerir realizar pruebas de velocidad sobre el flujo, el volumen de datos que se va a generar va a ser importante dadas las características de una Arduino, aunque te anticipo que tengo una versión que lo resuelve... una pista... Arduinos en TX RX.
Que interesante tu trabajo. Espero poder llevarlo a la práctica en algún momento. Me gustaría montar una estación meteorológica casera con Arduino, cargarlos en una API y consultarlos desde mi teléfono o desde alguna página web. No va a ser un camino fácil pero es muy estimulante. Gracias. Braian desde Buenos Aires
ResponderEliminarGracias Braian, ciertamente no será un camino fácil, pero como bien dices, esa es la la motivación.
ResponderEliminar