#include <Arduino.h>
/*
*****************************************
********** LCD 2x16 (8 bit) **********
*****************************************
En la década de los '80, del pasado siglo, Hitachi desarrolló el controlador
de pantalla LCD 'HD44780', contaba con el juego de caracteres ASCII, además
de japoneses y símbolos, en total puede mostrar hasta 80 caracteres, se hizo
tan popular, que numerosas pantallas de terceros fabricantes utilizan su interfaz,
así como su juego de instrucciones por compatibilidad, convirtiéndose de facto
en un estándar sin pretender serlo, y ya va para 42 años.
https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
Volviendo al LCD, posee 16 líneas:
- VSS GND
- VCC +5V
- Vo Ajuste del contraste Nota(2)
- RS Selección de registo
- R/W Lectura /Escritura
- EN Habilitación
- D0 a D7 Datos 8 bit
- A Ánodo Led retroiluminación
- K Cátodo
VRG (10/05/2022)
*/
// Declaración de variables y ctes
// #define lcd_Linea_Uno 0x00 // ver Nota (1)
// #define lcd_Linea_Dos 0x40
const uint8_t lcd_Linea_Uno = 0x00; // Direcciones DDRAM comienzo de la línea 1
const uint8_t lcd_Linea_Dos = 0x40; // y de la línea 2
// Interface paralelo 8 bit del LCD
const uint8_t DB[8] = {2, 3, 4, 5, 6, 7, 8, 9}; // Bus datos DB[7...0]
const uint8_t PE = 10; // Enable
const uint8_t RS = 11; // Registro de Datos/Instrucciones
// Instrucciones del LCD
const uint8_t lcd_Clear = 0b00000001; // pone en todos los caracteres el ASCII 'espacio'
const uint8_t lcd_Home = 0b00000010; // regresa el cursor a la primera posición de la primera línea
const uint8_t lcd_EntryMode = 0b00000110; // desplaza el cursor de izquierda a derecha en lectura/escritura
const uint8_t lcd_DisplayOff = 0b00001000; // apaga la pantalla
const uint8_t lcd_DisplayOn = 0b00001100; // pantalla activada, cursor desactivado, carácter sin parpadeo
const uint8_t lcd_FunctionReset = 0b00110000; // reinicia la pantalla
const uint8_t lcd_FunctionSet8bit = 0b00111000; // interface de 8 bits, pantalla de 2 líneas, fuente de 5x7 (5x8)
const uint8_t lcd_SetCursor = 0b10000000; // establecer la posición del cursor
char mensaje_1[] = "VICENTE"; // Mensaje inicial para depuración
char mensaje_2[] = "Rey Garcia";
// Prototipo de Funciones
void lcd_init_8b(); // inicializar el LCD para un interface de 8 bits
void lcd_escribir_texto(char[]); // escribir una cadena
void lcd_escribir_caracter(uint8_t); // escribir un carácter
void lcd_escribir(uint8_t);
void lcd_instruccion(uint8_t);
// Inicialización
void setup() {
for (int i = 0; i <= 7; i++) // Interface Bus de Datos 8 bits
pinMode(DB[i], OUTPUT);
pinMode(PE, OUTPUT); // Interface Bus de Control
pinMode(RS, OUTPUT); // PE enable, RS
lcd_init_8b(); // inicializar el LCD
lcd_escribir_texto(mensaje_1);
lcd_instruccion(lcd_SetCursor | lcd_Linea_Dos); // saltar a la segunda línea
delayMicroseconds(80); // minimo 40 uS retardo
lcd_escribir_texto(mensaje_2);
}
// ------------ Programa Principal ----------
void loop() {
}
// ------------ FIN --------------
void lcd_init_8b(){
delay(100); // retardo inicial (mayor de 40 ms)
lcd_instruccion(lcd_FunctionReset); // Primera parte de la secuencia de inicialización
delay(10); // 4,1ms min.
lcd_instruccion(lcd_FunctionReset);
delayMicroseconds(200); // 100µS min.
lcd_instruccion(lcd_FunctionReset);
delayMicroseconds(200); // 100µS min.
lcd_instruccion(lcd_FunctionSet8bit); // establercer modo, líneas y fuente
delayMicroseconds(80); // 40uS min
lcd_instruccion(lcd_DisplayOff); // poner display OFF
delayMicroseconds(80); // 40µs min
lcd_instruccion(lcd_Clear); // Borrar RAM de pantalla
delay(4); // 1,64ms min
lcd_instruccion(lcd_EntryMode); // establecer las características
delayMicroseconds(80); // 40µS min
lcd_instruccion(lcd_DisplayOn); // Enciende la pantalla
delayMicroseconds(80); // 40µs min
}
//-------------------------------------------------------------------------------------------
void lcd_escribir_texto(char texto[]) {
int i = 0;
while (texto[i] != '\0') { // recoger caracteres hasta la marca final '\0'
lcd_escribir_caracter(texto[i]);
i++;
delayMicroseconds(80);
}
}
//-------------------------------------------------------------------------------------------
void lcd_escribir_caracter(uint8_t lcd_dato) {
digitalWrite(RS, HIGH); // seleccionar Registro de Datos (RS = 1)
digitalWrite(PE, LOW); // inicialmente Enable = 0
lcd_escribir(lcd_dato); // escribir datos
}
//-------------------------------------------------------------------------------------------
void lcd_instruccion(uint8_t lcd_instruccion) {
digitalWrite(RS, LOW); // seleccionar Registro de Instrucción (RS = 0)
digitalWrite(PE, LOW); // inicialmente Enable = 0
lcd_escribir(lcd_instruccion); // escribir instrucción
}
//-------------------------------------------------------------------------------------------
void lcd_escribir(uint8_t lcd_bye) {
for (int i = 0; i <= 7; i++){
if (lcd_bye & 1 << i)
digitalWrite(DB[i], HIGH); // poner a '1'
else
digitalWrite(DB[i], LOW); // o a '0'
}
// tiempo de establecimiento de la dirección (40 nS)
digitalWrite(PE, HIGH); // Preparar permiso de escritura por flanco descendente.
delayMicroseconds(1); // tiempo de establecimiento de los datos (80 nS) y anchura de PE (230 nS)
digitalWrite(PE, LOW); // completar impulso de escritura
delayMicroseconds(1); // tiempo de retención de los datos (10 nS) y tiempo del ciclo de PE (500 nS)
}
/*
Direccionamiento de la DDRAM:
Indicamos al controlador dónde queremos que se almacene el primer carácter ASCII que se le envía, este
actualizará automáticamente su puntero de dirección y colocará el siguiente carácter que se envíe
en la dirección de memoria adyacente (se puede especificar si deseamos aumentar o disminuir el contador de direcciones),
normalmente se incrementa, por lo que el siguiente carácter se colocará en la siguiente dirección automáticamente.
Después de almacenar un código ASCII en la dirección 0x27, coloca el siguiente código en la dirección 0x40.
De manera similar, se incrementa desde la dirección 0x67 hasta las 0x00.
Estos son los 80 bytes de DDRAM en el controlador HD44780
LCD 40x2:
línea 1 --> 0x00, 0x01, 0x02, ... ...0x27
línea 2 --> 0x40, 0x41, 0x42, ... ...0x67
LCD 20x4:
línea 1 --> 0x00, 0x01, 0x02, ... ...0x13
línea 2 --> 0x40, 0x41, 0x42, ... ...0x53
línea 1 --> 0x14, 0x15, 0x16, ... ...0x27
línea 2 --> 0x54, 0x55, 0x56, ... ...0x67
LCD 20x2:
línea 1 --> 0x00, 0x01, 0x02, ... ...0x13
línea 2 --> 0x40, 0x41, 0x42, ... ...0x53
LCD 16x4:
línea 1 --> 0x00, 0x01, 0x02, ... ...0x0F
línea 2 --> 0x40, 0x41, 0x42, ... ...0x4F
línea 3 --> 0x10, 0x01, 0x02, ... ...0x1F
línea 4 --> 0x50, 0x41, 0x42, ... ...0x5F
LCD 16x2:
línea 1 --> 0x00, 0x01, 0x02, ... ...0x0F
línea 2 --> 0x40, 0x41, 0x42, ... ...0x4F
LCD 16x1:
línea 1 --> 0x00, 0x01, 0x02, ... ...0x07
línea 2 --> 0x40, 0x41, 0x42, ... ...0x47
LCD 40x4:
La pantalla LCD de 40 x 4 se trata esencialmente como dos dispositivos de 40 x 2.
Utiliza dos chips de controlador HD44780, por lo tanto, tiene dos mapas de memoria separados,
cada uno con el mismo rango de direcciones. Se accede a las memorias de forma individual mediante un pin de selección,
línea 1 --> 0x00, 0x01, 0x02, ... ...0x27
línea 2 --> 0x40, 0x41, 0x42, ... ...0x67
línea 3 --> 0x00, 0x01, 0x02, ... ...0x27
línea 4 --> 0x40, 0x41, 0x42, ... ...0x67
*/
/*
Nota (1)
Casi siempre se piensa que el uso de la directiva '#define' favorece el rendimiento del compilado
evitando la declaración de una variable se ahorra tiempo y espacio, y es verdad hasta cierto punto,
pero, en cualquier nivel de optimización del compilador no habrá una diferencia relevante,
ya que los valores constantes 'cosnt' se sustituyen ya en el mismo instante de la compilación.
La gran ventaja de usar 'const' es la de verificar tipos y hacer que el código sea conocido por el depurador,
por lo que realmente no hay una razón de peso para no usar variables 'const'.
*/