-- Título: GLCD_ks0108_optimizado.
-- Autor: David Persi Copyright (c) 2012..2012, Todos los derecho reservados.
-- WEB: www.meteorologiafacil.com.ar
--
-- Versión: 2.1
-- 
-- 
-- Descripción: Librería optimizada para el GLCD KS0108 128x64
--              Solo se dispone de lo básico para controlar dicho GLCD.
--              Se decidió así, para ahorrar memoria en el PIC.
--
-- INSTRUCCIONES DE USO:
-- ---------------------
-- 1. Definir las constantes que acontinuación se detalla, según sus necesidades
--	  para conectar el GLCD al PIC:
--
---var volatile byte GLCD_DATAPRT is portd
-- var volatile byte GLCD_DATAPRT_DIR is portd_direction
-- var volatile bit GLCD_DI is pin_b0
-- var volatile bit GLCD_RW is pin_b1
-- var volatile bit GLCD_E	is pin_b2
-- var volatile bit GLCD_CS1 is pin_b3
-- var volatile bit GLCD_CS2 is pin_b4
-- var volatile bit GLCD_RST is pin_b5
-- var volatile bit GLCD_DI_DIRECTION is pin_b0_direction
-- var volatile bit GLCD_RW_DIRECTION is pin_b1_direction
-- var volatile bit GLCD_E_DIRECTION is pin_b2_direction
-- var volatile bit GLCD_CS1_DIRECTION is pin_b3_direction
-- var volatile bit GLCD_CS2_DIRECTION is pin_b4_direction
-- var volatile bit GLCD_RST_DIRECTION is pin_b5_direction
--
-- NOTA: Los pines del PIC se puede cambiar a elección de cada uno según sus necesidades.
--
-- 2. Incluir la librería delay, (debe ir antes de la presente librería).
-- 3. Incluir la presente librería.
-- 4. Iniciar al GLCD con glcd_ini()
-- 5. Trabajar a gusto.
--
-- IMPORTANTE:
-- ----------
-- EJE HORIZONTAL (X): EL VALOR DEL PRIMER PIXEL ES 0, Y EL ÚLTIMO ES 127
-- EJE VERTICAL (Y):   EL VALOR DEL PRIMER PIXEL ES 0, Y EL ÚLTIMO ES 63
--
-- Las funciones y procedimiento para el usuario, empiezan con palabras.
-- Aquellas que comienzan con un guión bajo "_" son de uso interno. Si usted
-- desea utilizarlas, no hay problema. Estúdielas bien.
--
-- INTRUCCIONES PARA EL USO DE FUNCIONES Y PROCEDIMIENTOS:
-- -------------------------------------------------------
--
-- glcd_ini()              Inicializa al GLCD. Solo se debe ejecutar una vez.
-- glcd_llenar(llenar)     Enciende (1) y apaga (0) a todo los pixeles del GLCD.
-- escribir_pixel(x,y)     Enciende o apaga el pixel seleccionado por las
--                         coordenas x,y. Este procedimiento tiene función
--                         de alternar (toogle). Si estaba encendido,
--                         lo apaga y viceversa.
-- lectura_byte(x,y)       Devuelve el valor de una página que se encuentra dentro
--                         de las coordenadas elegidas (es una función).
--                         Ejemplo: lee_glcd = lectura_byte(10,7) Este ejemplo nos
--                         da el valor de la página 0 de la columna 10.
-- escribir_byte(x,y,dato) Escribe un byte dentro de la página correspondiente
--                         elegido en las coordenadas. 
-- ****************************************************************************
-- CONSTANTES
-- ----------
const GLCD_APAGADO			= 0x3E    
const GLCD_ENCENDIDO		= 0x3F    
const GLCD_PAGINA			= 0xB8    -- DIRECCIÓN RAM PAGINA
const GLCD_COLUMNA			= 0x40    -- DIRECCIÓN RAM COLUMNA
const GLCD_RAM				= 0xC0    -- ÚLTIMA DIRECCIÓN DE LA RAM
-- ****************************************************************************
-- VARIABLES GLOBALES:
-- -------------------
var byte x_verdadero				-- Uso interno en la librería. No tocar.
var bit pixel_enc_apa				-- Pixel: 1 --> Encendido. 0 --> Apagado
-- ****************************************************************************
-- CS1 y CS2 a 0
-- -------------
procedure _glcd_cs1_cs2() is
	GLCD_CS1 = 0
	GLCD_CS2 = 0
