Añada un display a un ESP32



I2C (Inter-Integrated Circuit) es un modo de comunicación en serie de dos hilos, que puede utilizarse para la conexión de microcontroladores y sus periféricos. Los dispositivos que utilizan la comunicación I2C deben estar conectados a la línea de datos serie (SDA), y la línea de reloj serie (SCL) (llamado bus I2C). Cada dispositivo tiene una dirección única y puede utilizarse como transmisor o receptor para comunicarse con los dispositivos conectados al bus.

Como es de suponer usar este tipo de comunicación I2C con un controlador LCD requiere muchos menos hilos para la gestión del mismo, pues tradicionalmente se controlaban según el bus de datos (4 bits o 8bits) con al menos 4 u 8 hilos de datos, uno para registro seleccionado(RS), otro para lectura/escritura (R/W) , el de reloj (enable) y dos hilos para alimentación. Es decir, la configuración de pines de este tipo de displays LCD sin este tipo de controladores I2C compatibles con el standard de Hitachi es/era la siguiente:

  1. Tierra
  2. VCC +3.3 a +5V (típico)
  3. Ajuste de contraste (VO) Esta es una entrada analógica , típicamente conectado a un potenciómetro. El usuario tiene que ser capaz de controlar este voltaje independiente de todos otros ajustes, para optimizar la visibilidad del display que varía con la temperatura y, en algunos casos, con la altura sobre el nivel de mar. Con un ajuste incorrecto el display parecerá para funcionar mal.
  4. Registro Seleccionado (RS). RS=0: Comando, RS=1: Dato
  5. Lectura/Escritura (R/W). R/W=0: Escribe, R/W=1: Lee (En la mayor parte de las aplicaciones que leer del HD44780 no tiene sentido. En ese caso este pin puede ser permanentemente conectado a tierra y no hay necesidad de asignar pines de entrada/salida para gestionarlo.)
  6. Reloj (Enable). Disparado por el borde descendente
  7. Bit 0 (No utilizado en operación de 4 bits)
  8. Bit 1 (No utilizado en operación de 4 bits)
  9. Bit 2 (No utilizado en operación de 4 bits)
  10. Bit 3 (No utilizado en operación de 4 bits)
  11. Bit 4
  12. Bit 5
  13. Bit 6
  14. Bit 7
  15. Backlight Ánodo (+) (Si aplica)
  16. Backlight Cátodo (-) (Si aplica)

En este ejemplo vamos a ver como conectar un display LCD1602 que integra un controlador I2C con un LCD y este con un ESP32 ,! lo cual solo requiere solo 4 hilos !.En este caso,la pantalla LCD1602 puede mostrar 2 líneas de caracteres en 16 columnas siendo capaz de mostrar números, letras, símbolos, código ASCII, etc. Además el precio es muy asequible pues ronda los 6€/unidad en Amazon y obviamente también existen displays de muchas mas líneas y de mas caracteres según las necesidades particulares de cada diseño.

Este módulo LCD I2C/IIC por tanto puede mostrar 2 líneas de caracteres, 16 para cada uno y es compatible con la mayoría de los microcontroladores de corriente. Los principales modelos de Arduino , Raspberry Pi,/ Raspberry Pi Pico, ESP32 o ESP8266 (otros controladores también pueden ser compatibles, pero el fabricante no proporciona tutorial y código).

A continuación se muestra una pantalla LCD1602 monocroma junto con su diagrama de circuito:

Como podemos ver la pantalla LCD1602 I2C integra una interfaz I2C que conecta el módulo de entrada serie y salida paralela a la pantalla LCD1602.

Esto nos permite utilizar sólo 4 líneas para operar el LCD1602: GND, VCC ( 5v DC),SDA y SCL.

El chip IC serie-paralelo utilizado en este módulo es PCF8574T (PCF8574AT), y su dirección I2C por defecto es 0x27(0x3F), de modo que si tiene problemas para ponerlo en funcionamiento con el código que veremos , ¡cambie 0x27 a 0x3F !-

El pin del módulo PCF8574 y el pin del LCD1602 se corresponden y conectan entre sí:


Así que sólo necesitamos 4 pines para controlar los 16 pines de la pantalla LCD1602 a través de la interfaz I2C.
En este ejemplo , vamos a utilizar el I2C LCD1602 para mostrar algunos caracteres estáticos y los dinámicas. Las conexiones por tanto del display con un ESP32 no pueden ser mas simples como podemos ver a continuación;

