' ----------------------------------------------------------- ' 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 ' ----------------------------------------------------------------