I2C Alphanumeric LCD interface using a PCF8574 or PCF8574A device

Started by top204, Sep 29, 2023, 11:25 AM

Previous topic - Next topic

top204

There have been some excellent code listings of using a PCF8574 or PCF8574A, I2C port expander device to interface with an alphanumeric LCD written by the users on this good forum, so I thought I would add my own library into the mix.

Sometimes, the pins available on a microcontroller are very few, and an alphanumeric 'Hitachi type' LCD can take too many pins to interface with, or the microcontroller type does not have enough pins, as in the case of 8-pin devices. So being able to interface to it using only 2 pins is ideal. The I2C interface is not known for its very high speed, however the alphanumeric LCDs do not operate at extreme speeds, so I2C is ideal for it. The library replaces the compiler's Print, Print At, Cls, and Cursor commands, so the program listing using an LCD does not need multiple procedure calls that can confuse things.

Below is the code listing for the "PCF8574x_LCD.inc" library file:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Alphanumeric LCD interface routines using a PCF8574A I2C I/O expander device that replaces the compiler's alphanumeric Print library subroutine
'
' Written for the Positron BASIC compiler by Les Johnson.
'
    #Disable Print                                                      ' Disable the compiler's Print command's library subroutines
'
' Set some default Port Pins for the I2C interface
'
$ifndef LCD_SDA_Pin
    $define LCD_SDA_Pin PORTB.0
    $SendWarning "$define LCD_SDA_Pin missing from the main program, so defaulting to pin PORTB.0"
$endif
$ifndef LCD_SCL_Pin
    $define LCD_SCL_Pin PORTB.1
    $SendWarning "$define LCD_SCL_Pin missing from the main program, so defaulting to pin PORTB.1"
$endif

$ifdef _PCF8574_                                                        ' Is the device being used a PCF8574?
    Symbol cPCF_I2C_Address      = %01000000                            ' Yes. So the PCF8574 device's slave address 0, 1, 0, 0, A2, A1, A0, RW.  Where Write = 0
$else                                                                   ' Otherwise... It is a PCF8574A
    Symbol cPCF_I2C_Address      = %01110000                            ' So... The PCF8574A device's slave address 0, 1, 1, 1, A2, A1, A0, RW.  Where Write = 0
$endif
'
' Bit patterns for the LCD via the I2C I/O extension
'
    Symbol cLCD_I2C_InitForLines = %00101000                            ' %00101000 for two line or four line LCD's
    Symbol cLCD_I2C_RS           = %00000001                            ' The LCD's RS line bit
    Symbol cLCD_I2C_RW           = %00000010                            ' The LCD's RW line bit
    Symbol cLCD_I2C_EN           = %00000100                            ' The LCD's EN line bit
    Symbol cLCD_I2C_RS_EN        = (cLCD_I2C_RS | cLCD_I2C_EN)          ' Both the LCD's RS and EN lines bits
    Symbol cLCD_I2C_BackLight    = %00001000                            ' The LCD's backlight bit
    Symbol cLCD_I2C_Init1        = %00110000
    Symbol cLCD_I2C_Init2        = %00100000
    Symbol cLCD_I2C_Init1_EN     = (cLCD_I2C_Init1 | cLCD_I2C_EN)       ' LCD initialisation nibble with EN line high
    Symbol cLCD_I2C_Init2_EN     = (cLCD_I2C_Init2 | cLCD_I2C_EN)       ' LCD initialisation nibble with EN line high
'
' Create some variables
'
    Dim BPF                  As Byte System                             ' Create a compiler system variable
    Dim LCD_I2C_tComOrData   As BPF.0                                   ' Holds 0 if data is to be sent to the LCD, else 1 for a command
    Dim LCD_I2C_tInitialised As BPF.1 = 0                               ' Holds 1 after the LCD has been initialised

    Dim LCD_I2C_bWregStore   As Byte                                    ' Holds a copy of WREG
    Dim LCD_I2C_bData        As Byte Access                             ' Holds the value to send to the LCD
    Dim LCD_I2C_bTemp        As LCD_I2C_bData                           ' Holds temporary values
    Dim LCD_I2C_bHighData    As Byte                                    ' Holds the high nibble data for the LCD
    Dim LCD_I2C_bLowData     As Byte                                    ' Holds the low nibble data for the LCD
    Dim LCD_I2C_bBL_State    As Byte                                    ' Holds the LCD's backlight state
    Dim LCD_I2C_tRSFlag      As Bit                                     ' Holds the state of the RS line

