===Driving LCD from MMBasic===
{{ :migratedattachments:mmbasic_original:lcd.pdf?linkonly}}
{{tag>HD4478}}
//This module is part of the original MMBasic library. It is reproduced here with kind permission of Hugh Buckle and Geoff Graham. Be aware it may reference functionality which has changed or is deprecated in the latest versions of MMBasic.//
Demonstrates how to talk to a "standard" LCD display based on the Hitachi HD44780 controller and compatibles. Later versions of MMBasic have inbuilt commands which are simple and faster. If you have anything that is non-standard (8 bit bus, shared bus etc.) then these pieces of code will give you a good insight into how to drive the LCD discreetly. The attached file shows the assumed connectivity.
LCD.BAS
' demonstration program
' send 2 lines to the LCD
InitLCD
PrintLCD 1, " Hello World"
PrintLCD 2, " Maximite LCD"
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' LCD driver for MMBasic 3.1 or later (uses defined subroutines)
' Geoff Graham, Jan 2012
'
' Will drive a standard 16 x 2 LCDs
' For example: futurlec.com LCD16X2
' altronics.com.au Z7001
' jaycar.com.au QP5512
'
' To use:
' - Setup the LCD with the command: InitLCD
' - Display a line using the command: PrintLCD LineNbr, Text$
'
' See documentation (LCD.PDF) for the schematic
' Maximite pin 11 is RS, pin 12 is EN
' pins 13 to 16 are D4 to D7
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Initialise the LCD
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub InitLCD
For i = 11 To 16 : SetPin i, 9 : Next i ' all open collector
LCD_Nibble &B0011, 0, 5 ' reset
LCD_Nibble &B0011, 0, 5 ' reset
LCD_Nibble &B0011, 0, 5 ' reset
LCD_Nibble &B0010, 0, 2 ' 4 bit mode
LCD_Nibble &B0010 : LCD_Nibble &B1100 ' 4 bits, 2 lines
LCD_Nibble &B0000 : LCD_Nibble &B1100 ' display on, no cursor
LCD_Nibble &B0000 : LCD_Nibble &B0110 ' increment on write
LCD_Nibble &B0000 : LCD_Nibble &B0001 ' clear the display
Pause 2
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Display a line on the LCD
' argument #1 is the line to be used (1 or 2)
' argument #2 is the line to display (can be any length)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub PrintLCD ( LineNumber, Line$ )
Local i, c
' first send the cursor position (in two nibbles)
LCD_Nibble &B1000 + (LineNumber - 1) * 4 : LCD_Nibble 0
' then send the text character by character (two nibbles per character)
For i = 1 To 16
c = Asc(Mid$(Line$ + Space$(16), i, 1))
LCD_Nibble Int(c/16), 1 : LCD_Nibble c, 1
Next i
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Send the lower 4 bits (called a nibble) to the LCD
' argument #1 is the nibble to send
' argument #2 is true if data, false if command (default is command)
' argument #3 is delay after the data has been sent (default is zero)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub LCD_Nibble ( Data, Flag, Wait_mSec )
Pin(11) = Flag
Pin(13) = Data And &B00000001
Pin(14) = Data And &B00000010
Pin(15) = Data And &B00000100
Pin(16) = Data And &B00001000
Pin(12) = 1 : Pin(12) = 0
Pause Wait_mSec
End Sub
LCD1_1.BAS
' demonstration program
' send lines to the LCD
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' LCD driver for MMBasic 3.1 or later (uses defined subroutines)
' Geoff Graham, Jan 2012.
' Modified by James Deakins to work with 20 x 4 LCDs, Feb 2012.
' Should also work with 8 x 1 and other configs, but not tested.
'
' Will drive standard 16 x 2 and 20 x 4 LCDs
' For example: futurlec.com LCD16X2
' altronics.com.au Z7001
' jaycar.com.au QP5512
'
' To use:
' - Define LCD size with the command: InitLCDVariables columns, lines
' - Setup the LCD with the command: InitLCD
' - Display a line using the command: PrintLCD LineNbr, Text$
'
' File LCD_LIB.BAS will provide an extended range of functions.
'
' See documentation (LCD.PDF) for the schematic
' Maximite pin 11 is RS, pin 12 is EN
' pins 13 to 16 are D4 to D7
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
DIM C_LineStart(4) ' an array to hold the start addresses for each line
C_Lines = 0 ' variable to hold the number of lines on the LCD
C_LineLength = 0 ' variable to hold the line length of the LCD
'
' **** Change the parameters to indicate whether you have a 16 x 2
' **** or a 20 x 4 LCD screen.
InitLCDVariables(20, 4) ' <<<<<<<<<<-------
InitLCD
' display simple lines, based on how many lines the LCD screen has
PrintLCD 1, " Hello World"
IF C_Lines > 1 THEN PrintLCD 2, " Maximite LCD"
IF C_Lines > 2 THEN PrintLCD 3, "with a 20 x 4 LCD,"
IF C_Lines > 3 THEN PrintLCD 4, "using Subroutines."
ENDIF
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Initialise the variables for this application
' (C_Prefix indicates constants).
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB InitLCDVariables(LCD_LineLength, LCD_Lines)
C_LineLength = LCD_LineLength
C_Lines = LCD_Lines
C_LineStart(1) = 0 ' Start address for line 1
C_LineStart(2) = 64 ' Start address for line 2
C_LineStart(3) = 20 ' Start address for line 3
C_LineStart(4) = 84 ' Start address for line 4
END SUB
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Initialise the LCD hardware
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB InitLCD
FOR i = 11 TO 16 : SETPIN i, 9 : NEXT i ' all open collector
LCD_Nibble &B0011, 0, 5 ' reset
LCD_Nibble &B0011, 0, 5 ' reset
LCD_Nibble &B0011, 0, 5 ' reset
LCD_Nibble &B0010, 0, 2 ' 4 bit mode
LCD_Nibble &B0010 : LCD_Nibble &B1100 ' 4 bits, 2 lines
LCD_Nibble &B0000 : LCD_Nibble &B1100 ' display on, no cursor
LCD_Nibble &B0000 : LCD_Nibble &B0110 ' increment on write
LCD_Nibble &B0000 : LCD_Nibble &B0001, 0, 2 ' clear the display, pause 2
END SUB
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Move cursor to a location on the LCD screen.
' argument #1 is the line to be used (1 to 4)
' argument #2 is the column to be used (1 to 20)
' This Subroutine isn't used by the other code, but
' is included because it's simple and useful.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB LCDLocate(Line, Column)
LOCAL curPosn
curPosn = 128 + C_LineStart(Line) + Column - 1
LCD_Nibble INT(curPosn/16) : LCD_Nibble curPosn
END SUB
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Display a line on the LCD
' argument #1 is the line to be used (1 to 4)
' argument #2 is the line to display (can be any length)
' Note: The text has to be padded out with spaces, otherwise
' 'odd' characters are displayed on the LCD.
' The code does the padding for you.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB PrintLCD ( LineNumber, Line$ )
LOCAL i, c, fillSpaces, fullLine$, curPosn
curPosn = 128 + C_LineStart(LineNumber)
' first, send the cursor position (in two nibbles)
LCD_Nibble INT(curPosn/16) : LCD_Nibble curPosn
fillSpaces = C_LineLength - LEN(Line$) ' is the line full?
IF fillSpaces > 0 THEN
fullLine$ = Line$ + SPACE$(fillSpaces)
ELSE
fullLine$ = Line$
ENDIF
' then send the text character by character (two nibbles per character)
FOR i = 1 TO C_LineLength
c = ASC(MID$(fullLine$, i, 1))
LCD_Nibble INT(c/16), 1 : LCD_Nibble c, 1
NEXT i
END SUB
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Send the lower 4 bits (called a nibble) to the LCD
' argument #1 is the nibble to send
' argument #2 is true if data, false if command (default is command)
' argument #3 is delay after the data has been sent (default is zero)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB LCD_Nibble ( Data, Flag, Wait_mSec )
PIN(11) = Flag
PIN(13) = Data AND &B00000001
PIN(14) = Data AND &B00000010
PIN(15) = Data AND &B00000100
PIN(16) = Data AND &B00001000
PIN(12) = 1 : PIN(12) = 0
IF Wait_mSec > 0 THEN PAUSE Wait_mSec ' modified 30/1/2012. Restore to Wait_mSec when Pause 0 bug corrected.
END SUB