I2C LCD driver for CCS PIC C compiler

Interfacing LCD displays with a PIC microcontroller using CCS C compiler needs at least 7 data pins (using the built-in LCD driver). Number of pins needed for the LCD can be reduced to 2 by using an I2C I/O (Input/Output) expander like PCF8574 or PCF8574A. Adding the I2C I/O expander builds an I2C LCD. The I2C LCD is connected with the microcontroller via 2 lines: SDA (serial data) and SCL (serial clock). I2C = IIC = Inter-Integrated Circuit.
This post shows how to interface PIC microcontroller with I2C LCD using CCS C compiler where a driver (library) will be used to simplify the interfacing source codes for further project.
This driver works also with DFRobot I2C LCD displays since they’ve the same main circuit connections.

Interfacing PIC microcontroller with I2C LCD circuit:

PIC microcontroller I2C LCD with PCF8574 expander

(All grounded terminals are connected together)

The main component of the I2C LCD display is the PCF8574 I/O expander, with only two pins SDA and SCL we get a maximum of 8 pins from P0 to P7. PCF8574A also can be used but it has a different address.

All LCD data pins are connected to the PCF8574 where: RS, RW, E, D4, D5, D6 and D7 are connected to P0, P1, P2, P4, P5, P6 and P7 respectively.

PCF8574 I/O expander SDA and SCL pins are connected to the PIC microcontroller SDA and SCL pins respectively.

PCF8574 I/O expander A0, A1 and A2 pins are the address pins which decide the I2C address of the chip. In this example each pin is connected to +5V through a 10k ohm resistor (the 10k resistor is optional, each pin can be connected directly to +5V).

The I2C address of the PCF8574 is: 0 1 0 0 A2 A1 A0 0
In the circuit shown above A2, A1 and A0 are connected to +5V (through 10k resistors) which means the I2C address is equal to 0x4E.

If the PCF8574A is used instead of the PCF8574 the I2C address is: 0 1 1 1 A2 A1 A0 0 = 0x7E.

The LCD and the PCF8574 are supplied with 5V.
Note that PCF8574T is the same as PCF8574 and PCF8574AT is the same as PCF8574A.

I2C LCD driver for CCS PIC C compiler:
Driver source code is below which can be downloaded from the link below.
I2C LCD driver download

User functions:
LCD_Begin(unsigned int8 _i2c_addr);  // Must be called before any other function, _i2c_addr is the I2C I/O expander address, for example 0x27.
LCD_Goto(unsigned int8 col, unsigned int8 row);  // Set write position on LCD (upper left is 1,1 and second row first position is 1,2)
LCD_Out(unsigned int8 LCD_Char);    // Display Char on the LCD
LCD_Cmd(unsigned int8 Command);  // Send a command to the LCD

The following commands can be used with LCD_Com function (example: LCD_Com(LCD_CLEAR);):

Command Description
LCD_FIRST_ROW Move cursor to the 1st row
LCD_SECOND_ROW Move cursor to the 2nd row
LCD_THIRD_ROW Move cursor to the 3rd row
LCD_FOURTH_ROW Move cursor to the 4th row
LCD_CLEAR Clear display
LCD_RETURN_HOME Return cursor to home position, returns a shifted display to its original position. Display data RAM is unaffected
LCD_CURSOR_OFF Turn off cursor
LCD_UNDERLINE_ON Underline cursor on
LCD_BLINK_CURSOR_ON Blink cursor on
LCD_MOVE_CURSOR_LEFT Move cursor left without changing display data RAM
LCD_MOVE_CURSOR_RIGHT Move cursor right without changing display data RAM
LCD_TURN_ON Turn Lcd display on
LCD_TURN_OFF Turn Lcd display off
LCD_SHIFT_LEFT Shift display left without changing display data RAM
LCD_SHIFT_RIGHT Shift display right without changing display data RAM

Driver source code:

Examples:
Interfacing PIC12F1822 microcontroller with I2C LCD