'---------------------------------------------------------------------------------------------------
$define LCD_Backlight_On() Print $FE, 3                                 ' Illuminate the LCD's Backlight
$define LCD_Backlight_Off() Print $FE, 4                                ' Extinguish the LCD's Backlight

'---------------------------------------------------------------------------------------------------
    Goto _LCD_I2C_Main_                                                 ' Jump over the replacement Print library subroutine

'---------------------------------------------------------------------------------------------------
' A replacement subroutine of the compiler's Print library, that uses a PCF8574 or PCF8574A device for I2C coms
' Input     : WREG holds the byte to send to the LCD
' Output    : WREG still holds the byte sent
' Notes     : If LCD_I2C_tInitialised is 0, the LCD will be initialised (is set to 1 after the LCD is initialised)
'
Sub __Print_()
    Wreg_Byte LCD_I2C_bWregStore                                        ' Save the contents of WREG

    If LCD_I2C_tInitialised = 0 Then                                    ' Has the LCD been inititalised?
        DelayMS 100                                                     ' No. So power-on delay for slow display types
        LCD_I2C_Write(cLCD_I2C_Init1_EN)                                ' EN line high and send command nibble 0011 (3)
        LCD_I2C_Write(cLCD_I2C_Init1)                                   ' EN line low
        DelayMS 20                                                      ' A small delay after the comand
        LCD_I2C_Write(cLCD_I2C_Init1_EN)                                ' EN line high and send command nibble 0011 (3)
        LCD_I2C_Write(cLCD_I2C_Init1)                                   ' EN line low
        DelayMS 20                                                      ' A small delay after the comand
        LCD_I2C_Write(cLCD_I2C_Init2_EN)                                ' EN line high and send command nibble 0010 (2)
        LCD_I2C_Write(cLCD_I2C_Init2)                                   ' EN line low
        DelayMS 20                                                      ' A small delay after the command
        LCD_I2C_bData = cLCD_I2C_InitForLines                           ' 4-bit mode and n lines
        LCD_I2C_Send(1)                                                 ' Send a control byte to the LCD
        LCD_I2C_bData = $0C                                             ' Enable display, cursor and blink off
        LCD_I2C_Send(1)                                                 ' Send a control byte to the LCD
        LCD_I2C_bData = $06                                             ' Move cursor after each write
        LCD_I2C_Send(1)                                                 ' Send a control byte to the LCD
        LCD_I2C_bData = $80                                             ' Goto column 1 line 1
        LCD_I2C_Send(1)                                                 ' Send a control byte to the LCD
        LCD_I2C_tInitialised = 1                                        ' Indicate that the LCD is initialised
    EndIf

    LCD_I2C_bData = LCD_I2C_bWregStore                                  ' Restore the value to write to the LCD
    If LCD_I2C_bData = $FE Then                                         ' Is it a command header?
        LCD_I2C_tRSFlag = 0                                             ' Yes. So clear a flag so we know the next byte will be a command
    Else                                                                ' Otherwise...
        If LCD_I2C_tRSFlag = 0 Then                                     ' Is this is a command byte?
            If LCD_I2C_bData = 3 Then                                   ' Yes. So does the backlight need illuminating?
                LCD_I2C_bBL_State = cLCD_I2C_BackLight                  ' Yes. So set its bit
            ElseIf LCD_I2C_bData = 4 Then                               ' Does the backlight need extinguishing?
                LCD_I2C_bBL_State = %00000000                           ' Yes. So clear its bit
            Else                                                        ' Otherwise...
                LCD_I2C_Send(1)                                         ' Send a control byte to the LCD
            EndIf
        Else
            LCD_I2C_Send(0)                                             ' Send data to the LCD
        EndIf
        LCD_I2C_tRSFlag = 1                                             ' Set a flag so the next byte will be sent as data
    EndIf
    Byte_Wreg LCD_I2C_bWregStore                                        ' Restore the contents of WREG
