Curso de Arduino y robótica: Componentes I2C

Ahora que sabemos cómo funciona la comunicación I2C; vamos a practicar con este nuevo conocimiento que nos proporciona Arduino.

Uno de los componentes más útiles para crear proyectos con Arduino son las pantallas LCD.

Muchas veces es útil disponer de un modelo gráfico de visualizar datos en una pantalla para reconocer valores o crear un modelo visor controlador .

Pantalla LCD

Las pantallas LCD suelen tener un cableado infernal para ponerlas a funcionar correctamente. Es por ello que recomendamos encarecidamente que a la hora de comprar elijamos un display con expansor de entradas y salidas por I2C, si no queremos tener que conectar los cables del siguiente esquema por el segundo que es más sencillo.

Imagen relacionada

 

 

Ahora que hemos ahorrado una cantidad de tiempo considerable, podemos comenzar a usar nuestra pantalla LCD para crear nuestros primeros sistemas de monitorización.

Librería LiquidCrystal

Por mucho que hayamos explicado cómo funciona el protocolo I2C, es muy posible que no tengamos que programar absolutamente nada relacionado con él, ya que todo vendrá correctamente definido en alguna librería con el conjunto de métodos creados en la misma.

Y es que el protocolo I2C es un modelo que nos facilita en gran medida el proceso de desarrollo, como si de una capa de abstracción se tratará. Así que solamente tendremos que instalar una librería, programar y practicar.

Nos podemos descargar nuestra librería LiquidCrystal y su extensión Liquidcrystal I2C desde el gestor de librerías o desde el repositorio oficial e instalarla copiando en la carpeta de Arduino tal y cómo mostramos en un tutorial anterior.

Nuestro primer programa con LCD por I2C

Como todos los programas de Arduino, nos costará hacer funcionar nuestro pantalla la primera vez , pero una vez desbloqueado este hito, podremos realizar programas más complejos.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f,16,2);

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("Arduino Course");
  lcd.setCursor(1,1);
  lcd.print("ZGZ MakerSpace");
}

void loop() {
  
}

Como podremos observar, una de las  instrucciones más importantes, es el propio constructor, en el que hay que especificar la dirección I2C al que hace referencia la pantalla LCD; en este caso es la 0x3f. Recordemos que en un tutorial anterior vimos cómo obtener esta dirección física para el I2C.

IMPORTANTE: Existen dos métodos en el setup del programa que siempre deben aparecer y que permiten que se inicialice la pantalla LCD y que se encienda que son, lcd.init() y lcd.backlight(). Sin estos métodos, la pantalla no se encendería o no funcionaría.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

void setup()
{
  lcd.init();                      
  lcd.backlight();
  Serial.begin(9600);
  Serial.setTimeout(300);
}

void loop()
{
  if (Serial.available()) {
    String text = Serial.readString();

    lcd.clear();
    lcd.print( text );

  }
}

Métodos Pantalla LCD

  • void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS );
  • void setCursor(uint8_t, uint8_t);
  • void clear();
  • void home();
  • void noDisplay();
  • void display();
  • void noBlink();
  • void blink();
  • void noCursor();
  • void cursor();
  • void scrollDisplayLeft();
  • void scrollDisplayRight();
  • void printLeft();
  • void printRight();
  • void leftToRight();
  • void rightToLeft();
  • void shiftIncrement();
  • void shiftDecrement();
  • void noBacklight();
  • void backlight();
  • void autoscroll();
  • void noAutoscroll();
  • void createChar(uint8_t, uint8_t[]);

Programación de eventos

En un tutorial anterior hicimos hincapie en el desarrollo de estrategias antibloqueo en programas que funcionan en bucle.

El manejo de pantallas LCD es un buen ejemplo de como debemos realizar una captura de eventos para realizar un cambio sobre la pantalla que ejecuta acciones dentro del bucle.

En este ejercicio, vamos a conectar nuestra pantalla con un botón, de manera que ejecuta un contador cada vez que presionemos sobre él.

Solamente tendremos que registrar un contador que detecte cada cambio en el estado del botón para transmitir solamente en ese momento la acción. Recordemos que si no hicieramos la comparación de cambio de estado en el botón, contaría tantas veces como registre el evento activo durante el bucle.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f,16,2);  

int flag = true;
int btncounter = 0;

void setup()
{
  Serial.begin(9600);
  lcd.init();                      
  lcd.backlight();
  pinMode(3,INPUT);
  lcd.setCursor(1,0);
  lcd.print("I2C ZMS ARDUINO");
  
}

