/* ------------------------------------------ */
/* Programa que funciona con USB Bootloader */
/* ------------------------------------------ */
/* E-mail: Jaalm741@yahoo.com.ar */
/*---------------------------------------------*/
/* Cambios para que funcione el Bootloader */
/*---------------------------------------------*/
/* Correr el vector de reset a la direccion */
/* 0x000800 en vez la opcion normal 0x00. */
/* correr el vector de interrupcion a la */
/* direccion 0x000808 (parte alta) en vez de */
/* la opcion normal 0x8 y la parte baja a la */
/* direccion 0x000818 en vez de la normal 0x18 */
/* configurar el pin RB4 del puertoB como */
/* entrada digital y no usar ese pin para nada */
/* Reset y RB4 deben estar a +Vcc (+5V) para */
/* trabajar en modo normal. */
/* para entrar en modo Bootloder debo poner RB4*/
/* a 0V(GND) y luego reset a 0V(GND). */
/* usar mr18f4550.lkr en vez del 18f4550.lkr */
/* que viene en el MCHPDFUSB */
/* (si no lo consiguen me lo piden por e-mail */
/* pero en la pagina de microchip seguro esta.)*/
/* poner a masa la bornera para que ande la */
/* placa sino no funciona, con el usb conectado*/
/* a la pc. */
/*---------------------------------------------*/
/*------------------------------------------------------------*/
/* Esta libreria para manejar el LCD Winstar es el resultado */
/* de varias librerias que andaban dando vuelta por la red. */
/* Las probe a todas por separado y ninguna funciono, asi que */
/* decidi escribir la mia propia que tiene un poco de cada */
/* una de ellas y ahora tambien les pertenece a ustedes. */
/* La mayoria de ellas estaba escrita en lenguaje ensamblador */
/* para pic 16f87X, alguna de ellas escrita en CSS. pero vi en*/
/* varios foros que a la mayoria no les funcionaba, y cada uno*/
/* tenia que realizar sus propio ajustes en el estrobe del */
/* enable ( los tiempos diferian mucho a los del data sheet ).*/
/* espero que la podamos hacer funcionar entre todos. */
/*------------------------------------------------------------*/
#include <p18f4550.h>
#include <delays.h>
/*----------------------------------------------------------*/
/* Definiciones de pines de control y Bus de datos del LCD */
/* Winstar WG 12864A TMI VN */
/* -------------------------------------------------------- */
#define LCD_DI PORTBbits.RB7 // dato o instruccion
#define LCD_LE PORTBbits.RB6 // lectura o escritura
#define LCD_E PORTBbits.RB5 // habilitacion
#define LCD_CS1 PORTBbits.RB3 // seleccion de chip 1
#define LCD_CS2 PORTBbits.RB2 // seleccion de chip 2
#define LCD_Reset PORTBbits.RB1 // reset del lcd
#define LCD_Bus_de_datos PORTD // bus de datos del lcd
/*----------------------------------------------------------*/
/* Codigos internos de instrucciones basicas del LCD Winstar*/
/* -------------------------------------------------------- */
/* Saque las instrucciones del data sheet del KS018B */
/* No si este LCD maneja KS0108A o KS0108B esa es mi duda */
/* lo unico que varia es el reset que esta complementado y */
/* y en el otro no. */
/* -------------------------------------------------------- */
#define i_LCD_encendido 0x3F
#define i_LCD_apagado 0x3E
#define i_LCD_pagina_0 0xB8
#define i_LCD_columna_0 0x40
#define i_LCD_linea_inicial_0 0xC0
/*----------------------------------------------------------*/
/* Definiciones basicas y tipos de datos fundamentales */
/* -------------------------------------------------------- */
typedef unsigned int ui;
typedef unsigned short int byte;
typedef unsigned short int usi;
#define lado_izquierdo_LCD 0
#define lado_derecho_LCD 1
#define modo_instruccion 0
#define modo_dato 1
#define modo_escritura 0
#define modo_lectura 1
/*----------------------------------------------------------*/
/* Cabeceras o prototipos de funciones del programa */
/*----------------------------------------------------------*/
void conf_puertos (int opcion);
void delay(usi opcion);
void delay2(usi opcion);
void envia_dato_o_instruccion(usi lado,usi d_i,byte dato);
byte LCD_leeBYTE (usi lado);
void LCD_limpiar (usi color);
void LCD_inicializar (void);
byte bit_clear ( byte x, usi n);
byte bit_set (byte x, usi n);
void LCD_pixel (usi a,usi b, usi color);
/* ---------------------------------- */
/* Declaracion del vector de reset */
/* ---------------------------------- */
extern void _startup (void); // mira tu c018i.c en tu directorio de compilador C18
#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
void _reset (void)
{
_asm goto _startup _endasm
}
/* ------------------------------------------ */
/* Declaraciones del vector de interrupcion */
/* ------------------------------------------ */
/* En este programa no uso interrupciones */
/* pero lo dejo como esqueleto para otros */
/* programas que si las usen. */
/* ------------------------------------------ */
#pragma code
#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808
void _high_ISR (void)
{
;
}
#pragma code _LOW_INTERRUPT_VECTOR = 0x000818
void _low_ISR (void)
{
;
}
#pragma code // vuelve a la seccion de codigo por defecto
/* -------------------------------- */
/* funcion principal del programa */
/* -------------------------------- */
void main (void)
{
int i;
conf_puertos (0);
LCD_inicializar();
while(1)
{
LCD_pixel (10,10,1);
for (i=1;i<=10;i++) // espera casi 10 segundos
{
Delay10KTCYx(250); //espera 0,5 segundos HS=20MHz
Delay10KTCYx(250); //espera 0,5 segundos
}
}
}
/* ------------------------------------------------------------- */
/* Configuraciones de los puertos y pines del microcontrolador */
/* ------------------------------------------------------------- */
void conf_puertos (int opcion)
{
ADCON1=0x0D; /* AN0,AN1 : analógicas */
/* AN2..AN12 : digitales */
/* Vref- = VSS */
/* Vref+ = VDD */
/* RA0/AN0: entrada 1 del osciloscopio */
/* RA1/AN1: entrada 2 del osciloscopio */
/* --------------------------------------- */
/* Configuracion de los puertos de E/S */
/* --------------------------------------- */
if (opcion == 0 ) // si opcion == 0 puerto D como salida
// si opcion <> 0 puerto D como entrada
{
PORTD = 0; /* Pines que se comunican con los pines del LCD winstar */
LATD = 0; /* para enviar y recibir datos */
TRISD = 0; /* Configuro todos los bits del puerto D como Salida */
}
else
{
PORTD = 0; /* Pines que se comunican con los pines del LCD winstar */
LATD = 0; /* para enviar y recibir datos */
TRISD = 255; /* Configuro todos los bits del puerto D como entradas */
}
PORTB = 0; /* Pines que se comunican con los pines del LCD winstar */
LATB = 0; /* para manejar los pines de control */
TRISB = 17; /* Configuro todos los bits del puerto B como Salida */
/* Salvo RB0 y RB4 que son de lectura. RB0 va a GND y */
/* RB4 que en modo normal va a +Vcc (tambien reset a +Vcc)*/
/* y en modo bootloader va RB4 a 0V (tambien reset a 0V) */
PORTA = 0;
LATA = 0;
CMCON = 7;
TRISA = 255;/* Configuro todos los bits del puerto A como entradas */
/* RA0,RA1 : entradas anlógicas */
/* RA2,RA3,RA4,RA5 : entradas digitales */
}
void delay(usi opcion)
{
/*-------------------------------------------------*/
/* Ciclo de instruccion = 4 *( 1 / 20MHz )= 0,2 Us */
/* ( 5 * Ciclo de instruccion )= 1 Us */
/* (10 * Ciclo de instruccion )= 2 Us */
/* Delay1TCY = 0,2 Us = Nop */
/*-------------------------------------------------*/
if (opcion == 0) // espera 1 Us
{
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
}
else // espera 2 Us
{
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
}
}
void delay2(usi opcion)
{
/*-------------------------------------------------*/
/* Ciclo de instruccion = 4 *( 1 / 20MHz )= 0,2 Us */
/* ( 100 * 50 * Ciclo de instruccion ) = 1 ms */
/* ( 100 * 100 * Ciclo de instruccion ) = 2 ms */
/* Delay1TCY = 20 Us */
/*-------------------------------------------------*/
if (opcion == 0) // espera 1 ms
{
Delay100TCYx(50);
}
else // espera 2 ms
{
Delay100TCYx(100);
}
}
/*---------------------------------------------------------*/
/* Escribe un byte en una de las mitades de la pantalla */
/* lado == 0 (parte izq lcd)| lado == 1 (parte der lcd) */
/*---------------------------------------------------------*/
void envia_dato_o_instruccion(usi lado,usi d_i, byte dato)
{
// lado debe valer 0 o 1
// dato puede tomar los siguientes valores : 0 .. 255
/* selecciono la mitad del LCD correspondiente */
if (lado == 0)
{
LCD_CS1 = 0;
LCD_CS2 = 1;
}
else
{
LCD_CS1 = 1;
LCD_CS2 = 0;
}
LCD_LE = modo_escritura;
LCD_DI = d_i;
LCD_Bus_de_datos = dato;
// genero el flanco descendente para el pin enable del LCD
delay(0); // espero 1 us
LCD_E = 1; // pongo el bit enable en alto
delay(1); // espero 2 us
LCD_E = 0; // pongo el bit enable en bajo
delay(0); // espero 1 us
/* libero las lineas CS1 y CS2 */
LCD_CS1=0;
LCD_CS2=0;
}
/*------------------------------------------------------*/
/* Lee un byte de una de las dos mitades de la pantalla */
/*------------------------------------------------------*/
byte LCD_leeBYTE (usi lado)
{
byte dato;
conf_puertos (1);
LCD_LE = modo_lectura;
/* selecciono la mitad del LCD correspondiente */
if (lado == 0)
{
LCD_CS1 = 0;
LCD_CS2 = 1;
}
else
{
LCD_CS1 = 1;
LCD_CS2 = 0;
}
// genero el flanco descendente para el pin enable del LCD
delay2(0); // espero 1 us
LCD_E = 1; // pongo el bit enable en alto
delay2(1); // espero 2 us
dato = LCD_Bus_de_datos; // leo los datos del LCD
LCD_E = 0; // pongo el bit enable en bajo
/* libero las lineas CS1 y CS2 */
LCD_CS1=0;
LCD_CS2=0;
conf_puertos (0);
return dato;
}
void LCD_limpiar (usi color)
{
usi i,j,k;
for(i = 1; i <=8 ;i++)
{
for(j = 1; j <=8 ;j++)
{
envia_dato_o_instruccion(lado_izquierdo_LCD,modo_instruccion,j+i_LCD_pagina_0);
envia_dato_o_instruccion(lado_derecho_LCD,modo_instruccion,j+i_LCD_pagina_0);
}
envia_dato_o_instruccion(lado_izquierdo_LCD,modo_instruccion,i_LCD_columna_0);
envia_dato_o_instruccion(lado_derecho_LCD,modo_instruccion,i_LCD_columna_0);
for(k = 1; k <=64 ;k++)
{
envia_dato_o_instruccion(lado_izquierdo_LCD,modo_dato,0);
envia_dato_o_instruccion(lado_derecho_LCD,modo_dato,0);
}
}
}
void LCD_inicializar (void)
{
LCD_E = 0;
LCD_Reset = 0;
LCD_Reset = 1;
envia_dato_o_instruccion(lado_izquierdo_LCD,modo_instruccion,i_LCD_apagado);
envia_dato_o_instruccion(lado_derecho_LCD,modo_instruccion,i_LCD_apagado);
LCD_limpiar (0);
envia_dato_o_instruccion(lado_izquierdo_LCD,modo_instruccion,i_LCD_encendido);
envia_dato_o_instruccion(lado_derecho_LCD,modo_instruccion,i_LCD_encendido);
}
/* rutina que pone en 0 el n bit del registro x */
byte bit_clear (byte x, usi n)
{
/* n puede tomar los valores : 0..7 */
usi i,s=0;
for(i=7 ; i>=n ; i--)
{
}
x&=(s-1);
return x;
}
/* rutina que pone en 1 el n bit del registro x */
byte bit_set (byte x, usi n)
{
x|=aux;
return x;
}
/*=========================================== */
/*= Funcion que dibuja un pixel por pantalla =*/
/*=========================================== */
void LCD_pixel (usi a,usi b, usi color)
{
/* a : 0..127 b: 0..63 */
byte dato;
usi lado = lado_izquierdo_LCD; // Lado en el que voy a dibujar
if(a > 63)
{
a-=64;
lado = lado_derecho_LCD;
}
a=bit_clear (a,7); // limpio el bit MSB
a=bit_set(a,6); // pongo el bit 6 en 1
envia_dato_o_instruccion(lado,modo_instruccion,a); // envio la direccion de la coordenada a
/* Calculo en que pagina de las 8 cae */
envia_dato_o_instruccion(lado,modo_instruccion,(b/8 & 191)|184);
LCD_DI = modo_dato;
//Se necesitan dos lecturas para que devuelva el dato en la nueva direccion
LCD_leeBYTE (lado);
dato = LCD_leeBYTE (lado);
// De acuerdo al valor de color ...
if(color == 1) dato=bit_set(dato,b%8); //enciendo el pixel
else dato=bit_clear(dato,b%8); //apago el pixel
envia_dato_o_instruccion(lado,modo_instruccion,a); // fijo el lado a escribir
envia_dato_o_instruccion(lado,modo_dato,dato); // dibujo el pixel
}