Servos y sensores climáticos


Se trata de un proyecto sencillo realizado por Miguel Torres Gordo donde nos muestra como mostrar la hora, la temperatura y la humedad en una habitación con pocos módulos. El diseño muestra solo la hora y los minutos, porque los segundos no son relevantes y obviamente encarecen el proyecto.

La foto muestra una posible distribución de la pantalla, pero se deja a la imaginación del lector cómo podrían usarse, por ejemplo, en una caja hecha con una impresora 3D.

Proyecto finalizado

Materiales necesarios

  • Chip Nano V3.0 CH340 presoldado, versión mejorada con cable USB
  • MAX7219 Módulo de pantalla LED de matriz de puntos 8×32 4 en 1
  • KY-015 DHT 11 Módulo de sensor de temperatura ( del que por cierto hemos tratado en numerosos proyectos en este blog)
  • Reloj en tiempo real DS3231 I2C (idéntico al DS1307).Alternativamente con modificaciones DS1302 Serial Real Time Clock RTC Real Time Clock Module. Este tipo de módulos lo hemos tratado tambien en numerosos ejemplos en este blog
  • Micro servomotor digital MG995 o micro servomotor SG90 Micro servomotor 9G o micro servomotor MG90S
  • MB 102 Kit de placa de pruebas – 830 Breadboard, adaptador de fuente de alimentación 3.3V 5V, 65pcs Jumpers
  • Fuente de alimentación externa (9V – 12V)

Software requerido

IMPORTANTE: Encuentre las bibliotecas que faltan en el IDE de Arduino a través de «Herramientas -> Administrar bibliotecas…»

Circuito y descripción de su funcionamiento

El módulo DS1302 RTC( que hemos tratado tambien en numerosos ejemplos en este blog )es responsable de proporcionar la hora en el microcontrolador, mientras que el módulo DHT-11 mide la temperatura y la humedad ( del que por cierto hemos usado tratado en este blog). A continuación, el microcontrolador utiliza la información para controlar el grupo de módulos LED de 8×8 para la hora y los servomotores para mostrar la temperatura y la humedad.

Es muy importante que introduzcamos una batería adecuada, ya que aunque este módulo funcionará correctamente sin ella, si desconectamos el módulo del circuito, se reiniciará la hora.

Para establecer la fecha y la hora actuales, debemos configurar el siguiente circuito usando los pines SDA/SCL de nuestra placa Arduino o compatible:

Configuración de RTC
RTC (I2C)Nano V3
VCC5V
GNDGND
CLKA5 (SCL)
DATA4 (SDA)
RST

A continuación, ejecutamos el sketch DS1307_setup.ino, abrimos el Monitor Serie y podemos ver tanto la fecha como la hora en que se ha guardado el módulo. Estos datos son los datos que proporciona el sistema operativo del PC en el momento en que se ejecuta el boceto. Si nos fijamos en el boceto, podemos ver que la línea de código

clock.setDateTime(__DATE__, __TIME__);

es el que carga el módulo con los dos datos del sistema. A partir de ese momento, hemos configurado el módulo con la hora y la fecha y gracias a la batería, estos datos no se eliminarán del módulo cuando se corte el voltaje.

Además en el diseño tenemos dos servos , un sensor dht11 y 4 Display que completen el total de conexiones junto a los hilos de alimentación de 5v DC correspondientes para cada módulo:

  • GND y VIN para alimentación de todos los dispositivos.
  • A4 y A5 para la conexión del DS1302.
  • D13, D11 y D10 para los 4 displays (MAX7219).
  • D3 y D4 para los dos servos.
  • D2 para el DHT11.

Después de configurar la hora y la fecha, unto con los otros módulos en el circuito y ejecutamos el boceto clock_temperature_humidity.ino. Cuando hayamos terminado de cargar, deberíamos ver la hora exacta en la matriz de LED y los dos servomotores deberían moverse hasta que se posicionen en el valor de la temperatura y la humedad en el ambiente.

Circuito

Para cargar el boceto en el microcontrolador, elimine la línea entre +5V y Vin.

Ampliada

Tenemos la fuente de alimentación de 5V DC, el microcontrolador, el módulo RTC DS1302, DHT-11, el array de LED y los 2 servomotores.

Foto de la construcción

Analicemos el código:

