Me 8 You 4 ( LCD PIC Interface With C)

rjenkins

Joined Nov 6, 2005
1,013
I don't know the compiler you are using, but with mine it's
set_tris_b(0xF0); or whatever.

The TRIS registers are the only way to enable/disable the output drivers in the PIC chip itself.

You may have to use compiler options to force it to allow you to control the TRIS settings, mine defaults to adding code to set the TRIS bits every time you read or write a port or port bit unless you explicitly disable this, which for the CCS compiler is:
#use fast_io(ALL)

You can then set all the TRIS registers to suit your hardware design & change them yourself as needed for I/O operations.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
after modification not work but it is very important point you said

Rich (BB code):
     temp = 0x00;
     temp = LCD_data & 0XF0;
     LCD_data = temp;

&

     temp = 0x00;
     temp = (LCD_data << 4) & 0XF0;
     LCD_data = temp;

and so on
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
I don't know the compiler you are using, but with mine it's
set_tris_b(0xF0); or whatever.

The TRIS registers are the only way to enable/disable the output drivers in the PIC chip itself.

You may have to use compiler options to force it to allow you to control the TRIS settings, mine defaults to adding code to set the TRIS bits every time you read or write a port or port bit unless you explicitly disable this, which for the CCS compiler is:
#use fast_io(ALL)

You can then set all the TRIS registers to suit your hardware design & change them yourself as needed for I/O operations.
iam using Mikroc and the command is TRISB = 0Xxx;
i tried it away from the LCD code and it didn't say any thing when wrote
TRISB = 0x00;
TRISB = 0xff;
but what i should mention about it is that

Rich (BB code):
     LCD_D7   = 1;           //Make D7th bit of LCD as i/p
works in 8 bit !!!!
 

rjenkins

Joined Nov 6, 2005
1,013
after modification not work but it is very important point you said

Rich (BB code):
     temp = 0x00;
     temp = LCD_data & 0XF0;
     LCD_data = temp;

&

     temp = 0x00;
     temp = (LCD_data << 4) & 0XF0;
     LCD_data = temp;

and so on
You must still be writing to LCD_Data before you call the subroutines or there could not be data to read/copy into temp.

You need to eliminate *any* use of LCD_Data except the masked (& 0xF0) writes in the output data subroutines, or where you are deliberately trying to change the LCD output pins.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
Rich (BB code):
#define LCD_port PORTB
#define LCD_rw   PORTB.F1
#define LCD_rs   PORTB.F2
#define LCD_en   PORTB.F3
#define LCD_D7   PORTB.F7
unsigned int LCD_data;
Rich (BB code):
     unsigned int temp;
     temp = 0x00;
     temp = LCD_data & 0XF0;
     LCD_port = temp;

&

     temp = 0x00;
     temp = (LCD_data << 4) & 0XF0;
     LCD_port = temp;
