Thursday, January 3, 2013

CGCOLORMAX LCD Shield Example


This example project shows how to program an LCD Shield installed on the CGCOLORMAX.

To use Shields, the Shield footprint is populated with female single inline sockets. Two six-by-one and two eight-by-one headers are soldered in place on the CGCOLORMAX so that a Shield (or a stack of them) can be added to the board.
The LCD Shield is actually two distinct circuits: an interface to a character-based LCD module, and a group of five buttons that can be read programmatically. (A sixth button is connected to the CGCOLORMAX reset line. Be careful as this will restart the ColorMax.) There is a line to control the LCD back light, too.
The buttons connect to Shield line A0 which is read by MMBasic with PIN(35). This line should be set to be an analog input. Without any buttons pressed the input reads approximately 3.3V. Pressing the left, right, up, or down button returns a different voltage. A function translates the voltages to the integer values 0-4 with 0 being no button pressed.
The function created to return the state of the buttons is below:
' ----------------------------------------------------
' Return button state
' 0 = no button
' 1 = right, 2 = up, 3 = down, 4 = left
' Because A/D on CGCOLORMAX is 3.3V max and this is a
' 5V resistor chain the SEL button does not work.
' ----------------------------------------------------
FUNCTION LCDShield_Button( )
' Button Input line
SETPIN 35, 1
LCDShield_Button = 0
IF PIN(35) < 2.85 THEN
LCDShield_Button = 4
ENDIF
IF PIN(35) < 1.95 THEN
LCDShield_Button = 3
ENDIF
IF PIN(35) < 1.1 THEN
LCDShield_Button = 2
ENDIF
IF PIN(35) < .32 THEN
LCDShield_Button = 1
ENDIF
END FUNCTION



The LCD connects to Shield signals D4-D9 which to MMBasic are pins 25-30. There are 4 data lines connected to communicate to the LCD as well as a line to indicate to the LCD that you wish to send a command or a character and a line that is a strobe for the end of data transfer. The pin direction is set up, four bits of data (value passed to the subroutine) are set, and the enable line pulsed. This sends a nibble of a command to the LCD.
The function created to send a command to the LCD is:
' ----------------------------------------------------
' Write 4-bit command
' ----------------------------------------------------
SUB LCDShield_Command4( LCDShield_value )
' Data lines
SETPIN 25, 8 : SETPIN 26, 8 : SETPIN 27, 8 : SETPIN 28, 8
' Register Select line
SETPIN 29, 8
' Enable line
SETPIN 30, 8
' Command (not displayable character)
PIN(29) = 0
' Enable high
PIN(30) = 1 : PAUSE 1
' Value onto data lines
PIN(28) = LCDShield_value AND &B00001000
PIN(27) = LCDShield_value AND &B00000100
PIN(26) = LCDShield_value AND &B00000010
PIN(25) = LCDShield_value AND &B00000001
' Enable low then high
PIN(30) = 0 : PAUSE 1
PIN(30) = 1 : PAUSE 1
END SUB



To write a character so that the LCD will display it, the module needs to be told that is is not getting a command but instead something to display. Also two nibbles of data are sent to the display, first the high nibble of the character to display and then the low nibble.
' ----------------------------------------------------
' Write 8-bit character
' ----------------------------------------------------
SUB LCDShield_Character( LCDShield_value )
' Character (not command)
PIN(29) = 1
' Enable high
PIN(30) = 1 : PAUSE 1
' Value (high nibble) onto data lines
PIN(28) = LCDShield_value AND &B10000000
PIN(27) = LCDShield_value AND &B01000000
PIN(26) = LCDShield_value AND &B00100000
PIN(25) = LCDShield_value AND &B00010000
' Enable low then high
PIN(30) = 0 : PAUSE 1
PIN(30) = 1 : PAUSE 1
' Value (low nibble) onto data lines
PIN(28) = LCDShield_value AND &B00001000
PIN(27) = LCDShield_value AND &B00000100
PIN(26) = LCDShield_value AND &B00000010
PIN(25) = LCDShield_value AND &B00000001
' Enable low then high
PIN(30) = 0 : PAUSE 1
PIN(30) = 1 : PAUSE 1
END SUB



