45- Arduino Proyecto fin de curso. Estación Meteorológica

La fuerza de Arduino como diseñador radica en el hecho de que absolutamente para cualquier pieza de hardware puede encontrar en Google una descripción, una biblioteca, un diagrama de cableado y un ejemplo de trabajo: un kit completamente listo para integrar en su proyecto. Como colofón a este curso de básico de Arduino realizaremos un proyecto medianamente serio, una estación meteorológica funcional.

! Volvamos a nuestro reloj meteorológico e intentemos «ensamblar» tal proyecto a partir de bocetos de ejemplo, ¡porque para eso se necesitan ejemplos! Nosotros necesitamos:

  • Arduino NANO.
  • Display. Como LCD1602 con adaptador i2c.
  • Módulo reloj en tiempo real, tomemos DS3231.
  • Termómetro ds18b20.

Paso 1, recopilar información.

La mayor parte del proyecto esta ya resuelto a «grosso modo, resuelto por mí» pero cada lector deberá esforzarse en dar a su proyecto su toque personal.

Comenzamos a buscar en Google información sobre la conexión y el ejemplo de cada módulo o pieza de hardware:

De las búsquedas de ejemplos de Google, aprendemos información tan importante como los diagramas de conexión: la pantalla y el reloj están conectados al bus i2c, y el sensor ds18b20 se puede conectar a cualquier otro pin. Nuestro diagrama de proyecto arduino queda así:

Diagrama del proyecto arduino
Diagrama del proyecto arduino.

Descargue las bibliotecas para nuestros módulos e instálelas. La biblioteca de visualización se nos proporciona directamente en este artículo:  la biblioteca para el reloj, por mi propia experiencia, recomiendo RTClib (la que está en el artículo del ejemplo no es muy buena). En el artículo sobre el sensor de temperatura, nos dijeron sobre la biblioteca DallasTemperature.h, no dieron un enlace. Bueno, busquemos “DallasTemperature.h” nosotros mismos, lo encontraremos en este enlace. También necesita la biblioteca OneWire, se proporcionó un enlace en el artículo sobre el termómetro. En total, debemos tener instaladas 4 bibliotecas.

Ahora nuestro objetivo es encontrar ejemplos que funcionen para cada pieza de hardware, para asegurarnos de que funcionen y asignarnos el conjunto mínimo de código para controlar el módulo, puede ser difícil: suele haber errores en los artículos y a veces copiar y pegar simplemente no funciona. Código: estos artículos a menudo se copian y pegan de personas alejadas de los temas, que no los dominan a fondo. Tomé un ejemplo de trabajo con una pantalla del artículo, pero tuve que mirar para el reloj y el termómetro en los ejemplos de la biblioteca. Hagamos un poco de combinación de ejemplos, dejemos solo las funciones para obtener los valores o resultados que necesitamos, voy dejando todo lo que necesito en:


Paso 2, seleccionar y probar.

void setup():

Código inicial para la pantalla de visualización LCD1602.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Configurar la pantalla
// la dirección puede ser 0x27 o 0x3f
void setup() {
  lcd.init();
  lcd.backlight();  // Enciende la luz de fondo de la pantalla
   // Coloca el cursor en la segunda línea y el carácter nulo.
  lcd.setCursor(0, 1);
  lcd.print("Hello!");  // hola
}
void loop() {
}

Código inicial para el reloj en tiempo real DS3231.

#include "RTClib.h"
RTC_DS3231 rtc;
void setup () {
  Serial.begin(9600);
 // verifica si el módulo está conectado
  if (! rtc.begin()) {
    Serial.println("No se pudo encontrar RTC");
    while (1);
  }
  // establecer el tiempo para compilar la hora
  // ¡si el módulo tuvo un reinicio!
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
 // mostrar valores de Hora
  DateTime now = rtc.now();
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
}
void loop () {
}

Código inicial para el termómetro ds18b20.

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
  Serial.begin(9600);
  sensors.begin();
  sensors.requestTemperatures(); // solicitud de temperatura
  float tempC = sensors.getTempCByIndex(0);  // lo cogemos
  Serial.println(tempC);  // se muestra
}
void loop() {
}

