MicroLib_LCD_I2C_PCF8574
MicroLib_LCD_I2C_PCF8574

If you want to connect a standard LCD-display to your Arduino, you should try this library!

With this MicroLib your Arduino board will be able to control a standard LCD-display, based on the Hitachi HD44780 display-controller and connected through a PCF8574 based I2C-adapter. It consist of the single header file MicroLib_LCD_I2C_PCF8574.h which must be included after including the Wire-library or the Software I2C-library - yes, this library works fine with the Software I2C library, see the included HelloWorld example programs.

The standard LiquidCrystal library does only support LCD-displays, connected directly to the Arduino I/O pins, no I2C. If you want to use an I2C-adapter only the New-LiquidCrystal-library from Fernando Malpartida is available which can replace the original LiquidCrystal-lib entirely.

Compared to those libraries, the MicroLib greatly reduces the size of the compiled code and the depth of the call-stack, by simply replacing sub-routines that would just call another subroutine to send a command to the display with C pre-processor macros and omitting all checks; You must know what you are doing: If you want to write a text into row 3 of a 16x2 display the MicroLib will happily store your data into the LCD-display controllers memory - don't be surprised if you don't see it!

The MicroLibrary is not compatible to any of the standard LiquidCrystal libraries at all, but here is the advantage in numbers:
If you compile the included HelloWorld example program with Fernandos NewLiquidCrystal-library the resulting code occupies 3,732 bytes of program memory, if you compile it with the MicroLib this amount goes down to 2,778 bytes. Of course, this is an extreme example, in larger programs the gain is not so exorbitant, but if you just have 30,720 bytes of program memory in your Arduino Nano every byte counts...

Almost all I2C-adapters that are being sold in the internet are following the schema below to connect to the LCD-display:

PCF8574 PortBitLCD-display pinPin NameFunction
04RSRegister Select
15RWRead not Write
26EEnable
311ABacklight Anode (through inverting transistor)
416D4Databit 4
512D5Databit 5
613D6Databit 6
714D7Databit 7

This schematic is available as Eagle-file and PDF-document. If your adapter has a different layout, you need to adjust the [LCD_SendByte] sub-routine.

[Library API] [HelloWorld example] [CharSet example] HD44780@WikipediA HD44780 data sheet [PCF8574 data sheet]
Library API

[Constants] [Types] [Sub-Routines]
[LCD_Init] [LCD_DefineChar]
[LCD_DisplayOff] [LCD_DisplayOn] [LCD_BacklightOn] [LCD_BacklightOff]
[LCD_Cls] [LCD_Home] [LCD_At] [LCD_CursorOff] [LCD_CursorLine] [LCD_CursorBlock] [LCD_CursorBlink]
[LCD_Print] [LCD_PrintAt] [LCD_PutChar] [LCD_PutByte] [LCD_PrintEEPROM] [LCD_PrintAtEEPROM]
[LCD_SendByte] [LCD_DefCh] [LCD_Pr] [LCD_prEEPROM]

Constant definitions
  • LCD display wiring bitmasks
    • LCD_IO_RS - bit-mask for the RS input (Default: PortBit 0)
    • LCD_IO_RW - bit-mask for the R/~W input (Default: PortBit 1)
    • LCD_IO_EN - bit mask for the EN input (Default: PortBit 2)
    • LCD_IO_BL - bit-mask for the BL input (Default: PortBit 3)
  • LCD display commands
    • LCD_CMD_NOOP - No operation
    • LCD_CMD_CLS - Clear Screen
    • LCD_CMD_HOME - Cursor home
    • LCD_CMD_MODE - Set mode options
    • LCD_CMD_DISP - Set display options
    • LCD_CMD_SHIFT - Shift display/cursor
    • LCD_CMD_FNSET - Set Function options
    • LCD_CMD_CGRAM - Set character generator RAM address
    • LCD_CMD_DDRAM - Set display data RAM address
  • LCD display command options
    • LCD_OPT_MODE_LTR - Cursor moves to the right
    • LCD_OPT_MODE_SHIFT - Display shifts with cursor
    • LCD_OPT_DISPLAY_ON - Display on
    • LCD_OPT_CURSOR_ON - Cursor on
    • LCD_OPT_BLINK_ON - Cursor is a blinking block
    • LCD_OPT_CURSOR_OFF - Cursor and blinking off
    • LCD_OPT_SHIFT_DISP - Display moves, cursor fixed
    • LCD_OPT_SHIFT_RIGHT - Shift display to the right
    • LCD_OPT_FNSET_8BIT - Set the interface to 8 bit
    • LCD_OPT_FNSET_2LINE - Set 2-lines mode
    • LCD_OPT_FNSET_5X11 - Set 5x11 matrix
  • SendByte options
    • LCD_SB_Reg 1 - Send data to the LCD display-controller register
    • LCD_SB_Mem 2 - Send data to the LCD display-controller memory
    • LCD_SB_Ini 3 - Send Initialization data to the LCD display-controller
