User Tools

Site Tools


mmbasic:driving_lcd_with_i2c_interface_using_a_micromite_5_3

Driving LCD with I2C interface using a Micromite (>5.3)

With later versions of MMBasic (>v4.5) the I2c command format changed. The purpose of this routine is to allow a Micromite to drive a character LCD display (based on the Hitachi HD4478) that has a cheap and cheerful PCF8574 I2c interface board attached. These boards can be picked up for around $1 AUD on a well known and loved auction site. The code is an adaptation of the original Maximite code by John Gerrard. I hope you all find it useful.

GTG!

' -----------------------------------------------------------
' Routines for Micromite to drive serial I2C LCD
' Tested on Explore28 Module running MMBasic V5.3
' by Andrew Hufer. June 2017 (GTG! TBS Forums)
'******************************************************************
' Originally Adapted from a Maximite I2CLCD program by John Gerrard
' Modified to suit Micromite & Chinese I2C LCD module by Jim Rowe.
' (different connections from PCF8574 to LCD)
'******************************************************************
 
' 3 subs have been created to make using the routine easier:-

' initLCD       - Initialises the LCD Controller
' ClearScreen   - Clears the display and sets cursor to line 1 position 1
' DisplayText row, cursorposition, text$  - which row to output on, repositions cursor to cursorposition, text to be displayed

' Note! The appropriate LCD delays have been inserted in the code but
' have been commented out, as I found that they weren't required on the
' particular 20x4 LCD I was using. If you encounter troubles, uncomment
' the lines as needed to re-enable the delays.

' LCD functions of PCF8574(A)T I/O bits P0 - P7:

' Name      8574 bit  LCD function

' RS        = P0      Reg select (pin 4) 0 = Cmd 1 = Data
' R/Wbar    = P1      R/W-bar (pin 5, should be 0 for writing)
' EN        = P2      EN (pin 6) 0 = Idle, 1 = Active
' BL        = P3      Backlight control (Q1 & LCD pin 16)
' DB4       = P4      Data Line 4 (pin 11)
' DB5       = P5      Data Line 5 (pin 12)
' DB6       = P6      Data Line 6 (pin 13)
' DB7       = P7      Data Line 7 (pin 14)
' ----------------------------------------------------------

OPTION AUTORUN ON
OPTION EXPLICIT
option default integer

' Note! Depending on the type of I2C expander used, the I2C address can be different!
' Select appropriate one or create new one accordingly:-

DIM AS LCDI2cAddr = &H27  ' PCF8574T I2C address A2,A1,A0=1 (&B01001110) All links out
'dim as LCDI2cAddr = &H3F  ' PCF8574AT I2C address A2,A1,A0=1 (&B01111110) All links out

' masks for preparing I2C bytes for writing to 8574 & LCD
DIM RSCmask = &B00000000 ' select cmd register (RS = 0)
DIM RSDmask = &B00000001 ' or data register (RS = 1)
DIM ENmask  = &B00000100 ' Enable (active = P2 high)
DIM BLmask  = &B00001000 ' Turn on backlighting (P3 = 1)
Dim CNT(6) ' array to store LCD config command bytes 
CNT(0) = &B00110011   ' &H33 --> 8-bit / 8-bit mode init
CNT(1) = &B00110010   ' &H32 --> 8-bit / 4-bit mode
CNT(2) = &B00101000   ' &H28 --> 4-bit mode, 2 lines, 5x7 pixels
CNT(3) = &B00001000   ' &H08 --> disp off, cursor off, no blink
CNT(4) = &B00000001   ' &H01 --> clear screen, return home cmd
CNT(5) = &B00000110   ' &H06 --> increment cursor, cursor move
CNT(6) = &B00001100   ' &H0C --> disp on, cursor off, no blink
Dim Delay(6) = (0.1, 0.1, 0.06, 0.06, 3, 0.06, 0.06)  ' array to store LCD config command byte delay times
dim line1home = &B10000000  ' &H80 --> Place cursor at start of line 1
Dim line2home = &B11000000  ' &HC0 --> Place cursor at start of line 2

PAUSE 100        ' wait 100ms for LCD to stabilise after powerup
I2C OPEN 100,100 ' enable I2C (bus speed 100kHz, 100ms timeout)
InitLCD          ' initialise the LCD + controller

