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);
            
}

Fáciles medidas de c.a. con Arduino


Medir la tensión de ca de la red de suministro con Arduino puede ser una labor compleja dado el rango de tensiones que manejamos ,pero gracias a los transformadores de tensión vamos a ver cómo medir voltaje CA hasta 250 V, tanto en 50 Hz como en 60 Hz, usando el ZMPT101B, (ese es el nombre del transformador solamente, pero lo encontrará con este nombre o «sensor de voltaje CA»).

Este módulo basado en un transformador de precisión para medidas (el zMPT101B) y un circuito operacional (el LM358) con la electronica asociada

Hemos de dicir que ,usado el código correcto, es mucho mejor esta electronica para las medidas, que los otros métodos que usan transformador + rectificador + divisor de voltaje….que no siempre dan los valores correctos. Puede que otros sistemas muestren la señal cuadrada o triangular,lo cual afecta seriamente el RMS, pues el RMS es lo que queremos medir, y para ello debemos mantener la misma forma de la señal asi que al adaptarlo para el Arduino,y aquí es cuando el módulo es útil.

Debemos advertir nuevamente que este tipo de circuitos pueden ser peligrosas si no se extrema las medidas pues en los bornes atornillados debemos conectar la carga de ca de 220V

Sineses.png

El módulo toma la señal que queremos medir, aquí una potencia doméstica de 220V, tiene alrededor de 311V como pico.

El transformador del módulo lo devuelve al pico de 2.5V

Luego agrega un desplazamiento de 2.5V para adaptarlo al Arduino.

  Y aquí preste atención, algunos códigos se usan con este módulo, solo hacen una muestra de la señal y miden los picos, luego una pequeña multiplicación, y puede mostrarle el «RMS» de esta señal, pero esos códigos funcionan solo para señal de onda sinusoidal perfecta, si está midiendo otra forma de la señal sería falsa.

Y, por ejemplo, aquí utilizamos un atenuador de luz(dimmer), que se basa en un Triac y ya conoces la forma «extraña» de la señal que hace un Triac.

artículo-2014julio-ics-responde-el-desafío-de-fig1

Aquí puede ver que para medir el RMS no solo debe medir los picos y hacer los mismos cálculos para la señal de onda sinusoidal.

Pero debe hacerlo de la manera correcta y es muy difícil de codificar, por eso usaremos una biblioteca simple que como siempre hará el trabajo por nosotros. 

Visualización de la información

Para mostrar las medidas se puede usar por ejemplo una pantalla OLED en lugar de las tipicas basadas en LCD con el controlador de Toshiba HD44780,

LCD es el acrónimo de Liquid Crystal Display (en español Pantalla de Cristal Líquido). No podemos considerar que se trate de una tecnología novedosa. El LCD lleva con nosotros mucho tiempo, solo tenemos que echar la mirada hacia atrás y recordar esos relojes Casio o las calculadoras que llevamos a clase de matemáticas.

Estamos acostumbrados a que la materia pueda estar en estado sólido, líquido o gaseoso, los llamados estados de la materia. Pero ya en el siglo XIX se descubrió que había más estados en los que podía encontrarse la materia. El cristal líquido se encuentra en algún lugar entre el sólido y líquido.No es el objetivo de este post la física involucrada detrás de los LCD, solo decir que utiliza las propiedades de la luz polarizada para mostrarnos la información en una pantalla. A partir de una serie de filtros, se consigue mostrar la información gracias a la iluminación de fondo.

Hay una amplia gama de pantallas LCDs que podemos utilizar con Arduino. Aparte de las funcionalidades extra que nos puedan dar cada una de ellas, las podemos diferenciar por el número de filas y columnas, su tamaño.

Por ejemplo, una pantalla LCD de 16×1 tendrá una fila de 16 caracteres es decir, solo podremos mostrar 16 caracteres simultáneamente, al igual que un LCD de 20×4 tendrá 4 filas de 20 caracteres cada una.

En este artículo vamos a trabajar con un LCD típico, de 16×2. Esto significa que vamos a poder mostrar 16 caracteres en la primera fila y los mismos en la segunda fila.

La mayoría de las pantallas LCD que se están haciendo ahora, vienen con una fila de dieciséis pines. Los primeros catorce pines se utilizan para controlar la visualización. Los dos últimos son para la iluminación de fondo.

Aunque el dato se puede enviar en 8 bits , lo normal es usarlo partido en «trozos» de 4 bits, labor que será transparente al usuario gracias a las librería LiquidCrystal.h y que como es obvio se emplea para ahorrarnos 4 lineas de datos del GPIO de modo que necesitaríamos 4 para datos + 3 de control =7 pines de datos lógicamente mas 2 mas para la alimentación de 5v DC

PINFUNCIÓN
1GND (Tierra)
25 Voltios
3Control de contraste pantalla
4RS – Selector entre comandos y datos
5RW – Escritura y lectura de comandos y datos
6Sincronización de lectura de datos
7-14Pines de datos de 8-bit
15Alimentación luz de fondo (5V)
16GND (Tierra) luz de fondo (0V)

En la siguiente imagen vemos la correspondencia con los pines físicos del LCD.

Esta imagen muestra la parte de abajo del LCD. Cuando lo conectes a la protoboard los pines estarán invertidos horizontalmente.