and still not :(
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
iam sorry i know its became heavy but i wander if really there no one have any idea about we talk about in the forum ?!!!!

Rich (BB code):
#define LCD_port PORTB
#define LCD_rw   PORTB.F1
#define LCD_rs   PORTB.F2
#define LCD_en   PORTB.F3
#define LCD_D7   PORTB.F7
unsigned int LCD_data;

void LCD_write_command () {
     unsigned int temp;
     temp = 0x00;
     temp = LCD_data & 0XF0;
     LCD_port = temp;
     LCD_rs   = 0;        //Selected command register
     LCD_rw   = 0;        //we are writing
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     temp = 0x00;
     temp = (LCD_data << 4) & 0XF0;
     LCD_port = temp;
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     LCD_D7   = 1;           //Make D7th bit of LCD as i/p
     LCD_en   = 1;           //Make port pin as o/p
     LCD_rs = 0;
     LCD_rw   = 1;        //we are reading
     while(LCD_D7){          //read busy flag again and again till it becomes 0
           LCD_en   = 0;     //Enable H->L
           LCD_en   = 1;
     }
}

void LCD_write_data(unsigned int output) {
     /*
     output => Data to be written
     */
     output = 0x00;
     output = LCD_data & 0XF0;
     LCD_port = output;
     LCD_rs   = 1;        //Selected data register
     LCD_rw   = 0;        //we are writing
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     output = 0x00;
     output = (LCD_data << 4) & 0XF0;
     LCD_port = output;
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     LCD_D7   = 1;           //Make D7th bit of LCD as i/p
     LCD_en   = 1;           //Make port pin as o/p
     LCD_rs = 1;
     LCD_rw   = 1;        //we are reading
     while(LCD_D7){          //read busy flag again and again till it becomes 0
           LCD_en   = 0;     //Enable H->L
           LCD_en   = 1;
     }
}
 

rjenkins

Joined Nov 6, 2005
1,013
No problem, I just find it easier to see it all in one go than separate parts.
OK, I can see other problems so quite a few modifications:

Rich (BB code):
#define LCD_port PORTB
#define LCD_rw   PORTB.F1
#define LCD_rs   PORTB.F2
#define LCD_en   PORTB.F3
#define LCD_D7   PORTB.F7
unsigned int LCD_data;

void LCD_write_command () {
int temp;

// Write High nibble
     LCD_port = LCD_data & 0XF0;
// PORTB is now = dddd0000 - All control lines are LOW and must be set as required.


// Lines marked *** are redundant here as port bits already low.
// BUT, for the write_data routine RS needs to be set High again before the E pulse, for each nibble.


     LCD_rs = 0;        //Selected command register ***
     LCD_rw = 0;        //we are writing            ***
     LCD_en = 1;        //Enable L->H
     LCD_en = 1;    // Duplicate to allow settling time; nothing changes, just a 'NOP'
     LCD_en = 0;        //Enable H->L

// Write Low nibble
     LCD_port = (LCD_data << 4) & 0XF0;

// PORTB = xxxx0000 - All control lines are LOW and must be set.
     LCD_rs = 0;        //Selected command register ***
     LCD_rw = 0;        //we are writing            ***
     LCD_en = 1;        //Enable L->H
     LCD_en = 1;
     LCD_en = 0;



// Busy Check - needs to read a Byte of data, two nibbles.

     LCD_D7 = 1;           //Make D7th bit of LCD as i/p
// I'm guessing that this compiler automatically switches a pin to input when it is read, so 
// the Busy test actually reads the pin

     LCD_rs = 0; // RS & RW must be stable BEFORE 'E' is active
     LCD_rw = 1;        //we are reading

     do{
// First E, get High nibble (Busy)
       LCD_en = 1;
       LCD_en = 1;  // Dummy to allow settling time
       temp = LCD_D7;
       LCD_en = 0;
       LCD_en = 0;  // Dummy


// Second E, LCD outputs Low nibble which we ignore
       LCD_en = 1; 
       LCD_en = 1;  // and again something to take time.
       LCD_en = 0;
     }
     while(temp);          //Loop as long as busy is set
           
}
 

rjenkins

Joined Nov 6, 2005
1,013
ANother though, just in case reading D7 does change it to Input, add
LCD_D7 = 1;

after the
while(temp);

so it's definitely set back to output mode again.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
about

Rich (BB code):
LCD_D7 = 1;
i guess you mean

Rich (BB code):
LCD_D7 = 0;
but after i saw and tested i can't promise you any thing :D
 

rjenkins

Joined Nov 6, 2005
1,013
I did not realise the schematic was a simulation!

OK, that does give some debug info. Somewhere it is getting an odd pulse on the E line, to make it think an odd number of nibbles have been written.

Also, it looks as if it needs the TRIS input/output changeover to stop the conflict messages.

(The LCD_D7 = 1; was not to set a level, it was just writing something to that bit in case the compiler was doing automatic input - output changes, so the bit was back to being an output for the next time it was needed.)

If I was doing this in MPLab, I'd switch on simulation and Register view, single step the program and look at the state of PORTB at each instruction.
That way you can see exactly where and why the E pin changes and spot any unintended or missing actions.

Can you do anything like that with your simulator?
 
Top