|
|
View previous topic :: View next topic |
Author |
Message |
Izolator
Joined: 10 Feb 2004 Posts: 12 Location: Denmark, (Scandinavia-Europe)
|
LCD & 16F877....weird INIT behaviour !?!?!?! |
Posted: Fri Feb 27, 2004 2:20 pm |
|
|
Hi guys,
I have connected a HD77480 2x16 lcd to Pic 16F877.
Compiler: PCM 3.173
20Mhz Quartz
I experience weird behaviour after my lcd_init() functions has run through a clean main() as the only function besides the while(1). Problems include but are not limited to:
- a semi-visible/transparent grey-boxed line on line 1 (e.g. like a konstant curser all the way through line 1)
- nothing on display
Once in a while it will boot ok and work......even if I have several lcd_putc functions in main, like it is supposed to.
I tried to switch the EN and RS lines and that produces a VERY visible grey-boxed line on line 1.
I switched them back again and the behaviour mentioned first starts all over.
I have removed all code not nescesary but not my diretives, as I need them for later.
I'm all out of ideas :-(
I hope someone can tell me if the set_tris_x are in the correct places.
I suspect it is my timing of outputting stuff to the display during the lcd_init that does not entirely corespond to:
http://preterhuman.net/texts/computing/HardwareDIY/LCDFaq.txt
2.6.1
If someone would modify the code or point out excactly where I mess up, I would be most grateful.
Code: |
#device PIC16F877 *=16
#include <16F877.h>
#include <F877.h> // the file Microchip used to supply, with port def's etc.
#include <string.h>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,WRT
#use delay(clock=20000000)
#use rs232(baud=9600,xmit=PIN_C6, rcv=PIN_C7)
#use I2C(master, sda=PIN_C4, scl=PIN_C3, slow, force_hw)
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
#bit LCD_RS = PORTA.3 // RA3
#bit LCD_RW = PORTA.2 // RA2
#bit LCD_EN = PORTA.1 // RA1
#byte LCD_DATA = PORTD // PORTD
void lcd_init()
{
byte i;
SET_TRIS_A(0x00); // set port A, output
SET_TRIS_D(0x00); // set port D, output
LCD_RS = 0;
LCD_RW = 0;
delay_ms(15);
for(i=1;i<=3;++i) // init af LCD
{
LCD_EN = 0;
LCD_DATA=0b00111000; //8 Bit Interface, 2 Lines
delay_cycles(1);
LCD_EN = 1;
delay_ms(5);
}
// konfig af LCD
lcd_write(0,0b00111000); // 8 Bit Interface, 2 Lines
lcd_write(0,0b00001101); // Turn on display, cursor off, blink ON
lcd_write(0,0x00000001); // clear display
lcd_write(0,0x00000110); // Increment cursor
}
void lcd_gotoxy(byte x, byte y)
{
byte address;
if(y!=1)
address=0x40;
else
address=0;
address+=x-1;
lcd_write(0,0x80|address);
}
void lcd_putc(char c)
{
switch (c)
{
case '\f' :
lcd_write(0,1);
break;
case '\n' :
lcd_gotoxy(1,2);
break;
default :
lcd_write(1,c);
break;
}
}
byte lcd_read(void)
{
byte word;
SET_TRIS_D(0xFF); // set port D as inputs
delay_cycles(1);
LCD_RW = 1;
delay_cycles(1);
LCD_EN = 1;
delay_cycles(4);
word = LCD_DATA;
LCD_EN = 0;
LCD_RW = 0;
SET_TRIS_D(0x00); //set port D as outputs
return( word );
}
void lcd_write(byte address, byte b)
{
SET_TRIS_A(0x00); // set port A, output
LCD_EN = 0;
LCD_RS = 0;
delay_cycles(4);
SET_TRIS_D(0xFF); // set port D, input
while ( bit_test(lcd_read(),7) ) ;
SET_TRIS_A(0x00); // set port A, output
LCD_RS = address;
LCD_RW = 0;
delay_cycles(1);
SET_TRIS_D(0x00); // set port D, output
LCD_DATA=b;
delay_cycles(1);
LCD_EN = 1;
delay_cycles(4);
LCD_EN = 0;
}
main()
{
lcd_init();
lcd_putc("\ftest"); // clears display with \f and writes test in line 1, as expected.
// I have tried with other text's like "test", "\f\ntest" ...etc., same problem.
while(1) {}
}
|
Best Regards
Rasmus 'Izolator' |
|
|
Kasper
Joined: 14 Jan 2004 Posts: 88 Location: Aurora, Ontario, Canada
|
|
Posted: Fri Feb 27, 2004 2:47 pm |
|
|
double check with the lcd.c driver which shipped with the compiler. it may give you a hint |
|
|
Izolator
Joined: 10 Feb 2004 Posts: 12 Location: Denmark, (Scandinavia-Europe)
|
|
Posted: Fri Feb 27, 2004 2:55 pm |
|
|
I'm a complete newie and I really need the features that my program offers. I looked at the lcd.c and it is for 4 line lcd, not my cup of tea.
I think my problems are related to the timing and was hoping others had used the code by mr. Troy Schultz, e.g. the lcd code I am using.
....any ideas ?
BR
Rasmus 'Izolator' |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Izolator
Joined: 10 Feb 2004 Posts: 12 Location: Denmark, (Scandinavia-Europe)
|
|
Posted: Fri Feb 27, 2004 3:34 pm |
|
|
I have it wired up ok, I guess:
LCD:Pic16F877
0: ground
1: +5V
3: -1.5V ( I got a potentiometer and steal the negative voltage from a maxim max233a, p10 => steady negative voltage)
4: pin5
5: pin6
6: pin4
7-14: D0-D7
15-16: not connected, backlight not present, I'm told
I dont have a scope, but I do have a voltmeter and I tested the pins, they are ok.
The problem is most notorious when it has been powered off for a few hours....weird.
Anyone else use the code posted who has had similar problems or solved them ?
BR
Rasmus 'Izolator' |
|
|
chava
Joined: 07 Sep 2003 Posts: 56
|
are you?... |
Posted: Fri Feb 27, 2004 4:31 pm |
|
|
are you using picdem2 board?
I remember when I started using the lcd, i had problems (can't remember what problems..)
if your using the picdem2 board ,here is a code I use which WORK
you may change the pin defines to alter it for your own connection
hope it will help
Code: |
//LCD //////////////////////////////
// As defined in the following structure the pin connection is as follows:
// pic lcd
// ---------------
// A1 enable
// A2 rw
// A3 rs
// D0 D4
// D1 D5
// D2 D6
// D3 D7
//
// LCD pins D0-D3 are not used and PIC D3 is not used.
//***********************************************************#if defined(__PCH__)
#byte lcd = 0xF83 // This puts the entire structure
#else
#byte lcd = 8 // on to port D (at address 8)
#endif
//***********************************************************#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
/ /The following are used for setting
// the I/O port direction register.
//***** lcd command port ******
struct lcd_command{
char none:1;
char enable:1;
char read_write:1;//rw
char data_command:1;//rs
};
struct lcd_command lcd_command_port;
#locate lcd_command_port=5
//---------------------------------------------------
struct lcd_data{
char data:4;
};
struct lcd_data lcd_data_port;
#locate lcd_data_port=8
//************ "COMMAND / DATA definition
#define COMMAND0 0
#define DATA1 1
//************ "READ / WRITE definition
#define WRITE0 0 //LCD <- MPU
#define READ1 1 //LCD -> MPU
//************ "E_UP / E_DOWN definition
#define E_DOWN 0
#define E_UP 1
//**********eeprom or flash*********************
#define EEPROM0 0 ;eeprom - not the program memory
#define FLASH1 1 ;program memory
//********* set tris d *********
#define set_tris_lcd_read(){\
set_tris_a(TRISA & 0xf1/*0b11110001*/);\
set_tris_d(TRISD | 0x0f/*0b00001111*/);\
}
#define set_tris_lcd_write(){\
set_tris_a(TRISA & 0xf1/*0b11110001*/);\
set_tris_d(TRISD & 0xf0/*0b11110000*/);\
}
//*********** clear LCD ***********************************
#define clear_lcd lcd_send_byte(0x1,COMMAND0);//clear lcd display
//***********************************************************
//**********************************************************
char lcd_read_byte(void){
char low,high;
set_tris_lcd_read();
lcd_command_port.read_write = READ1;
delay_cycles(1);
lcd_command_port.enable = E_UP;
delay_cycles(1);
high = lcd_data_port.data & 0x0f;
lcd_command_port.enable = E_DOWN;
delay_cycles(1);
lcd_command_port.enable = E_UP;
delay_us(1);
low = lcd_data_port.data & 0x0f;
lcd_command_port.enable = E_DOWN;
set_tris_lcd_write();
return( (high << 4) | low);
}
//*************** - -
void lcd_write_nibble(char temp_wr){
//Purpose:
lcd_data_port.data = temp_wr;
delay_cycles(1);
lcd_command_port.enable = 1;
delay_us(2);
lcd_command_port.enable = 0;
}
//*************** - -
void lcd_send_byte(char data , char data_or_command ) {
lcd_command_port.data_command = COMMAND0;
while ( bit_test(lcd_read_byte(),7) ) ;
lcd_command_port.data_command = data_or_command;
delay_cycles(1);
lcd_command_port.read_write = WRITE0;
delay_cycles(1);
lcd_command_port.enable = E_DOWN;
lcd_write_nibble(data >> 4);
lcd_write_nibble(data & 0xf);
}
//*********************************************************
void lcd_gotoxy( char location, char line) {//location 0...
char address;
if(line!=1)
address=40;//was80
else
address=0;
address+=location;
lcd_send_byte(0x80|address,COMMAND0);
}
//********** - 1 -
void lcd_init(void){
//Purpose: initiate the lcd
//turnning PORTA0=analog, PORTA1-7=digital
ADCON1=0x0e;
//turnning command pin of lcd to output
set_tris_lcd_write();
//delay 15msec
delay_ms(15);
lcd_command_port.enable=0;
lcd_command_port.data_command=0;
lcd_command_port.read_write=0;
lcd_data_port.data=0;
delay_ms(2);
lcd_write_nibble(0x03);//was 30 ddram address: 1:1bit,line:1bit,address:4bit
delay_ms(10);//more then 4.1msec
lcd_write_nibble(0x03);//was 30
delay_us(150);//more then 100usec
lcd_write_nibble(0x03);//was 30
delay_us(100);
lcd_write_nibble(0x02);//was 20
while(bit_test(lcd_read_byte(),7));
lcd_send_byte(0x28,COMMAND0);
// 4 bit low nibble, ddram address=0 first line
lcd_send_byte(0x0c,COMMAND0);//disp on
clear_lcd;
lcd_send_byte(0x6,COMMAND0);//entry inc
lcd_gotoxy(1,1);
}
//*********************************************************
void lcd_putc( char c) {//this function works good
switch (c) {
case '\f' : lcd_send_byte(1,COMMAND0); delay_ms(2); break; //Clear display
case '\n' : lcd_gotoxy(1,2); break; //Go to start of second line
case '\b' : lcd_send_byte(0x10,COMMAND0); break; //Move back one position
default : lcd_send_byte(c,DATA1); break; //send the actual character
}
}
//*************** - -
char lcd_getc( char location, char line) {
char value;
lcd_gotoxy(location,line);
while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low
lcd_command_port.data_command=1;
value = lcd_read_byte();
lcd_command_port.data_command=0;
return(value);
return 1;
}
//**********************************************************
//*************************----
void lcd_put_string(char *string){
//put string, starting from the curren cursor position
//assume that string not excides from lcd displayed RAM
char index=0;
while(string[index]!=0){
lcd_putc(string[index++]);
}
}
|
|
|
|
Izolator
Joined: 10 Feb 2004 Posts: 12 Location: Denmark, (Scandinavia-Europe)
|
|
Posted: Fri Feb 27, 2004 4:37 pm |
|
|
Problem solved, it seems:
Code: |
void lcd_write(byte address, byte b)
{
SET_TRIS_A(0x00); // set port A, output
LCD_EN = 0;
LCD_RS = 0;
delay_cycles(4);
// SET_TRIS_D(0xFF); <= problem line, allready tris'ed input in lcd_read
while ( bit_test(lcd_read(),7) ) ;
// SET_TRIS_A(0x00); <= problem line, allready tris'ed output in lcd_read
LCD_RS = address;
LCD_RW = 0;
delay_cycles(1);
SET_TRIS_D(0x00); // set port D, output
LCD_DATA=b;
delay_cycles(1);
LCD_EN = 1;
delay_cycles(4);
LCD_EN = 0;
}
|
Apparently setting the same tris as the port direction already has is not a good idea.....or that is my theory, because it works now :-)
Thankyou for your time guys, I was about to panick
...taught me to check the tris before asking again
BR
Rasmus 'Izolator' |
|
|
Guest
|
|
Posted: Mon Mar 01, 2004 6:33 pm |
|
|
while were on the topic,
could anybody tell me which is easier to use a parallel or serial LCD.
if anybody has some sample code for displaying on a serial LCD, from a 16f877
if you could mail it to kitedude@kitedemon.com it would be much appreciated.
Brian |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Tue Mar 02, 2004 9:55 am |
|
|
Here is the PICDEM2 PLUS driver I came up with.
Code: |
//////////////////////////////////////////////////////////////////////////
//// PICDEM2_LCD.C ////
//// Driver for common PICDEM2 PLUS LCD modules ////
//// ////
//// lcd_init() Must be called before any other function. ////
//// ////
//// lcd_putc(c) Will display c on the next position of the LCD. ////
//// The following have special meaning: ////
//// \f Clear display ////
//// \n Go to start of second line ////
//// \b Move back one position ////
//// ////
//// lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1) ////
//// ////
//// lcd_getc(x,y) Returns character at position x,y on LCD ////
//// ////
///////////////////////////////////////////////////////////////////////////
#define use_PICDEM2_lcd TRUE
#if defined use_PICDEM2_lcd
#define lcd_en PIN_A1
#define lcd_rw PIN_A2
#define lcd_rs PIN_A3
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
#define d_cycle 1
#endif
void lcd_send_nibble( BYTE n ) {
n=n&0x0f; //Strip off the top 4 bits.. This only sends bit 3:0
output_d(n);
delay_cycles(d_cycle);
output_high(lcd_en);
delay_us(20);
output_low(lcd_en);
}
BYTE lcd_read_byte() {
BYTE low,high;
output_high(lcd_rw);
delay_cycles(d_cycle);
output_high(lcd_en);
delay_cycles(d_cycle);
high = input_d(); //using d0:d3 for 4 bit data bus
output_low(lcd_en);
delay_cycles(d_cycle);
output_high(lcd_en);
delay_us(1);
low = input_d(); //using d0:d3 for 4 bit data bus
output_low(lcd_en);
return((high<<4) | low);
}
void lcd_send_byte( BYTE A0, BYTE n ) { //A0: 0=instruction, 1=Data
output_low(lcd_rs);
while ( bit_test(lcd_read_byte(),7) ) ; // wait until busy flag is low
if (A0==0){ output_low(lcd_rs);} //0=Instruction and 1=Data
if (A0==1){output_high(lcd_rs);} //0=Instruction and 1=Data
delay_cycles(d_cycle);
output_low(lcd_rw);
delay_cycles(d_cycle);
output_low(lcd_en);
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
void lcd_init() {
BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
// These bytes need to be sent to the LCD for initialization.
BYTE i;
fprintf(debug,"Init!!\n\r");
output_low(lcd_rs);
output_low(lcd_rw);
output_low(lcd_en);
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_nibble(3);
delay_ms(5);
}
lcd_send_nibble(2);
for(i=0;i<=3;++i){
lcd_send_byte(0,LCD_INIT_STRING[i]);
}
}
void lcd_gotoxy( BYTE x, BYTE y) {
BYTE Data;
if(y!=1)
Data=lcd_line_two;
else
Data=0;
Data+=x-1;
lcd_send_byte(0,0x80|Data);
}
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;
}
}
char lcd_getc( BYTE x, BYTE y) {
char value;
lcd_gotoxy(x,y);
while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low
output_high(lcd_rs);
value = lcd_read_byte();
output_low(lcd_rs);
return(value);
} |
Also double check that the circuit doesn't need any pull-up resisters. |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Tue Mar 02, 2004 9:57 am |
|
|
Opps,.. you wanted code for a serial LCD,... This was 4 bit parallel |
|
|
Guest
|
|
Posted: Wed Mar 10, 2004 6:43 pm |
|
|
the problem with the ide board is that pin 39 and 40 ar enot connected to the board so they can not be used.
the lcd.cd supplied with ccs uses these ports and hence has to be modified before its used |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|