end procedure
-- ****************************************************************************
-- ENVIA UN DATO.
-- --------------
procedure _glcd_dato() is
	GLCD_DI = 1
end procedure
-- ****************************************************************************
-- ENVIA UNA INSTRUCCIÓN.
-- ----------------------
procedure _glcd_inst() is
	GLCD_DI = 0
end procedure
-- ****************************************************************************
-- ACTIVA Y DESACTIVA AL GLCD PARA QUE TOME DICHA INSTRUCCIÓN (escritura).
-- -----------------------------------------------------------------------
procedure _accion_glcd_escritura() is
	GLCD_E = 1
	delay_1us()
	GLCD_E = 0
end procedure
-- ****************************************************************************
-- ACTIVA, LEE Y DESACTIVA AL GLCD PARA QUE TOME DICHA INSTRUCCIÓN (lectura).
-- --------------------------------------------------------------------------
function _accion_glcd_lectura() return byte is
	var byte lectura_glcd
	GLCD_E = 1
	delay_2us()
	lectura_glcd = GLCD_DATAPRT
	GLCD_E = 0
	_glcd_cs1_cs2()
	return lectura_glcd
end function
-- ****************************************************************************
-- ENVÍA EL DATO POR EL PUERTO AL GLCD.
-- ------------------------------------
procedure _envia_puerto(byte in dato) is
	GLCD_DATAPRT = dato
	asm nop
	asm nop
	_accion_glcd_escritura()
end procedure
-- ****************************************************************************
-- LEE EL PUERTO DEL GLCD.
-- -----------------------
function _lee_puerto() return byte is
	var byte lectura_glcd
	GLCD_RW = 1						-- Leemos al GLCD.
	GLCD_DATAPRT_DIR = all_input	-- Puerto como entrada.
	asm nop
	asm nop
	lectura_glcd = _accion_glcd_lectura()
	GLCD_RW = 0						-- Escritura al GLCD.
	GLCD_DATAPRT_DIR = all_output
	return lectura_glcd
end function
-- ****************************************************************************
-- CALCULA EL RESTO PARA ENCENDER EL PIXEL DESEADO.
-- ------------------------------------------------
const byte _resto_pixel[] = {
	0x01,
	0x02,
	0x04,
	0x08,
	0x10,
	0x20,
	0x40,
	0x80
}
procedure _calculo_resto(byte in y, byte in demas_pixeles) is
	var byte resto_pixel			-- Es el resultado del resto de la división.
	y = y % 8
	resto_pixel = _resto_pixel[y]
	resto_pixel = resto_pixel ^ demas_pixeles
	_envia_puerto(resto_pixel)
end procedure
-- ****************************************************************************
-- CALCULA EL CONTROLADOR NECESARIO QUE ES INGRESADO EN X.
-- -------------------------------------------------------
procedure _glcd_coord_x(byte in x) is
	if x > 63 then
		x = x - 64
		GLCD_CS1 = 0		-- x es mayor a 63, por lo tanto
		GLCD_CS2 = 1		-- se trabaja con el controlador 2.
	else
		GLCD_CS1 = 1		-- x es menor o igual a 63, por lo tanto
		GLCD_CS2 = 0		-- se trabaja con el controlador 1.
	end if
	x = x | GLCD_COLUMNA
	_envia_puerto(x)
end procedure
-- ****************************************************************************
-- CALCULA LA PAGINA NECESARIA QUE ES INGRESADO EN Y.
-- --------------------------------------------------
procedure _glcd_pagina(byte in y) is
	var byte temporal
	temporal = y
	temporal = temporal >> 3
	temporal = temporal | GLCD_PAGINA
	_envia_puerto(temporal)
