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

Flexible "I2C" LCD driver (PCF8574T) by Hugo Silva
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

Flexible "I2C" LCD driver (PCF8574T) by Hugo Silva
PostPosted: Sun Jun 21, 2015 7:11 pm     Reply with quote

Hi Everyone!

I'm glad to share this I2C Driver for common LCD with 1/2/3 or 4 rows by 1...20 columns using PCF8574T interface board with I2C protocol. I've been using it for a while with no issues at all.

Some points to be considered:
1- The driver is prepared for the given PCF8574T pinout, so any changes in it will affect its properly working.
2- In order to work with a different LCD display i.e. 2x16, just set it in the parameters below:
Code:

#define lcd_total_rows          4           //Number of rows: 1,2,3 or 4
#define lcd_total_columns     20          //Number of columns: 1...20
 

3- The Code was based in the existing "16x2 LCD driver" (Thanks to PCM Programmer!) So it will be easy to understand for those who are already using the non I2c version.
4- Any comments/updates will be appreciated!

Enjoy it...
BR,
Hugo Silva

Driver: i2c_Flex_LCD.h
Code:

//-----------------------------------------------------------------------------
// Title:         i2c_Flex_LCD
// Description:   Driver for common LCD with 1/2/3 or 4 rows by 1...20 columns
//                using PCF8574T interface board with I2C protocol.
// Date:          Nov-2013
// Ver.Rev.:      1.1
// Author:        Hugo Silva ([email protected]) #Based on the routines of
//                "20X4_LCD_I2C_DRIVER.h" from Pumrin S. and "lcd4_i2c.c" from XP8100
//-----------------------------------------------------------------------------
//
// 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 display
//     \n Set write position on next lcd line
//     \b LCD backspace
//     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
//
// lcd_backlight_led(ON)/lcd_backlight_led(OFF) = Turn ON/OFF LCD Backlight LED
//
//-----------------------------------------------------------------------------
// LCD pins D0-D3 are not used.
//-----------------------------------------------------------------------------
//
// Comment   : Control of a compatible LCD (1...4 rows by 1...4 columns) from
//              a bus I2C with an EXPANDER of I/O with connection I2C.
//              The tests of these routines have been programmed using the IC
//              Phillips PCF8574T. I've used 4 bits mode programming.
//              The 8 bits mode programming is possible if you use 2 x PCF8574T.
//              RW Pin is not being used.
//
// As defined in the following structure the pin connection is as follows:
//
//  PCF8574P     LCD
//  ========     ======
//     P0        RS
//     P1        RW    (Not used!)
//     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 lcd_total_rows        4           //Number of rows: 1,2,3 or 4
#define lcd_total_columns     20          //Number of columns: 1...20   

#define RS                    0b00000001  //P0 - PCF8574T Pin connected to RS
#define RW                    0b00000010  //P1 - PCF8574T Pin connected to RW
#define ENABLE                0b00000100  //P2 - PCF8574T Pin connected to EN
#define LCD_BACKLIGHT         0b00001000  //P3 - PCF8574T Pin connected to BACKLIGHT LED

#define addr_row_one          0x00        //LCD RAM address for row 1
#define addr_row_two          0x40        //LCD RAM address for row 2
#define addr_row_three        0x14        //LCD RAM address for row 3
#define addr_row_four         0x54        //LCD RAM address for row 4

#define ON                    1
#define OFF                   0
#define NOT                   ~
#define data_shifted          data<<4
int8 new_row_request=1, BACKLIGHT_LED=LCD_BACKLIGHT;

void lcd_backlight_led(byte bl)

      If (bl) BACKLIGHT_LED=LCD_BACKLIGHT; else BACKLIGHT_LED=OFF;
}

void i2c_send_nibble(byte data, byte type)
{   
   switch (type)
   {     
      case 0 :     
      i2c_write(data_shifted | BACKLIGHT_LED);
      delay_cycles(1);
      i2c_write(data_shifted | ENABLE | BACKLIGHT_LED );
      delay_us(2);
      i2c_write(data_shifted & NOT ENABLE | BACKLIGHT_LED);
      break;
     
      case 1 :
      i2c_write(data_shifted | RS | BACKLIGHT_LED);
      delay_cycles(1);
      i2c_write(data_shifted | RS | ENABLE | BACKLIGHT_LED );
      delay_us(2);
      i2c_write(data_shifted & RS | BACKLIGHT_LED);
      break;
   }
}
   
void lcd_send_byte(byte data, byte type)
   {
        i2c_start();
        i2c_write(LCD_ADDR);
        i2c_send_nibble(data >> 4 , type);
        i2c_send_nibble(data & 0xf , type);
        i2c_stop();       
   }

