|
|
View previous topic :: View next topic |
Author |
Message |
chin0609
Joined: 13 Sep 2011 Posts: 18
|
Need Help LCD 16x2 |
Posted: Tue Sep 13, 2011 9:05 pm |
|
|
Im using flex_lcd in my PIC16F877A but i only show black block?
here my code
flex_lcd.c
// 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_B4
#define LCD_DB5 PIN_B4
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_E PIN_B3
#define LCD_RS PIN_B2
#define LCD_RW PIN_B1
// 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
main code
#include <16F877A.H>
#use delay (clock=20000000) // 20MHz
#define LCD_POWER PIN_B0
#include <flex_lcd.c>
#FUSES HS,NOWDT, NOPROTECT, BROWNOUT, NOLVP, PUT
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7) //serial
#define SERVO1 PIN_c1
#define led_green PIN_d1
#define led_red PIN_d0
int8 i; // looping
void nocar()
{
for (i=0;i<30;i++) //0 deg
{
output_low(led_green);
output_high(led_red);
output_high(SERVO1);
delay_us(1500);
output_low(SERVO1);
delay_ms(18);
}
lcd_init();
lcd_putc("\fDoor Closed");
}
void car()
{
for (i=0;i<30;i++) // 90 deg
{
output_low(led_red);
output_high(led_green);
output_high(SERVO1);
delay_us(2000);
output_low(SERVO1);
delay_ms(18);
}
lcd_init();
lcd_putc("\fDoor Opened");
}
void main()
{
output_high(LCD_POWER); // Turn on power to LCD
output_low(LCD_RW);
while(1)
{
if(input(PIN_C0)) //Sensor input
{ nocar(); }
else
{ car(); }
}
} |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Sep 13, 2011 10:24 pm |
|
|
Fix this:
Quote: |
#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B4
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_E PIN_B3
#define LCD_RS PIN_B2
#define LCD_RW PIN_B1
|
Each signal must be on a separate pin. You can't use the same pin 2 times. |
|
|
chin0609
Joined: 13 Sep 2011 Posts: 18
|
|
Posted: Wed Sep 14, 2011 12:20 am |
|
|
I'm changed still come out black block.
Code: | // 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_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_E PIN_B3
#define LCD_RS PIN_B1
#define LCD_RW PIN_B2
// 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 |
main code:
Code: | #include <16F877A.H>
#use delay (clock=20000000) // 20MHz
#define LCD_POWER PIN_B0
#include <flex_lcd.c>
#FUSES HS,NOWDT, NOPROTECT, BROWNOUT, NOLVP, PUT
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7) //serial
#define SERVO1 PIN_c1
#define led_green PIN_d1
#define led_red PIN_d0
int8 i; // looping
void nocar()
{
for (i=0;i<30;i++) //0 deg
{
output_low(led_green);
output_high(led_red);
output_high(SERVO1);
delay_us(1500);
output_low(SERVO1);
delay_ms(18);
}
lcd_init();
lcd_putc("\fDoor Closed");
}
void car()
{
for (i=0;i<30;i++) // 90 deg
{
output_low(led_red);
output_high(led_green);
output_high(SERVO1);
delay_us(2000);
output_low(SERVO1);
delay_ms(18);
}
lcd_init();
lcd_putc("\fDoor Opened");
}
void main()
{
output_high(LCD_POWER); // Turn on power to LCD
output_low(LCD_RW);
lcd_init();
while(1)
{
if(input(PIN_C0)) //Sensor input
{ nocar(); }
else
{ car(); }
}
} |
LCD pin configure.
VSS to ground
VDD to +5v
VEE to potentiometer
RS to PortB1
RW to ground
E to PortB3
D4 to PortB4
D5 to PortB5
D6 to PortB6
D7 to PortB7 |
|
|
albal
Joined: 13 Sep 2011 Posts: 4 Location: United Kingdom
|
|
Posted: Wed Sep 14, 2011 1:37 am |
|
|
I don't think you mean to wire RW to GND. You should have it connected to PORTB2.
I would once again go over your physical connections and check that there are correct and valid against your declarations in your C code. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Sep 14, 2011 5:13 am |
|
|
RW can go to ground..it's the '6 pin' wiring for common LCDs that you use in 'write only'(please read comments at the top of the flex driver).I've done it for years, and I currently have an 877 with 2x16 LCD in this mode.
BTW you typically only need .5 volts for VEE, so the pot only needs to be a little above ground.
Also try connecting LCD VDD(+5v) directly to +5V,not controlled by I/O pin B0.
oh and add 'errors' to your use rs232(...) options otherwise the UART buffer with trap out and stall. |
|
|
chin0609
Joined: 13 Sep 2011 Posts: 18
|
|
Posted: Wed Sep 14, 2011 6:31 am |
|
|
my lcd only display black block only even i adjusted pot.
any wrong in my main code ?
i am new in ccs c..anyone can help me check the main code and lcd?
Quote: | and add 'errors' to your use rs232(...) options otherwise the UART buffer with trap out and stall. |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Sep 14, 2011 7:07 am |
|
|
Ok...best to start over and just test the LCD without the other code...
something like....
Code: |
void main()
{
lcd_init();
while(1)
{
lcd_putc("Hello World");
delay_ms(500);
}
}
|
You do NOT have to run lcd_init() more than once in your program.
Your program might be clearing the LCD in the loop that you have and you can't see what's really going on,so try the simple 'Hello world' test and then build upon that.
It helps to make changes, save as a new file 'test001, test002,test 003,...
That way you can always go back to a program that you know worked. |
|
|
chin0609
Joined: 13 Sep 2011 Posts: 18
|
|
Posted: Wed Sep 14, 2011 7:24 am |
|
|
Code: | void main()
{
lcd_init();
while(1)
{
lcd_putc("Hello World");
delay_ms(500);
}
}
|
tested this code..result still same ( black block)
just want to ask is the Flex_lcd.c only compatible in Microchip PicDem2-Plus board or??
BTW i am build the simple PIC16F877A board myself not using the PicDem2-Plus board. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Sep 14, 2011 8:47 am |
|
|
Ok...I downloaded the schematic of the PicDem-2 board and found your problem.
You have to redefine the correct pins for the onboard LCD. PicDem uses port D NOT B for the LCD connections.
Simply alter the flex_lcd driver to use the correct pins. I'd rename this new version to say 'picdem2_lcd.c' to keep the original 'safe'.
Be sure to include the new version NOT the original !
Also note that Microchip use a pin to control the voltage to the LCD, be sure to set that pin high to provide power to the LCD.A simple output_high(...) will do the job ! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Sep 14, 2011 12:30 pm |
|
|
Quote: |
i am build the simple PIC16F877A board myself not using the PicDem2-Plus board
|
I think the Flex driver should work with any normal 16x2 lcd, or it
can be configured to do so.
But in your posted code, you are using special commands that are ONLY
for the "Rohs" version of the PicDem2-Plus board.
The following lines in your code would be used for the "Rohs" version of
the PicDem2-Plus. If you don't have that board, you don't need to do this !
Quote: |
//#define USE_LCD_RW 1 // commented out
output_high(LCD_POWER); // Turn on power to LCD
output_low(LCD_RW);
|
Also, you have the two lines below, as if you are controlling the LCD power
with the PIC:
Quote: | #define LCD_POWER PIN_B0
output_high(LCD_POWER);
|
But then, in your list of connections below, you show that the LCD is
hard-wired to the +5v power supply rail ! So you don't need a pin called
"LCD Power".
Quote: |
LCD pin configure.
VSS to ground
VDD to +5v
VEE to potentiometer
RS to PortB1
RW to ground
E to PortB3
D4 to PortB4
D5 to PortB5
D6 to PortB6
D7 to PortB7
|
Go through your program and get rid of all the useless lines that are
for the "Rohs" board. Only put in code that is used by your board.
Go here, and get the "plain" Flex lcd driver. It's in the first post:
http://www.ccsinfo.com/forum/viewtopic.php?t=24661
Use it.
Also, in your list of LCD connections, you are using pins B6 and B7.
These pins are used by the ICD programmer/debugger. It needs those
pins. You can't run the debugger and the LCD together on those pins.
Quote: |
D4 to PortB4
D5 to PortB5
D6 to PortB6
D7 to PortB7
|
My advice is to use two other PIC pins for D6 and D7. Change the
connections on your board, and edit the list of pin #define statements
at the top of the flex lcd file, so it matches the new connections on your
board. |
|
|
chin0609
Joined: 13 Sep 2011 Posts: 18
|
|
Posted: Wed Sep 14, 2011 10:25 pm |
|
|
followed the plain flex_lcd still get the same result
Code: | // 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_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_A1
#define LCD_DB7 PIN_A2
#define LCD_E PIN_B3
#define LCD_RS PIN_B1
#define LCD_RW PIN_B2
// 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 |
Code: | void main()
{
lcd_init();
while(1)
{
output_high(PIN_A1);
delay_ms(1000);
output_low(PIN_A1);
printf(lcd_putc, "Hello World.");
delay_ms(1000);
}
} |
im using lcd jhd162a...does the unused pin connect to ground or just left it? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Sep 14, 2011 10:59 pm |
|
|
Quote: |
#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_A1
#define LCD_DB7 PIN_A2
#define LCD_E PIN_B3
#define LCD_RS PIN_B1
#define LCD_RW PIN_B2
// 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
lcd_init();
while(1)
{
output_high(PIN_A1);
delay_ms(1000);
output_low(PIN_A1);
printf(lcd_putc, "Hello World.");
delay_ms(1000);
}
|
Don't toggle a pin that you use for the LCD !
Quote: | does the unused pin connect to ground or just left it? |
Which unused pins ? Do you mean DB0 to DB3 on the LCD ?
Just leave them unconnected.
Upload a schematic of your board to a free image hosting website,
such as http://www.imageshack.com
Then post a link to the schematic in this thread, so we can look at it. |
|
|
chin0609
Joined: 13 Sep 2011 Posts: 18
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Thu Sep 15, 2011 9:29 am |
|
|
OK....I've confirmed it is NOT a basic driver or hardware problem.
I've used your pin assignments..
// modified flex_lcd.c
#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_A1
#define LCD_DB7 PIN_A2
#define LCD_E PIN_B1
#define LCD_RS PIN_B3
#define LCD_RW PIN_B2 //not used !
with LCD_RW pin(5) on LCD tied to ground( write only mode).
This is how I always wire LCDs as I do not need to read from them.
Hooked up to my trusty 16F877 with 20MHz xtal and it works fine
I do have fixed resistors on the LCD Vee pin3,about .5volts.
So the problem is NOT the flex_LCD driver,unless you've changed something other than the pin assignments. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 15, 2011 1:40 pm |
|
|
Post another photo of your LCD that is in focus and a close-up,
and that shows all the pins. I am beginning to suspect that you have
solder shorts between the pins, or you may picked the wrong side of
the connector as "pin 1". If you post a clear photo of the pins and wires
connected to them, then maybe it will show the problem.
Also, your schematic shows "switch" on the MCLR pin. Do you have a
pull-up resistor on MCLR ? You need one. Usually it's a 10K resistor to +5v.
Have you measured the voltage on the contrast pin of the LCD ?
It should be set to about 0.5 volts. |
|
|
|
|
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
|