end procedure
-- ****************************************************************************
-- USO INTERNO. COMÚN PARA LECTURA Y ESCRITURA.
-- --------------------------------------------
procedure _comun_escritura_lectura(byte in x, byte in y) is
	GLCD_RW  = 0			-- Escribimos
	_glcd_inst()			-- Le enviamos una instrucción
	_glcd_coord_x(x)		-- Calculamos el controlador y se lo envía al GLCD.
	_glcd_pagina(y)			-- Calculamos la página y se lo enviamos.
	_glcd_dato()			-- Le enviamos el dato.
end procedure
-- ****************************************************************************
-- ESCRIBE UN BYTE EN EL GLCD. Las coordenadas corresponde a la parte superior izquierda.
-- ---------------------------
procedure escribir_byte(byte in x, byte in y, byte in dato) is
	_comun_escritura_lectura(x,y)	-- Preparamos al GLCD.
	_envia_puerto(dato)				-- Le enviamos el dato.
	_glcd_cs1_cs2()
end procedure
-- ****************************************************************************
-- LEE AL GLCD ESPECIFICANDO LAS COORDENADAS DESEADAS.
-- ---------------------------------------------------
function lectura_byte(byte in x, byte in y) return byte is
	var byte lectura_glcd
	_comun_escritura_lectura(x,y)	-- Preparamos al GLCD.
	lectura_glcd = _lee_puerto()
	return lectura_glcd
end function
-- ****************************************************************************
-- ENCIENDE O APAGA UN PIXEL EN DICHAS COORDENADAS (tiene función de alternar (toggle)).
-- ----------------------------------------------------------------------------
procedure escribir_pixel(byte in x, byte in y) is
	var byte lectura_glcd
	lectura_glcd = lectura_byte(x,y)	-- Leemos para saber como están los 7 bit restantes.
	lectura_glcd = lectura_byte(x,y)	-- Se necesita leer dos veces.
	_comun_escritura_lectura(x,y)
	_calculo_resto(y,lectura_glcd)		-- Encendemos el el bit del puerto para encender.
									    -- el pixel deseado.
end procedure
-- ****************************************************************************
-- LLENA ENCIENDE O APAGA TODOS LOS PIXELES DEL GLCD.
-- --------------------------------------------------
procedure glcd_llenar(byte in llenar) is
	var byte x = 0
	var byte y = 0
	if llenar > 0 then
		llenar = 0xFF
	end if
	for 8 loop
		for 128 loop
			escribir_byte(x,y,llenar)
			x = x + 1
		end loop
		x = 0
		y = y + 8
	end loop
end procedure
-- ****************************************************************************
-- INICIALIZA AL GLCD.
-- -------------------
procedure glcd_ini() is
	GLCD_DATAPRT = 0x00
	GLCD_DATAPRT_DIR = all_output
	GLCD_RW_DIRECTION = output
	GLCD_CS1_DIRECTION = output
	GLCD_E_DIRECTION = output
	GLCD_DI_DIRECTION = output
	GLCD_RST_DIRECTION = output
	GLCD_CS2_DIRECTION = output
	GLCD_RST = high
	GLCD_E = low
	GLCD_RW = low 
	_glcd_inst()
	GLCD_CS1 = 1
	GLCD_CS2 = 0
	_envia_puerto(GLCD_RAM)
	_envia_puerto(GLCD_PAGINA)
	_envia_puerto(GLCD_COLUMNA)
	_envia_puerto(GLCD_ENCENDIDO)
	GLCD_CS1 = 0
	GLCD_CS2 = 1
	_envia_puerto(GLCD_RAM)
	_envia_puerto(GLCD_PAGINA)
	_envia_puerto(GLCD_COLUMNA)
	_envia_puerto(GLCD_ENCENDIDO)
	glcd_llenar(0)
end procedure
-- ****************************************************************************