En primer lugar, cargamos las librerías que son necesarias para la ejecución del boceto. Los tres primeros son para la matriz LED, los dos siguientes son para usar el módulo DS1307, el penúltimo es la biblioteca para el módulo DHT-11 y el último es para usar los servomotores:

#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <Wire.h>
#include <DS3231.h>
#include <DHT.h>
#include <Servo.h>

Después de las librerías, tenemos que configurar las conexiones de los módulos con los pines del microcontrolador. Luego el tipo de controlador y el número de módulos LED de la matriz (4 en nuestro caso). A continuación, el tipo de módulo DHT. Creamos las instancias de cada módulo y las variables necesarias para almacenar los datos de las mismas:

// Define hardware type, size, and output pins MAX7219 8x32 4 in 1 Dot Matrix LED Display Module
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 10

// Define hardware type andi pins DHT-11
#define DHTPIN 2
#define DHTTYPE DHT11

// Create a new instance of the MD_Parola class with hardware SPI connection:
MD_Parola reloj = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// Create a instance of DHT-11 sensor and variables for temperature and humidity
DHT dht(DHTPIN, DHTTYPE);
float t, hu;

// Instances of the servos for humidity and temperature
Servo servoTemperature;
Servo servoHumidity;

// Instance for the DS3231 clock
DS3231 clock;
RTCDateTime dt;

Después de configurar los parámetros del módulo, inicializamos los módulos en la función setup() del boceto:

      // Initialization of Monitor Serial
      Serial.begin(9600);
      Serial.println("Initialize RTC module");
  
      // Initialization of DS3231 Module
      clock.begin();

      // Initialization MAX7219 LED Matrix Display
      reloj.begin();                // Intialize the object
      reloj.setIntensity(0);        // Set the intensity (brightness) of the display (0-15)
      reloj.displayClear();         // Clear the display

      // Initialization DHT-11 module
      dht.begin();

      // Servo pins connections
      servoTemperature.attach(3);
      servoHumidity.attach(4);

La función loop() genera los valores medidos y los cálculos necesarios para la visualización.

En primer lugar, analizaremos los datos de temperatura y humedad. Asignamos el valor de temperatura a la variable t y el valor de humedad a la variable hu. Si no recibimos ningún dato, lo comunicamos a través del monitor de serie. Los rangos de valores con los que trabajaremos van de 0 a 50 grados centígrados de temperatura y de 0% a 100% de humedad. Sabemos que los servomotores suelen tener un rango de ángulo de 180 grados. Para que los servomotores marquen los datos correctamente, realizamos una sencilla operación matemática para asignar los valores máximos de los rangos a los 180 grados del ángulo de los servomotores.

     // Temperature and humidity reading
      t = dht.readTemperature();
      hu = dht.readHumidity();
      if (isnan(hu) || isnan(t)) {
              Serial.println("DHT sensor reading failure !!!");
      }

...
      servoTemperature.write((t*180)/50);   // Move the servos to value
      servoHumidity.write((hu*180)/100);

Como alternativa, puede utilizar la función map().

El procedimiento para registrar y mostrar las horas y los minutos es muy sencillo. Solo una nota: cuando el módulo DS1302 envía las horas y los minutos, envía los dígitos mínimos necesarios, es decir, del 0 al 9 solo un dígito. Entonces, si obtenemos menos de 10 horas o 10 minutos, solo veremos un dígito a la vez. Esto daría la impresión de un mal funcionamiento o no se ve bien. Así que siempre tenemos que mostrar dos dígitos en las horas y los minutos.

Con la primera línea, pedimos al módulo DS1302 que recupere los datos de fecha y hora. A continuación, creamos dos variables (h y m) para almacenar los datos en el formato de cadena de la hora y los minutos. Si los valores son menores que 10, la instrucción if va precedida de un 0 como carácter, no como un dígito, con concat. Ahora solo tenemos que mostrar estos datos en la matriz LED. Para mostrar que el reloj está corriendo, mostramos dos cadenas muy similares. Uno con la separación entre horas y minutos con dos puntos y otro sin dos puntos. La visualización se realiza en incrementos de 500 ms, lo que corresponde a medio segundo. Por lo tanto, los dos puntos parpadean.