void lcd_clear()

        lcd_send_byte(0x01,0);
        delay_ms(2);
        new_row_request=1;
}

void lcd_init(void)
{
   byte i;
   byte CONST lcd_type=2;  // 0=5x7, 1=5x10, 2=2 lines
   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.

   disable_interrupts(GLOBAL);
   delay_ms(50); //LCD power up delay
   
   i2c_start();
   i2c_write(LCD_ADDR);
      i2c_send_nibble(0x00,0);
      delay_ms(15);
   
   for (i=1;i<=3;++i)   
   {
      i2c_send_nibble(0x03,0);
      delay_ms(5);
   }   
      i2c_send_nibble(0x02,0);
      delay_ms(5);
   i2c_stop();
   
   for (i=0;i<=3;++i) {
   lcd_send_byte(LCD_INIT_STRING[i],0);
   delay_ms(5);
   }
   lcd_clear();  //Clear Display
   enable_interrupts(GLOBAL);
}

void lcd_gotoxy( byte x, byte y)
{
byte row,column,row_addr,lcd_address;
static char data;

   if (y>lcd_total_rows) row=lcd_total_rows; else row=y;
 
   switch(row)
   {
      case 1:  row_addr=addr_row_one;     break;
      case 2:  row_addr=addr_row_two;     break;
      case 3:  row_addr=addr_row_three;   break;
      case 4:  row_addr=addr_row_four;    break;
      default: row_addr=addr_row_one;     break; 
   } 
   
   if (x>lcd_total_columns) column=lcd_total_columns; else column=x; 
   lcd_address=(row_addr+(column-1));
   lcd_send_byte(0x80|lcd_address,0);
}

//Display the character on LCD screen.
void LCD_PUTC(char in_data)
{   
  switch(in_data)
   { 
     case '\f': lcd_clear();                       break;               
     
     case '\n':
     new_row_request++;
     if (new_row_request>lcd_total_rows) new_row_request=1;
     lcd_gotoxy(1, new_row_request);
     break;
                 
     case '\b': lcd_send_byte(0x10,0);             break;
       
     default: lcd_send_byte(in_data,1);            break;     
     
   }
}


Test Code: i2c_Flex_LCD_Test.c
Code:

//************************************************************************************
// LCD Display test code for "i2c_Flex_LCD" using Phillips PCF8574T
// By Hugo Silva - Jun 06Th 2015
// Based in the 20x4 LCD driver test code (by PCM programmer) with a few changes made
//************************************************************************************
#include <18f2550.h>
#use delay (clock=48000000)
#use i2c(Master,Fast=100000, sda=PIN_c6, scl=PIN_c7,force_sw)
#include <i2c_Flex_LCD.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1

