Autor Tema: Glcd 12864B  (Leído 273 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Trust

  • PIC16
  • ***
  • Mensajes: 141
Glcd 12864B
« en: 17 de Junio de 2017, 14:59:16 »
Hola, estoy unos dias haciendo pruebas con la lcd grafica que me he comprado, es de las mas baratas que usan el controlador st7920.
Estoy buscando informacion en decenas de páginas y no encuentro la solución.
Encontre el driver st7920.h  pero al compilarlo me da error, en este mismo foro hay un temas sobre este problema pero es de hace ya unos años y no se dio con la solución.
Veo que hay unas 2 tipos de glcd, unas que llevan 2 pines de chip selection, y la que yo tengo que lleva un pin PSB( para elegir entre paralelo o serie), entonces hay ejemplos que usan los pines de chip selection y mi glcd no tiene esos pines, pruebo la libreria que en teoria funciona con mi glcd y tampoco lo consigo.

No se si alguien me podra ayudar, hay gente que dice "leete el datasheet", si lo leo pero no entiendo nada.
Uso CCS.
Pongo la libreria st7920.h
Código: [Seleccionar]
/************************************************************************
*   LCD graphics driver for Digole 12864w with ST7920 driver using       *
*   CCS software. May work with other ST7920 driven LCD. It has          *
*   the following Pin assignments                                        *
*                                                                        *
*   Pin 1 ------------> Gnd                                              *   
*   Pin 2 ------------> +5volts                                          *
*   Pin 3 ------------> Contrast                                         *
*   Pin 4 ------------> Register Select                                  *
*   Pin 5 ------------> Read/Write                                       *
*   Pin 6 ------------> Enable                                           *
*   Pin 7-14 ---------> Data bits                                        *
*   Pin 15 -----------> PSB (parallel=high & serial=low)                 *
*   Pin 16 -----------> NoConnection                                     *
*   Pin 17 -----------> Reset                                            *
*   Pin 18 -----------> Vout                                             *
*   Pin 19 -----------> +5volts                                          *
*   Pin 20 -----------> Gnd                                              *
*                                                                        *
*   This driver is using 8bit parallel operation for optimal RAM         *
*   requirements, if you want i can change it to 4 bit operation.        *
*                                                                        *
*   Developed by Christian Rebogio                                       *
*   suggestions and request please email me at                           *
*   christian.rebogio@gmail.com                                          *
*                                                                        *
* READ THE DATASHEET FOR ST7920!!!!!!!                                   *
************************************************************************/
// change the pin assignment depending on your circuit

#define  rs  PIN_D4                    //COMMNAD/DATA SELECT
#define  rw  PIN_D5                    //READ/WRITE SELECT             
#define  e   PIN_D6                 //ENABLE SIGNAL                 
#define  rst PIN_D1                    //RESET SIGNAL   

#define ON   1
#define OFF   0
#define XVAL 16  // 16 X 16 or 256 for there is 8 word values for the upper and lower
#define YVAL 32

// PSB is tied to Vcc for this driver because this driver uses Parallel
// operation.
// data is sent using port B so change output_b() to other ports you
//want to use. Dont for get to change the Busy pin @ lcd_check_busy

#define GLCD_WIDTH   128



//////////////////////////////////////////////////////////////////////////////////
//The following are the functions included in this driver file
// glcd_readbyte();
// glcd_instruction( instruction );
// glcd_data( data ); - data can be an array of characters!
// glcd_check_busy();
// glcd_update(); -must be called always after writing a pixel or using functions
//                 from GRAPHICS.C .. Only applicaticable in Graphing mode
// glcd_fillscreen( ON or OFF);
// glcd_init_graph(); initialize for graphing mode
// glcd_init_basic(); initilize for accessing the stored Characters
//                     you can use glcd_data() for writing text
// glcd_pixel(x coordinate, y coordinate, ON or OFF); 
//            -WORKS WITH GRAPHIC.C  from CCS Drivers
// glcd_plot_image(width,height,X coor, Y coor, inverse);
//            -plots the image[] array. Declare it first before this driver.
//             or modify this driver
//
//////////////////////////////////////////////////////////////////////////////////



typedef union
{
  int16 word;
  int8 nbyte[2];
} Dots;

typedef struct
{
  int1 refresh;
  Dots pix[YVAL][XVAL];   // Max dimensions for display (x,y) = (128,32)
  } GD_RAM;             //  (0,0) corresponds to upper lefthand corner.

GD_RAM gdram;


unsigned int8 glcd_readByte (unsigned int1 address)
{
  unsigned int8 data;   // Stores the data read from the LCD
  if(address==1){
     output_high(rs);
  }
  if(address==0){
     output_low(rs);
  }
  output_high(rw);//GLCD_RW = RW_READ;      // Set for reading
  output_high(e);//GLCD_E = 1;      // Pulse the enable pin
  delay_us(1);
  data=input_b();      // Get the data from the display's output register
  output_low(e);//GLCD_E = 0;
  return (data);
}

 
void glcd_check_busy(){
   int1 busy=1;
   output_low(rs);      // LOW RS and High RW will put the lcd to
   output_high(rw);      // read busy flag and address counter
   while(busy){         // will cycle until busy flag is 0
      output_high(e);
      if(!input(PIN_B7)){
         busy=0;
      }
      output_low(e);
   }
}
 
void glcd_instruction(unsigned char x){
   glcd_check_busy();      //must be satisfied before sending instruction
   output_low(rs);      // LOW RS and LOW RW will put the lcd to
   output_low(rw);      // Write instruction mode
   output_b(x);         // 8bit data to bus
   output_high(e);      // enable
   delay_us(1);       
   output_low(e);      // disable
}
void glcd_data(unsigned char x){
   glcd_check_busy();
   output_high(rs);      // HIGH RS and LOW RW will put the lcd to
   output_low(rw);      // Write data register mode
   output_b(x);
   output_high(e);
   delay_us(1);
   output_low(e);
}
 

void glcd_fillScreen (unsigned int1 color)
{
  int8 v, h;
  int16 d;


  d = (color == ON ? 0xFFFFL : 0x0000L);

  for (v=0; v < YVAL; v++)
  {
    for (h=0; h < XVAL; h++)
    {
      gdram.pix[v][h].word = d;
    }
  }
  gdram.refresh = TRUE;
}


void glcd_update ()
{
  int8 v, h;


  if (gdram.refresh)
  {
    for (v=0; v <YVAL; v++)
    {
      glcd_instruction( 0x80 | v);   // Set Vertical Address.
      glcd_instruction( 0x80 | 0);   // Set Horizontal Address.

      for (h=0; h <XVAL; h++)
      {
        glcd_data( gdram.pix[v][h].nbyte[1]);   // Write High Byte.
        glcd_data(  gdram.pix[v][h].nbyte[0]);   // Write Low Byte.
      }
    }
    gdram.refresh = FALSE;
  }
}

void glcd_init_graph(){
   delay_ms(40);
   output_low(rst);         //reset LCD
   delay_us(1);                     
   output_high(rst);        //LCD normal operation
   glcd_instruction(0x30);   //set 8 bit operation and basic instruction set
   delay_us(144);
   glcd_instruction(0x0C);   //display on cursor off and char blink off
   delay_us(100);
   glcd_instruction(0x01);   //display clear
   delay_ms(10);
   glcd_instruction(0x06);   //entry mode set
   delay_us(72);                 
  glcd_instruction(0x34);    // Select extended instruction set.
  delay_ms (10);
  glcd_instruction(0x36);    // Graphic display ON.
  delay_ms (10);

  glcd_fillScreen (OFF);
  glcd_update ();

}

void glcd_init_basic(){
   delay_ms(40);
   output_low(rst);         //reset LCD
   delay_us(1);                     
   output_high(rst);        //LCD normal operation
   glcd_instruction(0x30);   //set 8 bit operation and basic instruction set
   delay_us(144);
   glcd_instruction(0x0C);   //display on cursor off and char blink off
   delay_us(100);
   glcd_instruction(0x01);   //display clear
   delay_ms(10);
   glcd_instruction(0x06);   //entry mode set
   delay_us(72);                 
}

void glcd_pixel(int8 x, int8 y, int1 color)
{
  int8 v, h, b;
  if(y>31){x += 128; y-= 32;};
  v = y;
  h = x/16;
  b = 15 - (x%16);
 
  if (color == ON) bit_set (gdram.pix[v][h].word, b);
  else bit_clear (gdram.pix[v][h].word, b);

  gdram.refresh = TRUE;
}

void glcd_plot_image(int width,int height,int x,int y,int inverse)
{
   unsigned int i=0, j=0, k=0;
   unsigned int16 count=0;
   //glcd_fillScreen(OFF);                        //Clears the screen (opt.)
   for(j=0;j<height;j++)
      {   
         for(;i<width;)
         {
            for(k=8;k>0;k--){
               if(inverse)glcd_pixel(i+x,j+y,~bit_test(image[count],(k-1)));
               else glcd_pixel(i+x,j+y,bit_test(image[count],(k-1)));
               
               i++;
            }
            count++;
         }
      i=0;
      }
}
//credits to http://www.ccsinfo.com/forum/viewtopic.php?t=32819&highlight=st7920//
///////////////////////////////////////////////////////////////////////////////////


Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 5829
Re:Glcd 12864B
« Respuesta #1 en: 17 de Junio de 2017, 15:36:04 »
Citar
No se si alguien me podra ayudar, hay gente que dice "leete el datasheet", si lo leo pero no entiendo nada.

"No Entiendo nada", es lo que siempre un alumno le dice a su profesor cuando esta mirando o pensando en otra cosa cuando este explica, y no prestando atencion o no hizo el esfuerzo.

Si lo leiste algo tenes que entender, Si abriste el PDF leiste 1 pagina y viste que eran 42 y las pasaste a todas mirando los graficos pensando que alguno te lo va a explicar todo rara ves ocurre.. es complicado que entiendas algo si hiciste esto.

¿Que es lo que no entendes del datasheet?
Prefiero explicar como guiarte en lo que dice el datasheet que acomodar el programa, te va a servir para otros micros por igual
« Última modificación: 17 de Junio de 2017, 15:39:55 por KILLERJC »

Desconectado Trust

  • PIC16
  • ***
  • Mensajes: 141
Re:Glcd 12864B
« Respuesta #2 en: 17 de Junio de 2017, 16:51:51 »
Entiendo muy poco y no se como empezar para empezar un driver o modificar otro.
Buscaré algun tutorial sobre realizar drivers aunque pienso que eso es para programadores avanzados y yo aunque llevo varios años, aun sigo en nivel principiante.
Si que me gustaría tener una guía de saber interpretar lo que dice el datasheet, gracias por tu respuesta, siempre estás aquí ayudando a la gente.
« Última modificación: 18 de Junio de 2017, 01:07:59 por Trust »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 5829
Re:Glcd 12864B
« Respuesta #3 en: 19 de Junio de 2017, 20:42:09 »
Este el el PDF que vamos a usar:

http://www.lcd-module.de/eng/pdf/zubehoer/st7920_chinese.pdf

El datasheet es de un driver de LCD, uno acostumbra a ver el LCD como una pieza, pero en realidad tiene ese integrado que es el driver el cual conecta cada uno los sementos del LCD y ademas provee una interfaz. Por eso cuando ves el datasheet y te encontras con los pines , ves que son 136..

Pero esto no nos afecta. Si manejaste un LCD 2x16 es muy parecido, en un LCD 2x16 lo que haces es primero "inicializar" el LCD. Luego para empezar a escribir en el LCD debes definir la direccion de la RAM donde vas a comenzar a escribir y luego proceder a escribir que solo va incrementandose la direccion de la memoria RAM dentro del LCD.
Luego el IC driver lee esa RAM y lo muestra en el LCD.

Entonces lo unico que hacemos al manejar un LCD es escribir una RAM y luego el driver se encarga de Actualizar el LCD con lo que nosotros pusimos.

La mayor diferencia es que en un LCD 2x16 uno escribe una de esas 32 posiciones, mientras que en un GLCD se hace punto a punto (pixel a pxiel). Hay otras salvedades.

-----------------------------------------------------------------------------
INTERFAZ

Entonces comenzamos, primero necesitamos saber como podemos conectarlo Leyendo al comienzo de la pagina 10 dice:

Citar
ST7920 supports 3 kinds of bus interface to MPU. 8 bits parallel, 4 bits parallel and clock synchronized serial interface

Dice que soporta 3 formas de interfaz, 8 bits, 4 bits y serial ( SPI) ocurre que casi siempre esto se selecciona con algunos pines del driver, los cuales no son accesibles y que dependen de quien armo el modulo del LCD y como lo conectó, por ejemplo en la libreria que vos pasaste usa una interfaz de 8bits. Vos vas a tener que revisar que la placa que tenes que conecciones te dan para determinar cual tenes ( o es 8bits o es SPI )

Esos son los pines de datos. Vamos a ver con un poco mas de detalle la comunicacion. Si vamos a la pagina 25 tenemos el interfaz paralelo ( 8 y 4 bits) Si observas en los graficos tenemos para los 8 bits, necesitamos 8 pines para datos, mas 3 de control ( E, RS y RW ). Si vamos a la descripcion de los pines tenemos que:

RS : Register Select
 0 -> Escritura de Instruccion, Lectura de flag de ocupado, Lectura del contador de direccion
 1 -> Escritura, Lectura de datos

RW:
 0 -> Escritura
 1 -> Lectura

E: Habilita disparador

Lo bueno de esos graficos es que te muestran en el tiempo como seria una comunicacion. Por ejemplo al principio RS esta en 0 ( una instruccion ), se ponen los 8 bits de la instruccion y se le da un pulso al pin E. Tal ves supongamos que estaba leyendo algo, ya que RW estaba en 0. Luego decide escribir un dato RS=1, RW=1 se pone el dato y se da un pulso en E.

-----------------------------------------------------------------------
INSTRUCCIONES

Vamos a saber que instrucciones tenemos, para decirle que escriba o decirle en que direccion comienze a contar, esto lo tenemos en la pagina 16. Alli comienza con todas las instrucciones, son bastantes, si lees algunas tenes: Limpiar, Volver al comienzo, Escribir RAM, Leer RAM, Se direccion de la DDRAM,  Display on/off (aca tenes el cursor, que parpadee y poder apagar el display)

Esa tabla resume bastante las instrucciones y tambien te dice que valor deben tomar RS y RW
A partir de la pagina 19 comienza bien detallado las instrucciones, por ejemplo en DISPLAY STATUS, te dice que es cada bit, que funcion cumple en esa instruccion. Algunos son fijos y otros podes modificarlo para acomodar a lo que te gusta.

--------------------------------------------------------------------------------------
INICIALIZACION

Dijimos que esto era igual que un LCD 2x16. Y que debiamos inicializarlo, Pero como? Que debemos enviarle?
En la pagina 28 el PDF nos da la inicializacion para 8bits.
Observa que apenas se alimenta el modulo, uno debe esperar 40ms antes de enviar el primer comando/instruccion, donde tiene las X no importa el valor que se le envie, lo importante es respetar los tiempos y los valores.

Una ves inicializado el LCD procedes a Setear la direccion de DDRAM y escribir.

-------------------------------------------------------------------------

Ahora ya podes entender masomenos que es lo del datasheet.

Miremos tu libreria. La inicializacion que es la funcion glcd_init_graph cumple con lo que dice el datasheet, tal ves posea algunas instrucciones mas.

Veamos si envia una instruccion:

Código: C
  1. void glcd_instruction(unsigned char x){
  2.    glcd_check_busy();      //must be satisfied before sending instruction
  3.    output_low(rs);      // LOW RS and LOW RW will put the lcd to
  4.    output_low(rw);      // Write instruction mode
  5.    output_b(x);         // 8bit data to bus
  6.    output_high(e);      // enable
  7.    delay_us(1);        
  8.    output_low(e);      // disable
  9. }
Revisa si esta ocupado, pone RS a 0 y RW a 0, es decir lectura e instruccion.
Luego pone la instruccion en el puertoB, los 8 bits.
Finalmente da un pulso en el pin E.

Que es exactamente lo que nos mostraba el grafico cuando vimos como era la interfaz.
Luego tenes muchas mas funciones dentro de la libreria, Lo que a veces usan es crear una RAM igual en el micro de esa forma cuando se cambia algo, se cambia en el micro, y luego tenes que llevarlo al LCD.

---------------------------------------------------

Una ultima gota mas de explicacion. Ya deberias tener una idea de como manejarte con el LCD, pero al comienzo hable sobre que el LCD tiene una memoria interna, lo que escribimos es realmente esa memoria que yo le llame simplente RAM. Pero si leiste el datasheet te encontras con VARIAS memorias GDRAM, IRAM, CGRAM, DDRAM, (CGROM aunque no es una RAM).

el GDRAM es la memoria que se lee y se muestra en el LCD por eso esta memoria va a tener 64 filas de 128 columnas, cada pixel es 1bit. Esto lo podes ver en la pagina 15. Entonces por cada fila podes enviar hasta 16bytes. los cuales esos bits van a encender y apagar cada pixel de esa primer fila. En ves de enviar Caracteres completos envias pixel a pixel. Esto es lo mas comun que vas a usar, entonces si queres usar una letra por ejemplo, vas a tener que dibujar la letra pixel a pixel.

Como se hace para escribir en un punto en especifico? Se debe seleccionar la direccion vertical primero y luego la horizontal, explicado en la pagina 12

Que pasa con las otras RAM/ROM?
CGROM = Es una memoria donde se guardan letras y numeros para que puedan ser usados en la DDRAM algunos de 16x16 pixel y otros de 8x8.
CGRAM = A veces se necesita algun caracter especial, entonces aca uno puede crear el caracter especial y luego usarlo.
IRAM = Lo mismo que la CGROM nomas que aca son iconos

Lo que no logro comprender porque no esta explicado, es ... Donde se muestra la DDRAM, ya que supuestamente son 2 lineas y podrias usar letras que se encuentran dentro de la ROM del driver.

Desconectado Trust

  • PIC16
  • ***
  • Mensajes: 141
Re:Glcd 12864B
« Respuesta #4 en: 20 de Junio de 2017, 04:09:50 »
Hola KILLERJC, de verdad muchas gracias por el esfuerzo en explicarme tan bien el funcionamiento de la Glcd.  Me has motivado mucho y quiero hacer que funcione mi glcd. Trabajo 11 horas al día y ahora mismo estoy cansado como para meterme de lleno a hacer prueba, pero en cuanto tenga un rato cada día lo intentaré.
He visto muchos códigos que no entiendo bién y pienso que ahora gracias a tu explicación les puedo dar más sentido a cada línea. Tengo muchas dudas sobre cómo guardan en la gdram los datos y los envían a la glcd, yo lo haría de otra forma aunque seguro que sería menos eficiente, pero por lo menos lo entendería.
Si logro hacer un código que funcione lo pondré aquí, que seguro que hay usuarios que se atascan con estas glcd.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 5829
Re:Glcd 12864B
« Respuesta #5 en: 20 de Junio de 2017, 13:48:59 »
La GDRAM esta en el integrado driver ( el ST7920 )

Si queres escribir esa memoria, primero debes seleccionar que direccion vas a grabar, suponete que queres hacer una linea horizontal continua a la mitad del LCD, entonces deberia hacer un codigo que me seleccione la direccion vertical 31 y horizontal 0, y luego de alli llenarlo con unos (1 en datos) toda la linea.

Me fijo en las instrucciones y me dice que debo enviar:
RS = 0
RW = 0
El primer byte a enviar es el vertical y que va de 0 a 63, yo voy a enviar 31
El segundo byte es la direccion horizontal asi que debe ser 0.

Cada ves que ponga uno de esos bytes procedo a dar el pulso en E.

Ya ahi tengo seteado la direccion de la memoria donde vamos a empezar a cargar los valores
Ahora falta enviar los valores para eso tenemos la instruccion WRITE RAM
RS = 1
RW = 0
Y en los datos le enviamos 0xFF
damos pulso en E

Y como tenemos el mismo dato, simplemente repetimos la operacion unas 9 veces para completar la linea.

------------

A veces en los microcontroladores como te decia se crea "una imagen" de la RAM del LCD, de esa forma si uno modifica algo lo hace en el micro. Porque es mas rapido de operar  y luego enviar, que intentar hacer todo junto. Especialmente en micros con DMA. Entonces te vas a encontrar con librerias que tienen un arrays de 64x128bits
como el que pasaste vos. Ejemplo aca creaste una estructura llamada GD_RAM (pensalo como agrupacion) en el cual el que dice pix es de 16 bits

Código: C
  1. typedef struct
  2. {
  3.   int1 refresh;
  4.   Dots pix[YVAL][XVAL];   // Max dimensions for display (x,y) = (128,32)
  5.   } GD_RAM;             //  (0,0) corresponds to upper lefthand corner.
  6.  
  7. GD_RAM gdram;

Es como poner:

Código: C
  1. int16 pix[32][16]

Este es el caso de tu libreria, si observas solo piensa en 32 filas de 16 x 16 = 256 bits. A pesar que el driver maneje el total de 64x256 bits, este posee conectado un LCD de 64x128. Asi que lo logico seria que fuera asi:

Código: C
  1. int16 pix[64][8]

o

Código: C
  1. int8 pix[64][16]

El problema de esto es que necesitas que tu micro tenga una memoria de 64 x 16 = 1024 bytes o 1KB destinado unicamente al GLCD.