void loop()
{
  Serial.println( digitalRead(3) );
  if(digitalRead(3) != flag){
    flag = digitalRead(3);
    if ( flag == true){
      btncounter++;
      Serial.println(btncounter);
      lcd.setCursor(7,1);
      lcd.print( btncounter );
    }
  }

}

También se puede realizar el mismo programa haciendo uso de interrupciones. Puede resultar un poco más abstracto en cuanto a la programación, pero se obtendría el mismo resultado atendiendo a las acciones externas del botón.

Scroll

Ahora que sabemos cómo programar con alguno de los métodos de nuestra pantalla, vamos a desarrollar un minijuego en el que utilizaremos el método Scroll para evitar un obstáculo.

Con el mismo esquema que teníamos anteriormente, en el que conectamos una pantalla LCD y un botón , vamos a ejecutar un formato temporal en el que irán apareciendo obstáculos, como si de una carretera se tratara, y por otra parte crearemos un objeto que será nuestro personaje y que irá cambiando de carril, en función del botón presionado.

Empezaremos creando nuestro personaje. Al igual que hicimos obteniendo el evento del botón presionado, cuando detectemos un cambio, realizaremos un cambio de carril, en una fila o en otra.

Podemos crear nuestros propios símbolos para hacer nuestro personaje, creando un vector de 8 bits.

Para diseñar nuestros símbolos personalizados, podemos acceder a la siguiente página  y copiar el vector generado para imprimir.

Nosotros usaremos la función write, en el que registraremos con un número, el símbolo correspondiente dentro de esta tabla.

 

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f,16,2);  

int flag = true;
int pos = 2;

void setup()
{
  Serial.begin(9600);
  lcd.init();                      
  lcd.backlight();
  pinMode(3,INPUT);

}

void loop()
{
  Serial.println( digitalRead(3) );
  if(digitalRead(3) != flag){
    flag = digitalRead(3);
    if ( flag == true){
      lcd.setCursor(pos,1);
      lcd.write( 32 );
      lcd.setCursor(pos,0);
      lcd.write( 126 );
    }
    if ( flag == false){
      lcd.setCursor(pos,0);
      lcd.write( 32 );
      lcd.setCursor(pos,1);
      lcd.write( 126 );
    }
    
  }

}

El evento de scroll para crear los obstáculos lo realizaremos con un conjunto al azar, en el que a priori, no conoceremos en qué posición se encontrará. Sí que sabemos que la anchura total del scroll es de 40 espacios, y empezará de nuevo, cuando hayan pasado esos espacios.

También debemos dejar un espacio entre obstáculo y obstáculo para poder esquivarlos. En principio  nosotros dejaremos 4 espacios entre uno y otro.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

int LCD_COLS = 16;
int LCD_ROWS = 2;
LiquidCrystal_I2C lcd(0x3f,LCD_COLS,LCD_ROWS);  

unsigned long scrolltimer;
unsigned long auxtimer;
int delayTime = 500;
int space = 4;
int totalscroll = 40;
boolean auxvar = true;

void setup()
{
  Serial.begin(9600);
  lcd.init();                      
  lcd.backlight();
  randomSeed( analogRead(0) );
  Serial.println( ( totalscroll )/space - 2);
  for (int i=0; i < ( totalscroll)/space -2; i++ ){ 
    int col = LCD_COLS+ space*i; 
    int row = random(0, 2); 
    Serial.println( (String)row + " - "+(String)col ); 
    lcd.setCursor( col, row ); 
    lcd.write( 255 ); 
  } 
} 

void loop() { 
  if( millis() - scrolltimer > delayTime){
    scrolltimer = millis();
    lcd.scrollDisplayLeft();
    Serial.println(millis());
  };

  if( millis() > delayTime*(totalscroll-LCD_COLS) && auxvar){
      auxvar = false;
      for (int i=0; i < ( LCD_COLS )/space -1; i++ ){
    
        int col = space*i;
        int row = random(0, 2);
        Serial.println( (String)row + " - "+(String)col );
        lcd.setCursor( col, row );
        lcd.write( 255  );
      }
  
  };

}

 

Ahora solo hace falta unir los dos códigos para recrear el juego. Pero recuerda, hay que borrar la antigua posición de nuestro símbolo jugador y crear la nueva posición de nuestro a medida que avanza.

¿Serás capaz de desarrollarlo? 😉


Una vez completado este tutorial, puedes acceder al siguiente nivel.

 

Los ejercicios de código, proyectos y recursos que desarrollaremos durante el curso se pueden consultar a través de nuestro Github.

Documentacion ZaragozaMakerSpace Github

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

9 − cinco =

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.