Es muy importante saber que la dirección I2C de este LCD varía entre los diferentes chips incorporados( Chip 8574AT: 0x3F y 8574T o chip en blanco: 0x27 )

En la imagen podemos ver una imagen , mas claramente como es este tipo de display y como ha evolucionado de un modelo antiguo donde claramente se aprecia el interfaz i2c una placa aparte y las versiones actuales donde ya va integrado dentro del diseño de la propia placa del LCD.

Podemos usar simplemente cuatro cablecillos hembra -hembra para probar el conjunto:

No es demasiado engorroso todo lo demás porque solo necesitaremos conectar un cable microusb para alimentar el conjunto:

Obviamente para poder escribir caracteres en la pantalla tendremos que cargar el fw adecuado y que vamos a ver a continuación ( sino cargamos nada simplemente aparecerá en la primera lineá los 16 caracteres oscuros)

Código de ejemplo

Antes de escribir código, necesitamos importar la librería necesaria, para lo cual utilizamos la librería de terceros LiquidCrystal I2C. Si aún no la ha instalado, por favor necesitara hacerlo para compilar el siguiente código de mas abajo.
Los pasos para añadir librerías de terceros son los siguientes:

  • Abra arduino ide
  • Vaya aSketch->Include library-> Manage Librerías.
  • Introduzca » LiquidCrystal I2C» en la barra de búsqueda
  • Seleccione » LiquidCrystal I2C » para su instalación

A continuación mostramos un ejemplo de como pintar cualquier carácter en la primera o segunda línea.


#include <LiquidCrystal_I2C.h>
#include <Wire.h>
/*
 * #define SDA 13 //Define SDA pins
#define SCL 14 //Define SCL pins
*/
#define SDA 13  /* 2// 4// 13 //Define SDA pins */
#define SCL 14  /*1//5//14 //Define SCL pins
/*
* note: If lcd1602 uses PCF8574T, IIC's address is 0x27,
* or lcd1602 uses PCF8574AT, IIC's address is 0x3F.
*/
//LiquidCrystal_I2C lcd(0x27,16,2); 
LiquidCrystal_I2C lcd(0x3F,16,2);

bool ledState = false; // Inicializar el estado del LED como apagado

void setup() {
   Serial.begin(115200); // Iniciar la comunicación serial
  pinMode(LED_BUILTIN, OUTPUT); // Configurar el pin del LED interno como salida

 Wire.begin(SDA, SCL); // attach the IIC pin
 lcd.init(); // LCD driver initialization
 lcd.backlight(); // Turn on the backlight
 lcd.setCursor(0,0); // Move the cursor to row 0, column 0
 lcd.print("hello, world! "); // The print content is displayed on the LCD
}

void loop() {
 lcd.setCursor(0,1); // Move the cursor to row 1, column 0
 lcd.print("Counter:"); // The count is displayed every second
 lcd.print(millis() / 1000);
 delay(1000);
 ledState = !ledState; // Cambiar el estado del LED
 digitalWrite(LED_BUILTIN, ledState); // Encender o apagar el LED según el estado actual

 Serial.print("LED state: "); // Imprimir el estado del LED en la consola
 Serial.println(ledState);


}

Este es un código de boceto Arduino que inicializa y controla una pantalla LCD con interfaz I2C y parpadea un LED al mismo tiempo.

La primera parte del código incluye las librerías necesarias para la comunicación I2C y el control de la pantalla LCD. Las líneas de comentario muestran diferentes opciones para los pines SDA y SCL que se pueden utilizar dependiendo de la placa que se utilice.

Las siguientes líneas establecen la dirección I2C del LCD y el número de filas y columnas de la pantalla. Luego, la librería Wire es inicializada para la comunicación I2C y el controlador LCD es inicializado. Finalmente, se enciende la luz de fondo y se imprime el mensaje «¡Hola, mundo!» en la primera fila de la LCD.

La función de bucle se ejecuta continuamente y actualiza la segunda fila de la LCD con el valor actual de la función millis() dividido por 1000, que se incrementa cada segundo. Al mismo tiempo, alterna el estado del LED usando el pin LED incorporado e imprime el estado actual del LED al Monitor Serial.

En la siguiente imagen podemos ver funcionando el display con el código anterior.

