Protocolo I2C

I2C significa Circuito Interintegrado (Inter-Integrated Circuit) es un protocolo de comunicación serial desarrollado por Phillips Semiconductors en la década de los 80s.

Librerías externas

El IDE de Arduino tiene su propio gestor de librerías para instalar nuevas, para acceder a él se entra a Programa > Incluir Librería > Gestionar Librerías

Librería LiquidCrystal_I2C

Librería LiquidCrystal_I2C por Frank de Brabander.

Constructor lcd()

Crea un objeto de la clase LiquidCrystal_I2C, con todas sus características correspondientes al LCD en uso.

Sintaxis

LiquidCrystal_I2C lcd(direccion, columnas, filas)

Parámetros

Parámetros

Referencia Tipo Descripción
direccion byte dirección I2C del LCD.
columnas int Número de columnas del LCD.
filas int Número de filas del LCD.

Método init()

Inicializa el modulo adaptador, esta función internamente configura lo necesario para utilizar el LCD mediante I2C.

Sintaxis

lcd.init()

Método backlight()

Enciende la luz del fondo de la pantalla.

Sintaxis

lcd.backlight()

Método noBacklight()

Apaga la luz del fondo de la pantalla.

Sintaxis

lcd.noBacklight()

Método setCursor()

Establecer la ubicación dónde empezará posteriormente la impresión de texto escrito.

A esta ubicación se le denomina cursor.

Sintaxis

lcd.setCursor(columna, fila)

Parámetros

Referencia Tipo Descripción
columna int Columna donde se posicionará el cursor.
fila int Fila donde se posicionará el cursor.

Método print()

Escribe un texto o mensaje en el LCD, su uso es similar a un Serial.print().

Sintaxis

lcd.print(texto)

Parámetros

Referencia Tipo Descripción
texto String Texto que se escribirá en el LCD.

Método clear()

Limpia la pantalla y posiciona el cursor en la esquina superior izquierda (posición (0, 0))

Sintaxis

lcd.clear()

Método scrollDisplayLeft()

Desplaza el contenido de la pantalla, texto y cursor, un espacio hacia la izquierda.

Sintaxis

lcd.scrollDisplayLeft()

Método scrollDisplayRight()

Desplaza el contenido de la pantalla, texto y cursor, un espacio hacia la derecha.

Sintaxis

lcd.scrollDisplayRight()

Método createChar()

Crea un carácter personalizado para su uso en la pantalla LCD.

Se admiten hasta ocho caracteres, numerados del 0 al 7, de 5x8 pixeles.

Sintaxis

lcd.createChar(numero, datos)

Parámetros

Referencia Tipo Descripción
numero int Número de carácter.
datos int[][] Matriz que contiene los pixeles del carácter.

Librería Keypad

Librería Keypad por Mark Stanley, Alexander Brevig.

Constructor Keypad

Sintaxis

Keypad(keyMap, pinsFilas, pinsColumnas, filas, columnas)

Parámetros

Referencia Tipo Descripción
keyMap Keymap Mapa de las teclas devuelto por makeKeymap().
pinsFilas int[] Arreglo que contiene los pines correspondiente a las filas.
pinsColumnas int[] Arreglo que contiene los pines correspondiente a las columnas.
filas int Número de filas del teclado.
columnas int Número de columnas del teclado.

Retorno

Un objeto Keypad que se usará para manipular el teclado.

Función makeKeymap()

Sintaxis

makeKeymap(teclas)

Parámetros

Referencia Tipo Descripción
teclas char[][] Matriz que contiene el valor de cada tecla.

Retorno

Un objeto Keymap que contiene un mapa de las teclas.

Método getKey()

Sintaxis

objetoKeypad.getKey()

Retorno

Un char correspondiente a la tecla presionada.

Método waitForKey()

Similar a getKey() con la diferencia de que se espera para siempre hasta que se presione una tecla.

Cuidado: bloquea toda la ejecución del programa hasta que se presione una tecla.

Método getState()

Devuelve el estado actual de cualquiera de las teclas.

Retorno

Una constante KeyState correspondiente a alguno de los cuatro estados: IDLE, PRESSED, RELEASED and HOLD.

boolean keyStateChanged()

New in version 2.0: Let’s you know when the key has changed from one state to another. For example, instead of just testing for a valid key you can test for when a key was pressed.

setHoldTime(unsigned int time)

Set the amount of milliseconds the user will have to hold a button until the HOLD state is triggered.

setDebounceTime(unsigned int time)

Set the amount of milliseconds the keypad will wait until it accepts a new keypress/keyEvent. This is the “time delay” debounce method.

addEventListener(keypadEvent)

Trigger an event if the keypad is used. You can load an example in the Arduino IDE.
[See File -> Examples -> Keypad -> Examples -> EventSerialKeypad] or see the KeypadEvent Example code.

Conectar un LCD 16x2

lcd i2c

Escaner I2C

Antes que nada, necesitamos averiguar la dirección I2C de nuestro LCD para llamar al constructor lcd(). Por esto, lo que haremos será escanear todos los dispositivos I2C que estén conectados a nuestra placa Arduino con el siguiente código.

void setup() {
  Wire.begin();
  Serial.begin(9600);
  while (!Serial);
  Serial.println("\nI2C Scanner");
}