La función delay() bloquea el flujo del programa, lo que no es relevante en este caso, ya que hay tiempo suficiente para leer y mostrar los datos.

      dt = clock.getDateTime();               // Reading data from the RTC module

      String h;                               // Variable for the hours
      String m;                               // Variable for the minutes
  
      int hora = (dt.hour);                   // The variable "hora" is used 
      if (dt.hour<10) {                       // to set the time to always show two digits 
	            h = "0";                        // two digits in the clock hours.
	            h.concat((String) hora);
      } else {
	            h = (String) hora;
      }

      int minuto = (dt.minute);               // The variable "minuto" is used
      if (dt.minute<10) {                     // to set the minutes to always
	            m ="0";                         // two digits en the clock minutes
	            m.concat((String) minuto);
      } else {
	            m = (String) minuto;
      }
      
      String r = h + ":" + m;                 // Hour and minutes with colon separation
      String q = h + " " + m;                 // Hour and minutes without colon separation

      Serial.print("Hora: ");
      Serial.print(dt.hour);   	Serial.print(":");
      Serial.print(dt.minute); 	Serial.print(":");
      Serial.print(dt.second); 	Serial.println("");
      Serial.print( "T = " );
      Serial.print(t);
      Serial.print(" ºC, H = ");
      Serial.print(hu);
      Serial.print( "%, " );

      reloj.setTextAlignment(PA_CENTER);    // Configuration the text centered
      reloj.print(r);                       // We change the text showing the separation
      delay(500);                           // and without it every half second for the
      reloj.print(q);                       // sensation of movement.
      delay(500);

A continuación el código completo:

/**************************************************************************************
 *   Easy Arduino project with clock, temperature and humidity measurement            *
 *   Last revisión 10-12-2021 - Getafe (Madrid) - España                              
 *   Miguel Torres Gordo                                                              
*************************************************************************************/

// Required Arduino libraries
#include <MD_Parola.h>                          // Matrix LED Display Module
#include <MD_MAX72xx.h>                         // MAX7219
#include <SPI.h>                                // SPI Communications

#include <Wire.h>                               // I2C communications protocol
#include <DS3231.h>                             // Real Time Clock Module

#include <DHT.h>                                // Temperature and Humidity module

#include <Servo.h>                              // Servomotors

// Define hardware type, size, and output pins MAX7219 8x32 4 in 1 Dot Matrix LED Display Module
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 10

// Define hardware type andi pins DHT-11
#define DHTPIN 2
#define DHTTYPE DHT11

// Create a new instance of the MD_Parola class with hardware SPI connection:
MD_Parola reloj = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// Create a instance of DHT-11 sensor and variables for temperature and humidity
DHT dht(DHTPIN, DHTTYPE);
float t, hu;

// Instances of the servos for humidity and temperature
Servo servoTemperature;
Servo servoHumidity;

// Instance for the DS3231 clock
DS3231 clock;
RTCDateTime dt;


void setup() {

      // Initialization of Monitor Serial
      Serial.begin(9600);
      Serial.println("Initialize RTC module");
  
      // Initialization of DS3231 Module
      clock.begin();

      // Initialization MAX7219 LED Matrix Display
      reloj.begin();                // Intialize the object
      reloj.setIntensity(0);        // Set the intensity (brightness) of the display (0-15)
      reloj.displayClear();         // Clear the display

      // Initialization DHT-11 module
      dht.begin();

      // Servo pins connections
      servoTemperature.attach(3);
      servoHumidity.attach(4);

}

void loop() {

      // Temperature and humidity reading
      t = dht.readTemperature();
      hu = dht.readHumidity();
      if (isnan(hu) || isnan(t)) {
              Serial.println("DHT sensor reading failure !!!");
      }
     
      dt = clock.getDateTime();               // Reading data from the RTC module

      String h;                               // Variable for the hours
      String m;                               // Variable for the minutes
  
      int hora = (dt.hour);                   // The variable "hora" is used 
      if (dt.hour<10) {                       // to set the time to always show two digits 
	            h = "0";                        // two digits in the clock hours.
	            h.concat((String) hora);
      } else {
	            h = (String) hora;
      }

      int minuto = (dt.minute);               // The variable "minuto" is used
      if (dt.minute<10) {                     // to set the minutes to always
	            m ="0";                         // two digits en the clock minutes
	            m.concat((String) minuto);
      } else {
	            m = (String) minuto;
      }
      
      String r = h + ":" + m;                 // Hour and minutes with colon separation
      String q = h + " " + m;                 // Hour and minutes without colon separation

      Serial.print("Hora: ");
      Serial.print(dt.hour);   	Serial.print(":");
      Serial.print(dt.minute); 	Serial.print(":");
      Serial.print(dt.second); 	Serial.println("");
      Serial.print( "T = " );
      Serial.print(t);
      Serial.print(" ºC, H = ");
      Serial.print(hu);
      Serial.print( "%, " );

      reloj.setTextAlignment(PA_CENTER);    // Configuration the text centered
      reloj.print(r);                       // We change the text showing the separation
      delay(500);                           // and without it every half second for the
      reloj.print(q);                       // sensation of movement.
      delay(500);

      // To display the value of temperature and humidity we assign
      // a maximum value (50ºC and 100% of humidity) to the 180 degrees of the servomotor and
      // by means of a rule of three we display the actual values.
      
      servoTemperature.write((t*180)/50);   // Move the servos to value
      servoHumidity.write((hu*180)/100);
            
}

