CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

LCD HD44780 PCF8574T i2c Driver
Goto page 1, 2, 3, 4, 5, 6  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Zilog750



Joined: 19 Oct 2013
Posts: 6

View user's profile Send private message

LCD HD44780 PCF8574T i2c Driver
PostPosted: Sat Oct 19, 2013 3:13 pm     Reply with quote

Hello,

trying to control an LCD via i2c, I have this hardware

* PIC16F877
* LCD HD44780
* Arduino-IIC-LCD GY-LCD-V1 (with PCF8574T)

also I have CCS 4.108 and this library

Code:

//-----------------------------------------------------------------------------
// Title:         lcd4_i2c.c
// Description:   Driver for common LCD 4 row modules using I2C protocol.
// Date:          May-2002
// Ver.Rev.:      1.1
// Author:        XP8100 (blixenonline@terra.es) #Based on the routines LCD.C from CCS#
// Modified:      To HM-Baybus Project by Manuel Díaz
//-----------------------------------------------------------------------------
//
// 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
//   
// Go to start of second line
//      Move back one position
//
//     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
//
//-----------------------------------------------------------------------------
// LCD pins D0-D3 are not used.
//-----------------------------------------------------------------------------
//
// Commment   : Control of a compatible LCD HITACHI from a bus I2C with
//              an EXPANDER of I/O with connection I2C. The tests of these
//              routines have been programmed using the IC PCF8574P of Phillips.
//              I use 4 bits mode programming. The 8 bits mode programming
//              is possible if you uses 2 x PCF8574P.
//
// As defined in the following structure the pin connection is as follows:
//
//  PCF8574P     LCD
//  ========     ======
//     P0        Enable
//     P1        RS
//     P2        RW
//     P3        No connect
//     P4        D4
//     P5        D5
//     P6        D6
//     P7        D7
//
//
//
// THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
//-----------------------------------------------------------------------------

#define lcd_type 2            // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40     // LCD RAM address for the second line
#define lcd_line_three 0x14   // LCD Ram address for the 3 line
#define lcd_line_four 0x54    // LCD Ram address for the 4 line

#define IOE_ADDR  0x40        // I2C addr for i/o expander PCF8574P

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.

byte address; // The following are used for setting the I/O port direction register.

void lcd_send_nibble( byte n, byte type ) {
   switch (type) {
      case "C" :
                  i2c_write(n << 4);
                  delay_cycles(1);
                  i2c_write(n << 4 | 0x01);
                  delay_us(2);
                  i2c_write(n << 4 & 0xFE);
                  break;
      case "D" :
                  i2c_write(n << 4 | 0x02);
                  delay_cycles(1);
                  i2c_write(n << 4 | 0x03);
                  delay_us(2);
                  i2c_write(n << 4 & 0x02);
                  break;
       }
}

void lcd_send_byte( byte n, byte type ) {
   delay_ms(1);
   lcd_send_nibble(n >> 4, type);
   lcd_send_nibble(n & 0xf, type);
}


void lcd_init() {
byte i;
   i2c_start();
   i2c_write(IOE_ADDR);
   lcd_send_nibble(0, "C");
   delay_ms(15);
   for (i=1;i<=3;++i)   {
      lcd_send_nibble(3, "C");
      delay_ms(5);
   }
   lcd_send_nibble(2, "C");
   delay_ms(5);
   for (i=0;i<=3;++i)   {
     lcd_send_byte(LCD_INIT_STRING, "C");
   }
   i2c_stop();
}

void lcd_gotoxy( byte x, byte y) {
   i2c_start();
   i2c_write(IOE_ADDR);
   switch(y){
      case 1: address= 00; break;
      case 2: address= lcd_line_two; break;
//      case 3: address= lcd_line_three; break;
      default: address= 00; break;
//      default: address= lcd_line_four; break;
   }
   address+=x-1;
   lcd_send_byte(0x80|address, "C");
   i2c_stop();
}

void lcd_gotonl (){
 /*  switch(address){
      case 00 : address= lcd_line_two; break;
  //    case lcd_line_two : address= lcd_line_three; break;
  //    case lcd_line_three: address= lcd_line_four; break;
      default : address= 00; break;
   }*/
   address= lcd_line_two;
   lcd_send_byte(0x80|address, "C");
}

void lcd_putc( char c) {
   i2c_start();
   i2c_write(IOE_ADDR);
   switch (c) {
      case "f" : lcd_send_byte(1, "C");
                  delay_ms(2);
                  break;
      case "
" : lcd_gotonl(); break;
      case "" : lcd_send_byte(0x10, "C"); break;
      default : lcd_send_byte(c, "D"); break;
   }
   i2c_stop();
}


And using this main code

Code:

/************************************************************/
/*               P R E P R O C E S S O R                    */
/************************************************************/

#include <16F877.h>
#device ADC=10

/************************************************************/
/*                      F U S E S                           */
/************************************************************/

#fuses XT,NOWDT,NOPROTECT,NOLVP,BROWNOUT

/************************************************************/
/*           O S C I L A T O R   &   D E L A Y              */
/************************************************************/


#use delay(clock=4000000) /* one instruction=1us? */

