[BR][BR][BR]////////////////////////////////////////////////////////////////////////////////////////////////[BR]//// Libreria LCD_CCS_4b16x2.C ////[BR]//// //// [BR]//// Destripada, comentada y adaptada por Juanelete (Spain) 10/03/06 ////[BR]//// ////[BR]//// 4 bits de datos y 1 o 2 lineas ////[BR]//// ////[BR]//// Configurable los puertos y pines a utilizar ////[BR]//// ////[BR]//// lcd_init() Must be called before any other function. ////[BR]//// ////[BR]//// lcd_putc(c) Will display c on the next position of the LCD. ////[BR]//// The following have special meaning: ////[BR]//// f Clear display ////[BR]////
Go to start of second line ////[BR]//// Move back one position ////[BR]//// ////[BR]//// lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1) ////[BR]//// ////[BR]//// lcd_getc(x,y) Returns character at position x,y on LCD ////[BR]//// ////[BR]//////////////////////////////////////////////////////////////////////////////////////////////[BR][BR][BR]// Aqui no tocar nada[BR]#define PORT_A 0x05[BR]#define PORT_B 0x06[BR]#define PORT_C 0x07[BR]#define PORT_D 0x08[BR]#define PORT_E 0x09[BR]#define DAT_SALIDA 0b0000[BR]#define DAT_ENTRADA 0b1111[BR][BR]struct lcd_bus_dat // Declaro la structura que va a contener los 4 bits de datos[BR]{[BR] int sin_usar : 4; // Nible bajo (No se usa)[BR] int data : 4; // Nible alto, Bus de datos del LCD[BR]} lcd;[BR][BR][BR]// Lo primero es seleccionar en que puerto vamos a conectar el Bus de datos del LCD.[BR]// Puede ser cualquier puerto (siempre que tenga 8 pines), y siempre se utilizaran[BR]// los los 4 pines altos del mismo, osea B4-B7 ó C4-C7...[BR][BR]#byte lcd = PORT_B // Aqui hay que elegir el puerto para el bus de datos (PORT_B, PORT_C,...)[BR][BR]#define set_tris_lcd(x) set_tris_b(x) // Aqui hay que poner el mismo puerto (set_tris_b(x), set_tris_c(x),...)[BR][BR][BR]// Ahora vamos a elegir donde conectaremos los pines de control del LCD.[BR]// Puede ser cualquier pin de cualquier puerto, pero siempre del mismo puerto[BR][BR]#bit lcd_enable = PORT_C.0[BR]#bit lcd_rs = PORT_C.1[BR]#bit lcd_rw = PORT_C.2[BR][BR][BR]// Si hemos elegido el mismo puerto para el bus de datos y los pines de control del LCD descomentar[BR]// lo siguiente, sino comentarlo[BR][BR]// Los 3 pines utilizados para el control del LCD hay que ponerlos como salidas (0),[BR]// el cuarto pin lo pondremos segun la utilidad que le vayamos a dar en nuestro programa.[BR]//#define PIN_CONTROL 0bxxxx //Pines R3-R0 (0=Salida 1=Entrada)[BR]//[BR]// Fin mismo puerto bus datos y control[BR][BR][BR][BR]// Si hemos elegido un puerto diferente para el bus de datos y los pines de control del LCD descomentar[BR]// lo siguiente, sino comentarlo[BR][BR]// Como solo se utilizan 4 pines para el bus de datos, quedan los otros 4 pines del puerto[BR]// libres para utilizarlos como queramos, aunque deberemos configurarlos ahora[BR]// como entradas o salidas segun queramos.[BR]#define PIN_CONTROL 0b0000 //Pines R3-R0 (0=Salida 1=Entrada)[BR][BR]// Lo siguiente deberemos de colocarlo en el main de nuestro programa[BR]// Tenemos tambien que configurar obligatoriamente los pines de los puertos utilizados para el control[BR]// del LCD como salidas, y el resto de los pines configurarlos como queramos.[BR]//set_tris_c(0b00000000); //Pines R7-R0 (0=Salida 1=Entrada)[BR]//[BR]// Fin puerto diferente bus datos y control[BR][BR][BR]// Ya no hay que modificar nada mas[BR][BR][BR]// Se declaran dos constantes LCD_WRITE y LCD_READ, y se les asignan dos valores, estos valores[BR]// representan el estado de cada uno de los pines del puerto asignado al bus de datos del LCD.[BR]struct lcd_bus_dat const LCD_WRITE = {PIN_CONTROL , DAT_SALIDA}; // xxxx 0000[BR]struct lcd_bus_dat const LCD_READ = {PIN_CONTROL , DAT_ENTRADA}; // xxxx 1111[BR][BR][BR]#define LCD_LINEA_2 0x40 // Direccion comienzo segunda linea LCD[BR][BR]#define LCD_DATO 1[BR]#define LCD_COMANDO 0[BR][BR]#define FUN_SET 32 // Funcion SET[BR]#define LCD_FUENTE 0 // 0=5x7, 1=5x10[BR]#define LCD_LINEAS 2 // 0=1 Linea, 2=2 Lineas[BR]#define LCD_BUS 0 // 0=4 Bits, 4=8 Bits[BR]#define DISPLAY_CTRL 8 // Funcion Display control[BR]#define LCD_BLINK 0 // 0=Off, 1=On[BR]#define LCD_CURSOR 0 // 0=Off, 2=On[BR]#define LCD_DISPLAY 4 // 0=Off, 4=On[BR]#define CLEAR_DISPLAY 1 // Funcion Borrar pantalla[BR]#define ENTRY_MODE 4 // Funcion Modo entrada[BR]#define DESPLAZ_TXT 0 // 0=Off, 1=On Desplazamiento del texto al escribir un nuevo caracter[BR]#define INC_DEC_CURSOR 2 // 0=Decremento, 2=Incremento Incr/Decr autoamtico de la pos. del cursor[BR][BR][BR]// Como estoy en modo 4 bits, cuando quiero leer el bus de datos del LCD, primero leo el nibble alto y despues[BR]// el nibble bajo.[BR]int8 lcd_read_byte()[BR]{[BR] int8 low,high; // Acojeran el nibble alto y bajo del byte leido[BR][BR] set_tris_lcd(LCD_READ); // Pines puerto como entrada[BR] lcd_rw = 1; // Modo lectura LCD[BR] delay_cycles(1);[BR] lcd_enable = 1;[BR] delay_cycles(1);[BR] high = lcd.data; // leo el nibble alto y lo meto en un Byte xxxx DDDD[BR] lcd_enable = 0;[BR] delay_cycles(1);[BR] lcd_enable = 1;[BR] delay_us(1);[BR] low = lcd.data; // Leo el nibble bajo y lo meto en un Byte xxxx DDDD[BR] lcd_enable = 0;[BR] set_tris_lcd(LCD_WRITE); // Pines puerto como salida[BR][BR] return( (high<<4) | low); // Tengo que formar un solo byte con la parte importante de cada Byte (high y low)[BR][BR]}[BR][BR][BR]// Envia el nibble al LCD[BR]void lcd_send_nibble( int8 n ) // Formato n -> 0000 DDDD DDDD = nibble a enviar[BR]{[BR] lcd.data = n; // Cargo el valor en el puerto. Se pierde la parte alta del byte[BR] delay_cycles(1);[BR] lcd_enable = 1; // Activo brevemente el LCD para que reciba los datos[BR] delay_us(2);[BR] lcd_enable = 0;[BR]}[BR][BR][BR]// Esta funcion descompone el dato en dos nibbles y los mete en sendos bytes para enviarlos a LCD[BR]void lcd_send_byte( int8 address, int8 n )[BR]{[BR] lcd_rs = 0; // Modo comando. Necesario para la instruccion siguiente.[BR] while ( bit_test(lcd_read_byte(),7) ) ; // Espero a que el bit 7 (Bussy Flag) este a 0 (LCD deshocupado)[BR][BR] lcd_rs = address; // Si addres=0, modo comando[BR][BR] delay_cycles(1);[BR] lcd_rw = 0; // Modo escritura[BR] delay_cycles(1);[BR] lcd_enable = 0; // Desactiva LCD[BR] lcd_send_nibble(n >> 4); // Elimino la parte baja y envio la parte alta con este formato: 0000 AAAA[BR] lcd_send_nibble(n & 0xf); // Pongo a cero la parte alta y solo envio la parte baja 0000 BBBB[BR]}[BR][BR]// Antes de nada hay que inicializar el LCD segun una secuencia determinada por el fabricante[BR]void lcd_init()[BR]{[BR] int8 i;[BR][BR] set_tris_lcd(LCD_WRITE); // Pines puerto como salida[BR][BR] lcd_rs = 0;[BR] lcd_rw = 0;[BR] lcd_enable = 0;[BR] delay_ms(15);[BR][BR] for(i=1;i<=3;++i)[BR] {[BR] lcd_send_nibble(0x03); // 0011 Segun Datasheet[BR] delay_ms(5);[BR] }[BR] lcd_send_nibble(0x02); // 0010 Segun Datasheet[BR][BR] // Configuro parametros LCD[BR][BR] lcd_send_byte(LCD_COMANDO,FUN_SET | ((LCD_FUENTE + LCD_LINEAS + LCD_BUS) << 2));[BR][BR] lcd_send_byte(LCD_COMANDO,DISPLAY_CTRL | (LCD_BLINK + LCD_CURSOR + LCD_DISPLAY));[BR][BR] lcd_send_byte(LCD_COMANDO,CLEAR_DISPLAY);[BR][BR] lcd_send_byte(LCD_COMANDO,ENTRY_MODE | (DESPLAZ_TXT + INC_DEC_CURSOR));[BR]}[BR][BR][BR][BR]void lcd_gotoxy( BYTE x, BYTE y) // x=Columna y=linea[BR]{[BR] int8 address;[BR][BR] if(y!=1) // Linea 2[BR] address=LCD_LINEA_2; //0x40[BR] else // Linea 1[BR] address=0;[BR][BR] address+=x-1; // La posicion es la pos. de inicio (0x0 o 0x40) + el desplazamiento[BR][BR] // 1DDDDDDD Comando Desplazamiento cursor[BR] // 0x80 = 10000000 Osea que para poner el valor del desplazamiento en el comando, hay que hacer OR con 0x80[BR] // Ejemplo: Col=8 y Lin=2 => address=0x40 + 0x08 - 0x01 = 0x47 = 01000111 Este seria el desplazamiento[BR] // Ahora hay que poner (hacer OR) en el byte comando el valor del desplazamiento: 10000000 OR 01000111 = 11000111[BR] lcd_send_byte(0 , 0x80|address);[BR]}[BR][BR][BR][BR]void lcd_putc( char c)[BR]{[BR] switch (c) {[BR] case "f" : lcd_send_byte(0,CLEAR_DISPLAY);[BR] delay_ms(2);[BR] break;[BR] case "
" : lcd_gotoxy(1,2); // Desplaza cursor segunda linea Col=1 Lin=2[BR] break;[BR] case "" : lcd_send_byte(0, ENTRY_MODE | (DESPLAZ_TXT + INC_DEC_CURSOR)); // 0001 0 0 00 Comando desplazar cursor, sin alterar ddram, Izquierda[BR] break;[BR] default : lcd_send_byte(1,c); // Envio byte en modo caracter[BR] break;[BR] }[BR]}[BR][BR][BR]char lcd_getc( int8 x, int8 y)[BR]{[BR] char value;[BR][BR] lcd_gotoxy(x,y);[BR] while ( bit_test(lcd_read_byte(),7) ); // Esperar a que el busy flag (bit 7) este a cero[BR][BR] lcd_rs=1; // Modo caracter[BR] value = lcd_read_byte();[BR] lcd_rs=0; // Modo comando[BR] return(value);[BR]}[BR][BR][BR]/////////////////////////////////////////////////////////////////////////[BR]//// PruLCD4B16x2.C ////[BR]//// ////[BR]/////////////////////////////////////////////////////////////////////////[BR][BR]#INCLUDE <16F876.H>[BR]#fuses HS,NOWDT,NOPROTECT,NOLVP[BR]//#ORG 0x1F00,0x1FFF {} //Para 8k Pic 16F876/7 (necesario para bootloader)[BR][BR]#use delay(clock=20000000)[BR][BR]#include <LCD_CCS_4B16x2.c> // Libreria LCD.C modificada[BR][BR][BR]void main()[BR]{[BR] int c="A";[BR] int n=0;[BR][BR] //Hay que incluir esto en el main para que funcione el LCD[BR] //Poner obligatoriamente los pines de control como salidas y el resto segun necesitemos[BR] set_tris_c(0b00000000); //R7-R0 0=Salida 1=Entrada[BR][BR] lcd_init();[BR] lcd_putc("fPreparado...
");[BR] delay_ms(1000);[BR][BR] while(TRUE)[BR] {[BR] lcd_gotoxy(2,2);[BR] printf(lcd_putc,"%U",n);[BR] n++;[BR] delay_ms(1000);[BR] };[BR][BR]}[BR]// flex_lcd.c
// These pins are for the Microchip PicDem2-Plus board,
// which is what I used to test the driver. Change these
// pins to fit your own board.
#define LCD_DB4 PIN_B1
#define LCD_DB5 PIN_B2
#define LCD_DB6 PIN_B3
#define LCD_DB7 PIN_B4
#define LCD_E PIN_E2
#define LCD_RS PIN_E0
#define LCD_RW PIN_E1
// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.
#define USE_LCD_RW 1
//========================================
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line
int8 const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};
//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
output_bit(LCD_DB4, !!(nibble & 1));
output_bit(LCD_DB5, !!(nibble & 2));
output_bit(LCD_DB6, !!(nibble & 4));
output_bit(LCD_DB7, !!(nibble & 8));
delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}
//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.
#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3
retval = 0;
output_high(LCD_E);
delay_cycles(1);
retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
output_low(LCD_E);
return(retval);
}
#endif
//---------------------------------------
// Read a byte from the LCD and return it.
#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;
output_high(LCD_RW);
delay_cycles(1);
high = lcd_read_nibble();
low = lcd_read_nibble();
return( (high<<4) | low);
}
#endif
//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);
#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif
if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);
delay_cycles(1);
#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif
output_low(LCD_E);
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//----------------------------
void lcd_init(void)
{
int8 i;
output_low(LCD_RS);
#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif
output_low(LCD_E);
delay_ms(15);
for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);
// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 60 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_LCD_RW
delay_ms(5);
#endif
}
}
//----------------------------
void lcd_gotoxy(int8 x, int8 y)
{
int8 address;
if(y != 1)
address = lcd_line_two;
else
address=0;
address += x-1;
lcd_send_byte(0, 0x80 | address);
}
//-----------------------------
void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1,2);
break;
case '\b':
lcd_send_byte(0,0x10);
break;
default:
lcd_send_byte(1,c);
break;
}
}
//------------------------------
#ifdef USE_LCD_RW
char lcd_getc(int8 x, int8 y)
{
char value;
lcd_gotoxy(x,y);
// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));
output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);
return(value);
}
#endif