Entonces, los ejemplos los hemos adaptado y verificado, todos los módulos funcionan correctamente. ¡Comencemos a combinar todo en un proyecto! Este bloque de lecciones Arduino, es básico, por lo que escribiremos este proyecto en el estilo de «boceto»; colocaremos todo el código en un archivo y rezaremos para que todo funcione y no haya conflictos de nombres. En un siguiente bloque de lecciones en el curso avanzado, en la lección sobre la creación de grandes proyectos, volveremos a este ejemplo y lo haremos con un enfoque más serio, sin variables globales y con un desglose en archivos de subrutinas independientes.


Paso 3, unificar.

En primer lugar, al comienzo del boceto, conectamos todas las bibliotecas, objetos declarados, tipos de datos y variables. Para mayor belleza y claridad, ordenamos: primero la configuración (#define), luego las bibliotecas conectadas y al final los datos:

// AJUSTES
#define ONE_WIRE_BUS 2   // pin ds18b20
// Bibliotecas
#include "RTClib.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// OBJETOS Y VARIABLES
// la dirección puede ser 0x27 o 0x3f
LiquidCrystal_I2C lcd(0x3f, 16, 2); // Configurar la pantalla
RTC_DS3231 rtc;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
}
void loop() {
}

A continuación, pasamos a la inicialización de setup():

