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 support@ccsinfo.com

Flexible "I2C" LCD driver (PCF8574T) by Hugo Silva

 
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: 51
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 (sergio-hugo@bol.com.br) #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 dispay
//     \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.
//-----------------------------------------------------------------------------
//
// Commment   : 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);
      } 

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

//Backligth 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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
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