Por cierto, si planea usar un display de este tipo ha de saber que los caracteres se sobrescriben en la línea correspondiente ,por lo que es responsabilidad del usuario borrar la pantalla cuando corresponda ( por ejemplo escribiendo 16 caracteres en blanco en la línea que nos interese)

Secuenciador aleatorio con Arduino


Arduino Uno es una placa de microcontrolador basada en el microcontrolador ATmega328P de la compañía Atmel (ahora adquirida por Microchip Technology). Fue lanzada en 2010 y se convirtió en una de las placas más populares en la plataforma Arduino.

La placa Arduino Uno es una plataforma de hardware de código abierto que permite a los usuarios crear proyectos electrónicos interactivos y controlar dispositivos electrónicos usando software y hardware personalizado.

La placa Arduino Uno incluye pines de entrada y salida digitales y analógicos que permiten a los usuarios conectar sensores, actuadores y otros componentes electrónicos para crear proyectos personalizados. La placa se puede programar utilizando el entorno de desarrollo integrado (IDE) de Arduino, que se puede descargar gratuitamente desde el sitio web de Arduino, pero actualmente ya existen otras herramientas de desarrollo.

Vamos a ver una simple aplicación de una placa Arduino Uno conectada una placa de relés, lo cual puede servir como secuenciador por ejemplo para maquetas , juegos de luces, medidas eléctricas, escaparates , escenarios , SIMULAR LA ACTIVIDAD EN UNA VIVIENDA cuando estamos fuera, y un largo etc.

El aspecto del conjunto es el siguiente:

Como vemos en la iamgen anterior, solo usaremos 5 salidas binarias correspondientes a los pines d2, d3, d4, d5 las cuales conectaremos directaemente a las entradas de la placa de relés ( no olvidar la masa ).

Las conexiones no pueden ser mas simples ,porque se conectan las salidas binarias de la placa Arduino pin a pin a la placa de relés sin olvidar la masa o GND.

No recomendamos para nada alimentar desde la propia placa Arduino la placa de relés, porque esta puede consumir según el modelo de placa de relés mas energia de la que puede aportar la salida de Arduino de 5v y además casi todas las placas de relés de cierta calidad se alimentan a 12V, por lo que se recomienda alimentar la placa de relés externamente.

Y ahora presentamos el código Arduino del ejemplo , donde también sacamos por consola los nombres de las cargas que vamos encendiendo y el tiempo de conexión total.

Por supuesto los nombre de los aplicativos a conectar se deberían cambiar con el nombre de los dispositivos eléctricos que conectemos

Es de interes destacar que calculamos cualquier combinación de 5 bits , la cual sacamos por los puertos binarios.

Además del combinación de salidas activadas que es aleatoria, también permanece en un estado de tiempo aleatorio entre 6000 y 100.000 ( la variable se llama tiempoEncendido) así como también hay una breve pausa de todo apagado entre 10.000 y 60000 ( la variable se llama tiempo_pausa), ambas por supuesto que debemos cambiar en función de la utilidad que se desee.

El resto de la funcionalidad del programa es sacar por consola el / o los electrodomésticos a encender , el tiempo que se va a encender y luego apagar así como el tiempo total de funcionamiento

El código completo de todo el programa es el siguiente, el cual se debería adaptar y personalizar a las necesidades de cada caso concreto:




int soldador = 2;
int luz_led = 3;
int luz_halogena = 4;
int ordenador = 5;
int ventilador = 6;

unsigned long tiempoEncendidoTotal = 0; // tiempo total que se va invirtiendo en milisegundos

void setup() {
  Serial.begin(115200);
  Serial.println("Iniciando ..");
 
  pinMode(soldador, OUTPUT);
  pinMode(luz_led, OUTPUT);
  pinMode(luz_halogena, OUTPUT);
  pinMode(ordenador, OUTPUT);
  pinMode(ventilador, OUTPUT);
  
  randomSeed(analogRead(A0));


  digitalWrite(soldador, HIGH); // apaga el soldador
    digitalWrite(luz_led, HIGH); // apaga la luz LED
 digitalWrite(luz_halogena, HIGH); // apaga la luz halógena
   digitalWrite(ordenador, HIGH); // apaga el ordenador
digitalWrite(ventilador, HIGH); // apaga el ventilador


 delay (1000);
}