A string subroutine uses the character subroutine to send a string to the display:
' ----------------------------------------------------
' Write string
' ----------------------------------------------------
SUB LCDShield_String( LCDShield_string$ )
FOR LCDShield_loop = 1 to LEN(LCDShield_string$)
LCDShield_Character( ASC(MID$(LCDShield_string$, LCDShield_loop )))
NEXT
END SUB



The back light of the LCD display can be controlled by turning a line on and off:
' ----------------------------------------------------
' Backlight on/off
' 0 = off, 1 = on
' ----------------------------------------------------
SUB LCDShield_Backlight ( LCDShield_blstate )
' pin = 31
SETPIN 31, 8
PIN(31) = LCDShield_blstate
END SUB



With this library in place, some simple example code can operate the LCD.
First the LCD back light is tested by flashing the display:
' Flash display
FOR a = 1 TO 5
LCDShield_Backlight( 0 ) : PAUSE 40
LCDShield_Backlight( 1 ) : PAUSE 60
NEXT a



A series of nibbles are sent to Initialize the LCD. Four-bit (nibble) mode is selected repeatedly to be sure, and other LCD characteristics are set. The display is then cleared.
' Initialize display
' Select 4 bit mode
LCDShield_Command4(&H03)
LCDShield_Command4(&H03)
LCDShield_Command4(&H03)
LCDShield_Command4(&H02)


' Select 4 bit mode, two LCD lines
LCDShield_Command4(&H02)
LCDShield_Command4(&H0C)


' Select display on, cursor off, no blink
LCDShield_Command4(&H00)
LCDShield_Command4(&H0C)


' Clear display
LCDShield_Command4(&H00)
LCDShield_Command4(&H01)



A message to my Mom is then sent by sending each character one at a time. Then the program pauses for a second:
' Write Hi Mom! message to line 1
LCDShield_Character(72)
LCDShield_Character(73)


LCDShield_Character(32)


LCDShield_Character(77)
LCDShield_Character(111)
LCDShield_Character(109)


LCDShield_Character(33)


PAUSE 1000



The display is then cleared:
' Clear display
LCDShield_Command4(&H00)
LCDShield_Command4(&H01)



A new message is sent to the LCD by writing a few strings.
' Write message to line 1
LCDShield_String ( "CircuitGizmos" )


' Move to line 2
LCDShield_Command4(&H0C)
LCDShield_Command4(&H00)


' Write message to line 2
LCDShield_String ( "Rules!" )



The state of the buttons is displayed for two minutes.
FOR a = 1 TO 120
PRINT LCDShield_Button()
PAUSE 1000
NEXT a



When no button is pressed, 0 is printed. When a button is pressed the numbers 1-4 are printed.

The program in its entirety:
' ====================================================
'
' LCDShield example
'
' ====================================================


' Flash display
for a = 1 to 5
LCDShield_Backlight( 0 ) : PAUSE 40
LCDShield_Backlight( 1 ) : PAUSE 60
next a


' Initialize display
' Select 4 bit mode
LCDShield_Command4(&H03)
LCDShield_Command4(&H03)
LCDShield_Command4(&H03)
LCDShield_Command4(&H02)


' Select 4 bit mode, two LCD lines
LCDShield_Command4(&H02)
LCDShield_Command4(&H0C)


' Select display on, cursor off, no blink
LCDShield_Command4(&H00)
LCDShield_Command4(&H0C)


' Clear display
LCDShield_Command4(&H00)
LCDShield_Command4(&H01)




' Write Hi Mom! message to line 1
LCDShield_Character(72)
LCDShield_Character(73)


