Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Los hay desde 1 a 4 líneas, desde 8 a 40 letras por línea, algunos con iluminación de
fondo, con diferente tecnología de fabricación, etc. Dada la compatibilidad en el control
de todos ellos, la elección de un modelo en particular queda a tu cargo.
Los pines 15 y 16 corresponden a la iluminación de fondo del LCD, pero aquí el orden varía
mucho. Sea como fuere, los 14 primeros pines siempre deberían coincidir.
Nombre de
Función
señal
DB0-DB7 8 líneas de bus de datos. Para transferencia bidireccional de datos entre el MCU y el LCD.
o DB7 también se puede usar como bit busy flag. En operación de 4 bits solo se usa el nibble
D0-D7 alto.
E Enable – Señal de inicio de operación de lectura/escritura.
Señal para seleccionar operación de lectura o escritura.
R/W 0 : Escribir en LCD
1 : Leer de LCD
Register Select
0: Registro de comandos (escritura).
RS
: Busy flag + puntero de RAM (lectura).
1 : Registro de datos (escritura, lectura). Acceso a DDRAM o CGRAM.
Vee o Vo Ajuste de contraste del LCD. Vee = GND es máximo contraste.
Vdd o Vcc Alimentación = +5 V típicamente.
Vss Alimentación = 0 V (GND).
AyK Son los pines de Anodo y Katodo de la iluminación de fondo que tienen algunos LCD.
Un modo de operación del LCD (con ventajas y desventajas) le permite trabajar sin
conectar el pin RW al microcontrolador. En ese modo pin RW siempre debe plantarse a
GND.
La iluminación basada en LEDs suele activarse con los pines 15 y 16, identificados
como A (de ánodo) y K (de cátodo) pero no necesariamente en ese orden. Estos pines
son independientes del controlador interno del LCD así que de poco sirve que nuestro
LCD diga ser compatible con HD44780. La polaridad varía tanto que en los diagramas
he puesto 15/16 para no especificar. En todo caso, la independencia de los pines A y K
permitirá que todas las prácticas de este curso funcionen con iluminación o sin ella.
Es la zona de memoria donde se encuentran grabados los patrones de todos los caracteres que
puede visualizar el LCD de fábrica. Tiene grabados cerca de 200 (varía mucho) tipos de
caracteres de 5×7 puntos (lo más común) o 32 caracteres de 5×10 puntos. Este último modo es
raramente usado porque no todos los modelos lo soportan.
La DDRAM almacena los códigos de las letras que se visualizan en la pantalla del LCD. Tiene
capacidad de 80 bytes, un byte por carácter si la fuente es de 5×7 puntos. Observa que no
siempre se podrán visualizar los 80 caracteres.
Por lo tanto, podemos entender que siempre tenemos un LCD virtual de 2×40; aunque solo
podamos ver 8, 16 ó 20 letras por cada línea. Los otros datos escritos en la DDRAM
permanecen allí aunque no se visualicen.
La CGRAM es una RAM de 64 bytes donde el usuario puede programar los patrones de nuevos
caracteres gráficos, ya sean de 5×7 puntos (hasta 8 caracteres) o de 5×10 puntos (hasta 4
caracteres). Este tema lo detallaré en la práctica final.
El Puntero de RAM
Llamado también Address Counter, es un registro que sirve para acceder a las memorias RAM
del LCD. Por ejemplo, si el Puntero de RAM vale 0x00, accedemos a la locación de DDRAM
(o CGRAM) de esa dirección.
Ahora bien, solo hay un puntero de RAM que trabaja con las dos RAMs del LCD, y para saber a
cuál de ellas accede actualmente debemos ver la instrucción enviada más recientemente.
Las instrucciones Clear Display, Return Home y Set DDRAM Address designan el Puntero de
RAM a la DDRAM, mientras que Set CGRAM Address lo designa a la CGRAM.
Es el controlador interno HD44780 (u otro) del LCD quien ejecutará las operaciones de mostrar
las letras en la pantalla, mover el cursor, desplazar el contenido de la pantalla, etc. Lo que nos
toca a nosotros es enviarle los códigos de esas operaciones. A continuación, un resumen.
Conviene saber que las instrucciones Clear Display y Return Home tienen un tiempo de
ejecución de cerca de 1.52 ms. Las demás toman algo de 40 µs.
El LCD cuenta con dos registros internos principales, que dividen, grosso modo, las
instrucciones en de datos y de comando.
Con RS = 0 accedemos al registro de comandos para escribir instrucciones de control del LCD
(Clear Display, Function Set, etc.). En el caso de una lectura, obtenemos un dato particular que
contiene el valor del puntero de RAM junto con el bit Busy flag.
Clear display: 0 0 0 0 0 0 0 1
Limpia toda la pantalla del LCD. También retorna el cursor a su posición inicial (cima
izquierda), esto es, designa el puntero de RAM a la dirección 0x00 de la DDRAM.
Return home: 0 0 0 0 0 0 1 x
Regresa el cursor a su posición inicial pero sin alterar el texto del display, es decir, solo designa
el puntero de RAM a la dirección 0x00 de la DDRAM.
D = 1: El display se prende.
D = 0: Apaga el display. (No significa que los datos de las RAMs se vayan a borrar.)
C = 1: Despliega el cursor.
C = 0: No despliega el cursor
B = 1: La letra indicada por el cursor parpadea.
B = 0: La letra no parpadea.
Tabla S/C
Function set: 0 0 1 DL N F x x
Ejemplo, para escribir un texto en la segunda línea del display (que tiene dirección inicial 0x40),
primero habría que enviar el comando Set DDRAM Address con el número 0x40 en el
parámetro AAAAAAA.
Leer bit Busy Flag (BF) y el valor del puntero de RAM. BF = 1 indica que una operación
interna está en progreso. El LCD no aceptará una nueva instrucción hasta que BF sea 0.
Es posible prescindir del bit BF. Para ello debemos esperar el tiempo adecuado antes de enviar
la siguiente instrucción.
incrementa o decrementa, según se haya configurado el display. Ver instrucción Entry Mode
Set.
Lee un dato de 8 bits de la DDRAM o CGRAM, dependiendo de cuál de ellas esté siendo
direccionada actualmente. Después de la lectura el puntero de RAM se incrementa o decrementa
en uno, según la configuración del display. Ver instrucción Entry Mode Set.
Los LCDs tienen un circuito interno de reset que los inicializan automáticamente tras la
alimentación. Lo cierto es que la auto-inicialización no siempre es fiable. Por eso existe la
inicialización por software, que permite una completa configuración de los parámetros del LCD.
Se constituye de una serie de pasos aparentemente bastante exóticos, sobre todo los primeros,
pero que se justifican si tratamos de entender que este procedimiento debe ser capaz de
configurar el LCD para que funcione con bus de datos de 4 u 8 bits, sin importar cómo estuvo
operando antes, es decir, podemos cambiar "al vuelo" entre un modo y otro.
Además de ello cada nueva instrucción debe ser enviada al LCD asegurándonos de que no se
encuentre ocupado. El LCD indica su disponibilidad mediante el llamado bit BF (Busy Flag).
BF = 1 indica LCD ocupado y BF = 0 es LCD listo. BF es el MSbit del byte que se lee del LCD
cuando el pin RS = 0. Obviamente la lectura implica que debemos poder controlar el pin RW.
De no usar este pin en nuestra conexión, debemos hacer pausas entre una instrucción y otra.
Pero incluso si usamos el bit BF, al inicio debemos poner pausas porque se supone que el LCD
aún no sabe si va trabajar con bus de datos de 4 u 8 bits y no sabe cómo responder a las
instrucciones de lectura (no sabe si entregar bytes enteros o en nibbles). Que enredo!, ¿verdad?
Por eso los siguientes flowcharts se ven tan complicados pese a tratarse de los LCD más simples
del mundo. La inicialización de los LCD gráficos por ejemplo es más pequeña.
Esta presentación es poco usual. Los libros o los manuales de los compiladores suelen resaltar
solo la interface de la librería que proveen. Esta exposición va pensando en los noveles
usuarios del Arduino, que encuentran algo confusa la inicialización de su librería de
LCD por contemplar tofdos los modos de operación viables.
Aunque los LCDs parezcan simples de usar, para bien o para mal sus características abren
puertas a diversos modos de interface. Considerando que el bus de datos puede ser de 8 o 4 bits
y que se puede usar o prescindir de la línea de control RW, podemos obtener los siguientes 4
tipos de conexión. (Nota, la conexión de los pines de alimentación, de contraste y de la
iluminación de fondo se estudia en la sección pines del LCD)
La interface de 11 líneas
se trabaja con los 8 bits del bus de datos y las 3 líneas de Control. El uso del pin RW controla
las operaciones de escritura (RW = 0) y lectura (RW = 1) del LCD.
Las lecturas nos permiten por un lado conocer si el LCD está ocupado o no para saber si
podemos enviar la siguiente instrucción de escritura, así como leer la posición actual del cursor.
La otra finalidad de las lecturas es obtener los datos de las memorias DDRAM y CGRAM del
LCD. Los datasheets dicen que el acceso bidireccional a las rams del LCD permiten utilizarlas
como memoria extendida del sistema. Ahora parece hasta ridículo pero tiene cierto sentido
considerando que estos LCDs nacieron en la prehistoria de los microcontroladores , donde los
microcontroladores tenían muy poca RAM o en su lugar se usaban microprocesadores (que
simplemente no tienen RAM).
En la interface de 10 lineas el pin RW del LCD va siempre plantado a GND (RW = 0). Ello
significa que el LCD solo aceptará operaciones de escritura del microcontrolador. Renunciar a
la lectura de las memorias RAM es un hecho que pasa casi desapercibido. El punto clave de no
controlar el pin RW es no enviar al LCD una nueva instrucción sin que haya terminado de
procesar la anterior. Ya que no podemos leer del LCD para saber su estado, debemos calcular su
disponibilidad a partir de los tiempos que demoran en ejecutarse las instrucciones. Por ejemplo,
una vez inviada la instrucción Clear Display debemos esperar al menos 1.6 ms (que es su
tiempo de ejecución) antes de enviar la siguiente instrucción.
En la interface de 7 líneas
el bus de datos del LCD se conecta con el microcontrolador por sus 4 pines más altos: D4, D5,
D6 y D7. Como todas las instrucciones (de datos y de comando) son de un byte, los bytes deben
ser transferidos en dos mitades. Primero se envía o recibe el nibble alto y luego el nibble bajo,
siendo cada nibble validado por un pulso del pin Enable. Esas rutinas extras harán crecer un
poco el firmware (programa del microcontrolador).
Los LCDs están fabricados con tecnología CMOS, por lo que algunos modelos sugieren
conectar los pines de entrada no usados a alguna señal estable para evitar que por ellos se filtre
algún ruido que pueda perturbar la operación del LCD.
Por último tenemos la interface de 6 líneas. Aquí se nos juntan todas las desventajas software de
tener que trabajar a base de nibbles y de renunciar a las lecturas del LCD para obtener datos de
sus memorias RAM o para saber si el LCD está ocupado o no antes de poder enviarle una nueva
instrucción. A pesar de todo eso, pueden darse ocasiones, como disponer de un
microcontrolador de muy pocos pines, donde tengamos que recurrir a esta conexión.
LABORATORIO 05
VISUALIZACION DE MENSAJES
1. Objetivo
Diseñar y desarrollar un programa utilizando el dsPIC33FJ12MC202 que despliegue el
siguiente mensaje: primera línea: UNAC-FIEE-2020A, segunda línea: APELLIDOS
2. Desarrollo.
Para mostrar cualquier mensaje en un LCD es necesario contar con las librerías xlcd.h y
xlcd.c.
Estas librerías contienen la configuración de la conexión del LCD con el dsPIC33FJMC202.
Adicionalmente en estas librerías se establece la programación para inicializar el LCD,
desplegar un carácter o una cadena de caracteres, la posición de escritura del LCD, y limpiar la
pantalla del LCD.
Existen diferentes librerías LCD para diferentes tipos de dsPICs pero todas cumplen con las
mismas funciones ya mencionadas.
En el caso del dsPIC33FJ12MC202 se tuvo que modificar la librería LCD para que ésta fuera
compatible con el DSPIC.
Teniendo estas librerías podemos mostrar cualquier mensaje, en la posición deseada con el
LCD. En la Tabla 1 se presenta el mensaje a desplegar.
Tabla 1. Mensaje a mostrar.
MENSAJE POSICION
FIEE-UNAC-2020A LINEA1
MICROCONTROLADORES LINEA2
3. Diagrama de flujo.
En la Fig. Se presenta el diagrama de flujo del programa desarrollado para el ejemplo 1. Se
observa al inicio del diagrama de flujo que se configura el programa, mediante el llamado de las
librerías y los encabezados, entre ellas se encuentran xlcd.h ( incluir: xlcd.c)
Posteriormente se habilita el puerto B en modo salida y el puerto A para controlar el LCD.
Hecho esto, se inicializa el LCD y se limpia pantalla. Se indica que posición tomará cada línea
del mensaje.
INICIO
LLAMADO DE X
LIBRERIAS
xlcd_inicializa
xllcd _limpiar
FIN
A continuación se presenta el código del programa del ejemplo 1, donde el color azul
representa palabras reservadas, identificadores o tipos de datos.
El verde indica que son comentarios que definen el uso de cada sentencia. Y el color negro son
los bloques de código.
5. Diagrama circuital.
En la Fig.2 se muestra el diagrama del circuito a implementar. En el se puede
Observar la conexión del dsPIC33FJMC202 donde el pin 1 está conectada al circuito RESET.
Del pin 2, 3 y 12 a los pines de control del LCD (RW, RS, E) y los Pines RB0, RB1, RB3 y
RB3 van conectados a los pines D4-D7 del LCD.
Los pines D0 al D3 del LCD deberán estar conectados a GND para no ocasionar conflicto con
los pines de datos que si están siendo utilizados.
El oscilador de cristal con sus respetivos capacitores se posiciona en los pines 9 y 10. Además
que es importante mantener alimentado todo el DSPIC para su correcto
6. Funcionamiento en proteus.
Ensamblaje y prueba.
LCD1
LM016L
VDD
VEE
VSS
RW
RS
D7
D6
D5
D4
D3
D2
D1
D0
E
14
13
12
11
10
9
8
7
6
5
4
3
2
1
R1 U1
10k
1 4
MCLR RB0/CN4/RP0/AN2/EMUD1/PGD1
20 5
VDDCORE RB1/CN5/RP1/AN3/EMUC1/PGC1
6
RB2/CN6/RP2/AN4
7
RB3/CN7/RP3/AN5
11
RB4/CN1/RP4/SOSCI/EMUD3/PGD3
14
RB5/CN27/RP5/ASDA1
28 15
AVDD RB6/CN24/RP6/ASCL1
27 16
AVSS RB7/CN23/RP7/INT0
17
RB8/CN22/RP8/SCL1/PWM2H1/TCK
18
RB9/CN21/RP9/SDA1/PWM2L1/TDO
21
RB10/CN16/RP10/PWM1H3/TDI
2 22
RA0/CN2/VREF+/AN0/EMUD2/PGD2RB11/CN15/RP11/PWM1L3/TMS
3 23
RA1/CN3/VREF-/AN1/EMUC2/PGC2 RB12/CN14/RP12/PWM1H2
9 24
RA2/CN30/CLKI/OSCI RB13/CN13/RP13/PWM1L2
10 25
1
RA3/CN29/CLKO/OSCO RB14/CN12/RP14/PWM1H1
12 26
RA4/CN0/T1CK/SOSCO/EMUC3/PGC3 RB15/CN11/RP15/PWM1L1
X1
CRYSTAL DSPIC33FJ12MC202
RV1
2
1k
38%
Finalmente se demostró que el programa junto con el diseño del circuito, funciona
correctamente.
Conclusiones
Recomendaciones
GRACIAS
////**************************************xlcd.h************************************************
#ifndef XLCD_H
#define XLCD_H
/* DATA_PORT defines the port to which the LCD data lines are connected */
//#define WRITE_DATA_PORT PORTD
//#define READ_DATA_PORT PORTD
#define DATA_PORT PORTB
#define TRIS_DATA_PORT TRISB
/* CTRL_PORT defines the port where the control lines are connected.
* These are just samples, change to match your application.
*/
#define RW_PIN LATAbits.LATA0 /* PORT for RW */
#define TRIS_RW TRISAbits.TRISA0 /* TRIS for RW */
#define RS_PIN LATAbits.LATA1 /* PORT for RS */
#define TRIS_RS TRISAbits.TRISA1/* TRIS for RS */
#define E_PIN LATAbits.LATA4 /* PORT for E */
#define TRIS_E TRISAbits.TRISA4 /* TRIS for E */
/* OpenXLCD
* Configures I/O pins for external LCD
*/
void OpenXLCD(unsigned char lcdtype);
/* SetCGRamAddr
* Sets the character generator address
*/
void SetCGRamAddr(unsigned char);
/* SetDDRamAddr
* Sets the display data address
*/
void SetDDRamAddr(unsigned char);
/* BusyXLCD
* Returns the busy status of the LCD
*/
unsigned char BusyXLCD(void);
/* ReadAddrXLCD
* Reads the current address
*/
unsigned char ReadAddrXLCD(void);
/* ReadDataXLCD
* Reads a byte of data
*/
char ReadDataXLCD(void);
/* WriteCmdXLCD
* Writes a command to the LCD
*/
void WriteCmdXLCD(unsigned char cmd);
/* WriteDataXLCD
* Writes a data byte to the LCD
*/
void WriteDataXLCD(char);
/* putcXLCD
* A putc is a write
*/
#define putcXLCD WriteDataXLCD
/* putsXLCD
* Writes a string of characters to the LCD
*/
void putsXLCD(char *);
/* putrsXLCD
* Writes a string of characters in ROM to the LCD
*/
void putrsXLCD(const char *buffer);
#endif /* XLCD_H */
//*********************************ARCHIVO xlcd.c*************************************************
#include <xc.h>
#include "reloj.h"
#include <libpic30.h>
#include "xlcd.h"
void Delay_1us( void )
{
__delay_us(1);
return;
}
/* Provide at least a 15ms delay */
void DelayPORXLCD( void )
{
__delay_ms(200);
return;
}
/* Provide at least a 5ms delay */
void DelayXLCD( void )
{
__delay_ms(5);
return;
}
void XLCDInit(void)
{ unsigned char i;
/* ----------------------------- Inicializacion del LCD 2x16 --------------------------------------------------*/
DelayPORXLCD(); // retardo incial para que la tension de alimentacion se
estabilice
OpenXLCD( FOUR_BIT & LINES_5X7); // Initialize LCD
DelayXLCD(); // Retardo de por lo menos 4.1 ms
WriteCmdXLCD( DON & CURSOR_OFF & BLINK_OFF ); // Set parameters
DelayXLCD(); // Retardo de por lo menos 4.1 ms
WriteCmdXLCD(CLEAR_XLCD);
DelayXLCD(); // Retardo de por lo menos 4.1 ms
WriteCmdXLCD(0x80); // Escribe el comando para poner el cursor a una
dirección en la memoria DDRAM
DelayXLCD(); // Retardo de por lo menos 4.1 ms
}
void XLCD_WriteChr_CGRAM( const char *buffer, unsigned char Addres)
{ unsigned char i=0;
SetCGRamAddr(Addres*8);
for (i=0;i<8;i++) // Write data to LCD up to null
{ WriteDataXLCD(*buffer); // Write character to LCD
++buffer;
}
}
void OpenXLCD(unsigned char lcdtype)
{
//TRIS_PWR = 0; // PWR control pin made output
//PWR_PIN = 1; // Power LCD
DelayPORXLCD(); // Delay 15ms
#endif
E_PIN = 1; // Clock the cmd in
Delay_1us();
E_PIN = 0;
// Clear display
while(BusyXLCD()); // Wait if LCD busy
WriteCmdXLCD(0x01); // Clear display
return;
}
#endif
Delay_1us();
E_PIN = 1; // Clock cmd and address in
Delay_1us();
E_PIN = 0;
#ifdef UPPER // Upper nibble interface
TRIS_DATA_PORT |= 0xf0; // Make inputs
#else // Lower nibble interface
TRIS_DATA_PORT |= 0x0f; // Make inputs
#endif
#endif
return;
}
char ReadDataXLCD(void)
{
char data;
while(BusyXLCD());
#ifdef BIT8 // 8-bit interface
RS_PIN = 1; // Set the control bits
RW_PIN = 1;
Delay_1us();
E_PIN = 1; // Clock the data out of the LCD
Delay_1us();
data = DATA_PORT; // Read the data
E_PIN = 0;
RS_PIN = 0; // Reset the control bits
RW_PIN = 0;
#else // 4-bit interface
RW_PIN = 1;
RS_PIN = 1;
Delay_1us();
E_PIN = 1; // Clock the data out of the LCD
Delay_1us();
#ifdef UPPER // Upper nibble interface
data = DATA_PORT&0xf0; // Read the upper nibble of data
#else // Lower nibble interface
DATA_PORT |= cmd&0x0f;
#endif
Delay_1us();
E_PIN = 1; // Clock command in
Delay_1us();
E_PIN = 0;
#ifdef UPPER // Make data nibble input
TRIS_DATA_PORT |= 0xf0;
#else
TRIS_DATA_PORT |= 0x0f;
#endif
#endif
return;
}
Archivos adicionales:
//**************config1.h**************************************
// FBS
#pragma config BWRP = WRPROTECT_OFF // Boot Segment Write Protect (Boot Segment
may be written)
#pragma config BSS = NO_FLASH // Boot Segment Program Flash Code Protection (No
Boot program Flash segment)
// FGS
#pragma config GWRP = OFF // General Code Segment Write Protect (User program
memory is not write-protected)
#pragma config GSS = OFF // General Segment Code Protection (User program
memory is not code-protected)
// FOSCSEL
#pragma config FNOSC = PRI // Oscillator Mode (Primary Oscillator (XT, HS, EC))
#pragma config IESO = ON // Internal External Switch Over Mode (Start-up device
with FRC, then automatically switch to user-selected oscillator source when ready)
// FOSC
#pragma config POSCMD = XT // Primary Oscillator Source (XT Oscillator Mode)
#pragma config OSCIOFNC = OFF // OSC2 Pin Function (OSC2 pin has clock out
function)
#pragma config IOL1WAY = ON // Peripheral Pin Select Configuration (Allow Only One
Re-configuration)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Both Clock
Switching and Fail-Safe Clock Monitor are disabled)
// FWDT
#pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler (1:32,768)
#pragma config WDTPRE = PR128 // WDT Prescaler (1:128)
#pragma config WINDIS = OFF // Watchdog Timer Window (Watchdog Timer in Non-
Window mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable (Watchdog timer
enabled/disabled by user software)
// FPOR
#pragma config FPWRT = PWR128 // POR Timer Value (128ms)
#pragma config ALTI2C = OFF // Alternate I2C pins (I2C mapped to SDA1/SCL1 pins)
#pragma config LPOL = ON // Motor Control PWM Low Side Polarity bit (PWM module
low side output pins have active-high output polarity)
#pragma config HPOL = ON // Motor Control PWM High Side Polarity bit (PWM
module high side output pins have active-high output polarity)
#pragma config PWMPIN = ON // Motor Control PWM Module Pin Mode bit (PWM
module pins controlled by PORT register at device Reset)
// FICD
#pragma config ICS = PGD1 // Comm Channel Select (Communicate on
PGC1/EMUC1 and PGD1/EMUD1)
#pragma config JTAGEN = OFF // JTAG Port Enable (JTAG is Disabled)
#include <xc.h>
//*******************reloj.h******************************
define FCY 4000000
#define BAUDRATE 9600
#define BRGVAL ((FCY/BAUDRATE)/16)-1