void loop() {
  long tiempo_pausa = random(10000, 60000); // tiempo aleatorio entre 10 y 60 segundos en milisegundos
  int dispositivo = random(0, 33); // número aleatorio entre 0 y 32
  Serial.print("Numero generado: ");
  Serial.println(dispositivo);
  String binaryString = String(dispositivo, BIN);
     Serial.print("Cadena:");
      Serial.println(binaryString);
      
  

   

  if (dispositivo & (1 << 0)) { // verifica si el bit 0 está activado
    digitalWrite(soldador, LOW); // enciende el soldador
    Serial.println("Soldador encendido");
  } else {
    digitalWrite(soldador, HIGH); // apaga el soldador
  }

  if (dispositivo & (1 << 1)) { // verifica si el bit 1 está activado
    digitalWrite(luz_led, LOW); // enciende la luz LED
    Serial.println("Luz LED encendida");
  } else {
    digitalWrite(luz_led, HIGH); // apaga la luz LED
  }

  if (dispositivo & (1 << 2)) { // verifica si el bit 2 está activado
    digitalWrite(luz_halogena, LOW); // enciende la luz halógena
    Serial.println("Luz halógena encendida");
  } else {
    digitalWrite(luz_halogena, HIGH); // apaga la luz halógena
  }

  if (dispositivo & (1 << 3)) { // verifica si el bit 3 está activado
    digitalWrite(ordenador, LOW); // enciende el ordenador
        Serial.println("Ordenador encendido");
  } else {
    digitalWrite(ordenador, HIGH); // apaga el ordenador
  }

  if (dispositivo & (1 << 4)) { // verifica si el bit 4 está activado
    digitalWrite(ventilador, LOW); // enciende el ventilador
       Serial.println("Ventilador encendido");
  } else {
    digitalWrite(ventilador, HIGH); // apaga el ventilador
  }



 
long tiempoEncendido = random(6000, 300000); //genera un número aleatorio entre 1 minuto (60000ms) y 5 minutos (300000ms)
  
Serial.print("Tiempo encendido nuevo estado: ");
Serial.println(tiempoEncendido/1000);


 Serial.print(" Tiempo de pausa tras nuevo estado: ");
  Serial.print(tiempo_pausa/1000); // muestra el tiempo en segundos
  Serial.println(" segundos");

  tiempoEncendidoTotal += tiempoEncendido;
  unsigned long tiempoAcumulado = tiempoEncendidoTotal / 1000;
  unsigned int horas = tiempoAcumulado / 3600;
  unsigned int minutos = (tiempoAcumulado % 3600) / 60;
  unsigned int segundos = tiempoAcumulado % 60;

 

delay(tiempoEncendido); //espera el tiempo aleatorio generado


  

  
  digitalWrite(soldador, HIGH);
  digitalWrite(luz_led, HIGH);
  digitalWrite(luz_halogena, HIGH);
  digitalWrite(ordenador, HIGH);
  digitalWrite(ventilador, HIGH);

  




  delay(tiempo_pausa);
   Serial.print("Tiempo encendido total: ");
  Serial.print(horas);
  Serial.print(":");
  if (minutos < 10) {
    Serial.print("0");
  }
  Serial.print(minutos);
  Serial.print(":");
  if (segundos < 10) {
    Serial.print("0");
  }
  Serial.println(segundos);
}

Extracto

Este código, escrito en el IDE de Arduino , controla el estado de encendido/apagado de varios dispositivos (soldador, luz_led, luz_halogena, ordenador, ventilador) basándose en números binarios generados aleatoriamente. Los dispositivos están conectados a pines digitales específicos de la placa Arduino y se encienden/apagan cambiando la señal digital de estos pines de alta a baja (encendido) o de baja a alta (apagado).

El programa también realiza un seguimiento del tiempo total de encendido de todos los dispositivos en segundos y lo muestra en horas, minutos y segundos. El tiempo de encendido de cada dispositivo se genera aleatoriamente y varía entre 1 minuto (6000ms) y 5 minutos (300000ms), mientras que el tiempo de pausa entre los tiempos de encendido de cada dispositivo también se genera aleatoriamente entre 10 y 60 segundos.

El programa comienza inicializando todos los dispositivos en el estado de apagado, luego entra en un bucle infinito que genera un nuevo número binario y enciende/apaga los dispositivos en consecuencia, basándose en el estado de cada bit en el número binario. Después de cada período de encendido, todos los dispositivos se apagan y se inserta un tiempo de pausa antes de que comience el siguiente ciclo.