void main() { 
int i=0;
lcd_init();
lcd_backlight_led(ON); //Backligth ON
 
 while (TRUE) {
   lcd_clear();  //Clear Display

   // Test the clear screen and newline commands.
   // Also test that we can write to all 4 lines.
   printf(lcd_putc, "\fThis is the 1st line");
   delay_ms(500);
   printf(lcd_putc, "\nNext is the 2nd line");
   delay_ms(500);
   printf(lcd_putc, "\nThis is the 3rd line");
   delay_ms(500);
   printf(lcd_putc, "\nFinally the 4th line");
   delay_ms(1000);

   // Test some additional characters.
   printf(lcd_putc, "\fABCDEFGHIJKLMNOPQRST");
   delay_ms(500);
   printf(lcd_putc, "\nabcdefghijklmnopqrst");
   delay_ms(500);
   printf(lcd_putc, "\n12345678901234567890");
   delay_ms(500);
   printf(lcd_putc, "\n!@#$^&*(){}[]:;<>?/=");
   delay_ms(500);

   // Clear the LCD.
   printf(lcd_putc, "\f");
   delay_ms(500);

   // Test that lcd_gotoxy() works.  Go to each of
   // the four corners and put a number in each one,
   // in a clockwise direction, starting with the upper
   // left corner.
   lcd_gotoxy(5, 2);       
   printf(lcd_putc, "Put a Nr. in");   
   lcd_gotoxy(5, 3);       
   printf(lcd_putc, "each corner");
   delay_ms(500);
   lcd_gotoxy(1, 1);       
   printf(lcd_putc, "1");
   delay_ms(500);
   lcd_gotoxy(20, 1);       
   printf(lcd_putc, "2");
   delay_ms(500);
   lcd_gotoxy(20, 4);       
   printf(lcd_putc, "3");
   delay_ms(500);
   lcd_gotoxy(1, 4);       
   printf(lcd_putc, "4");   
   delay_ms(1000);

// Read the character that was written in each corner
// of the LCD and display it.   This tests the lcd_getc()
// function.   
// The following test can only be done if we can read
// from the LCD.  If the RW pin is not used, then the
// LCD is in write-only mode, and we can't do this test.
// The #ifdef statement will prevent the code from
// being compiled, in that case.

#ifdef USE_RW_PIN   
   // Test if lcd_getc() can read
   // a byte from each corner.
   b1 = lcd_getc(1,1);   
   b2 = lcd_getc(20,1);   
   b3 = lcd_getc(20,4);   
   b4 = lcd_getc(1,4);   
   lcd_gotoxy(1, 1);       
   printf(lcd_putc, "\fRead these bytes\n");
   printf(lcd_putc, "from the 4 corners:\n\n");
   printf(lcd_putc, "     %c %c %c %c", b1, b2, b3, b4);       
   delay_ms(3000);
#endif

   // Type some characters and backspace over them.
   printf(lcd_putc, "\f\nType characters and\n");
   printf(lcd_putc,   "backspace over them.");
   delay_ms(500);

   // Go to end of 3rd line.
   lcd_gotoxy(20, 3);       

   // Backspace over 2nd line.
   for(i = 0; i < 20; i++)
      {
       printf(lcd_putc," \b\b");
       delay_ms(50);
      }

   // Go to end of first line.               
   lcd_gotoxy(20, 2);       

   // Backspace over first line.
   for(i = 0; i < 20; i++)
      {
       printf(lcd_putc," \b\b");
       delay_ms(50);
      } 

//Backlight OFF
         lcd_backlight_led(OFF);
         printf(LCD_PUTC,"\fLCD BackLight\n     OFF      ");
         delay_ms(1000);

//Backlight ON
         lcd_backlight_led(ON);
         printf(LCD_PUTC,"\fLCD BackLight\n     ON      "); 
         delay_ms(1000);

   }   
}

_________________
Hugo Silva
TranVhien



Joined: 12 Mar 2016
Posts: 1
Location: SaiGon city

View user's profile Send private message

PostPosted: Sat Mar 12, 2016 1:22 pm     Reply with quote

I have checked the program but it does not work. I find the error and fix
Code:
void i2c_send_nibble(byte data, byte type)
{   
   switch (type)
   {     
      case 0 :     
      i2c_write(data_shifted | BACKLIGHT_LED);
      delay_cycles(1);
      i2c_write(data_shifted | ENABLE | BACKLIGHT_LED );
      delay_us(2);
      i2c_write(data_shifted & NOT ENABLE | BACKLIGHT_LED);
      break;
     
      case 1 :
      i2c_write(data_shifted | RS | BACKLIGHT_LED);
      delay_cycles(1);
      i2c_write(data_shifted | RS | ENABLE | BACKLIGHT_LED );
      delay_us(2);
     i2c_write(data_shifted | RS | BACKLIGHT_LED); //fix
      break;
   }
}
bertamf



Joined: 02 Aug 2016
Posts: 1

View user's profile Send private message

PostPosted: Tue Aug 02, 2016 8:32 am     Reply with quote

Thanks a lot, younder! You have been of great help Smile
savotech



Joined: 13 Dec 2012
Posts: 12

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Mon Feb 04, 2019 4:07 am     Reply with quote

Can someone post a code of how custom Characters are used on i2c serial lcd using pcf8574. Please I have searched through all post but could not get a clue
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Feb 04, 2019 10:49 am     Reply with quote

Here is a link to lcd custom character code:
http://www.ccsinfo.com/forum/viewtopic.php?t=40565
You can integrate (by cut and paste) that code into the i2c lcd driver code.
savotech



Joined: 13 Dec 2012
Posts: 12

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Tue Feb 05, 2019 4:16 am     Reply with quote

Thanks PCM programmer but i have seen the link before.
The problem am having is the code conversion. On the custom lcd code we have:
Code:

void lcd_load_custom_chars(void)
{
int8 i;

// Set address counter pointing to CGRAM address 0.
lcd_send_byte(0, 0x40);

// Load custom lcd character data into CGRAM.
// It can only hold a maximum of 8 custom characters.
for(i = 0; i < sizeof(lcd_custom_chars); i++)
   {
    lcd_send_byte(1, lcd_custom_chars[i]);
   }

// Set address counter pointing back to the DDRAM.
lcd_send_byte(0, 0x80);
}