Otra alternativa es usar una pantalla OLED i2c de 128 * 32 , cuyo coste es irrisorio. Este tipo de pantallas esde reducidasa dimensiones y , puede usarlas en algunos proyectos pequeños de bricolaje y también les brinda muchas posibilidades para hacer (diferentes fuentes y tamaños de textos, diferentes formas, desplazamiento, imágenes bmp …) Tenga en cuenta que este tipo de pantalla no es una pantalla a color, las «nornales » solo imprimen en azul (Izquierda) pero las hay en blanco, y algunos pueden tener amarillo + uno de los colores anteriores .

Este es un ejemplo cableado con una pantalla OLED .Este cableado depende de su versión de pantalla ,( el que vemos usa 4 pines : dos para la alimentacion con 3,3V DC y los dos de datos no cableando el pin RST).

circuito

Conexiones finales

Wiring.png

Este es todo el cableado y, como se mencionó, estamos usando una pantalla OLED de 128 × 32, puede usarla o no, el módulo está alimentado por 5v y entrega una señal analógica.

Configuración:

Lo primero que debe hacer es calibrar el módulo con su potenciómetro, cablear el módulo, enchufar el Arduino y cargar este simple código, y no olvide colocar las sondas de medición en la toma de corriente (¡¡¡CUIDADO !!! ) y ya conoce el voltaje.

El código para probar esto es realmente simple , usando eso si, el Serial Plotter de Arduino IDE:

void setup() {
Serial.begin(9600);
}

void loop() 
{
Serial.println(analogRead(A0));
}

Abra el trazador de serie del IDE de Arduino:

parcela1
plot2

Verá algo como esto en su trazador de serie, significa que no adquiere toda la señal, ajuste el potenciómetro hasta que tenga algo que parezca una onda sinusoidal. Sé que esa no es la señal de onda sinusoidal de CA.

plot3

Cuando tenga algo como esto, puede agregar un retraso para ver una buena onda sinusoidal, aquí es porque estoy midiendo justo después de mi atenuador de luz, verá un pequeño pico antes del pico de señal si mide el enchufe directamente, no lo hará

sinewaveee.png

Ahora que su módulo está calibrado, las calibraciones del código se basarán en él, así que trate de no cambiarlo.

Código:

La biblioteca que usamos es Filters.h, reduce la cantidad de trabajo para usted, descargue aquí o desde Github . 

Bibliotecas de pantallas OLED de Adafruit

 /* This code works with ZMPT101B AC voltage sensor module and 128x32 OLED display
 * It permits you to measure any AC voltage up to 250V, BE CAREFUL !!!
 * The functions from Filters library permits you to calculate the True RMS of a signal
 * Refer to www.surtrTech.com or SurtrTech YouTube channel for more details
 */

#include <Filters.h> //Easy library to do the calculations
#include <SPI.h>     //Libraries for the OLED display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET    -1 //

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //Declaring the display name (display)

float testFrequency = 50;                     // test signal frequency (Hz)
float windowLength = 40.0/testFrequency;     // how long to average the signal, for statistist

int Sensor = 0; //Sensor analog input, here it's A0

float intercept = -0.04; // to be adjusted based on calibration testing
float slope = 0.0405; // to be adjusted based on calibration testing
float current_Volts; // Voltage

unsigned long printPeriod = 1000; //Refresh rate
unsigned long previousMillis = 0;


void setup() {
  Serial.begin( 9600 );    // start the serial port
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Start the OLED display 
  display.clearDisplay();
  display.setTextSize(2);                   
  display.setTextColor(WHITE);              
  display.setCursor(1,1);               
  display.print("SurtrTech");
  display.setCursor(1,20);
  display.setTextSize(1);
  display.print("AC Voltmeter");
  display.display();
  delay(5000);

}

void loop() {
  
  RunningStatistics inputStats;                //Easy life lines, actual calculation of the RMS requires a load of coding
  inputStats.setWindowSecs( windowLength );
   
  while( true ) {   
    Sensor = analogRead(A0);  // read the analog in value:
    inputStats.input(Sensor);  // log to Stats function
        
    if((unsigned long)(millis() - previousMillis) >= printPeriod) {
      previousMillis = millis();   // update time every second
            
      Serial.print( "\n" );
      
      current_Volts = intercept + slope * inputStats.sigma(); //Calibartions for offset and amplitude
      current_Volts= current_Volts*(40.3231);                //Further calibrations for the amplitude
      
      Serial.print( "\tVoltage: " );
      Serial.print( current_Volts ); //Calculation and Value display is done the rest is if you're using an OLED display
      
      
      display.clearDisplay();
      display.setTextSize(3);       //size of the text that will follow              
      display.setTextColor(WHITE);  //its color            
      display.setCursor(1,1);      //position from where you want to start writing           
      display.print(current_Volts,1);
      display.setCursor(115,00);
      display.setTextSize(2);
      display.print("V");
      display.setCursor(115,15);
      display.setTextSize(1);
      display.print("AC");
      display.display();
    }
  }

}

Pruebas:

Los valores seguramente no son perfectos y 100% precisos, pero como ve, necesita calibraciones muy precisas para hacerlo perfecto, y no olvide que está usando un módulo de 10 $ o menos, y allí se compara con un multímetro que usa TRMS. , Verdadero valor eficaz.

     Un multímetro que no sea TRMS también le dará una lectura falsa para una señal que no sea de onda sinusoidal,