EndSub

'---------------------------------------------------------------------------------------------------
' Write an 8-bit value to the I2C bus
' Input     : pData holds the 8-bit data to write
' Output    : None
' Notes     : None
'
Proc LCD_I2C_Write(pData As LCD_I2C_bData)
    I2Cout LCD_SDA_Pin, LCD_SCL_Pin, cPCF_I2C_Address, [pData]
EndProc

'---------------------------------------------------------------------------------------------------
' Send a data or control byte to the LCD
' Input     : pComDat holds 0 for a data byte, 1 for a control byte
'           : Global variable "LCD_I2C_bData" holds the data value to send
' Output    : None
' Notes     : None
'
Proc LCD_I2C_Send(pComDat As LCD_I2C_tComOrData)
    LCD_I2C_bHighData = LCD_I2C_bData & %11110000                       ' Mask LSBs
    LCD_I2C_bLowData = LCD_I2C_bData << 4                               ' Shift left

    If pComDat = 0 Then                                                 ' Is it data to be sent to the LCD?
        LCD_I2C_bTemp = cLCD_I2C_RS_EN | LCD_I2C_bHighData              ' Yes. So EN line high and send the high nibble to the LCD
        LCD_I2C_bTemp = LCD_I2C_bTemp | LCD_I2C_bBL_State               ' Keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)

        LCD_I2C_bTemp = cLCD_I2C_RS | LCD_I2C_bHighData                 ' RS high and send the high nibble byte to the LCD
        LCD_I2C_bTemp = LCD_I2C_bTemp | LCD_I2C_bBL_State               ' Keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)

        LCD_I2C_bTemp = cLCD_I2C_RS | LCD_I2C_bBL_State                 ' RS high and keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)                                    ' Delay, RS on throughout

        LCD_I2C_bTemp = cLCD_I2C_RS_EN | LCD_I2C_bLowData               ' RS and EN lines high and send the low nibble to the LCD
        LCD_I2C_bTemp = LCD_I2C_bTemp | LCD_I2C_bBL_State               ' Keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)

        LCD_I2C_bTemp = cLCD_I2C_RS | LCD_I2C_bLowData                  ' RS line high and send the low nibble byte to the LCD
        LCD_I2C_bTemp = LCD_I2C_bTemp | LCD_I2C_bBL_State               ' Keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)

    Else                                                                ' Otherwise... Send a control byte to the LCD
        LCD_I2C_bTemp = cLCD_I2C_EN | LCD_I2C_bHighData                 ' So... EN line high and send the high nibble to the LCD
        LCD_I2C_bTemp = LCD_I2C_bTemp | LCD_I2C_bBL_State               ' Keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)

        LCD_I2C_bTemp = LCD_I2C_bHighData | LCD_I2C_bBL_State           ' RS and EN lines low and keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)

        LCD_I2C_bTemp = LCD_I2C_bBL_State                               ' \
        LCD_I2C_Write(LCD_I2C_bTemp)                                    ' / Delay

        LCD_I2C_bTemp = cLCD_I2C_EN | LCD_I2C_bLowData                  ' EN line high and send the low nibble to the LCD
        LCD_I2C_bTemp = LCD_I2C_bTemp | LCD_I2C_bBL_State               ' Keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)

        LCD_I2C_bTemp = LCD_I2C_bLowData | LCD_I2C_bBL_State            ' RS and EN lines low and keep the backlight bit's condition
        LCD_I2C_Write(LCD_I2C_bTemp)
    EndIf
EndProc

'---------------------------------------------------------------------------------------------------
_LCD_I2C_Main_:

Copy the code listing above into the compiler's IDE and save it as "PCF8574x_LCD.inc" in the "Includes" folder, located here: "C:\Users\User Name\PDS\Includes\". This means all program listings can see the library file with a simple Include directive. Or use the "PCF8574x_LCD.inc" file from the attached .zip file.

