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:
- Pantalla (arduino lcd 1602 i2c): un ejemplo en este enlace de Google
- Reloj RTC (arduino ds3231): un ejemplo en este enlace de Google
- Termómetro (arduino ds18b20): un ejemplo en este enlace de Google
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í:
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 =)