Mini transmisor basado en Attiny85


En una reciente articulo  Indigod0g  describió una mini estación meteorológica que funciona bastante bien, usando dos Arduinos.  Tal vez no todos queramos sacrificar 2 Arduinos para obtener las lecturas de temperatura y humedad, así  que este post vamos a ver como hacer  hacer una función similar con de dos Attiny85  basándonos en la idea de  combinar  un interfaz de pantalla LCD de 2 hilos para Arduino o Attiny   aso como también ,como no, usando  el sw que permite recibir y enviar datos entre Attiny85 (1.06 IDE de Arduino)

 

Para implementar esta idea se ha optado por  una solución de lcd de dos hilos con un registro de cambio, en lugar de un LCD I2C porque en el Attiny el turno de registro es más fácil de implementar que el bus I2C. Sin embargo… si por ejemplo quiere leer un sensor de presión BMP180 o BMP085, necesita I2C para que de todos modos  funcione, así que puede usar un LCD I2C entonces también. TinyWireM es una buena biblioteca para I2C en un Attiny (aunque se requiere espacio adicional).

 

Los componentes usados son los  siguientes:

El transmisor:

  • DHT11
  • Attiny85
  • resistencia de 10 k
  • Módulo transmisor 433MHz

El receptor

  • Attiny85
  • resistencia de 10 k
  • Módulo receptor de 433 MHz

La pantalla

  • 74LS164 cambio de registro
  • 1N14148 diodo
  • resistencia de 2x1k
  • resistor variable 1x1k
  • una pantalla LCD 2 x 16

 

El transmisor 

En cuanto   al circuito  transmisor utiliza  una configuración muy básica de la Attiny85 con una  resistencia de 10 k en la línea de reset.

Un módulo transmisor de 433Mhz   está conectado al pin digital ‘0’ y el pin de datos DHT11 se conecta al pin digital 4.

Conecte un cable de 17,2 cm como antena.

Todo el conjunto lo podemos ver en el siguiente diagrama ( solo aparece la linea de datos del DHT11  de modo que se sobreentiende que se alimenta también el DHT11 con +5V)

 

dht11

El software empleado  es como sigue:

//will work on Attiny85/45
//RF433=D0 pin 5
//DHT11=D4 pin 3

// libraries


dht11 DHT11;
DHT11PIN 4
TX_PIN 0 //pin where your transmitter is connected
//variables
float h=0;
float t=0;
int transmit_t = 0;
int transmit_h = 0;
int transmit_data = 0;

void setup()
{
pinMode(1, INPUT);
man.setupTransmit(TX_PIN, MAN_1200);
}

void loop() {
int chk = DHT11.read(DHT11PIN);
h=DHT11.humidity;
t=DHT11.temperature;
// I know, I am using 3 integer variables here
// where I could be using 1
// but that is just so it is easier to follow
transmit_h=100* (int) h;
transmit_t=(int) t;
transmit_data=transmit_h+transmit_t;
man.transmit(transmit_data);
delay(500);
}

El software utiliza código de Manchester para enviar los datos. Se lee el DHT11 y almacena la temperatura y humedad en 2 float separados. Como el código de Manchester no envía los números  float, pero si un número entero, tenemos varias opciones:
1 -Dividir el float en dos enteros cada y enviarlos
2 – Enviar cada float como un entero
3 – Enviar los dos float  como un entero

