I2CLCDPCF8574
The I2CLCD Module
This module allows you to use the I2C LCD Displays that are interfaced with the PCF8574 expander chip. It works with both the hardware and software I2C libraries. And supports both 16x2 line and 16x4 line displays with no configuration.
I have worked with the I2CLCD module to get it as close as possible to the original Swordfish LCD module for the HD44780 display. This allows you to use the same LCD instructions as you would with the Swordfish LCD library.
- Note: This library will require you to use the latest version of Swordfish as of v2.2.3.3
About PCF8574
The PCF8574 module board is a breakout board for the I2C IO Expander chip PCF8574 designed for LCD interfacing via a 16-pin header. There is a jumper to turn on or off the LCD backlight. As well as a potentiometer to adjust the LCD screen contrast. And with solder pads, A0 A1 A2. You can solder any bit of them to make it a different address if needed. The board has a power led as well as a voltage regulator and most importantly a header to connect your I2C 2-wires (SCL, SDA).
The SCL and SDA lines will require the use of a pullup resistor since it is used as a bidirectional open-drain. Serial clock (SCL), serial data (SDA)) @ 100kHz.
Module Options
The modules default I2C address is set to $4E, this was the address that my test boards was set too, but you are able to change the address to suit. As the module is self Initialized you will need to disable the Initialize() options within the module, and add the Initialize() code to your main prog with the included address within the parenthesis.
Example: Change the following module options to false
#option I2CLCD_INITIALIZE = true
And add the following code to your main prog (with your desired address).
Initialize($4E)
Sample Code (Software SI2C)
This sample code shows you how to use the I2CLCD library with the software SI2C options. You don't need to include the I2C/S12C libraries as the module takes care of that for you. You just need to add the optional lines of code and set your SDA, SCL pins.
' Using software I2C to control the I2CLCD display. Device = 18F2550 Clock = 20 // optional configure SDA and SCL if using software I2C... #option USE_SI2C = true #option I2C_SDA = PORTA.4 #option I2C_SCL = PORTA.5 // import libraries... Include "I2CLCD.bas" ' write string to display at locations... I2CLCD.WriteAt(1,2,"Swordfish") I2CLCD.WriteAt(2,4,"I2C LCD") I2CLCD.WriteAt(3,6,"Library") I2CLCD.WriteAt(4,8,"by Bitfogav.")
Sample Code (BarGraphs)
' Draws two graphs to the LCD display lines.. Device = 18F2550 Clock = 20 // import libraries... Include "I2CLCD.bas" Include "utils.bas" // refresh speed... Const UpdateMS = 50 // initialise bit patterns... // programmable characters are available that use codes $00 to $07. // Create the bit patterns that make up the bars in the LCD's CGRAM. // The vertical bars are made up of 8 identical bit patterns Const CGRAM(32) As Byte = ($00,$00,$00,$00,$00,$00,$00,$00, // base bar $10,$10,$10,$10,$10,$10,$10,$00, // 8 x %10000 = | $14,$14,$14,$14,$14,$14,$14,$00, // 8 x %10100 = || $15,$15,$15,$15,$15,$15,$15,$00) // 8 x %10101 = ||| // output byte pRepValue times... NoInline Sub Rep(pValue, pRepValue As Byte) Dim Index As Byte Index = 0 While Index < pRepValue I2CLCD.Write(pValue) Inc(Index) Wend End Sub // display the bar... NoInline Sub Bargraph(pLine, pBarValue As Byte) Const BASE_BAR = 0 // ASCII value of 0 bar (blank) Const FULL_BAR = 3 // ASCII value of ||| bar Const BAR_WIDTH = 16 // Max width in characters of bar Const MAX_BAR_COUNT = BAR_WIDTH * 3 // Max bar counts Dim NumberOfBars As Byte = pBarValue / 3 Dim Balance As Byte = pBarValue Mod 3 I2CLCD.MoveCursor(pLine,1) Rep(FULL_BAR,NumberOfBars) I2CLCD.Write(Balance) Rep(BASE_BAR,BAR_WIDTH - (NumberOfBars + Min(Balance,1))) End Sub // loop index Dim Index As Byte // starting point of prog... I2CLCD.Write(CGRAM) DelayMS(2000) // display the bar While true For Index = 0 To 48 Bargraph(1,Index) Bargraph(2,48 - Index) DelayMS(UpdateMS) Next For Index = 48 To 0 Step -1 Bargraph(1,Index) Bargraph(2,48 - Index) DelayMS(UpdateMS) Next Wend
I2CLCD Module
{ ***************************************************************************** * Name : I2CLCD.BAS * * Author : Gavin Wiggett (Bitfogav) * * Notice : Copyright (c) 2020 * * : All Rights Reserved * * Date : 14/06/2020 * * : * * Version : 1.0 * * Notes : I2CLCD.bas Lib for use with the PCF8574 controlled LCD. * * : It will work with I2C Hardward or Software Libraries. * * : just include the optonal settings in your main prog. * * : * * : Works with 2line and 4line LCD. * * : * * : Note: Lib doesn't support reading the PCF8574 or LCD busy flag.* * : (this maybe added in a future update). * ***************************************************************************** } Module I2CLCD // default module options for software I2C if used - user options can override these values... #option USE_SI2C = false #option I2C_SDA = PORTB.2 #option I2C_SCL = PORTB.3 // Use hardware or software I2C, (default is hardware I2C)... #if IsOption (USE_SI2C) And Not (USE_SI2C in (true, false)) #error USE_SI2C, "Invalid Option, USE_SI2C must be true or false" #endIf // SCL option for software I2C only... #if IsOption(I2C_SCL) And Not IsValidPortPin(I2C_SCL) #error I2C_SCL, "Invalid option. I2C clock must be a valid port pin." #endif // SDA option for software I2C only... #if IsOption(I2C_SDA) And Not IsValidPortPin(I2C_SDA) #error I2C_SDA, "Invalid option. I2C data line must be a valid port pin." #endif // By default, the module includes a call to I2C lcd Initialize() at startup. // set this option false to exclude initializer... user MUST then call Initialize() // you can then change the I2C address by calling Initialize() and adding your // desired address for example I2CLCD.Initialize($20). #option I2CLCD_INITIALIZE = true #if Not(I2CLCD_INITIALIZE in (true, false)) #error I2CLCD_INITIALIZE, "Invalid option" #endif // Depending on the #option USE_SI2C setting, will select Hardware or Software I2C... #if (_mssp > 0) And Not USE_SI2C Include "I2C.bas" #else Include "SI2C.bas" #endif // public LCD control commands... Public Const cmdCGRAM = $40, cmdDDRAM = $60, cmdClear = $01, cmdHome = $02, cmdEntryMode = $04, cmdUnderLineON = $0E, cmdCursorOFF = $0C, cmdCursorON = $0F, cmdBackLightON = $08, cmdBackLightOFF = $00, cmdMoveCursorLeft = $10, cmdMoveCursorRight = $14, cmdDisplayON = $0C, cmdDisplayOFF = $08, cmdMoveLeft = $18, cmdMoveRight = $1E // Bring LCD controls into the module... Private Dim RS, // LCD register select pin. I2C_Addrs As Byte, // I2C device address (default $4E). I2CInitialize As Initialize // Bring Hardware or Software I2C into the module... Private Dim FPosX As Byte = 1, // local x, y coordinates. FPosY As Byte = 1 // initialized as per compiler update 2.2.3.3. // Bring LCD backlight into the module... Private Dim BackLight_State As Byte = cmdBackLightON '**************************************************************************** '* Name : ExpanderWrite * '* Purpose : Write data to PCF8574 I2C * '**************************************************************************** Private Sub ExpanderWrite(pData As Byte) Start() WriteByte(I2C_Addrs) WriteByte(pData Or BackLight_State) Stop() End Sub '**************************************************************************** '* Name : SetData * '* Purpose : Write 4 bit data (4 bit interface) * '**************************************************************************** Private Sub SetData(pNibble As Byte) pNibble = pNibble Or RS // Include RS Value To LSB OF Data ExpanderWrite(pNibble Or $04) ExpanderWrite(pNibble And $FB) DelayUS(50) End Sub '**************************************************************************** '* Name : Command * '* Purpose : Write command data to LCD (4 bit interface) * '**************************************************************************** Public Sub Command(pCommand As Byte) RS = 0 SetData(pCommand And $F0) SetData((pCommand << 4) And $F0) DelayUS(50) End Sub '**************************************************************************** '* Name : WriteItem (OVERLOAD) * '* Purpose : Write a single byte to the LCD (4 bit interface) * '**************************************************************************** Private Sub WriteItem(pData As Byte) RS = 1 SetData(pData And $F0) SetData((pData << 4) And $F0) DelayUS(50) End Sub '**************************************************************************** '* Name : WriteItem (OVERLOAD) * '* Purpose : Write a string to the LCD * '**************************************************************************** Private Sub WriteItem(pText As String) Dim TextPtr As POSTINC0 Dim Text As INDF0 FSR0 = AddressOf(pText) While Text <> 0 WriteItem(TextPtr) Wend End Sub '**************************************************************************** '* Name : WriteItem (OVERLOAD) * '* Purpose : Initialise the CGRAM with constant data array. Eight * '* : programmable characters are available (0..7). * '**************************************************************************** Private Sub WriteItem(ByRefConst pBitmap() As Byte) Dim Index As Byte Command(cmdCGRAM) For Index = 0 To Bound(pBitmap) WriteItem(pBitmap(Index)) Next Command(cmdDDRAM) End Sub '**************************************************************************** '* Name : Write (COMPOUND) * '* Purpose : Calls one or more WriteItem() subroutines * '**************************************************************************** Public Compound Sub Write(WriteItem) '**************************************************************************** '* Name : MoveCursor * '* Purpose : Move the cursor to line and column * '**************************************************************************** Public Sub MoveCursor(pLine, pCol As Byte) Dec(pCol) Select pLine Case 1 : Command($80 + pCol) Case 2 : Command($C0 + pCol) Case 3 : Command($94 + pCol) Case 4 : Command($D4 + pCol) EndSelect End Sub '**************************************************************************** '* Name : MoveTo (PRIVATE) * '* Purpose : Moves cursor to module private x, y location * '**************************************************************************** Private Inline Sub MoveTo() MoveCursor(FPosY, FPosX) End Sub '**************************************************************************** '* Name : SetLocationX (PRIVATE) * '* Purpose : Set cursor x * '**************************************************************************** Private Inline Sub SetLocationX(pX As FPosX) End Sub '**************************************************************************** '* Name : SetLocationY (PRIVATE) * '* Purpose : Set cursor y * '**************************************************************************** Private Inline Sub SetLocationY(pY As FPosY) End Sub '**************************************************************************** '* Name : WriteAt (COMPOUND) * '* Purpose : Calls one or more WriteItem() subroutines at location x, y * '**************************************************************************** Public Compound Sub WriteAt(SetLocationY, SetLocationX, MoveTo, WriteItem) '**************************************************************************** '* Name : Cls * '* Purpose : Clear the LCD screen * '**************************************************************************** Public Sub Cls() Command($01) DelayMS(30) End Sub '**************************************************************************** '* Name : Backlight * '* Purpose : Set LCD backlight on/off * '**************************************************************************** Public Sub Backlight(pSet As Boolean = true) If pSet = true Then BackLight_State = cmdBackLightON Else BackLight_State = cmdBackLightOFF End If ExpanderWrite($00) End Sub '**************************************************************************** '* Name : ShiftLeft * '* Purpose : Shift the LCD display left * '**************************************************************************** Public Sub ShiftLeft() Command($18) DelayUS(40) End Sub '**************************************************************************** '* Name : ShiftRight * '* Purpose : Shift the LCD display right * '**************************************************************************** Public Sub ShiftRight() Command($1C) DelayUS(40) End Sub '**************************************************************************** '* Name : Initialize (Public) * '* Purpose : Initialize the LCD - Optional User can define i2c device addr * '**************************************************************************** Public Sub Initialize(pAddr As Byte = $4E) DelayMS(100) // wait for LCD to stabilise... I2C_Addrs = pAddr ExpanderWrite($00) DelayMS(30) Command($03) DelayMS(5) Command($03) DelayMS(5) Command($03) DelayMS(5) Command(cmdHome) DelayMS(5) Command($20 Or (2 << 2)) ' function set (4-bit interface, 2 lines, 5*7 Pixels) DelayMS(50) Command(cmdDisplayON) DelayMS(50) Command(cmdClear) DelayMS(50) Command(cmdEntryMode Or cmdHome) DelayMS(50) End Sub // initialise the I2C module (HW or SW)... I2CInitialize() // initialise the I2CLCD module, you must disable the option above // if you wish to use your own I2C address, see the option above... #if I2CLCD_INITIALIZE Initialize() #endif End Module
Download Library
Download I2CLCD Library V1.0
I2CLCDv1.zip