To use a PCF8574 device, as opposed to a PCF8574A device, add the $define "$define _PCF8574_" to the code listing, before the library is included in the code listing.

Below is a demonstration code listing of the above library operating via a PCF8574A device, working with a 4 line by 20 character LCD, but it will also work with a 2 line by 16 character type:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate interfacing to an alphanumeric LCD using I2C via a PCF8574 or PCF8574A I/O expander device
'
' Written for the Positron8 BASIC compiler by Les Johnson.
'
    Device = 18F26K22                                               ' Tell the compiler what device to compile for
    Declare Xtal = 64                                               ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Float_Display_Type = Fast                               ' Enable the faster, and more accurate, floating point to ASCII library routine
'
' Setup the pins to use for the I2C interface to the PCF8574 or PCF8574A device
' These must be setup before the "PCF8574x_LCD.inc" library is included in the program, so it can see them.
'
$define LCD_SCL_Pin PORTC.0                                         ' Setup the pin to use for the PCF8574x/LCD's SCL line
$define LCD_SDA_Pin PORTC.1                                         ' Setup the pin to use for the PCF8574x/LCD's SDA line
'$define _PCF8574_                                                  ' Uncomment to use a PCF8574 in the LCD library, instead of a PCF8574A

    Include "PCF8574x_LCD.inc"                                      ' Load the PCF8574x I2C LCD library routines into the program
'
' Create some variables for the demo
'
    Dim wCounter As Word = 0
    Dim lCounter As Long = 0
    Dim dCounter As Dword = 0
    Dim fCounter As Float = 0

'---------------------------------------------------------------------------------------------------
' The main program starts here
' Display incrementing values on an alphanumeric LCD
'
Main:
    IntOsc_64MHz()                                                  ' Setup the device to use its internal oscillator at 64MHz

    LCD_Backlight_On()                                              ' Illuminate the LCD's Backlight
    Cls                                                             ' Clear the LCD's display
    Do                                                              ' Create a loop
        Print At 1, 1, "Word:  ", Dec wCounter, "     ",            ' \
              At 2, 1, "Long:  ", Dec lCounter, "     ",            ' | Display the values on the LCD
              At 3, 1, "Dword: ", Dec dCounter, "     ",            ' |
              At 4, 1, "Float: ", Dec1 fCounter                     ' /
        Inc(wCounter, 1)                                            ' \
        Inc(lCounter, 10)                                           ' | Increment the variables
        Inc(dCounter, 100)                                          ' |
        Inc(fCounter, 0.1)                                          ' /
        DelayMS 100                                                 ' A small delay so the values can be seen incrementing
    Loop                                                            ' Do it forever

'---------------------------------------------------------------------------------------------------
' Setup the device to use its internal oscillator at 64MHz
' Input     : None
' Output    : None
' Notes     : For use with PIC18Fx6K22 devices
'
Proc IntOsc_64MHz()
    OSCCON  = $70
    OSCCON2 = $04
    OSCTUNE = $40
    Repeat : Until OSCCON2bits_PLLRDY = 1                           ' Wait for the PLL to stabilise
EndProc