Con la opción 1  necesitaríamos combinar los enteros en float en el receptor e identificar que entero es cada cual con  código .
Con la opción 2  aún es necesario identificar que entero es para la humedad y que para la temperatura. No podemos  ir por secuencia solo en caso de que un entero se pierde en la transmisión, así que tendríamos que enviar una identificación adjunta al entero.
Con la opción 3, podemos enviar un número entero. Obviamente esto hace un poco menos precisa – dentro de 1 grado – las lecturas y uno no se puede enviar por debajo de temperaturas bajo cero, pero es sólo un simple código y hay maneras alrededor de eso. Por ahora es sólo el principio.

Así que lo que hacemos  es que se convierta los float  en enteros y multiplicamos la humedad con 100. A continuación, añadimos la temperatura a la humedad y los multiplicamos.
Dado el hecho de que la humedad nunca será 100%,el número máximo admitido que conseguiremos es el  9900. Dado el hecho de que la temperatura también no será superior a 100 grados, el número máximo será de 99, por lo tanto, el número más alto que le enviaremos es el  9999 y es fácil de separar todo esto en el lado receptor.

Por supuesto este  cálculo en  que se  utilizan  3 enteros es algo  exagerado ya que fácilmente podría hacerse con 1 variable,  pero en realidad se ha escrito el código asi para que sea más fácil de seguir.

Todo el código anterior se compila ahora como un binario tamaño: 2.836 bytes (de un octeto 8.192 máximo) y así cabe en un 45 Attiny o 85

 

 El receptor 

tiny

 

Otra vez el Attiny85 se utiliza en una configuración básica con el pin Reset tirado de alta resistencia de 10 k. El módulo receptor está conectado a pin digital 1 (pin 6 del chip). La pantalla LCD se une a dos pines  digitales binarios . Conecte un cable de 17,2 cm como antena.

El código es como sigue:


LiquidCrystal_SR lcd(0,2,TWO_WIRE);
RX_PIN 1 //= physical pin 6

void setup() {
lcd.begin(16,2);
lcd.home();
man.setupReceive(RX_PIN, MAN_1200);
man.beginReceive();
}

void loop() {
if (man.receiveComplete()) {
uint16_t m = man.getMessage();
man.beginReceive();
lcd.print(«Humid: «);
lcd.print(m/100);
lcd.setCursor(0,1);
lcd.print(«Temp «);
lcd.print(m%100);
}
}

El código es bastante simple: el entero transmitido es recibido y almacenado en una variable .
Se divide por 100 para la humedad y el modulo de 100 da la temperatura,por ejemplo supongamos que el entero recibido 3325
3325/100 = 33
3325% 100 = 25

 
Este código se compila como 3380 bytes y, por tanto, sólo puede utilizarse con un attiny85, no con un 45

 

Por ultimo para la pantalla de 16 x 2 común se  utiliza un shiftregister que puede funcionar con dos pines digitales. Por supuesto, si usted prefiere usar una pantalla lista I2C, también es posible, pero entonces necesitemos  implementar un protocolo I2C en el Attiny. El Protocolo de Tinywire puede hacer eso pero  necesita  usar un reloj de 1 Mhz.

Este diseño pues  demuestra  que se puede hacer una mini estación meteorológica con dos attiny85 de (incluso con una attiny85 + 1 attiny45).Es cierto  que sólo envía humedad y temperatura, utilizando un DHT11, pero sin embargo, el Attiny tiene 5 pines  digitales a utilizar, 6 incluso con algunos trucos, asi que es posible enviar datos demás sensores .

La limitación en el uso de un attiny85 como receptor es  relativa  en cuanto a  la presentación de los datos dado que la memoria es limitada: textos como ‘temperatura, humedad, luminosidad, se  acercán  a llenar el espacio valioso memoria bastante rápido.  Sin embargo, no hay razón para usar dos Arduino  al menos  para enviar y recibir la temperatura y la humedad.

Además, es posible llevar  el transmisor a estado sleep ( dormir) y sólo  despertarlo  para enviar datos cada 10 minutos y así alimentarlo  con una pila  de botón.
Obviamente, no sólo los datos de temperatura o humedad pueden enviarse  : también  uno puede tener una matriz de pequeños transmisores de envío así como las lecturas de humedad de suelo, o agregar un anemómetro o un medidor de lluvia  !solo hay limite en la imaginación de usted!

 

 

Fuente  aqui