void loop() {
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    } else if (error==4) {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);
}

En el monitor serial:

Scanning...
I2C device found at address 0x3F  !
done

Dónde 0x3F será nuestra dirección I2C correspondiente al LCD y la llamada al constructor se vería algo así:

LiquidCrystal_I2C lcd(0x3F, 16, 2);

La dirección 0x3F puede ser distinta dependiendo de cada caso, por lo que siempre es bueno hacer un escaneo para asegurarse.

Escribir en la pantalla

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

LiquidCrystal_I2C lcd(0x3F, 16, 2);

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(3, 0); 
  lcd.print("Club INNDEV");
  lcd.setCursor(6, 1);
  lcd.print("UTEM");
}

void loop() {
}

Crear un nuevo caracter

Hay herramientas que nos facilitan mucho este trabajo, como esta aplicación que con sólo empezar a dibujar en el panel de 8x5 que tiene disponible, nos genera un código automáticamente.

Sólo necesitamos copiar el arreglo customChar que nos genera la aplicación.

Conectar un teclado matricial 4x4

Sin desconectar el LCD, conectaremos el teclado matricial de la siguiente manera:

analogreadserial2lcd_led_bb

Escribir en el monitor serial

#include <Keypad.h>

const byte FILAS = 4;
const byte COLUMNAS = 4;

char significadoTeclas[FILAS][COLUMNAS] = {
  {'0','1','2','3'},
  {'4','5','6','7'},
  {'8','9','A','B'},
  {'C','D','E','F'}
};

byte pinsFilas[FILAS] = {5, 4, 3, 2};
byte pinsColumnas[COLUMNAS] = {9, 8, 7, 6};

Keypad teclado = Keypad(makeKeymap(significadoTeclas), pinsFilas, pinsColumnas, FILAS, COLUMNAS); 

void setup(){
  Serial.begin(9600);
}
  
void loop(){
  char presionada = teclado.getKey();
  
  if (presionada) {
    Serial.println(presionada);
  }
}

Escritura en tiempo real en el LCD

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

const byte FILAS = 4;
const byte COLUMNAS = 4;

char significadoTeclas[FILAS][COLUMNAS] = {
  {'1','4','7','*'},
  {'2','5','8','0'},
  {'3','6','9','#'},
  {'A','B','C','D'}
};

byte pinsFilas[FILAS] = {5, 4, 3, 2};
byte pinsColumnas[COLUMNAS] = {9, 8, 7, 6};
int contador = 0;
int posicionFila = 0;

Keypad teclado = Keypad(makeKeymap(significadoTeclas), pinsFilas, pinsColumnas, FILAS, COLUMNAS); 
LiquidCrystal_I2C lcd(0x3F, 16, 2);

void setup(){
  lcd.init();
  lcd.backlight();
}
  
void loop(){
  char presionada = teclado.getKey();
  if (presionada) {
  contador++;
    if (contador >= 16) {
      contador = 0;
      if (posicionFila == 0)
        posicionFila = 1;
      else
        posicionFila = 0;
      lcd.setCursor(0, posicionFila);
    }
    lcd.print(presionada);
  }
}

Verificación de contraseña

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

const byte FILAS = 4;
const byte COLUMNAS = 4;

const String contrasenia = "9#B0";

String textoIngresado = "";

char significadoTeclas[FILAS][COLUMNAS] = {
  {'1','4','7','*'},
  {'2','5','8','0'},
  {'3','6','9','#'},
  {'A','B','C','D'}
};

byte pinsFilas[FILAS] = {5, 4, 3, 2};
byte pinsColumnas[COLUMNAS] = {9, 8, 7, 6};
int contador = 0;
int posicionFila = 0;

Keypad teclado = Keypad(makeKeymap(significadoTeclas), pinsFilas, pinsColumnas, FILAS, COLUMNAS); 
LiquidCrystal_I2C lcd(0x3F, 16, 2);

void setup(){
  lcd.init();
  lcd.backlight();
  lcd.setCursor(2, 0); // Se mueve el cursor para que el texto quede centrado
  lcd.print("Contrasenia:");
  lcd.setCursor(6, 1); // Se mueve el cursor para que la contraseña quede centrada
}
  
void loop() {
  char presionada = teclado.getKey(); // Guardamos la tecla presionada
  if (presionada) { // Si se presiona una tecla
    textoIngresado = textoIngresado + presionada;
    if (contador >= 3) {
      lcd.clear();
      if (contrasenia == textoIngresado) {
        lcd.setCursor(4, 1); // Se mueve el cursor para que el texto quede centrado
        lcd.print("Correcto");
        lcd.setCursor(2, 1); // Se mueve el cursor para que el texto quede centrado
        lcd.print("Bienvenido");
        delay(2000);
      } else {
        lcd.print("Incorrecto");
        lcd.setCursor(2, 1); // Se mueve el cursor para que el texto quede centrado
        lcd.setCursor(0, 1);
        lcd.print("Prueba otra vez");
        delay(2000);
      }
      lcd.clear();
      textoIngresado = "";
      contador = 0;
      lcd.setCursor(2, 0);
      lcd.print("Contrasenia:");
      lcd.setCursor(6, 1);
    } else {
      lcd.print("*");
      contador++;
    }
  }
}