' main program loop starts here

' This example was designed for a 20x4 LCD display as a test routine
DO
  ClearScreen 
  DisplayText 1, 0, "1234567890"
  DisplayText 2, 0, "GoodToGo!!"
  DisplayText 3, 0, "abcdefghij"
  DisplayText 4, 10, "zyxwvutsrq"
  PAUSE 1000
  DisplayText 1, 10, "1234567890"
  DisplayText 2, 10, "GoodToGo!!"
  DisplayText 3, 10, "abcdefghij"
  DisplayText 4, 0, "zyxwvutsrq"  
  pause 1000
  DisplayText 1, 0, "GoodToGo!!"
  DisplayText 2, 0, "1234567890"
  DisplayText 3, 0, "abcdefghij"
  DisplayText 4, 10, "zyxwvutsrq"
  PAUSE 1000
  DisplayText 1, 10, "GoodToGo!!"
  DisplayText 2, 10, "1234567890"
  DisplayText 3, 10, "abcdefghij"
  DisplayText 4, 0, "zyxwvutsrq" 
  pause 1000
 LOOP

END ' end of main part of program, subs follow 

' -----------------------------------------------------------------

' subroutine to Display text on LCD.
sub DisplayText row, cursorposition, text$
local I
select case row
  case 1
  sendcmdbyte (line1home + cursorposition)      'row 1 on 16x2, 20x4 LCD panels
  case 2
  sendcmdbyte line2home + cursorposition)       'row 2 on 16x2, 20x4 LCD panels
  case 3
  sendcmdbyte (line1home + 20 + cursorposition) 'row 3 on 20x4 LCD panels
  case 4
  sendcmdbyte (line2home + 20 + cursorposition) 'row 4 on 20x4 LCD panels
end select
  For I = 1 To Len(text$)
    SendDataByte ASC(Mid$(text$, I, 1))
  Next I
end sub

' -----------------------------------------------------------------

' subroutine to clear LCD screen
sub ClearScreen
    SendCmdByte CNT(4)
    'PAUSE 3 ' pause as per datasheet but may not be necessary due to code delays
  end sub

' -----------------------------------------------------------------

'  subroutine to initialise the LCD
SUB InitLCD
local I
    For I = 0 To 6
      SendCmdByte CNT(I)
      'PAUSE Delay(I)  ' pause as per datasheet but may not be necessary due to code delays
    Next
END SUB

' -----------------------------------------------------------------

' subroutine to send a command byte (aByte) to the LCD controller
SUB SendCmdByte aByte
local temp, RSbit
    RSbit = RSCmask  ' make sure we're sending to cmd reg (RS=0)
    ' then prepare the more significant nibble
    temp = (aByte AND &HF0) Or RSbit OR BLmask
    DirectSend temp  ' and send it
    ' then prepare the less significant nibble
    temp = ((aByte AND &H0F) << 4) Or RSbit OR BLmask
    DirectSend temp  ' and also send it  
END SUB

' -----------------------------------------------------------------

' subroutine to send a data byte (aByte) to the LCD controller
SUB SendDataByte aByte
local temp, RSbit
    RSbit = RSDmask  ' make sure we're sending to data reg (RS=1)
    ' then prepare the more significant nibble (from aByte)
    temp = (aByte AND &B01110000) Or RSbit OR BLmask
    DirectSend temp  ' and send it
    ' then prepare the less significant nibble (from aByte)
    temp = ((aByte AND &H0F) << 4) OR RSbit OR BLmask
    DirectSend temp  ' and also send it
END SUB

' -----------------------------------------------------------------

' subroutine to send a nibble (in temp) to the LCD
SUB DirectSend temp
    temp = temp Xor ENmask            ' make EN=1
    I2C WRITE LCDI2CAddr, 0, 1, temp  ' send it with EN=1
    'Pause 0.004                       ' pause for 4us as per PCF8574 Datsheet but not needed due code delays
    temp = temp Xor ENmask            ' now make EN=0 again
    I2C WRITE LCDI2CAddr, 0, 1, temp  ' before sending again
END SUB
' ----------------------------------------------------------------
mmbasic/driving_lcd_with_i2c_interface_using_a_micromite_5_3.txt · Last modified: 2024/02/24 16:41 by gerry