Controlando un GLCD GDM12864-5 con controlador ST7920 usando CCS C y PIC18F25K22
- Resolución:
128×64. - Se divide en 32 filas (
YVAL=32) de 16 palabras de 16 bits (XVAL=16). - Cada palabra (16 bits) representa 16 píxeles horizontales.
glcd_DrawPixel(x,y,...)calculav=y,h=x/16,b=15-(x%16).- Para
y>31se compensax+=128(metodología usada en este driver). - Lecturas y “busy flag” conmutan
TRISBa entrada temporalmente. - Se aumentaron los
delay_us()alrededor deEpara robustez. - Comandos de inicialización siguen la secuencia del datasheet (doble
0x30, gráfico 0x34/0x36). glcd_init_graph(): modo gráfico (recomendado para dibujar). Limpia y actualiza.glcd_init_basic(): modo básico (texto interno del ST7920).glcd_instruction(uint8),glcd_data(uint8): envío al LCD.glcd_readByte(address): lectura (respeta TRISB).glcd_check_busy(): espera a que BF=0 (PIN_B7).glcd_DrawPixel(int8 x,int8 y,int1 color): dibuja engdramy marcarefresh=TRUE.glcd_fillScreen(ON|OFF): rellena GDRAM con 1 o 0; marcarefresh=TRUE.glcd_update(): vuelca toda la GDRAM al LCD (sirefresh==TRUE).- Alimentación estable: desacopla con 100 nF cerca del LCD y del PIC; añade 10 µF en la línea de 5 V.
- RST (C3): el driver asertará reset al iniciar; puedes añadir un pull-up (~10 kΩ) si tu placa lo requiere.
- Entradas flotantes: si usas teclas/entradas, usa resistencias de pull-up/pull-down para evitar ruido que cause cuelgues.
- Temporizado: si subes el clock o cambias de PIC, conserva o incrementa ligeramente los
delay_us()alrededor deE. - Refresh: llama a
glcd_update()sólo cuando termines un “lote” de dibujo; reduce parpadeo y tráfico al LCD. - Compatibilidad:
PSBa Vcc (paralelo); si usas serial del ST7920, este driver no aplica. - Se borra la pantalla al rato: revisa alimentación y ruido; agrega pull-ups donde proceda; mantén delays y no llames
update()en bucles ultra-rápidos sin necesidad. - Pantalla en blanco: confirma
PSB→Vcc, orden de init (doble 0x30), y conexiones de datos D0–D7 con PORTB. - Texto/bitmap invertido: verifica la función que genera el array (MSB-first) y la dirección de bits en
glcd_DrawPixel()(b = 15 - (x%16)).
Resumen del funcionamiento

RS→C0, RW→C1, E→C2, RST→C3.
La línea PSB del display debe ir a Vcc (modo paralelo).
El render se hace en RAM de usuario (gdram) y se “vuelca” al LCD con
glcd_update(). Esto evita parpadeos y permite dibujar múltiples píxeles/figuras antes de refrescar.
Funcionamiento en físico
Mapa de memoria lógico
Protocolo y temporizado
API del Driver
Inicialización
Acceso de bajo nivel
Rasterizado en RAM y refresco
Importante: Las operaciones que dibujan sólo modifican la memoria del usuario.
Nada se verá en el LCD hasta llamar a
glcd_update(). Puedes dibujar muchas cosas y actualizar una sola vez.
Ejemplo mínimo (inicio + píxel + pantalla llena)
// <main.c> – CCS C (ejemplo mínimo)
// Ajusta fuses/clock según tu proyecto
#include <18F25K22.h>
#device ADC=10
#fuses NOWDT, INTRC_IO, NOMCLR, NOLVP, PUT, NOCPD
#use delay(internal=64MHz)
// Incluye tu driver tal cual lo compartiste
#include "st7920_driver.c" // renombra con el nombre real del archivo
void main(void)
{
glcd_init_graph(); // Modo gráfico
glcd_fillScreen(OFF); // Limpia la GDRAM (apagado)
glcd_update(); // Refresca LCD
// Dibuja un píxel en (10,10)
glcd_DrawPixel(10, 10, ON);
glcd_update(); // ¡Ahora se ve!
while(TRUE) { }
}
Ejemplo: dibujar una línea horizontal y un rectángulo hueco
Como el driver expone sólo DrawPixel, aquí van helpers simples para figuras básicas:
// Helpers sencillos basados en DrawPixel
void glcd_hline(int x1, int x2, int y, int1 c){
int x; if(x2<x1){int t=x1; x1=x2; x2=t;}
for(x=x1;x<=x2;x++) glcd_DrawPixel(x,y,c);
}
void glcd_vline(int x, int y1, int y2, int1 c){
int y; if(y2<y1){int t=y1; y1=y2; y2=t;}
for(y=y1;y<=y2;y++) glcd_DrawPixel(x,y,c);
}
void glcd_rect_hollow(int x1,int y1,int x2,int y2,int1 c){
glcd_hline(x1,x2,y1,c);
glcd_hline(x1,x2,y2,c);
glcd_vline(x1,y1,y2,c);
glcd_vline(x2,y1,y2,c);
}
// Uso
glcd_fillScreen(OFF);
glcd_hline(5, 122, 10, ON);
glcd_rect_hollow(20, 20, 100, 50, ON);
glcd_update();
Ejemplo: texto 5×7 escalable (si ya tienes font5x7[])
Si tu proyecto incluye font5x7 y la rutina glcd_text57() (la que compartiste), úsala así:
extern const unsigned int8 font5x7[][5];
void glcd_text57(int x,int y,char* text,int size,int1 color); // tu implementación
glcd_fillScreen(OFF);
glcd_text57(2, 2, "HELLO", 1, ON); // 5x7
glcd_text57(2, 14, "WORLD", 2, ON); // 10x14
glcd_text57(2, 32, "GLCD", 3, ON); // 15x21 (triplicado)
glcd_update();
Ejemplo: animación suave (sin parpadeo)
Dibuja varias cosas y refresca una sola vez por fotograma:
int x = 5, y = 24, dx = 1;
while(TRUE){
glcd_fillScreen(OFF); // limpia el backbuffer (GDRAM)
glcd_rect_hollow(x, y, x+20, y+10, ON);
// ... (dibuja más cosas si quieres)
glcd_update(); // 1 solo refresco
x += dx;
if(x<=0 || x+20>=127) dx = -dx;
delay_ms(30);
}
Buenas prácticas y notas eléctricas
Tabla rápida de pines y macros
// Señales (PORTC)
#define rs PIN_C0 // Register Select
#define rw PIN_C1 // Read/Write
#define e PIN_C2 // Enable
#define rst PIN_C3 // Reset
// Datos (PORTB, D0..D7)
output_b(value); // Escribe 8 bits
input_b(); // Lee 8 bits
set_tris_b(mask); // Dirección del puerto (1=input)
/* Conexiones sugeridas:
ST7920 D0..D7 <—> PIC PORTB RB0..RB7
ST7920 RS <—> PIC RC0
ST7920 RW <—> PIC RC1
ST7920 E <—> PIC RC2
ST7920 RST <—> PIC RC3
ST7920 PSB —> Vcc (paralelo)
Vdd/Vss/VO/LED según módulo
*/
Solución de problemas
Este driver probado físicamente permite un control completo del GLCD, integrando gráficos y texto en proyectos embebidos de forma eficiente.