void setup() {
  // monitor
  lcd.init();
  lcd.backlight();  // Enciende la luz de fondo de la pantalla
  // termómetro
  sensors.begin();
  // reloj
  rtc.begin();
  // establecer el tiempo para compilar el tiempo
  if (rtc.lostPower()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

¡Excelente! Ahora lo más difícil: debes pensar en la lógica del programa. Vamos a dividirlo en pasos simples:

  • 1 vez por segundo: visualización del reloj (HH: MM: SS) y el valor actual del sensor.
  • 2 veces por segundo – LED parpadeante en la placa.
  • 5 veces por segundo: medición y promediado de temperatura.

Así es va quedando nuestro loop():

void loop() {
  // 2 veces por segundo
  if (millis() - myTimer1 >= 500) {
    myTimer1 = millis();// reiniciar el temporizador
    toggleLED();
  }
  // 5 veces por segundo
  if (millis() - myTimer2 >= 200) {
    myTimer2 = millis(); // reiniciar el temporizador
    getTemp();
  }
  // cada segundo
  if (millis() - myTimer3 >= 1000) {
    myTimer3 = millis(); // reiniciar el temporizador
    redrawDisplay();
  }
}

Crearemos y completaremos las funciones basadas en el temporizador, las siguientes- toggleLED() getTemp() redrawDisplay().

void toggleLED() {
  digitalWrite(13, LEDflag);  // encendido apagado
  LEDflag = !LEDflag; // bandera invertida
}
void getTemp() {
  // suma la temperatura en una variable común
  tempSum += sensors.getTempCByIndex(0);
  sensors.requestTemperatures();
  // contador de medidas
  tempCounter++;
  if (tempCounter >= 5) { // si más de 5  
    tempCounter = 0;  // si 0
    temp = tempSum / 5; //promedio
    tempSum = 0;  // si 0
  }
}
void redrawDisplay() {
  // hora
  DateTime now = rtc.now(); // coge la hora
  lcd.setCursor(0, 0);      // hora en 0,0
  lcd.print(now.hour());    // hora
  lcd.print(':');
   // el primer cero es para decoracion
  if (now.minute() < 10) lcd.print(0);
  lcd.print(now.minute());
  lcd.print(':');
  // el primer cero es para decoracion
  if (now.second() < 10) lcd.print(0);
  lcd.print(now.second());
  // Temperatura
  lcd.setCursor(11, 0);    // cursor en 11.0
  lcd.print("Temp:");
  lcd.setCursor(11, 1);    // cursor en 11,1
  lcd.print(tempcursor
  // fecha
  lcd.setCursor(0, 1);      // cursor en 0,1
  // el primer cero es para decoracion
  if (now.day() < 10) lcd.print(0);
  lcd.print(now.day());
  lcd.print('.');
  // el primer cero es para decoracion
  if (now.month() < 10) lcd.print(0);
  lcd.print(now.month());
  lcd.print('.');
  lcd.print(now.year());
}

Para el funcionamiento de los temporizadores y el conteo de temperatura, también necesitábamos variables globales, escribámoslas en setup ():

uint32_t myTimer1, myTimer2, myTimer3;
boolean LEDflag = false;
float tempSum = 0, temp;
byte tempCounter;

Paso 4, ajustar, probar (y rezar)

Y en general, ¡nuestro proyecto está terminado! Durante el montaje, con el termómetro, se hizo evidente una característica interesante: la lectura del código se ralentiza mucho, el comando requestTemperatures() espera una respuesta del sensor y bloquea la ejecución del código, razón por la cual el reloj no tiene tiempo para ejecutarse 1 vez por segundo. Examinando los ejemplos, encontré un sondeo asincrónico del sensor: se agregó una línea a la configuración del sensor. sensors.setWaitForConversion(false);. En consecuencia, aquí está el código completo del proyecto, el archivo se llama meteoClock.ino:

// AJUSTES
#define ONE_WIRE_BUS 2  // pin ds18b20
// BIBLIOTECAS
#include "RTClib.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// OBJETOS Y VARIABLES
// la dirección puede ser 0x27 o 0x3f
LiquidCrystal_I2C lcd(0x3f, 16, 2);// Configurar la pantalla
RTC_DS3231 rtc;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
uint32_t myTimer1, myTimer2, myTimer3;
boolean LEDflag = false;
float tempSum = 0, temp;
byte tempCounter;
void setup() {
  Serial.begin(9600); //para depurar
  pinMode(13, 1);
  // monitor
  lcd.init();
  lcd.backlight();  // Enciende la luz de fondo de la pantalla
  // termómetro
  sensors.begin();
  sensors.setWaitForConversion(false); // obtener datos de forma asincrona
  // reloj
  rtc.begin();
  // establecer el tiempo para compilar la hora
  if (rtc.lostPower()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}
void loop() {
  // 2 veces por segundo
  if (millis() - myTimer1 >= 500) {
    myTimer1 = millis(); // reiniciar el temporizador
    toggleLED();
  }
  // 5 veces por segundo
  if (millis() - myTimer2 >= 200) {
    myTimer2 = millis(); // reiniciar el temporizador
    getTemp();
  }
  // cada segundo
  if (millis() - myTimer3 >= 1000) {
    myTimer3 = millis(); // reiniciar el temporizador
    redrawDisplay();
  }
}
void toggleLED() {
  digitalWrite(13, LEDflag);     // encendido apagado
  LEDflag = !LEDflag;      // bandera invertida
}
void getTemp() {
  // suma la temperatura en una variable común
  tempSum += sensors.getTempCByIndex(0);
  sensors.requestTemperatures();
  // contador de medidas
  tempCounter++;
  if (tempCounter >= 5) { // mas de 5
    tempCounter = 0;  // si 0
    temp = tempSum / 5; // promedio
    tempSum = 0;  // si 0
  }
}
void redrawDisplay() {
  // hora
  DateTime now = rtc.now(); // pilla tiempo
  lcd.setCursor(0, 0);      //cursor en 0,0
  lcd.print(now.hour());    // reloj
  lcd.print(':');
  // el primer cero es decoracion
  if (now.minute() < 10) lcd.print(0);
  lcd.print(now.minute());
  lcd.print(':');
  // el primer cero es decoracion
  if (now.second() < 10) lcd.print(0);
  lcd.print(now.second());
  // TEMP
  lcd.setCursor(11, 0);    // cursor en 11,0
  lcd.print("Temp:");
  lcd.setCursor(11, 1);    //  cursor en 11,1
  lcd.print(temp);
  // HORA
  lcd.setCursor(0, 1);      // cursor en 0,1
  // el primer cero es decoracion
  if (now.day() < 10) lcd.print(0);
  lcd.print(now.day());
  lcd.print('.');
  // el primer cero es decoracion
  if (now.month() < 10) lcd.print(0);
  lcd.print(now.month());
  lcd.print('.');
  lcd.print(now.year());
}

Y así es como se ve nuestro proyecto en la vida real =)

Proyecto fin de curso terminado
Proyecto fin de curso terminado

Deja un comentario