LCD 4X20 (A SAGA)

CAROS COLEGAS, ESTOU COM DIFICULDADES DE FAZER FUNCIONAR UM DISPLAY 4X20 COM PIC, POIS TODOS OS PROGRAMAS QUE CONSEGUI NÃO FUNCIONAM DIREITO, QUANDO NÃO DEIXA LENTA A AMOSTRAGEM, NÃO FUNCIONA QUANDO PRECISO MOSTRAR O VALOR DE UMA VARIAVEL.
ESTOU USANDO ESTE MODIFICADO DO FABIO PEREIRA:
USO CCS.
//******************************************************************************
//* MOD_LCD2.C - Biblioteca de manipulação de módulo LCD
//*
//* Modificado por Márcio José Soares para compatibilizar com 16F628
//* do original de Fábio Pereira - Pic Programação em C - Editora Erica
//* Atende agora também quatro tipos de displays
//******************************************************************************
//******************************************************************************
/* endereços para linhas dos display's possíveis para este
módulo:
Display 1ª linha 2ª linha 3ª linha 4ª linha
16 x 2 80H C0H XX XX
16 x 4 80H C0H 94H D4H
20 x 4 80H C0H 90H D0H
40 x 2 80H C0H XX XX
*/
//******************************************************************************
//******************************************************************************
// Arquivos incluídos
//******************************************************************************
#include "mod_lcd2.h"
//******************************************************************************
// Funções do módulo
//******************************************************************************
//******************************************************************************
// Função para enviar nibble para o display
// envia um dado de quatro bits para o display
// recebe - byte a enviar
// retorna - nada
//******************************************************************************
void lcd_envia_nibble( byte dado )
{
// coloca os quatro bits nas saidas
output_bit(lcd_d4,bit_test(dado,0));
output_bit(lcd_d5,bit_test(dado,1));
output_bit(lcd_d6,bit_test(dado,2));
output_bit(lcd_d7,bit_test(dado,3));
// dá um pulso na linha enable
output_high(lcd_enable);
output_low(lcd_enable);
}
//******************************************************************************
// Função para enviar dados para o display
// recebe - endereço -> 0 - comando, 1 dado
// dado
// retorna - nada
//******************************************************************************
void lcd_envia_byte( boolean endereco, byte dado )
{
// coloca a linha rs em 0
output_low(lcd_rs);
// aguarda o display ficar desocupado
//while ( bit_test(lcd_le_byte(),7) ) ;
// configura a linha rs dependendo do modo selecionado
output_bit(lcd_rs,endereco);
delay_us(100); // aguarda 100 us
// caso a linha rw esteja definida, coloca em 0
#ifdef lcd_rw
output_low(lcd_rw);
#endif
// desativa linha enable
output_low(lcd_enable);
// envia a primeira parte do byte
lcd_envia_nibble(dado >> 4);
// envia a segunda parte do byte
lcd_envia_nibble(dado & 0x0f);
}
//******************************************************************************
// Função para inicializar o display
// recebe - nada
// retorna - nada
//******************************************************************************
void lcd_ini()
// rotina de inicialização do display
{
byte conta;
output_low(lcd_d4);
output_low(lcd_d5);
output_low(lcd_d6);
output_low(lcd_d7);
output_low(lcd_rs);
#ifdef lcd_rw
output_high(lcd_rw);
#endif
output_low(lcd_enable);
delay_ms(15);
// envia uma seqüência de 3 vezes 0x03
// e depois 0x02 para configurar o módulo
// para modo de 4 bits
for(conta=1;conta<=3;++conta)
{
lcd_envia_nibble(3);
delay_ms(5);
}
lcd_envia_nibble(2);
// envia string de inicialização do display
for(conta=0;conta<=3;++conta) lcd_envia_byte(0,INI_LCD[conta]);
}
//******************************************************************************
// Função para mudar a linha no display
// implementada por Márcio José Soares
// para alterar a linha de trabalho de um lcd
// com mais de uma linha.
// recebe:
// byte x = display utilizado
// 0 -> 16 x 2
// 1 -> 20 x 4
// 2 -> 16 x 4
// 3 -> 40 x 2
//
// byte y = número da linha a pular
//
// retorna - nada
//******************************************************************************
byte lcd_muda_linha(byte x, byte y)
{
byte endereco, ret;
if(y==1){
endereco = lcd_prim_lin;
ret = 1;
}
else if(y==2){
endereco = lcd_seg_lin;
ret = 2;
}
else if(y==3){
if (x==2)
endereco = lcd_terc_lin;
else
endereco = lcd_terc_lin + 0x04;
ret = 3;
}
else if(y==4){
if (x==2)
endereco = lcd_quar_lin;
else
endereco = lcd_quar_lin + 0x04;
ret = 4;
}
else
endereco = lcd_prim_lin;
lcd_envia_byte(0,endereco);
return ret;
}
//******************************************************************************
// Função para posicionar o caracter no display
// recebe - linha e coluna (posição relativa no display)
// retorna - nada
//******************************************************************************
void lcd_pos(byte lin, byte pos){
byte pos1;
if ((LCD_TP==0) || (LCD_TP==1) || (LCD_TP==3))
switch (lin){
case 1:
pos1 = lcd_prim_lin+pos;
break;
case 2:
pos1 = lcd_seg_lin+pos;
break;
case 3:
pos1 = lcd_terc_lin+pos;
break;
case 4:
pos1 = lcd_quar_lin+pos;
break;
default:
pos1 = pos;
break;
}
if (LCD_TP==2)
switch (lin){
case 1:
pos1 = lcd_prim_lin+pos;
break;
case 2:
pos1 = lcd_seg_lin+pos;
break;
case 3:
pos1 = (lcd_terc_lin-4)+pos;
break;
case 4:
pos1 = (lcd_quar_lin-4)+pos;
break;
default:
pos1 = pos;
break;
}
lcd_envia_byte(0,pos1);
return;
}
//******************************************************************************
// Função para apagar o display
// recebe - nada
// retorna - nada
//******************************************************************************
void lcd_clear(){
lcd_envia_byte(0,1);
return;
}
//******************************************************************************
// Função para enviar um byte para o display
// recebe - caracter a ser enviado
// retorna - nada
//******************************************************************************
void lcd_escreve(char c)
{
lcd_envia_byte(1,c);
return;
}
//******************************************************************************
// Arquivo mod_lcd2.h
// Desenvolvido por Márcio José Soares
// diretrizes de pré-compilação para módulo mod_lcd2.c
//******************************************************************************
//******************************************************************************
// As definições a seguir são utilizadas para acesso aos pinos do display
// caso o pino RW não seja utilizado, comente a definição lcd_rw
//
//algumas definições foram modificadas para compatibilizar com a PIC16F628
//definições modificadas (pinos de trabalho para o LCD)
//******************************************************************************
#ifndef lcd_enable
#define lcd_enable pin_b0 // pino enable do LCD
#define lcd_rs pin_b3 // pino rs do LCD
//#define lcd_rw pin_e2 // pino rw do LCD
#define lcd_d4 pin_b4 // pino de dados d4 do LCD
#define lcd_d5 pin_b5 // pino de dados d5 do LCD
#define lcd_d6 pin_b6 // pino de dados d6 do LCD
#define lcd_d7 pin_b7 // pino de dados d7 do LCD
#endif
//******************************************************************************
// Define setup do LCD
//******************************************************************************
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 linhas
//******************************************************************************
// Definições para endereços das linhas (sempre na primeira coluna)
// Endereço base display 16 caracteres por coluna
// para outros LCD, somar ou subtrair
//******************************************************************************
#define lcd_prim_lin 0x80 // Endereço da primeira linha na RAM do LCD 16x4
#define lcd_seg_lin 0xC0 // Endereço da segunda linha na RAM do LCD 16x4
#define lcd_terc_lin 0x94 // Endereço da terceira linha na RAM do LCD 16x4
#define lcd_quar_lin 0xD4 // Endereço da quarta linha na RAM do LCD 16x4
//#define lcd_back pin_a7 // pino para back ligth do LCD
//#define lcd_led pin_a3 // pino para o led de apoio do display
//******************************************************************************
// Variáveis globais do módulo
//******************************************************************************
// a constante abaixo define a seqüência de inicialização do módulo LCD
byte CONST INI_LCD[4] = {0x20 | (lcd_type << 2), 0x0F, 1, 6};
ESTE NÃO CONSIGO MOSTRAR VARIAVEIS COMO:
LCD_ESCREVE("MENSAGEM %3U ",VARIAVEL);
ESTE DEIXA O PROGRAMA LENTO
// LCD STUFF
#define LCD_D4 PIN_b6 //pino 11 lcd 40 pic
#define LCD_D5 PIN_b4 //pino 12 lcd 37
#define LCD_D6 PIN_b7 //pino 13 lcd 39
#define LCD_D7 PIN_b5 //pino 14 lcd 38
#define LCD_EN PIN_b3 //pino 6 lcd 36
#define LCD_RS PIN_b2 //pino 4 lcd 35
#define PRI_LINE 0x80
#define SEC_LINE 0xC0
#define TER_LINE 0x94
#define QUA_LINE 0xD4
#define CLEAR_DISP 0x01
#define CURS_ON 0x0e
#define CURS_OFF 0x0c
//------------------------------------------------------------------------------
// proto statements
void LCD_Init ( void );
void LCD_SetPosition ( unsigned int cX );
void LCD_PutChar ( unsigned int cX );
void LCD_PutCmd ( unsigned int cX );
void LCD_PulseEnable ( void );
void LCD_SetData ( unsigned int cX );
//------------------------------------------------------------------------------
void LCD_Init ( void )
{
LCD_SetData ( 0x00 );
output_low ( LCD_RS );
LCD_SetData ( 0x03 ); // init with specific nibbles to start 4-bit mode
LCD_PulseEnable();
LCD_PulseEnable();
LCD_PulseEnable();
LCD_SetData ( 0x02 ); // set 4-bit interface
LCD_PulseEnable(); // send dual nibbles hereafter, MSN first
LCD_PutCmd ( 0x2C ); // function set (all lines, 5x7 characters)
LCD_PutCmd ( 0x0C ); // display ON, cursor off, no blink
LCD_PutCmd ( 0x01 ); // clear display
LCD_PutCmd ( 0x06 ); // entry mode set, increment
}
void LCD_SetPosition ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) | 0x08 );
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) );
LCD_PulseEnable();
}
void LCD_PutChar ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
output_high ( LCD_RS );
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
output_low ( LCD_RS );
}
void LCD_PutCmd ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
}
void LCD_PulseEnable ( void )
{
output_high ( LCD_EN );
delay_us ( 10 );
output_low ( LCD_EN );
delay_ms ( 2 );//ALTERA TEMPO DE AMOSRA NO LCD
}
void LCD_SetData ( unsigned int cX )
{
output_bit ( LCD_D4, cX & 0x01 );
output_bit ( LCD_D5, cX & 0x02 );
output_bit ( LCD_D6, cX & 0x04 );
output_bit ( LCD_D7, cX & 0x08 );
}
//------------------------------------------------------------------------------
ALGUEM TEM ALGUMA IDEIA OU ROTINA QUE FUNCIONE?!
ESTOU USANDO ESTE MODIFICADO DO FABIO PEREIRA:
USO CCS.
//******************************************************************************
//* MOD_LCD2.C - Biblioteca de manipulação de módulo LCD
//*
//* Modificado por Márcio José Soares para compatibilizar com 16F628
//* do original de Fábio Pereira - Pic Programação em C - Editora Erica
//* Atende agora também quatro tipos de displays
//******************************************************************************
//******************************************************************************
/* endereços para linhas dos display's possíveis para este
módulo:
Display 1ª linha 2ª linha 3ª linha 4ª linha
16 x 2 80H C0H XX XX
16 x 4 80H C0H 94H D4H
20 x 4 80H C0H 90H D0H
40 x 2 80H C0H XX XX
*/
//******************************************************************************
//******************************************************************************
// Arquivos incluídos
//******************************************************************************
#include "mod_lcd2.h"
//******************************************************************************
// Funções do módulo
//******************************************************************************
//******************************************************************************
// Função para enviar nibble para o display
// envia um dado de quatro bits para o display
// recebe - byte a enviar
// retorna - nada
//******************************************************************************
void lcd_envia_nibble( byte dado )
{
// coloca os quatro bits nas saidas
output_bit(lcd_d4,bit_test(dado,0));
output_bit(lcd_d5,bit_test(dado,1));
output_bit(lcd_d6,bit_test(dado,2));
output_bit(lcd_d7,bit_test(dado,3));
// dá um pulso na linha enable
output_high(lcd_enable);
output_low(lcd_enable);
}
//******************************************************************************
// Função para enviar dados para o display
// recebe - endereço -> 0 - comando, 1 dado
// dado
// retorna - nada
//******************************************************************************
void lcd_envia_byte( boolean endereco, byte dado )
{
// coloca a linha rs em 0
output_low(lcd_rs);
// aguarda o display ficar desocupado
//while ( bit_test(lcd_le_byte(),7) ) ;
// configura a linha rs dependendo do modo selecionado
output_bit(lcd_rs,endereco);
delay_us(100); // aguarda 100 us
// caso a linha rw esteja definida, coloca em 0
#ifdef lcd_rw
output_low(lcd_rw);
#endif
// desativa linha enable
output_low(lcd_enable);
// envia a primeira parte do byte
lcd_envia_nibble(dado >> 4);
// envia a segunda parte do byte
lcd_envia_nibble(dado & 0x0f);
}
//******************************************************************************
// Função para inicializar o display
// recebe - nada
// retorna - nada
//******************************************************************************
void lcd_ini()
// rotina de inicialização do display
{
byte conta;
output_low(lcd_d4);
output_low(lcd_d5);
output_low(lcd_d6);
output_low(lcd_d7);
output_low(lcd_rs);
#ifdef lcd_rw
output_high(lcd_rw);
#endif
output_low(lcd_enable);
delay_ms(15);
// envia uma seqüência de 3 vezes 0x03
// e depois 0x02 para configurar o módulo
// para modo de 4 bits
for(conta=1;conta<=3;++conta)
{
lcd_envia_nibble(3);
delay_ms(5);
}
lcd_envia_nibble(2);
// envia string de inicialização do display
for(conta=0;conta<=3;++conta) lcd_envia_byte(0,INI_LCD[conta]);
}
//******************************************************************************
// Função para mudar a linha no display
// implementada por Márcio José Soares
// para alterar a linha de trabalho de um lcd
// com mais de uma linha.
// recebe:
// byte x = display utilizado
// 0 -> 16 x 2
// 1 -> 20 x 4
// 2 -> 16 x 4
// 3 -> 40 x 2
//
// byte y = número da linha a pular
//
// retorna - nada
//******************************************************************************
byte lcd_muda_linha(byte x, byte y)
{
byte endereco, ret;
if(y==1){
endereco = lcd_prim_lin;
ret = 1;
}
else if(y==2){
endereco = lcd_seg_lin;
ret = 2;
}
else if(y==3){
if (x==2)
endereco = lcd_terc_lin;
else
endereco = lcd_terc_lin + 0x04;
ret = 3;
}
else if(y==4){
if (x==2)
endereco = lcd_quar_lin;
else
endereco = lcd_quar_lin + 0x04;
ret = 4;
}
else
endereco = lcd_prim_lin;
lcd_envia_byte(0,endereco);
return ret;
}
//******************************************************************************
// Função para posicionar o caracter no display
// recebe - linha e coluna (posição relativa no display)
// retorna - nada
//******************************************************************************
void lcd_pos(byte lin, byte pos){
byte pos1;
if ((LCD_TP==0) || (LCD_TP==1) || (LCD_TP==3))
switch (lin){
case 1:
pos1 = lcd_prim_lin+pos;
break;
case 2:
pos1 = lcd_seg_lin+pos;
break;
case 3:
pos1 = lcd_terc_lin+pos;
break;
case 4:
pos1 = lcd_quar_lin+pos;
break;
default:
pos1 = pos;
break;
}
if (LCD_TP==2)
switch (lin){
case 1:
pos1 = lcd_prim_lin+pos;
break;
case 2:
pos1 = lcd_seg_lin+pos;
break;
case 3:
pos1 = (lcd_terc_lin-4)+pos;
break;
case 4:
pos1 = (lcd_quar_lin-4)+pos;
break;
default:
pos1 = pos;
break;
}
lcd_envia_byte(0,pos1);
return;
}
//******************************************************************************
// Função para apagar o display
// recebe - nada
// retorna - nada
//******************************************************************************
void lcd_clear(){
lcd_envia_byte(0,1);
return;
}
//******************************************************************************
// Função para enviar um byte para o display
// recebe - caracter a ser enviado
// retorna - nada
//******************************************************************************
void lcd_escreve(char c)
{
lcd_envia_byte(1,c);
return;
}
//******************************************************************************
// Arquivo mod_lcd2.h
// Desenvolvido por Márcio José Soares
// diretrizes de pré-compilação para módulo mod_lcd2.c
//******************************************************************************
//******************************************************************************
// As definições a seguir são utilizadas para acesso aos pinos do display
// caso o pino RW não seja utilizado, comente a definição lcd_rw
//
//algumas definições foram modificadas para compatibilizar com a PIC16F628
//definições modificadas (pinos de trabalho para o LCD)
//******************************************************************************
#ifndef lcd_enable
#define lcd_enable pin_b0 // pino enable do LCD
#define lcd_rs pin_b3 // pino rs do LCD
//#define lcd_rw pin_e2 // pino rw do LCD
#define lcd_d4 pin_b4 // pino de dados d4 do LCD
#define lcd_d5 pin_b5 // pino de dados d5 do LCD
#define lcd_d6 pin_b6 // pino de dados d6 do LCD
#define lcd_d7 pin_b7 // pino de dados d7 do LCD
#endif
//******************************************************************************
// Define setup do LCD
//******************************************************************************
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 linhas
//******************************************************************************
// Definições para endereços das linhas (sempre na primeira coluna)
// Endereço base display 16 caracteres por coluna
// para outros LCD, somar ou subtrair
//******************************************************************************
#define lcd_prim_lin 0x80 // Endereço da primeira linha na RAM do LCD 16x4
#define lcd_seg_lin 0xC0 // Endereço da segunda linha na RAM do LCD 16x4
#define lcd_terc_lin 0x94 // Endereço da terceira linha na RAM do LCD 16x4
#define lcd_quar_lin 0xD4 // Endereço da quarta linha na RAM do LCD 16x4
//#define lcd_back pin_a7 // pino para back ligth do LCD
//#define lcd_led pin_a3 // pino para o led de apoio do display
//******************************************************************************
// Variáveis globais do módulo
//******************************************************************************
// a constante abaixo define a seqüência de inicialização do módulo LCD
byte CONST INI_LCD[4] = {0x20 | (lcd_type << 2), 0x0F, 1, 6};
ESTE NÃO CONSIGO MOSTRAR VARIAVEIS COMO:
LCD_ESCREVE("MENSAGEM %3U ",VARIAVEL);
ESTE DEIXA O PROGRAMA LENTO
// LCD STUFF
#define LCD_D4 PIN_b6 //pino 11 lcd 40 pic
#define LCD_D5 PIN_b4 //pino 12 lcd 37
#define LCD_D6 PIN_b7 //pino 13 lcd 39
#define LCD_D7 PIN_b5 //pino 14 lcd 38
#define LCD_EN PIN_b3 //pino 6 lcd 36
#define LCD_RS PIN_b2 //pino 4 lcd 35
#define PRI_LINE 0x80
#define SEC_LINE 0xC0
#define TER_LINE 0x94
#define QUA_LINE 0xD4
#define CLEAR_DISP 0x01
#define CURS_ON 0x0e
#define CURS_OFF 0x0c
//------------------------------------------------------------------------------
// proto statements
void LCD_Init ( void );
void LCD_SetPosition ( unsigned int cX );
void LCD_PutChar ( unsigned int cX );
void LCD_PutCmd ( unsigned int cX );
void LCD_PulseEnable ( void );
void LCD_SetData ( unsigned int cX );
//------------------------------------------------------------------------------
void LCD_Init ( void )
{
LCD_SetData ( 0x00 );
output_low ( LCD_RS );
LCD_SetData ( 0x03 ); // init with specific nibbles to start 4-bit mode
LCD_PulseEnable();
LCD_PulseEnable();
LCD_PulseEnable();
LCD_SetData ( 0x02 ); // set 4-bit interface
LCD_PulseEnable(); // send dual nibbles hereafter, MSN first
LCD_PutCmd ( 0x2C ); // function set (all lines, 5x7 characters)
LCD_PutCmd ( 0x0C ); // display ON, cursor off, no blink
LCD_PutCmd ( 0x01 ); // clear display
LCD_PutCmd ( 0x06 ); // entry mode set, increment
}
void LCD_SetPosition ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) | 0x08 );
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) );
LCD_PulseEnable();
}
void LCD_PutChar ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
output_high ( LCD_RS );
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
output_low ( LCD_RS );
}
void LCD_PutCmd ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
}
void LCD_PulseEnable ( void )
{
output_high ( LCD_EN );
delay_us ( 10 );
output_low ( LCD_EN );
delay_ms ( 2 );//ALTERA TEMPO DE AMOSRA NO LCD
}
void LCD_SetData ( unsigned int cX )
{
output_bit ( LCD_D4, cX & 0x01 );
output_bit ( LCD_D5, cX & 0x02 );
output_bit ( LCD_D6, cX & 0x04 );
output_bit ( LCD_D7, cX & 0x08 );
}
//------------------------------------------------------------------------------
ALGUEM TEM ALGUMA IDEIA OU ROTINA QUE FUNCIONE?!