Quick-Links
Type definitions
  • struct t_LCD; display-handle, elements:
    • uint8_t Address - The I2C address of the LCD-display adapter (usually 0x27)
    • uint8_t BacklightStatus - Status of the backlight (internally used)
    • uint8_t DisplayMode - Status of the display and the cursor (internally used)
    • uint8_t RowAddresses[4] - The start-addresses of the display rows in the controllers memory (internally used)
Quick-Links
Sub-routines and pre-processor macros

  • void LCD_SendByte; Send a single byte to the LCD display-controller, parameters:
    • t_LCD* p_LCD - The address of the display-handle (call with &Handlename)
    • uint8_t p_Data - The data-byte to be sent to the controller
    • uint8_t p_Mode - The mode
    • uint8_t p_Delay - A delay time for a display-controller command to execute
    Usually there is no need to use this sub-routine in your programs, you should really know what you are doing if you use it!
    Quick-Links

  • t_LCD LCD_Init; Initialize the LCD display-controller and return display-handle, parameters:
    • uint8_t p_Address - The I2C-address of the adapter
    • uint8_t p_Columns - The number of columns of the display
    • uint8_t p_Rows - The number of rows of the display
    Example: Display = LCD_Init(LCD_I2C_ADDR,20,4); // 20x4 display
    Quick-Links

  • void LCD_DefCh; Define character(s), parameters:
    • t_LCD* p_LCD - Address of the display-handle (call with &HandleName)
    • uint8_t p_Start - Number of character to be defined (0-7)
    • uint8_t p_Length - Length of the pattern in bytes
    • uint8_t p_Pattern[] - The bit-pattern that defines the character(s)
    It is possible to re-define more than one character with one call of this sub-routine.
    Instead of using this sub-routine, better use the pre-processor macro LCD_DefineChar.
    Example: LCD_DefineChar(&Display,1,8,v_CharBuffer); // define character 1
    Quick-Links

  • LCD_DefineChar(; Define characters, parameters:
    • p_LCD - The display-handle
    • uint8_t p_Start - Number of character to be defined (0-7)
    • uint8_t p_Length - Length of the pattern in bytes
    • uint8_t p_Pattern[] - The bit-pattern that defines the character(s)
    Pre-Processor macro, calls LCD_DefCh to avoid the pointer syntax &HandleName.
    Example: LCD_BacklightOn(Display);
    Quick-Links

  • LCD_BacklightOn(; Switch the LCD-display's backlight on, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, calls LCD_SendByte and updates the display-handle.
    Example: LCD_BacklightOn(Display);
    Quick-Links

  • LCD_BacklightOff(; Switch the LCD-display's backlight off, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, calls LCD_SendByte and updates the display-handle.
    Example: LCD_BacklightOn(Display);
    Quick-Links

  • LCD_Cls(; Clear screen, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_Cls(Display);
    Quick-Links

  • LCD_Home(; Home cursor, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_Home(Display);
    Quick-Links

  • LCD_CursorOff(; Switch cursor off, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_CursorOff(Display);
    Quick-Links

  • LCD_CursorLine(; Switch cursor to an underline, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_CursorLine(Display);
    Quick-Links

  • LCD_CursorBlock(; Switch cursor to a steady block, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_CursorBlock(Display);
    Quick-Links

  • LCD_DisplayOff(; Switch the display off, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_DisplayOff(Display);
    Quick-Links

  • LCD_DisplayOn(; Switch the display on, parameters:
    • p_LCD - The display-handle
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_DisplayOn(Display);
    Quick-Links

  • LCD_At; Position cursor in the display, parameters:
    • p_LCD - The display-handle
    • p_Column - The column to which the cursor is moved, column numbers start with zero.
    • p_Row - The row to which the cursor is moved, row numbers start with zero.
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_At(Display,0,1); // position cursor to the left of the second row
    Quick-Links

  • void LCD_pr; Print a text on the display, parameters:
    • t_LCD* p_LCD - The address of the display-handle (call with &HandleName)
    • char p_Text[] - The text to be printed as a c-string
    Instead of using this sub-routine, better use the pre-processor macro LCD_Print
    Quick-Links

  • LCD_Print; Print a text on the display, parameters:
    • p_LCD - The display-handle
    • char p_Text - The text to be printed as a c-string
    Pre-Processor macro, just a call to LCD_pr to avoid the pointer syntax &HandleName
    Example: LCD_Print(Display,"Hello World!");
    Quick-Links

  • LCD_PutChar; Print a character on the display, parameters:
    • p_LCD - The display-handle
    • char p_ch - The character to be printed
    Pre-Processor macro, just a call to LCD_SendByte to avoid typing the type-cast
    Example: LCD_PutChar(Display,'*');
    Quick-Links

  • LCD_PutByte; Print a byte on the display, parameters:
    • p_LCD - The display-handle
    • char p_by - The byte to be printed
    Pre-Processor macro, just a call to LCD_SendByte
    Example: LCD_PutByte(Display,0x02);
    Quick-Links

  • LCD_PrintAt; Position Cursor and print a text on the display, parameters:
    • p_LCD - The display-handle
    • p_Column - The column to which the cursor is moved, column numbers start with zero.
    • p_Row - The row to which the cursor is moved, row numbers start with zero.
    • p_Text - The text to be printed as a c-string
    Pre-Processor macro, calls LCD_at, then LCD_pr
    Example: LCD_PrintAt(Display,0,1,"Hello World!");
    Quick-Links

  • void LCD_prEEPROM; Print a text, stored in the EEPROM on the display, parameters:
    • t_LCD* p_LCD - The address of the display-handle (call with &HandleName)
    • uint16_t p_Address - The address of text to be printed in the EEPROM (null-terminated)
    Instead of using this sub-routine, better use the pre-processor macro LCD_PrintEEPROM
    Example: LCD_prEEPROM(&Display,0x0100);
    Quick-Links

  • LCD_PrintEEPROM; Print a text, stored in the EEPROM on the display, parameters:
    • p_LCD - The display-handle
    • p_Address - The address of the text to be printed in the EEPROM (null-terminated)
    Pre-Processor macro, just a call to LCD_prEEPROM to avoid the pointer syntax &HandleName
    Example: LCD_PrintEEPROM(Display,0x0100);
    Quick-Links

  • LCD_PrintAtEEPROM; Position Cursor and print a text, stored in the EEPROM on the display, parameters:
    • p_LCD - The display-handle
    • p_Column - The column to which the cursor is moved, column numbers start with zero.
    • p_Row - The row to which the cursor is moved, row numbers start with zero.
    • p_Address - The address of the text to be printed in the EEPROM (null-terminated)
    Pre-Processor macro, calls LCD_at, then LCD_prEEPROM
    Example: LCD_PrintAt(Display,0,1,"Hello World!");
    Quick-Links
HelloWorld example program

THE standard example: Print the text "Hello World!" to the connected LCD display. Connect your LCD-Display to the pins A5 (SCL, yellow wire) and A4 (SDA, green wire) and run this program to see "Hello World" on your display.

By changing line 17 of the program from

//#define USE_LCD_MicroLib

to

#define USE_LCD_MicroLib

switching between the new LiquidCrystal library and the MicroLib you can compare the difference in code-size.

Back to the top of the document.
Charset example program

Another simple example program which demonstrates how to define all eight custom characters and cyclically displays the whole character-set in chunks of 16 characters. This program can be used with the standard Wire or the Software I2C library, see line 14 in the source-code.

Back to the top of the document.