LCDShield_Character(32)


LCDShield_Character(77)
LCDShield_Character(111)
LCDShield_Character(109)


LCDShield_Character(33)


PAUSE 1000


' Clear display
LCDShield_Command4(&H00)
LCDShield_Command4(&H01)


' Write message to line 1
LCDShield_String ( "CircuitGizmos" )


' Move to line 2
LCDShield_Command4(&H0C)
LCDShield_Command4(&H00)


' Write message to line 2
LCDShield_String ( "Rules!" )


for a = 1 to 500
PRINT LCDShield_Button()
PAUSE 1000
next a




' ----------------------------------------------------
' LCDShield library
' ----------------------------------------------------


' ----------------------------------------------------
' Backlight on/off
' 0 = off, 1 = on
' ----------------------------------------------------
SUB LCDShield_Backlight ( LCDShield_blstate )
' pin = 31
SETPIN 31, 8
PIN(31) = LCDShield_blstate
END SUB




' ----------------------------------------------------
' Write 4-bit command
' ----------------------------------------------------
SUB LCDShield_Command4( LCDShield_value )


' Data lines
SETPIN 25, 8 : SETPIN 26, 8 : SETPIN 27, 8 : SETPIN 28, 8


' Register Select line
SETPIN 29, 8


' Enable line
SETPIN 30, 8


' Command
PIN(29) = 0


' Enable high
PIN(30) = 1 : PAUSE 1


' Value onto data lines
PIN(28) = LCDShield_value AND &B00001000
PIN(27) = LCDShield_value AND &B00000100
PIN(26) = LCDShield_value AND &B00000010
PIN(25) = LCDShield_value AND &B00000001


' Enable low then high
PIN(30) = 0 : PAUSE 1
PIN(30) = 1 : PAUSE 1


END SUB




' ----------------------------------------------------
' Write 8-bit character
' ----------------------------------------------------
SUB LCDShield_Character( LCDShield_value )


' Character
PIN(29) = 1


' Enable high
PIN(30) = 1 : PAUSE 1


' Value (high nibble) onto data lines
PIN(28) = LCDShield_value AND &B10000000
PIN(27) = LCDShield_value AND &B01000000
PIN(26) = LCDShield_value AND &B00100000
PIN(25) = LCDShield_value AND &B00010000


' Enable low then high
PIN(30) = 0 : PAUSE 1
PIN(30) = 1 : PAUSE 1


' Value (low nibble) onto data lines
PIN(28) = LCDShield_value AND &B00001000
PIN(27) = LCDShield_value AND &B00000100
PIN(26) = LCDShield_value AND &B00000010
PIN(25) = LCDShield_value AND &B00000001


' Enable low then high
PIN(30) = 0 : PAUSE 1
PIN(30) = 1 : PAUSE 1


END SUB




' ----------------------------------------------------
' Write string
' ----------------------------------------------------
SUB LCDShield_String( LCDShield_string$ )
FOR LCDShield_loop = 1 to LEN(LCDShield_string$)
LCDShield_Character( ASC(MID$(LCDShield_string$, LCDShield_loop )))
NEXT
END SUB




' ----------------------------------------------------
' Return button state
' 0 = no button
' 1 = right, 2 = up, 3 = down, 4 = left
' Because A/D on CGCOLORMAX is 3.3V max and this is a
' 5V resistor chain the SEL button does not work.
' ----------------------------------------------------
FUNCTION LCDShield_Button( )
' Button Input line
SETPIN 35, 1
LCDShield_Button = 0
IF PIN(35) < 2.85 THEN
LCDShield_Button = 4
ENDIF
IF PIN(35) < 1.95 THEN
LCDShield_Button = 3
ENDIF
IF PIN(35) < 1.1 THEN
LCDShield_Button = 2
ENDIF
IF PIN(35) < .32 THEN
LCDShield_Button = 1
ENDIF
END FUNCTION