The lcd_send_byte has 2 variable values passed into it which is cgram address and data.

But on this I2c Lcd code we have
Code:

void lcd_send_byte(byte data, byte type)
   {
        i2c_start();
        i2c_write(LCD_ADDR);
        i2c_send_nibble(data >> 4 , type);
        i2c_send_nibble(data & 0xf , type);
        i2c_stop();       
   }

Which the lcd_send_byte has Data and type.

My question is... How do we convert the address data to data type ?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Feb 05, 2019 10:54 am     Reply with quote

He has reversed the order of the parameters in lcd_send_byte().
That's annoying. It makes it harder to add new features from
pre-existing code.

The modified custom chars function is below. You should now be able
to use this function with the i2c lcd code:
Code:

void lcd_load_custom_chars(void)
{
int8 i;

// Set address counter pointing to CGRAM address 0.
// lcd_send_byte(0, 0x40); 
lcd_send_byte(0x40, 0);    // Reverse the parameter order

// Load custom lcd character data into CGRAM.
// It can only hold a maximum of 8 custom characters.
for(i = 0; i < sizeof(lcd_custom_chars); i++)
   {
//    lcd_send_byte(1, lcd_custom_chars[i]);
    lcd_send_byte(lcd_custom_chars[i], 1);  // Reverse the parameter order

   }

// Set address counter pointing back to the DDRAM.
// lcd_send_byte(0, 0x80);   
lcd_send_byte(0x80, 0);  // Reverse the parameter order

}
savotech



Joined: 13 Dec 2012
Posts: 12

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Wed Feb 06, 2019 2:38 am     Reply with quote

Thanks a lot PCM programmer. It was really helpful. My code is working well and I can design any custom characters.
bhas_r



Joined: 19 May 2009
Posts: 18

View user's profile Send private message Send e-mail

Unable to get custom char in i2c lcd
PostPosted: Sat Aug 17, 2019 12:10 am     Reply with quote

Unable to get custom char in i2c lcd.
only first up arrow is displayed down arrow or degrees symbol not displayed
looking for correction
_________________
Thanks and Regards

R.Bhaaskar
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Aug 17, 2019 12:54 pm     Reply with quote

Try to use the lcd in normal 4-bit parallel mode, if possible.
Do the custom symbols work in that mode ?
bhas_r



Joined: 19 May 2009
Posts: 18

View user's profile Send private message Send e-mail

thank you PCM programmer
PostPosted: Sat Aug 17, 2019 1:17 pm     Reply with quote

Quote:
Try to use the lcd in normal 4-bit parallel mode, if possible.
Do the custom symbols work in that mode ?


previously, i used in 4 bit mode that was successful. now the same project i need more pins, almost i used all pins of pic16f877a. so i am looking for i2c with cgram if possible.
_________________
Thanks and Regards

R.Bhaaskar
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Aug 18, 2019 2:51 am     Reply with quote

Then experiment. Try using a lower oscillator frequency for the PIC.
Or, put a delay of 10 msec at the end of the send_byte() function.

Assume there is something wrong, maybe in the timing, and do
experiments to see if you can find the reason.
bhas_r



Joined: 19 May 2009
Posts: 18

View user's profile Send private message Send e-mail

i will try this but
PostPosted: Sun Aug 18, 2019 6:19 am     Reply with quote

PCM programmer wrote:
Then experiment. Try using a lower oscillator frequency for the PIC.
Or, put a delay of 10 msec at the end of the send_byte() function.

Assume there is something wrong, maybe in the timing, and do
experiments to see if you can find the reason.


but remaining normal data are displaying well.

the only cgram first char is displayed remaining not.

tonight I will try and post
_________________
Thanks and Regards

R.Bhaaskar
bhas_r



Joined: 19 May 2009
Posts: 18

View user's profile Send private message Send e-mail

Added 10ms
PostPosted: Mon Aug 19, 2019 12:28 am     Reply with quote

10 ms delay added in send byte, no improvements.

i found another program from internet, i will check and post the same if works properly
_________________
Thanks and Regards

R.Bhaaskar
-Terppa-



Joined: 08 Jan 2018
Posts: 59
Location: Finland

View user's profile Send private message

Re: Unable to get custom char in i2c lcd
PostPosted: Tue Nov 26, 2019 11:28 am     Reply with quote

bhas_r wrote:
Unable to get custom char in i2c lcd.
only first up arrow is displayed down arrow or degrees symbol not displayed
looking for correction


I have exactly the same problem! Everything works like a charm but only one custom character shows up and it is first char. What could be wrong?

EDIT:
Nothing.. I have messed up my bitmap table.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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