'-----------------------------------------------------------------------------------------
' Configure the fuses to operate using the internal oscillator, on a PIC18F26K22 device
'
Config_Start
    FOSC     = INTIO67          ' Use the internal oscillator for the device's oscillator
    PLLCFG   = Off              ' Disable PLL
    PRICLKEN = On               ' Primary clock enabled
    FCMEN    = Off              ' Fail-Safe Clock Monitor disabled
    IESO     = Off              ' Internal/External Oscillator Switchover mode disabled
    PWRTEN   = On               ' Power up timer enabled
    BOREN    = SBORDIS          ' Brown-out Reset enabled in hardware only (SBOREN is disabled)
    BORV     = 190              ' Brown Out Reset Voltage set to 1.90 V nominal
    WDTEN    = Off              ' Watch dog timer is always disabled. SWDTEN has no effect.
    WDTPS    = 128              ' Watchdog Timer Postscale 1:128
    CCP2MX   = PORTC1           ' CCP2 input/output is multiplexed with RC1
    PBADEN   = Off              ' PORTB<5:0> pins are configured as digital I/O on Reset
    CCP3MX   = PORTB5           ' P3A/CCP3 input/output is multiplexed with RB5
    HFOFST   = On               ' HFINTOSC output and ready status are not delayed by the oscillator stable status
    T3CMX    = PORTC0           ' Timer3 Clock Input (T3CKI) is on RC0
    P2BMX    = PORTB5           ' ECCP2 B (P2B) is on RB5
    MCLRE    = EXTMCLR          ' MCLR pin enabled, RE3 input pin disabled
    STVREN   = Off              ' Stack full/underflow will not cause Reset
    LVP      = Off              ' Single-Supply ICSP disabled
    XINST    = Off              ' Instruction set extension and Indexed Addressing mode disabled
    Debug    = Off              ' Debug Disabled
    Cp0      = Off              ' Block 0 (000800-001FFF) not code-protected
    CP1      = Off              ' Block 1 (002000-003FFF) not code-protected
    CP2      = Off              ' Block 2 (004000-005FFF) not code-protected
    CP3      = Off              ' Block 3 (006000-007FFF) not code-protected
    CPB      = Off              ' Boot block (000000-0007FF) not code-protected
    CPD      = Off              ' Data EEPROM not code-protected
    WRT0     = Off              ' Block 0 (000800-001FFF) not write-protected
    WRT1     = Off              ' Block 1 (002000-003FFF) not write-protected
    WRT2     = Off              ' Block 2 (004000-005FFF) not write-protected
    WRT3     = Off              ' Block 3 (006000-007FFF) not write-protected
    WRTC     = Off              ' Configuration registers (300000-3000FF) not write-protected
    WRTB     = Off              ' Boot Block (000000-0007FF) not write-protected
    WRTD     = Off              ' Data EEPROM not write-protected
    EBTR0    = Off              ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1    = Off              ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTR2    = Off              ' Block 2 (004000-005FFF) not protected from table reads executed in other blocks
    EBTR3    = Off              ' Block 3 (006000-007FFF) not protected from table reads executed in other blocks
    EBTRB    = Off              ' Boot Block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

The demonstration program above is working on an 18F device operating at 64MHz, but the library will also work with 14-bit core devices because the I2C interface is using the software method via the I2COut command, that is so much more flexible than the I2C peripheral and its I2C operations are exactly the same.

Below is a screenshot of the above demonstration program, working within the Proteus simulator. The library source code and demonstration source code and Proteus simulation projects are attached at the bottom of this post in a zip file named: "PCF8574x_I2C_LCD_Library.zip". It has been scanned for any problems, so enjoy coding with the Positron compilers!

I2C_LCD_Interface.jpg

top204

Below is another demonstration program listing using the "PCF8574x_LCD.inc" library from the above post, and operating on a small enhanced 14-bit core, 8-pin microcontroller. How's that for flexability of the compiler's software based I2C commands?

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate interfacing to an alphanumeric LCD using I2C via a PCF8574 or PCF8574A I/O expander device on an 8-pin microcontroller
'
' Written for the Positron8 BASIC compiler by Les Johnson.
'
    Device = 12LF1572                                               ' Tell the compiler what device to compile for
    Declare Xtal = 8                                                ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Float_Display_Type = Fast                               ' Enable the faster, and more accurate, floating point to ASCII library routine
'
' Setup the pins to use for the I2C interface to the PCF8574 or PCF8574A device
' These must be setup before the "PCF8574x_LCD.inc" library is included in the program, so it can see them.
'
$define LCD_SCL_Pin PORTA.0                                         ' Setup the pin to use for the PCF8574x/LCD's SCL line
$define LCD_SDA_Pin PORTA.1                                         ' Setup the pin to use for the PCF8574x/LCD's SDA line
'$define _PCF8574_                                                  ' Uncomment to use a PCF8574 in the LCD library, instead of a PCF8574A

    Include "PCF8574x_LCD.inc"                                      ' Load the PCF8574x I2C LCD library routines into the program
'
' Create some variables for the demo
'
    Dim wCounter As Word = 0
    Dim lCounter As Long = 0
    Dim dCounter As Dword = 0
    Dim fCounter As Float = 0

