|
|
View previous topic :: View next topic |
Author |
Message |
masacra
Joined: 15 Nov 2004 Posts: 4
|
LCD in 8 bit mode, help please |
Posted: Mon Nov 15, 2004 1:16 pm |
|
|
Hi, I´m new in programming PICs in C. It looked easy until I tried to use a LCD in 8 bit mode. I am using a 16F877A with an oscilator of 4Mhz.
I want to use the E port for enable,R/W and RS and the whole D port for data. I´ve tried to adapt the LCD.c archive which came with the compiler to satisfy my needs, but it does not result. It would be great if anyone could give me a kind of LCD.c arrchive with the LCD most common instructions, such as lcd_putc(), lcd_get_c() and so on.
Can anybody help me, please? |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Nov 15, 2004 1:20 pm |
|
|
Pretty easy to do. Take a look at this post where I modified CCS's code to allow different pins to be used. Give it a go and if you can't get it, let me know and I will help you more.
http://www.ccsinfo.com/forum/viewtopic.php?t=20182 |
|
|
masacra
Joined: 15 Nov 2004 Posts: 4
|
|
Posted: Mon Nov 15, 2004 1:30 pm |
|
|
Thank you for answering me so fast!! I´ve already seen and tried to get the lcdd.c to work, but I´ve trouble with it.
How can I select the pins I want to interface the LCD in this program? I´ve seen no place to do that, and I find it hard to see where can I apply the changes I need without making this program definitely fail.
In this program also the LCD is accesed in 4-bit mode, I´ve tried to change that, to make it work in 8-bit mode but it doesn´t work.
Many thanks |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Nov 15, 2004 1:38 pm |
|
|
Did you look at the post? It differs from CCS's code in the declaration. Here is an example on how to modify the declares to move the control lines to portE and 8bit data. You will still have to modify the code and const for 8bit mode. Give it a shot.
Code: | // This structure is overlayed onto the data ports so that you may use
// whatever ports you desire
struct lcd_pin_map
{
int unusedA; // portA is not used
int unusedB; // portB is not used
int unusedC; // portC is not used
int data; // portD is used for data lines
BOOLEAN enable; // PinE0
BOOLEAN rw; // PinE1
BOOLEAN rs; // PinE2
int unusedE : 5; // The rest of portE
} lcd;
#if defined(__PCH__)
#locate lcd = 0xF80
#else
#locate lcd = 5
#endif
struct lcd_tris_map
{
int unusedA; // The rest of portA
int unusedB; // portB is not used
int unusedC; // portC is not used
int data; // portD is used for data lines
int control : 3; // portE for control
int unusedE : 5; // The rest of portE
} lcdtris;
|
|
|
|
masacra
Joined: 15 Nov 2004 Posts: 4
|
|
Posted: Tue Nov 16, 2004 11:34 am |
|
|
Well I´ve tried to make some changes, but the code still doesn´t work. I am using a 2x16 LCD and I don´t know where to fit that fact in the code.
Some things I´ve changed are constants such as the following:
Code: |
#define LCD_READ 0xFF // For read mode data pins are in
|
But I´ve no idea how to change the code to make it work, I have read it many times and still don´t understand it fully.
Another thing is that I have working routines in assembly for LCD and keypad, if I include those will they work with CCS C?
Thanks a lot, you´re so helpfull. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Nov 16, 2004 12:42 pm |
|
|
This works for me:
Code: |
// This structure is overlayed onto the data ports so that you may use
// whatever ports you desire
struct lcd_pin_map
{
int unusedA; // portA is not used
int unusedB; // portB is not used
int unusedC; // portC is not used
int data; // portD is used for data lines
BOOLEAN enable; // PinE0
BOOLEAN rw; // PinE1
BOOLEAN rs; // PinE2
int unusedE : 5; // The rest of portE
} lcd;
#if defined(__PCH__)
#locate lcd = 0xF80
#else
#locate lcd = 5
#endif
struct lcd_tris_map
{
int unusedA; // The rest of portA
int unusedB; // portB is not used
int unusedC; // portC is not used
int data; // portD is used for data lines
int control : 3; // portE for control
int unusedE : 5; // The rest of portE
} lcdtris;
#if defined(__PCH__)
#locate lcdtris = 0xF92
#else
#locate lcdtris = 0x85
#endif
#define set_tris_lcd(x) lcdtris.data = (x); lcdtris.control = 0;
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
BYTE const LCD_INIT_STRING[4] = {8, 0xc, 1, 6};
// These bytes need to be sent to the LCD
// to start it up.
// The following are used for setting
// the I/O port direction register.
#define LCD_WRITE 0 // For write mode all pins are out
#define LCD_READ 0xFF // For read mode data pins are in
BYTE lcd_read_byte() {
BYTE data;
set_tris_lcd(LCD_READ);
lcd.rw = 1;
delay_cycles(1);
lcd.enable = 1;
delay_cycles(1);
data = lcd.data;
lcd.enable = 0;
set_tris_lcd(LCD_WRITE);
return( data );
}
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;
while ( bit_test(lcd_read_byte(),7) ) ;
lcd.rs = address;
delay_cycles(1);
lcd.rw = 0;
delay_cycles(1);
lcd.enable = 0;
lcd.data = n;
delay_cycles(1);
lcd.enable = 1;
delay_us(2);
lcd.enable = 0;
}
void lcd_init() {
BYTE i;
set_tris_lcd(LCD_WRITE);
lcd.rs = 0;
lcd.rw = 0;
lcd.enable = 0;
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_byte(0, 0x38);
delay_ms(5);
}
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
}
void lcd_gotoxy( BYTE x, BYTE y) {
BYTE 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;
}
}
char lcd_getc( BYTE x, BYTE y) {
char value;
lcd_gotoxy(x,y);
lcd.rs=1;
value = lcd_read_byte();
lcd.rs=0;
return(value);
}
|
and a test program:
Code: |
#include <16F876.h>
#device *=16
#case
#use delay(clock=20000000)
#fuses HS,NOWDT,NOPROTECT,NOLVP
#ZERO_RAM
#include "lcdd.c"
//======================= MAIN ============================//
void main(void)
{
lcd_init();
printf(lcd_putc,"Hello World");
printf(lcd_putc,"\nSecond Line");
while(1)
{
}
} |
|
|
|
masacra
Joined: 15 Nov 2004 Posts: 4
|
|
Posted: Tue Nov 16, 2004 1:30 pm |
|
|
Thanks a lot! You have saved me a lot of work. I had to change some of your code to make it run, just a couple of litle things, nothing reliable.
I needed this because I am going to start working with more powerfull MCUs oriented to interfacing LCDs. I am interested in scrolls (specially vertical, the horizontal ones I already know) and in anything related to using LCDs, how can I program the lcd to make vertical scrolls or other kind of efects?(Also Iwould like to enter new characters in the LCD´s RAM).
I have done almost everything above in assembly, but I find myself quite lost in C. Thanks again! |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Nov 16, 2004 1:34 pm |
|
|
If you can do it in asm then you can do it in C. Most of the stuff in asm is just setting the registers to certain values. The same holds true for C. The same LCD code could have been written using bit_set and bit_clear on the port registers. The C Struct just kind of "hides" it. Note you can also embed asm code in a C routine with the #asm. |
|
|
Boyko
Joined: 11 Oct 2004 Posts: 13 Location: Sofia
|
|
Posted: Fri Nov 26, 2004 5:44 am |
|
|
Could you please help me. I'd like to use my LCD like this:
PortD.4-7 : data lnes
PortE.0 : rs
PortE.1 : enable
PortE.2 : rw
I tried to modify the Mark's lcdd.c file, but when I compile the test program I get an error message, in the lcdd.c file, saying "Illegal C character in input file 0xA0". Here is the lcdd.c file I modified:
Code: |
// This structure is overlayed onto the data ports so that you may use
// whatever ports you desire
struct lcd_pin_map
{
int unusedA; // portA is not used
int unusedB; // portB is not used
int unusedC; // portC is not used
int unusedD : 4; // lower nibble of portD unused
int data : 4; // high nibble of portD for data
boolean rs; // pin E0
booelan enable; // pin E1
boolean rw; // pin E2
int unusedE : 5; // rest unused
} lcd;
#if defined(__PCH__)
#locate lcd = 0xF80
#else
#locate lcd = 5
#endif
struct lcd_tris_map
{
int unusedA; // The rest of portA
int unusedB; // portB is not used
int unusedC; // portC is not used
int unusedD : 4; // lower nibble of portD is unused
int data : 4; // data lines
int control : 3; //
int unusedE : 5; // unused
} lcdtris;
#if defined(__PCH__)
#locate lcdtris = 0xF92
#else
#locate lcdtris = 0x85
#endif
#define set_tris_lcd(x) lcdtris.data = (x); lcdtris.control = 0;
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
// These bytes need to be sent to the LCD
// to start it up.
// The following are used for setting
// the I/O port direction register.
#define LCD_WRITE 0 // For write mode all pins are out
#define LCD_READ 15 // For read mode data pins are in
BYTE lcd_read_byte() {
BYTE low,high;
set_tris_lcd(LCD_READ);
lcd.rw = 1;
delay_cycles(1);
lcd.enable = 1;
delay_cycles(1);
high = lcd.data;
lcd.enable = 0;
delay_cycles(1);
lcd.enable = 1;
delay_us(1);
low = lcd.data;
lcd.enable = 0;
set_tris_lcd(LCD_WRITE);
return( (high<<4) | low);
}
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;
while ( bit_test(lcd_read_byte(),7) ) ;
lcd.rs = address;
delay_cycles(1);
lcd.rw = 0;
delay_cycles(1);
lcd.enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
void lcd_init() {
BYTE i;
set_tris_lcd(LCD_WRITE);
lcd.rs = 0;
lcd.rw = 0;
lcd.enable = 0;
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 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;
}
}
char lcd_getc( BYTE x, BYTE y) {
char value;
lcd_gotoxy(x,y);
lcd.rs=1;
value = lcd_read_byte();
lcd.rs=0;
return(value);
}
|
And the test program:
Code: |
#include <18F452.h>
#use delay(clock=4000000)
#fuses HS,NOWDT,NOPROTECT,NOLVP
#include "lcdd.c"
//======================= MAIN ============================//
void main(void)
{
lcd_init();
printf(lcd_putc,"Hello World");
printf(lcd_putc,"\nSecond Line");
while(1)
{
}
}
|
What am I doing wrong? _________________ Regards
Boyko |
|
|
Boyko
Joined: 11 Oct 2004 Posts: 13 Location: Sofia
|
|
Posted: Sat Nov 27, 2004 12:34 pm |
|
|
Come on friends. I need help. I'm a novice with the CCS PIC C. I have got the LAB-X1 development system where the LCD is connected:
PortD.4 - data
PortD.5 - data
PortD.6 - data
PortD.7 - data
PortE.0 - rs
PortE.1 - enable
PortE.2 - rw
I can't manage to run it. The original lcd.c file is for PortA or PortB. What modification I've to do? Till now I used Proton+. _________________ Regards
Boyko |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sat Nov 27, 2004 12:54 pm |
|
|
Compiles just fine if you change boolean to BOOLEAN |
|
|
|
|
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
|