/************************************************************/
/*                S E T U P   R S - 2 3 2                   */
/************************************************************/

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

/************************************************************/
/*                  S E T U P   I 2 C                       */
/************************************************************/

#use I2C(master, SCL=PIN_C3, SDA=PIN_C4)

/************************************************************/
/*                   D E F I N I T I O N S                  */
/************************************************************/

//

/******************************************************************/
/*                      I N C L U D E S                           */
/******************************************************************/

#include "lcd4_i2c.c"

/************************************************************/
/*           G L O B A L   V A R I A B L E S                */
/************************************************************/


/************************************************************/
/*                 F U N C T I O N S                        */
/************************************************************/


/******************************************************************/
/*             I N T E R R U P T   V E C T O R S                  */
/******************************************************************/

// NONE

/******************************************************************/
/*                      M A I N   P R O G R A M                   */
/******************************************************************/

void main()
{
   delay_ms (200);
   output_high (PIN_B2);
   delay_ms (200);
   output_low (PIN_B2);
   delay_ms (200);
   lcd_init ();

   while (TRUE)
   {
      lcd_putc ("Hello");
      delay_ms (100);
      output_high (PIN_B1);
      delay_ms (100);
      output_low (PIN_B1);
      delay_ms (50);
   }
}


When compiling I have "Attempt to create a pointer to a constant" errors on lines like

Code:
lcd_send_nibble(0, "C");


and also

Code:
lcd_send_byte(LCD_INIT_STRING, "C");


I don't have experience on i2c nor CCS Compiler. Any idea what's is happening?

Regards
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Oct 19, 2013 5:40 pm     Reply with quote

