|
|
View previous topic :: View next topic |
Author |
Message |
newguy Guest
|
lcd problems |
Posted: Tue Nov 25, 2003 12:51 am |
|
|
Hi all,
Long time reader, first time poster.
I've done quite a bit of programming with CCS and pics (18f452, 252, 242, 16f877). However, I've run into a problem and I can't figure it out.
My present project uses an 18f242 and a standard 2x16 lcd character display. This is the first time that I've wired an lcd to port A, and I'm really beginning to question why I did that in the first place. Hindsight is always 20/20, I guess.
The code that I use to communicate with the lcd is basically the same code (lcd.c) that came with the ccs compiler. I've wired the lcd's D4-D7 lines to A0-A3, enable to A4, and rs to A5. Since A4 is an open drain output, I also have a pullup on that line. The lcd's R/W line is grounded, and I'm communicating with it in 4 bit mode. The relevant declarations follow:
struct lcd_pin_map {
int data : 4;
boolean enable;
boolean rs;
} lcd;
#byte lcd = 0xf80
void lcd_send_nibble( byte n ) {
lcd.data = n;
delay_cycles(1);
lcd.enable = 1;
delay_us(2);
lcd.enable = 0;
}
void lcd_send_byte( byte address, byte n ) {
lcd.rs = 0;
delay_us(350);
lcd.rs = address;
delay_cycles(1);
delay_cycles(1);
lcd.enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
What gets me is this same code works when I connect an lcd to port C on a 18f252. The only change I make is the #byte lcd = 0xf82 to point to port C's memory location.
Everything else seems to work, since I can get the pic to toggle lines which control relays, and they click away just fine if I make them toggle. The lcd seems sort of like it hasn't been initialized properly, which means that the code above isn't doing what it's supposed to be doing.
And yes, analogs have been turned off. Can someone please tell me what I'm overlooking? Was hooking an lcd to port A a really stupid idea?
-- Mark |
|
|
Ttelmah Guest
|
Re: lcd problems |
Posted: Tue Nov 25, 2003 3:55 am |
|
|
newguy wrote: | Hi all,
Long time reader, first time poster.
I've done quite a bit of programming with CCS and pics (18f452, 252, 242, 16f877). However, I've run into a problem and I can't figure it out.
My present project uses an 18f242 and a standard 2x16 lcd character display. This is the first time that I've wired an lcd to port A, and I'm really beginning to question why I did that in the first place. Hindsight is always 20/20, I guess.
The code that I use to communicate with the lcd is basically the same code (lcd.c) that came with the ccs compiler. I've wired the lcd's D4-D7 lines to A0-A3, enable to A4, and rs to A5. Since A4 is an open drain output, I also have a pullup on that line. The lcd's R/W line is grounded, and I'm communicating with it in 4 bit mode. The relevant declarations follow:
struct lcd_pin_map {
int data : 4;
boolean enable;
boolean rs;
} lcd;
#byte lcd = 0xf80
void lcd_send_nibble( byte n ) {
lcd.data = n;
delay_cycles(1);
lcd.enable = 1;
delay_us(2);
lcd.enable = 0;
}
void lcd_send_byte( byte address, byte n ) {
lcd.rs = 0;
delay_us(350);
lcd.rs = address;
delay_cycles(1);
delay_cycles(1);
lcd.enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
What gets me is this same code works when I connect an lcd to port C on a 18f252. The only change I make is the #byte lcd = 0xf82 to point to port C's memory location.
Everything else seems to work, since I can get the pic to toggle lines which control relays, and they click away just fine if I make them toggle. The lcd seems sort of like it hasn't been initialized properly, which means that the code above isn't doing what it's supposed to be doing.
And yes, analogs have been turned off. Can someone please tell me what I'm overlooking? Was hooking an lcd to port A a really stupid idea?
-- Mark |
Have you tried 'toggling relays' on portA?. If not, then the problem is almost certainly the initialisation of the port. On the 18F family, portA, also handles the analog inputs. By default it is configures in this way. Hence you have to add the line:
setup_adc_ports(NO_ANALOGS);
If you want to use the port for normal I/O.
There is nothing 'wrong' with using portA for the LCD. :-)
Best Wishes |
|
|
newguy Guest
|
Re: lcd problems |
Posted: Tue Nov 25, 2003 10:38 am |
|
|
[guote="TTelma"]Have you tried 'toggling relays' on portA?. If not, then the problem is almost certainly the initialisation of the port. On the 18F family, portA, also handles the analog inputs. By default it is configures in this way. Hence you have to add the line:
setup_adc_ports(NO_ANALOGS);
If you want to use the port for normal I/O.
There is nothing 'wrong' with using portA for the LCD. :-)
Best Wishes
[/quote]
Yep, did that. The port initializes properly, and timer0 is setup so that it uses the internal source, not the external source on pin A4.
Here's the initialization code:
Code: |
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_wdt(WDT_ON);
setup_timer_0(RTCC_DIV_256|RTCC_8_bit);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
set_tris_a(0x00);
lcd_init();
lcd_putc("\fTest");
}
|
I've taken a look at the .lst file, and it seems as though everything is getting initialized properly.
What size pullup would you recommend to use on pin A4? 10k? 20k? Smaller?
I'm really starting to pull my hair out over this. Is there something that I'm overlooking?
I should mention that I'm using PCH v3.178.
Thanks,
-- Mark |
|
|
Guest Guest
|
|
Posted: Tue Nov 25, 2003 10:58 am |
|
|
Your problem might be that your enable pin (RA4) has a pullup which pulls the signal H during program reset thus causing one pulse on E which the display might misinterpret ...
Just try to swap your E and RS pins as a pulse on the RS line should not cause any harm and check if the problem is still there.
hope this helps |
|
|
Guest
|
|
Posted: Tue Nov 25, 2003 10:59 am |
|
|
Are you reseting the WDT? TTY |
|
|
newguy Guest
|
THAT DID IT!!!! |
Posted: Tue Nov 25, 2003 12:16 pm |
|
|
Guest wrote: | Your problem might be that your enable pin (RA4) has a pullup which pulls the signal H during program reset thus causing one pulse on E which the display might misinterpret ...
Just try to swap your E and RS pins as a pulse on the RS line should not cause any harm and check if the problem is still there.
hope this helps |
Guest, whoever you are, THANK YOU!!!!
I'm now finally able to display a test message on the lcd - your suggestion to swap the E and RS pins was excellent. I owe you a beer.
-- Mark |
|
|
curt2go
Joined: 21 Nov 2003 Posts: 200
|
|
Posted: Tue Nov 25, 2003 12:35 pm |
|
|
|
|
|
Guest Guest
|
Re: THAT DID IT!!!! |
Posted: Wed Nov 26, 2003 1:54 am |
|
|
newguy wrote: | Guest wrote: | Your problem might be that your enable pin (RA4) has a pullup which pulls the signal H during program reset thus causing one pulse on E which the display might misinterpret ...
Just try to swap your E and RS pins as a pulse on the RS line should not cause any harm and check if the problem is still there.
hope this helps |
Guest, whoever you are, THANK YOU!!!!
I'm now finally able to display a test message on the lcd - your suggestion to swap the E and RS pins was excellent. I owe you a beer.
I know thes problems for a long time :-)
You might consider changeing your LCD init code to something like this which works for me in all configurations:
1) POWER ON
2) Wait 15ms
3)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 1 1
4) Wait 4.1ms
5)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 1 1
6) Wait 100us
7)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 1 1
8) Wait 4.1ms
9)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 1 0
4-bit operation
10) Wait 40us
11)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 1 0
12)
RS R/W DB7 DB6 DB5 DB4
0 0 1 F x x
4-bit operation
1/16 duty cycle
F=font, 1 for 5x11 dot matrix
0 for 5x8 dot matrix
x=don't care
13) Wait 40us
14)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 0 0
15)
RS R/W DB7 DB6 DB5 DB4
0 0 1 0 0 0
Display off, cursor off, blink off
16) Wait 40us
17)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 0 0
18)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 0 1
Clear screen, cursor home
19) Wait 1.64ms
20)
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 0 0
21)
RS R/W DB7 DB6 DB5 DB4
0 0 0 1 1 0
Increment cursor to the right
when writing, don't shift screen
21 and a half!!! (addendum)
>RS R/W DB7 DB6 DB5 DB4
>0 0 0 0 0 0
>0 0 0 1 1 0 Increment cursor to the right
> when writing, don't shift screen
>
>Wait 40us
RS R/W DB7 DB6 DB5 DB4
0 0 0 0 0 0
0 0 1 1 C B Turn on display, C=1: turn cursor on,
B=1: make character at cursor position blink
(end addendum)
22) Wait 40us
23) INITIALIZATION COMPLETE
This is from the LCD Faq posted here:
http://preterhuman.net/texts/computing/HardwareDIY/LCDFaq.txt
have fun
-- Mark |
|
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Wed Nov 26, 2003 5:49 pm |
|
|
You might want to be careful about simply connecting your R/W line to ground. I've done several projects using 1 and 2 line displays with the R/W line tied to ground. It works fine but every once-in-a-while I would get garbage on the display and would need to cycle power to get it to go away. After digging into the actual requirements I found out that it is best if you check the 'busy' flag each time you want to send a command or data to the display. Here's the code that I came up with. It might not be the cleanest code but since I have started using it I have not had any problems with any of my LCD displays 'wigging' out.
I have the display lines connected up in the following order:
MCU---------LCD
PIN_A0-----DB4
PIN_A1-----DB5
PIN_A2-----DB6
PIN_A3-----DB7
PIN_A4-----ENABLE
PIN_A5-----RS
PIN_E0-----R/W
This code is for a 1X16 display. Modify it slightly to be used for a 2X16.
//////////////////////
#define ENB PIN_A4 // enable for the LCD display
#define RS PIN_A5 // RS pin of the LCD display
#define RW PIN_E0 // R/W bit for the LCD display
void pulse(unsigned int8 bits) // sends out the clock pulse to the LCD display
{
output_high(ENB);
output_a(bits);
delay_cycles(2);
output_low(ENB);
}
void bf_check(void) // checks the 'busy flag' for the LCD chipset
{
int1 BF = 0;
set_tris_a(0x0F);// set bits 0-3 as inputs
output_low(RS);
output_high(RW);
delay_cycles(3);
do
{
output_high(ENB);
delay_cycles(6);
if(input(PIN_A3))
{
BF = 1;
}
else
{
BF = 0;
}
output_low(ENB);
delay_cycles(3);
output_high(ENB);
delay_cycles(6);
output_low(ENB);
}while(BF);
set_tris_a(0x00);// set all bits to outputs
}
void ctlnib(int8 niblet) // sends a control command to the LCD display
{
int8 msn, lsn;
bf_check();
msn = niblet & 0xF0;
msn = msn >> 4;
msn = msn | 0x10;
output_low(RW);
output_low(RS);
pulse(msn);
lsn = niblet & 0x0F;
lsn = lsn | 0x10;
pulse(lsn);
}
void datnib(int8 niblet) // sends a data byte to the LCD display
{
int8 msn, lsn;
bf_check();
msn = niblet & 0xF0;
msn = msn >> 4;
msn = msn | 0x30;
output_low(RW);
output_high(RS);
pulse(msn);
lsn = niblet & 0x0F;
lsn = lsn | 0x30;
pulse(lsn);
}
void disline(char outstr[], int8 dline) // format is; string - line
{ // displays a line of text on the LCD display
int8 llg, dindex, track;
track = dline;
ctlnib(dline);
llg = strlen(outstr);
for(dindex = 0; dindex <= llg - 1; dindex++)
{
if(track == 0x88) //this is for 1X16 displays, modify this section for 2X16 displays
{
ctlnib(0xC0);
}
datnib(outstr[dindex]);
track++;
}
}
void initdisp(void) // initialize the LCD display
{
output_low(RW);
delay_ms(30);
pulse(0x03);
delay_ms(10);
pulse(0x03);
delay_us(300);
pulse(0x03);
pulse(0x02);
ctlnib(0x28);
ctlnib(0x80);
ctlnib(0x01);
ctlnib(0x06);
ctlnib(0x0C);
}
Hope this might help. :o)
Ronald |
|
|
|
|
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
|