'---------------------------------------------------------------------------------------------------
' The main program starts here
' Display incrementing values on an alphanumeric LCD
'
Main:
    IntOsc_Init()                                                   ' Setup the device to use its internal oscillator

    LCD_Backlight_On()                                              ' Illuminate the LCD's Backlight
    Cls                                                             ' Clear the LCD's display
    Do                                                              ' Create a loop
        Print At 1, 1, "Word:  ", Dec wCounter, "     ",            ' \
              At 2, 1, "Long:  ", Dec lCounter, "     ",            ' | Display the values on the LCD
              At 3, 1, "Dword: ", Dec dCounter, "     ",            ' |
              At 4, 1, "Float: ", Dec1 fCounter                     ' /
        Inc(wCounter, 1)                                            ' \
        Inc(lCounter, 10)                                           ' | Increment the variables
        Inc(dCounter, 100)                                          ' |
        Inc(fCounter, 0.1)                                          ' /
        DelayMS 100                                                 ' A small delay so the values can be seen incrementing
    Loop                                                            ' Do it forever

'---------------------------------------------------------------------------------------------------
' Setup the device to use its internal oscillator
' Input     : None
' Output    : None
' Notes     : None
'
Proc IntOsc_Init()
    OSCCON  = $70
    OSCTUNE = $00
EndProc

'-----------------------------------------------------------------------------------------
' Configure the fuses to operate using the internal oscillator, on a PIC12LF1572 device
'
    Config1 FOSC_INTOSC,_       ' I/O function on CLKIN pin
            WDTE_OFF,_          ' WDT disabled
            PWRTE_OFF,_         ' PWRT disabled
            MCLRE_ON,_          ' MCLR/VPP pin function is MCLR
            CP_OFF,_            ' Program memory code protection is disabled
            BOREN_ON,_          ' Brown-out Reset enabled
            CLKOUTEN_OFF        ' I/O function on the CLKOUT pin

    Config2 WRT_OFF,_           ' Write protection off
            PLLEN_OFF,_         ' 4x PLL disabled
            STVREN_ON,_         ' Stack Overflow or Underflow will cause a reset
            BORV_LO,_           ' Brown-out Reset Voltage (Vbor), low trip point selected
            LPBOREN_OFF,_       ' LPBOR is disabled
            LVP_OFF             ' High-voltage on MCLR/VPP must be used for programming

And below is a screenshot of the proteus simulator running the above post's "PCF8574x_LCD.inc" library working on a tiny PIC12LF1572 device:

PIC12LF1572_I2C_LCD_Interface.jpg


keytapper

I think there could be a more option for the SPI hardware. I, a bit long ago, made an interface with the 75xx595 and I oriented the pins to the display as it's for the PCF8574xx.
This arrangement may be better performing that the I2C, whenever the MCU has the capabilities. Just the cost of one more pin to spend.
Thanks for the efforts Mr Les.
Ignorance comes with a cost

charliecoutas

Les

Will this work with the dsPIC33 series? If so it will fix a real problem I have.

Best regards
Charlie

top204

I can't see any reason why it will not work on the 16-bit microcontrollers Charlie. It is using the software I2C commands, and they operate the same on all devices, because they do not rely on a dedicated peripheral, and just toggle pins in the right directions at the right times. :-)

I much prefer the software based I2C commands when used as a master because they are a lot more controllable and predictable with the changes that are constantly made by microchip with their peripherals.

charliecoutas

Thanks Les, that makes sense. Yes I like the software I2C and use them a lot.

Charlie

XTlegend

Great stuff, finally got a display to work - took me a weekend to realise that the 3 address inputs on the piggy back board were floating ......   :o

Mustafa_cmbz

What should be the physical value of the crystal we use when using this library? 4mhz 8mhz 20mhz?

keytapper

Ignorance comes with a cost

top204

The demo code listings are using the microcontroller's internal oscillator, so no crystal is required. And as keytapper stated, the compiler will alter the delays in the I2C commands to make sure they do not run too fast, regardless of the device's speed.