The function declaration for your nibble routine looks like this:
Quote:
void lcd_send_nibble( byte n, byte type ) {

The 2nd parameter is a byte. But below, and in several other places, you
are trying to give it a string:
Quote:
lcd_send_nibble(0, "C");


To give it a parameter of the letter C, then you need to put it in single
quotes. Example:
Code:
lcd_send_nibble(0, 'C');

Also change your switch-case statement to put the characters in single
quotes. This will give you a byte instead of a string.
Zilog750



Joined: 19 Oct 2013
Posts: 6

View user's profile Send private message

PostPosted: Sun Oct 20, 2013 3:36 am     Reply with quote

Hello,

changed code as this on lib

Code:
//-----------------------------------------------------------------------------
// Title:         lcd4_i2c.c
// Description:   Driver for common LCD 4 row modules using I2C protocol.
// Date:          May-2002
// Ver.Rev.:      1.1
// Author:        XP8100 (blixenonline@terra.es) #Based on the routines LCD.C from CCS#
// Modified:      To HM-Baybus Project by Manuel Díaz
//-----------------------------------------------------------------------------
//
// 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
//   
// Go to start of second line
//      Move back one position
//
//     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
//
//-----------------------------------------------------------------------------
// LCD pins D0-D3 are not used.
//-----------------------------------------------------------------------------
//
// Commment   : Control of a compatible LCD HITACHI from a bus I2C with
//              an EXPANDER of I/O with connection I2C. The tests of these
//              routines have been programmed using the IC PCF8574P of Phillips.
//              I use 4 bits mode programming. The 8 bits mode programming
//              is possible if you uses 2 x PCF8574P.
//
// As defined in the following structure the pin connection is as follows:
//
//  PCF8574P     LCD
//  ========     ======
//     P0        Enable
//     P1        RS
//     P2        RW
//     P3        No connect
//     P4        D4
//     P5        D5
//     P6        D6
//     P7        D7
//
//
//
// THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
//-----------------------------------------------------------------------------

#define lcd_type 2            // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40     // LCD RAM address for the second line
#define lcd_line_three 0x14   // LCD Ram address for the 3 line
#define lcd_line_four 0x54    // LCD Ram address for the 4 line

#define IOE_ADDR  0x40        // I2C addr for i/o expander PCF8574P

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.

byte address; // The following are used for setting the I/O port direction register.

void lcd_send_nibble( byte n, byte type )
{
   switch (type)
   {
      case 'C' :
                  i2c_write(n << 4);
                  delay_cycles(1);
                  i2c_write(n << 4 | 0x01);
                  delay_us(2);
                  i2c_write(n << 4 & 0xFE);
                  break;
      case 'D' :
                  i2c_write(n << 4 | 0x02);
                  delay_cycles(1);
                  i2c_write(n << 4 | 0x03);
                  delay_us(2);
                  i2c_write(n << 4 & 0x02);
                  break;
       }
}

void lcd_send_byte( byte n, byte type )
{
   delay_ms(1);
   lcd_send_nibble(n >> 4, type);
   lcd_send_nibble(n & 0xf, type);
   delay_ms (1);
}

void lcd_init()
{
   byte i;
   i2c_start();
   i2c_write(IOE_ADDR);
   lcd_send_nibble(0, 'C');
   delay_ms(15);
   
   for (i=1;i<=3;++i)   
   {
      lcd_send_nibble(3, 'C');
      delay_ms(5);
   }
   
   lcd_send_nibble(2, 'C');
   delay_ms(5);
   
   for (i=0;i<=3;++i)   
   {
     lcd_send_byte(LCD_INIT_STRING[i], 'C');
   }
   i2c_stop();
}

void lcd_gotoxy( byte x, byte y)
{
   i2c_start();
   i2c_write(IOE_ADDR);
   
   switch(y)
   {
      case 1: address= 00; break;
      case 2: address= lcd_line_two; break;
//      case 3: address= lcd_line_three; break;
      default: address= 00; break;
//      default: address= lcd_line_four; break;
   }
   
   address+=x-1;
   lcd_send_byte(0x80|address, 'C');
   i2c_stop();
}

void lcd_gotonl ()
{
 /*  switch(address){
      case 00 : address= lcd_line_two; break;
  //    case lcd_line_two : address= lcd_line_three; break;
  //    case lcd_line_three: address= lcd_line_four; break;
      default : address= 00; break;
   }*/
   address= lcd_line_two;
   lcd_send_byte(0x80|address, 'C');
}

void lcd_putc( char c)
{
   i2c_start();
   i2c_write(IOE_ADDR);

   switch (c)
   {
      case "f" : lcd_send_byte(1, 'C');
                  delay_ms(2);
                  break;
      case "
" : lcd_gotonl(); break;
      case "" : lcd_send_byte(0x10, 'C'); break;
      default : lcd_send_byte(c, 'D'); break;
   }
   
   i2c_stop();
}


Intersed some wait time on

Code:
void lcd_send_byte( byte n, byte type )
{
   delay_ms(1);
   lcd_send_nibble(n >> 4, type);
   lcd_send_nibble(n & 0xf, type);
   delay_ms (1);
}


And some array addressing at lcd_init()
Code:
for (i=0;i<=3;++i)   
   {
     lcd_send_byte(LCD_INIT_STRING[i], 'C');
   }


And main code is more or less equal

Code:
/************************************************************/
/*               P R E P R O C E S S O R                    */
/************************************************************/

#include <16F877.h>
#device ADC=10

/************************************************************/
/*                      F U S E S                           */
/************************************************************/

#fuses XT,NOWDT,NOPROTECT,NOLVP,BROWNOUT

/************************************************************/
/*           O S C I L A T O R   &   D E L A Y              */
/************************************************************/


#use delay(clock=4000000) /* one instruction=1us? */

/************************************************************/
/*                S E T U P   R S - 2 3 2                   */
/************************************************************/

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

/************************************************************/
/*                  S E T U P   I 2 C                       */
/************************************************************/

#use I2C(master, SCL=PIN_C3, SDA=PIN_C4)

/************************************************************/
/*                   D E F I N I T I O N S                  */
/************************************************************/

//

/******************************************************************/
/*                      I N C L U D E S                           */
/******************************************************************/

#include "lcd4_i2c.c"

/************************************************************/
/*           G L O B A L   V A R I A B L E S                */
/************************************************************/


/************************************************************/
/*                 F U N C T I O N S                        */
/************************************************************/


/******************************************************************/
/*             I N T E R R U P T   V E C T O R S                  */
/******************************************************************/

// NONE

/******************************************************************/
/*                      M A I N   P R O G R A M                   */
/******************************************************************/

void main()
{
   lcd_init ();
   
   delay_ms (200);
   output_high (PIN_B2);
   delay_ms (200);
   output_low (PIN_B2);
   delay_ms (200);

   while (TRUE)
   {
      lcd_putc ("Hello");
      delay_ms(100);
   }
}


At this point I can see PCF8574 working with an oscilloscope but nothing happens on LCD. Any Idea or have someone a working lib for this?

Thanks
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Sun Oct 20, 2013 12:23 pm     Reply with quote

The driver does work....

Reason's it won't.

Using D0 to D3 instead of D4 to D7 on the LCD.
Not having a suitable Vo on the LCD.
Then just general connection problems.
You need about 500mSec delay _before_ lcd_init.

LCD's generally need about 60 to 100mSec after their supply goes 'good', before they will work. Many types don't see their supply as 'good', till a long time after the PIC. Hence 00 to 500mSec delay is needed before sending anything.

If you want an alternative look at the flex_lcd driver in the code forum, which is slightly more generic, and often works easier.

Best Wishes
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 20, 2013 1:14 pm     Reply with quote

Post a link to the webpage for the LCD that you bought so we can look
at the specs and documentation for the LCD.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Thu Nov 14, 2013 6:31 pm     Reply with quote

Hi Folks

I'm testing the same i2c lcd interface (with PCF8574T)... but could not make it works so far... I've tried the driver posted in this thread...

http://www.ebay.com/itm/IIC-I2C-TWI-SP-Serial-Interface-Board-Module-Port-for-5V-Arduino-1602LCD-Display-/400531106960?pt=LH_DefaultDomain_2&hash=item5d4183ac90

As you can see on the link... we can change the address by grounding A0, A1 & A2...what is the default address if I did not ground none of these? On the product description it says 0X20~0X27... I've tested both but neither one works...

I would appreciate any help.
Thanks
_________________
Hugo Silva
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Thu Nov 14, 2013 6:58 pm     Reply with quote

I just found out that:

For PCF8574A the addressing is:

Jp3 Jp2 Jp1
A2 A1 A0 Dec Hex
L L L 56 0x38
L L H 57 0x39
L H L 64 0x40
L H H 74 0x4A
H L L 75 0x4B
H L H 76 0x4C
H H L 77 0x4D
H H H 78 0x4E

For PCF8574 the addressing is:

Jp3 Jp2 Jp1
A2 A1 A0 Dec Hex
L L L 32 0x20
L L H 33 0x21
L H L 34 0x22
L H H 35 0x23
H L L 36 0x24
H L H 37 0x25
H H L 38 0x26
H H H 39 0x27
_________________
Hugo Silva
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Nov 14, 2013 7:35 pm     Reply with quote

Run this program to find out what the i2c slave address is:
http://www.ccsinfo.com/forum/viewtopic.php?t=49713
Change the top 5 lines of that program to fit your board.
Then run it and see what it shows.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Thu Nov 14, 2013 10:38 pm     Reply with quote

Thanks PCM Programmer... The Address is 0x4e... but the driver in this thread still not working... I could make the lcd work only through another 16x4 driver...but my display is 16x2...maybe it is the reason that I got a bug in the backlight.. it turns it off when I send the command ON. I'll post the driver code below:
Code:

//////////////////////////////////////////////////////////////////////////////
// This is the simple CCS program for I2C (PCF8574T) lcd module
// Auther: Pumrin S.
// Pin map:
// PCF8574T > 20x4 LCD
//   P0     >   RS
//   P1     >   R/W
//   P2     >   E
//   P3     >   NC
//   P4     >   D4
//   P5     >   D5
//   P6     >   D6
//   P7     >   D7
// Note: The SCL and SDA pins should be pull-up resister allway.
//////////////////////////////////////////////////////////////////////////////
#include <18f4550.h>
#device ICD = TRUE
#device ADC=10               
#use delay (clock=48000000)
#use i2c(Master,Fast=100000, sda=PIN_D6, scl=PIN_D7,force_sw)
#include <lcd20x4.h>   
#fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1,DEBUG,ICSP1 // configura fuses

#define LCDADDR        0x70 // default slave address
#define ON             0x08
#define OFF            0x00

#define LCD_SET_BIT(x)    fetch_data(x)

byte LCD_ADDR=0x4E; //0X4e I2C slave address for Funduino LCD module

//Transmittion data
void transceiver(unsigned char data)
   {   
        i2c_start();
        i2c_write(LCD_ADDR); //the slave addresse
        i2c_write(data);   
        i2c_stop();
   }

//Clocking the LCD's enable pin during transmit data
void fetch_data(unsigned char data)
   {
        data=data|0b00000100;//set pin E is a 1
        transceiver(data);
        delay_ms(1);
        data=data-4;//toggle E back to 0
        transceiver(data);
        delay_ms(1);

   }

void lcd_init()
{

   //Request works on the command by set the RS = 0 R/W = 0 write
        LCD_SET_BIT(0x00);
        LCD_SET_BIT(0x10);
        LCD_SET_BIT(0x00);
        LCD_SET_BIT(0x00);
        LCD_SET_BIT(0x10);
           //First state in 8 bit mode
        LCD_SET_BIT(0x30);
        LCD_SET_BIT(0x30);
           //Then set to 4-bit mode
        LCD_SET_BIT(0x30);
        LCD_SET_BIT(0x20);
           //mode 4 bits, 2 lines, characters 5 x 7 (28 h)
        LCD_SET_BIT(0x20);
        LCD_SET_BIT(0x80);
           //no need cursor on (0Ch)
        LCD_SET_BIT(0x00);
        LCD_SET_BIT(0xC0);
           //the cursor moves to the left (06 h)
        LCD_SET_BIT(0x00);
        LCD_SET_BIT(0x60);
           //clears the display
        LCD_SET_BIT(0x00);
        LCD_SET_BIT(0x10);
}

void lcd_clear()
{
    LCD_SET_BIT(0x00);
    LCD_SET_BIT(0x10);
}

// Need the backlight lid.
void lcd_backlight(byte state)
{
  LCD_SET_BIT(0x00);
  LCD_SET_BIT(state);
}

//Display the character on LCD screen.
void display(char in_data)
{
        char data;
        data=in_data&0xF0;
        data=data+1; //set RS pin to 1
        fetch_data(data);
        data=in_data&0x0F;
        data=data<<4;
        data=data+1; //set RS pin to 1
        fetch_data(data);

}

//Make the x/y pointer
void lcd_goto_xy(byte x, byte y)
{
  byte ptr1, ptr2;
 
  fetch_data(0x10);
  fetch_data(0x00);

  switch(y)
  {
   case 1:
          ptr1=line_1[x]&0xF0;// stamp the high bit
          ptr2=line_1[x]&0x0F;// stamp the low bit
       
     break;

   case 2:
           ptr1=line_2[x]&0xF0;
          ptr2=line_2[x]&0x0F;
         
     break;

   case 3:
          ptr1=line_3[x]&0xF0;
          ptr2=line_3[x]&0x0F;
         
     break;

   case 4:
           ptr1=line_4[x]&0xF0;
          ptr2=line_4[x]&0x0F;
         
     break;

   default:
          fetch_data(0x80);
          fetch_data(0x00);
     break;
     
  }
          ptr2=ptr2<<4;
          fetch_data(ptr1);
          fetch_data(ptr2);         
}

void main()
{
  lcd_init();     
        while (TRUE)
   {

        lcd_goto_xy(0,1);
        display("ABCDEFGHIJKLMNOP");
        //lcd_backlight(ON);
        delay_ms(1000);
        lcd_goto_xy(0,2);
        display("1234567890123456");
        //lcd_backlight(ON);     If I declare here, it clears the display
        delay_ms(1000);
                   
         output_high(PIN_D2);   
         delay_ms(100);
         output_low(PIN_D2);
         delay_ms(100);
   }
     
}


lcd20x4.h

Code:

//*** START LCD Command ***
#define  LCD_CLEAR_SCREEN   0B00000001
#define  LCD_RETURN_HOME    0B00000010

//Entry mode set (BIT2=1)
#define  LCD_ENTRY_MODE     0B00000100
#define  INCREMENTS_LCD     0B00000010
#define  DECREMENTS_LCD     0B00000000
#define  NO_SCROLL_LCD      0B00000000
#define  SCROLL_LCD         0B00000001

//Display ON/OFF (BIT3=1)
#define  DISPLAY_LCD        0B00001000
#define  LCD_ON             0B00000100
#define  LCD_OFF            0B00000000
#define  LCD_CURSOR_ON      0B00000010
#define  LCD_CURSOR_OFF     0B00000000
#define  LCD_BLINK_ON       0B00000001
#define  LCD_BLINK_OFF      0B00000000

//Scroll Display/Shift Cursor (BIT4=1)
#define  LCD_SCROLL_SHIFT   0B00010000
#define  LCD_SHIFT_CURSOR   0B00000000
#define  LCD_SHIFT_DISPLAY  0B00001000
#define  LCD_SHIFT_LEFT     0B00000000
#define  LCD_SHIFT_RIGHT    0B00000100

//Function set (BIT5=1)
#define  LCD_FUNCTION_SET   0B00100000
#define  LCD4BIT_MODE       0B00000000
#define  LCD8BIT_MODE       0B00010000
#define  LCD_LINE1          0B00000000
#define  LCD_LINE2          0B00001000
#define  LCD_FONT_5X7       0B00000000
#define  LCD_FONT_5X10      0B00000100

//Move To CGRAM Address (BIT6=1)
#define  LCD_CGRAM_ADDRESS  0B01000000

//Move To DDRAM Address (BIT7=1)
#define  LCD_DDRAM_ADDRESS  0B10000000

//*** END LCD Command ***

// Prepare x,y address byte
//line1=80h, line2=C0h line3=94h, line4=D4h
//   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
//1 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93
//2 C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3
//3 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7
//4 D4 D5 D6 D7 D8 D9 DA DB DC DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8

byte line_1[20]={0x80,0x81,0x82,0x83,0x84,
                 0x85,0x86,0x87,0x88,0x89,
                 0x8A,0x8B,0x8C,0x8D,0x8E,
                 0x8F,0x90,0x91,0x92,0x93};
byte line_2[20]={0xC0,0xC1,0xC2,0xC3,0xC4,
                 0xC5,0xC6,0xC7,0xC8,0xC9,
                 0xCA,0xCB,0xCC,0xCD,0xCE,
                 0xCF,0xD0,0xD1,0xD2,0xD3};
byte line_3[20]={0x94,0x95,0x96,0x97,0x98,
                 0x99,0x9A,0x9B,0x9C,0x9D,
                 0x9E,0x9F,0xA0,0xA1,0xA2,
                 0xA3,0xA4,0xA5,0xA6,0xA7}; 
byte line_4[20]={0xD4,0xD5,0xD6,0xD7,0xD8,
                 0xD9,0xDA,0xDB,0xDC,0xDE,
                 0xDF,0xE0,0xE1,0xE2,0xE3,
                 0xE4,0xE5,0xE6,0xE7,0xE8};

_________________
Hugo Silva
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Sat Nov 16, 2013 5:39 pm     Reply with quote

Hi Folks Again

The issue with the driver shared by Zilog750 (in my case) was the PCF8574T i2c interface Pins, which does not match the ones declared in that driver. Can anyone explain how to change it in the driver? the code seems to be a bit complex to me,,, and would really appreciate if someone can explain how the driver is accessing these pins... is there a better way to do that?

I want to change it from:

// PCF8574P LCD
// ======== ======
// P0 Enable
// P1 RS
// P2 RW
// P3 No connect
// P4 D4
// P5 D5
// P6 D6
// P7 D7

To:

// PCF8574P LCD
// ======== ======
// P0 > RS
// P1 > R/W
// P2 > Enable
// P3 > No connect
// P4 > D4
// P5 > D5
// P6 > D6
// P7 > D7

Driver:
Code:

//-----------------------------------------------------------------------------
// Title:         lcd4_i2c.c
// Description:   Driver for common LCD 4 row modules using I2C protocol.
// Date:          May-2002
// Ver.Rev.:      1.1
// Author:        XP8100 (blixenonline@terra.es) #Based on the routines LCD.C from CCS#
// Modified:      To HM-Baybus Project by Manuel Díaz
//-----------------------------------------------------------------------------
//
// 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
//   
// Go to start of second line
//      Move back one position
//
//     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
//
//-----------------------------------------------------------------------------
// LCD pins D0-D3 are not used.
//-----------------------------------------------------------------------------
//
// Comment    : Control of a compatible LCD HITACHI from a bus I2C with
//              an EXPANDER of I/O with connection I2C. The tests of these
//              routines have been programmed using the IC PCF8574P of Phillips.
//              I use 4 bits mode programming. The 8 bits mode programming
//              is possible if you uses 2 x PCF8574P.
//
// As defined in the following structure the pin connection is as follows:
//
//  PCF8574P     LCD
//  ========     ======
//     P0        Enable
//     P1        RS
//     P2        RW
//     P3        No connect
//     P4        D4
//     P5        D5
//     P6        D6
//     P7        D7
//
//
//
// THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
//-----------------------------------------------------------------------------

#define lcd_type 2            // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40     // LCD RAM address for the second line
#define lcd_line_three 0x14   // LCD Ram address for the 3 line
#define lcd_line_four 0x54    // LCD Ram address for the 4 line

#define IOE_ADDR  0x40        // I2C addr for i/o expander PCF8574P

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.

byte address; // The following are used for setting the I/O port direction register.

void lcd_send_nibble( byte n, byte type )
{
   switch (type)
   {
      case 'C' :
                  i2c_write(n << 4);
                  delay_cycles(1);
                  i2c_write(n << 4 | 0x01);
                  delay_us(2);
                  i2c_write(n << 4 & 0xFE);
                  break;
      case 'D' :
                  i2c_write(n << 4 | 0x02);
                  delay_cycles(1);
                  i2c_write(n << 4 | 0x03);
                  delay_us(2);
                  i2c_write(n << 4 & 0x02);
                  break;
       }
}

void lcd_send_byte( byte n, byte type )
{
   delay_ms(1);
   lcd_send_nibble(n >> 4, type);
   lcd_send_nibble(n & 0xf, type);
   delay_ms (1);
}

void lcd_init()
{
   byte i;
   i2c_start();
   i2c_write(IOE_ADDR);
   lcd_send_nibble(0, 'C');
   delay_ms(15);
   
   for (i=1;i<=3;++i)   
   {
      lcd_send_nibble(3, 'C');
      delay_ms(5);
   }
   
   lcd_send_nibble(2, 'C');
   delay_ms(5);
   
   for (i=0;i<=3;++i)   
   {
     lcd_send_byte(LCD_INIT_STRING[i], 'C');
   }
   i2c_stop();
}

void lcd_gotoxy( byte x, byte y)
{
   i2c_start();
   i2c_write(IOE_ADDR);
   
   switch(y)
   {
      case 1: address= 00; break;
      case 2: address= lcd_line_two; break;
//      case 3: address= lcd_line_three; break;
      default: address= 00; break;
//      default: address= lcd_line_four; break;
   }
   
   address+=x-1;
   lcd_send_byte(0x80|address, 'C');
   i2c_stop();
}

void lcd_gotonl ()
{
 /*  switch(address){
      case 00 : address= lcd_line_two; break;
  //    case lcd_line_two : address= lcd_line_three; break;
  //    case lcd_line_three: address= lcd_line_four; break;
      default : address= 00; break;
   }*/
   address= lcd_line_two;
   lcd_send_byte(0x80|address, 'C');
}

void lcd_putc( char c)
{
   i2c_start();
   i2c_write(IOE_ADDR);

   switch (c)
   {
      case "f" : lcd_send_byte(1, 'C');
                  delay_ms(2);
                  break;
      case "
" : lcd_gotonl(); break;
      case "" : lcd_send_byte(0x10, 'C'); break;
      default : lcd_send_byte(c, 'D'); break;
   }
   
   i2c_stop();
}


Thanks!!
_________________
Hugo Silva
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 17, 2013 1:27 am     Reply with quote

Quote:

I would really appreciate if someone can explain how the driver is
accessing these pins.

It's done with the numbers shown in bold below. My advice is to change
those numbers from hex format (0x) to binary format (0b prefix). Then
compare the values in bits 0 to 2, to the pin table for pins P0, P1 and P2
given below. You will see a correspondence.
Quote:

// PCF8574P LCD
// ======== ======
// P0 Enable
// P1 RS
// P2 RW
// P3 No connect
// P4 D4
// P5 D5
// P6 D6
// P7 D7


switch (type)
{
case 'C' :
i2c_write(n << 4);
delay_cycles(1);
i2c_write(n << 4 | 0x01);
delay_us(2);
i2c_write(n << 4 & 0xFE);
break;

case 'D' :
i2c_write(n << 4 | 0x02);
delay_cycles(1);
i2c_write(n << 4 | 0x03);
delay_us(2);
i2c_write(n << 4 & 0x02);
break;
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Sun Nov 17, 2013 2:14 am     Reply with quote

Or of course, use the names...
Code:

/ PCF8574P LCD
// ======== ======
// P0 Enable
// P1 RS
// P2 RW
// P3 No connect
// P4 D4
// P5 D5
// P6 D6
// P7 D7
#define ENABLE 1
#define RS 2
#define NOT ~
#define n_shifted n<<4

switch (type)
{
case 'C' :
i2c_write(n_shifted);
delay_cycles(1);
i2c_write(n_shifted | ENABLE);
delay_us(2);
i2c_write(n_shifted & NOT ENABLE);
break;

case 'D' :
i2c_write(n_shifted | 0xRS);
delay_cycles(1);
i2c_write(n_shifted | RS | ENABLE);
delay_us(2);
i2c_write(n_shifted & RS);
break;
}

This way the names reflect what pins you are operating.

Best Wishes
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

Working Driver!!!
PostPosted: Sun Nov 17, 2013 5:59 pm     Reply with quote

Thanks for the tips Ttelmah!!!

Both Drivers are working now... but I've modified and recompiled a third one... I will share it here for anyone who needs in future...after all.. I owe a lot to this forum...

It can control any compatible LCD HITACHI from a bus I2C with
an PCF8574T I/O expander.

The Driver worked with 2x16, 2x20 and 4x20 lcd modules.

I renamed it for "i2c_Flex_LCD.h"

Driver code:
Code:

//-----------------------------------------------------------------------------
// Title:         i2c_Flex_LCD
// Description:   Driver for common LCD with 1/2/3 or 4 row modules using PCF8574T interface board with I2C protocol.
// Date:          Nov-2013
// Ver.Rev.:      1.0
// Author:        Hugo Silva (sergio-hugo@bol.com.br) #Based on the routines of 20X4_LCD_I2C_DRIVER.h from Pumrin S.
//-----------------------------------------------------------------------------
//
// lcd_init() Must be called before any other function.
//
// lcd_putc(c) Will display c on the next position of the LCD.
// 
//     \f Clear LCD dispay
//     \1 Set write position on LCD Line 1
//     \2 Set write position on LCD Line 2
//     \3 Set write position on LCD Line 3
//     \4 Set write position on LCD Line 4
//
//     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
//
//-----------------------------------------------------------------------------
// LCD pins D0-D3 are not used.
//-----------------------------------------------------------------------------
//
// Commment   : Control of a compatible LCD HITACHI from a bus I2C with
//              an EXPANDER of I/O with connection I2C. The tests of these
//              routines have been programmed using the IC PCF8574T of Phillips.
//              I used 4 bits mode programming. The 8 bits mode programming
//              is possible if you use 2 x PCF8574T.
//
// As defined in the following structure the pin connection is as follows:
//
//  PCF8574P     LCD
//  ========     ======
//     P0        RS
//     P1        RW
//     P2        Enable 
//     P3        Led Backlight
//     P4        D4
//     P5        D5
//     P6        D6
//     P7        D7
//
//  The SCL and SDA pins should be pull-up resistor as shown below:
//
//             +5v
//               |
//               <
//               > 4.7K       
//               <         
//To PIC         |          To i2c slave
//pin xx ------------------ SDA pin 
//(SDA)                     
//              +5v
//               |
//               <
//               > 4.7K       
//               <         
//To PIC         |          To i2c slave
//pin xx ------------------ SCL pin 
//(SCL)
//
//To PIC                    To i2c slave
//Vss pin ----------------- Vss or ground pin 
//                |
//              -----
//               ---  Ground
//                - 
// 
// THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
//-----------------------------------------------------------------------------

#define LCD_ADDR       0x4E //I2C slave address for LCD module

#define ON             1
#define OFF            0
#define RS             0b00000001  //P0 - PCF8574T Pin connected to RS
#define RW             0b00000010  //P1 - PCF8574T Pin connected to RW
#define EN             0b00000100  //P2 - PCF8574T Pin connected to EN
#define BACKLIGHT_LED  0b00001000  //P3 - PCF8574T Pin connected to BACKLIGHT LED

#define lcd_line_one   0x80   // LCD RAM address for line 1
#define lcd_line_two   0xC0   // LCD RAM address for line 2
#define lcd_line_three 0x94   // LCD RAM address for line 3
#define lcd_line_four  0xD4   // LCD RAM address for line 4
 
byte address;
int1 lcd_backlight=ON;

void i2c_send_nibble(unsigned char data)
   {   
        i2c_start();
        delay_us(20);
        i2c_write(LCD_ADDR); //the slave addresse
        delay_us(20);
        i2c_write(data);
        delay_us(20);
        i2c_stop();
        delay_us(20);
   }

void lcd_send_byte(unsigned char data)
   {
        if (lcd_backlight) data=data|EN|BACKLIGHT_LED; else data=data|EN; //set pin EN
        i2c_send_nibble(data);
        data=data-4;       //toggle EN back to 0
        i2c_send_nibble(data);
   }
   
void lcd_clear()
{
    lcd_send_byte(0x00);
    lcd_send_byte(0x10);
    delay_ms(2);
}

void lcd_init()
{
    delay_ms(200); //LCD power up delay
       
   //Request works on the command by set the RS = 0 R/W = 0 write
        lcd_send_byte(0x00);
        lcd_send_byte(0x10);
        lcd_send_byte(0x00);
        lcd_send_byte(0x00);
        lcd_send_byte(0x10);
           //First state in 8 bit mode
        lcd_send_byte(0x30);
        lcd_send_byte(0x30);
           //Then set to 4-bit mode
        lcd_send_byte(0x30);
        lcd_send_byte(0x20);
           //mode 4 bits, 2 lines, characters 5 x 7 (28 h)
        lcd_send_byte(0x20);
        lcd_send_byte(0x80);
           //no need cursor on (0Ch)
        lcd_send_byte(0x00);
        lcd_send_byte(0xC0);
           //the cursor moves to the left (06 h)
        lcd_send_byte(0x00);
        lcd_send_byte(0x60);
           //clears the display
        lcd_clear();
}

void lcd_gotoxy( byte x, byte y)
{     
static char data;
     
   switch(y)
   {
      case 1:  address= lcd_line_one;     break;
      case 2:  address= lcd_line_two;     break;
      case 3:  address= lcd_line_three;   break;
      case 4:  address= lcd_line_four;    break;
      default: address= lcd_line_one;     break; 
   }
 
   address+=x-1;
   data=address&0xF0;
   lcd_send_byte(data);
   data=address&0x0F;
   data=data<<4;
   lcd_send_byte(data);
}

//Display the character on LCD screen.
void LCD_PUTC(char in_data)
{
 char data;     
  switch(in_data)
   { 
     case '\f': lcd_clear()    ;  break;               
     case '\1': lcd_gotoxy(1,1);  break;
     case '\2': lcd_gotoxy(1,2);  break;
     case '\3': lcd_gotoxy(1,3);  break;
     case '\4': lcd_gotoxy(1,4);  break;

     default:
        data=in_data&0xF0;
        data=data|RS; //set RS pin to 1
        lcd_send_byte(data);
        data=in_data&0x0F;
        data=data<<4;
        data=data|RS; //set RS pin to 1
        lcd_send_byte(data);
     break;
   }
}


Main code:
Code:

#include <18f4550.h>
#device ICD = TRUE
#device ADC=10               
#use delay (clock=48000000)
#use i2c(Master,Fast=100000, sda=PIN_D6, scl=PIN_D7,force_sw)
#include <i2c_Flex_LCD.h>   
#fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1,DEBUG,ICSP1 // configura fuses

void main()
{
Char string="Test";
int16 test=1;

  lcd_init();
  lcd_backlight=ON;
 
        while (TRUE)
   {   
         test=test+1;
         
         lcd_clear();  //Clear Display
         printf(LCD_PUTC,"\1%s","LCD Line 1");  //Print on LCD line 1
         delay_ms(1000);
         
         printf(LCD_PUTC,"\2%s","LCD Line 2");  //Print on LCD line 2
         delay_ms(1000);
       
         printf(LCD_PUTC,"\f\1%s","LCD Line 1"); //Clear display, print again on Line 1
         delay_ms(1000);
         
         printf(LCD_PUTC,"\f\2%s","LCD Line 2"); //Clear display, print again on Line 2
         delay_ms(1000); 
         
         lcd_backlight=OFF;
         printf(LCD_PUTC,"\f\1%s\2%s","LCD BackLight","     OFF      "); //Clear display, print again on Line 1
         delay_ms(1000);
         
         lcd_backlight=ON;
         printf(LCD_PUTC,"\f\1%s\2%s","LCD BackLight","     ON      "); //Clear display, print again on Line 2
         delay_ms(1000);
   }   
}


Thanks guys for all support!
BR
Hugo
_________________
Hugo Silva
dyeatman



Joined: 06 Sep 2003
Posts: 1937
Location: Norman, OK

View user's profile Send private message

PostPosted: Sun Nov 17, 2013 7:30 pm     Reply with quote

Why not add it to the Code Library?
_________________
Google and Forum Search are some of your best tools!!!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Mon Nov 18, 2013 1:22 am     Reply with quote

As a minor 'consider this', why not change the init to something like:
Code:

void lcd_init(void)
{
    delay_ms(200); //LCD power up delay
    cont int8 init_data[] = {0x0,0x10,0x0,0x0,0x10, \
    0x30,0x30, \ //8bit mode
    0x30,0x20, \ //4bit mode
    0x20,0x80, \ //2lines 5*7
    0x00,0xC0, \ //No cursor
    0x00,0x60 };
    int8 ctr;
    //Request works on the command by set the RS = 0 R/W = 0 write
    for (ctr=0;ctr<sizeof(init_data;ctr++)
         lcd_send_byte(ctr); //send initialisation
    //clears the display
    lcd_clear();
}

When you are using the same command fifteen times, it may well be a case of 'better to loop'. Smile

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2, 3, 4, 5, 6  Next
Page 1 of 6

 
Jump to:  
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