6 comments

  1. Question, I cannot make this to work with pic16f877a:

    #include
    #fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
    #use delay(clock=4000000)
    #use I2C(MASTER, SCL= 18, SDA=23,FORCE_HW,SLOW)

    #include

    //===========================
    void main()
    {
    int8 c;

    while(1);
    }

    I get error:

    Clean: Deleting intermediary and output files.
    Clean: Deleted file “test.ESYM”.
    Clean Warning: File “D:\PICC Proyectos\kk\test.o” doesn’t exist.
    Clean: Deleted file “test.ERR”.
    Clean: Done.
    Executing: “C:\Program Files (x86)\PICC\Ccsc.exe” +FM “test.c” +DF +LN +T +A +M +Z +Y=9 +EA
    *** Error 12 “D:\PICC Proyectos\kk\I2C_LCD.c” Line 112(13,20): Undefined identifier I2C_LCD
    *** Error 12 “D:\PICC Proyectos\kk\I2C_LCD.c” Line 113(13,20): Undefined identifier I2C_LCD
    *** Error 12 “D:\PICC Proyectos\kk\I2C_LCD.c” Line 114(13,20): Undefined identifier I2C_LCD
    *** Error 12 “D:\PICC Proyectos\kk\I2C_LCD.c” Line 115(12,19): Undefined identifier I2C_LCD
    4 Errors, 0 Warnings.
    Halting build on first failure as requested.
    BUILD FAILED: Thu Oct 04 00:36:14 2018

    Any suggestions to make it work?

    1. You’ve to add the I2C stream to #use I2C (STREAM=I2C_LCD), so it becomes:
      #use I2C(MASTER, SCL= 18, SDA=23,FORCE_HW,SLOW,STREAM=I2C_LCD)

      1. Thanks, now I have only 1 error, instead the 4 I had. It’s this:

        Executing: “C:\Program Files (x86)\PICC\Ccsc.exe” +FM “LCD_prog_877A.c” +EXPORT +DF +LN +T +A +M +Z +Y=9 +EA
        D:\PICC Proyectos\lcdi2c\LCD_prog_877A.o ===> 0 Errors, 0 Warnings.
        Executing: “C:\Program Files (x86)\PICC\Ccsc.exe” +FM “I2C_LCD.c” +EXPORT +DF +LN +T +A +M +Z +Y=9 +EA
        *** Error 128 “D:\PICC Proyectos\lcdi2c\I2C_LCD.c” Line 29(1,2): A #DEVICE required before this line
        D:\PICC Proyectos\lcdi2c\I2C_LCD.o ===> 1 Errors, 0 Warnings.
        Halting build on first failure as requested.
        BUILD FAILED: Thu Oct 04 14:52:39 2018

        It’s in the I2C_LCD.c library, line 29, instruction:

        int1 RS;

        Thanks again.

  2. Well, code is ok, no errors, but for some reason, no data from SDA and SCL… Help plz! Code:

    #include {16f877a.h} // replace {

    #device *=16 ADC=10 ICD=true
    #fuses noprotect, nowdt, xt, nolvp
    #use delay (clock=4000000) //Fosc=4Mhz
    #use i2c(master,SDA=23,SCL=18,FORCE_HW,STREAM=I2C_LCD)

    #include {I2C_LCD.c} // replace {

    void main() {

    unsigned int8 i = 0;

    //setup_oscillator(OSC_4MHZ); // Set internal oscillator to 8MHz

    LCD_Begin(0x27); // Initialize LCD module with I2C address = 0x4E

    LCD_Goto(2, 1); // Go to column 2 row 1
    LCD_Out(“Hello, world!”);

    while(TRUE) {
    lcd_goto(7, 2); // Go to column 7 row 2
    printf(lcd_out, “%03u”, i++); // Print i with 3 numbers max
    delay_ms(500);
    }

    }

  3. Proteus give me the following error:

    [PIC16 CORE] PC=0x003D. Indirect write of 0x04 to address 0x0000 is itself an indirect write. [U1]
    [PIC16 CORE] PC=0x0040. Indirect write of 0x00 to address 0x0000 is itself an indirect write. [U1]
    [PIC16 CORE] PC=0x0043. Indirect write of 0x00 to address 0x0000 is itself an indirect write. [U1]
    [PIC16 CORE] PC=0x001B. Indirect write of 0x00 to address 0x0000 is itself an indirect write. [U1]
    [PIC16 CORE] PC=0x0022. Indirect write of 0x00 to address 0x0000 is itself an indirect write. [U1]
    [PIC16 CORE] PC=0x0023. Indirect write of 0x04 to address 0x0000 is itself an indirect write. [U1]

    This is the circuit:

    https://ibb.co/fUNSZK

    Also tested in real circuit, same result.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.