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






Tuesday, December 11, 2012

CGKEYCHIP1 Custom Keypad Example



The Maximite design uses a PS/2 connection as a keyboard interface. You can use a full keyboard connected to either a CGCOLORMAX1 or the CGMMSTICK1.
If you want to embed either of these two setups into a project, you might choose to replace the full keyboard with something either more compact or custom for your application. The CGKEYCHIP1 wired into a “ColorMax” or “stick” lets you create your own keyboard by adding your own buttons.
The CGKEYCHIP1 is a 24 pin chip in a DIP (through-hole) package. Four wires connect to the Maximite that include ground, power, and the two PS/2 communication signals (data/clock). You can wire in twelve distinct buttons for the keyboard keys plus three “modifier” buttons.
The CGKEYCHIP1 has two sets of keys that it can transmit:

Set1
Set2
F1
Up Arrow
F2
Down Arrow
F3
Left Arrow
F4
Right Arrow
F5
Space Bar
F6
Page Up
F7
Page Down
F8
Enter
F9
End
F10
Home
F11
Tab
F12
Backspace


An input pin on the chip selects between these sets of keys.
The CGKEYCHIP1 runs off of the 5V that the PS/2 connection provides. Both chip grounds should be connected to ground. The pins marked “NoConnect” should not be connected to anything.
Supplied with the CGKEYCHIP1 is a 1.3 kohm resistor that has to be connected from pin 11 to pin 15 for the chip to operate correctly
The PS/2 data signals are open-collector signals. When you connect the GCKEYCHIP1 to a CGCOLORMAX1 there are pull up resistors already on the ColorMax. When you connect to a CGMMSTICK1 and CGVGAKBD1 combination, the CGVGAKBD1 board already has pull up resistors in place for the two PS/2 lines. No additional resistors are needed in this case.

When you connect the CGKEYCHIP1 to just a CGMMSTICK1, you will need to attach two pull-up resistors in order to have the chip function correctly. Each of the two PS/2 lines should be pulled to 5V through a 10 kohm resistor.
The SetSelect input to the CGKEYCHIP1 selects the key set that you wish to use, either set 1 or set 2. Connecting this input directly to 5V will select set 1, while connecting this input to ground selects set 2.
The key inputs are activated by momentary contact to ground. Simple SPST buttons can be used.


You can write a very simple MMBasic program to check the codes that the keys transmit against the list of codes found in this document:
do
a$ = inkey$
if a$ <> "" then
print asc(a$)
endif
loop




When run, set 1 will return these codes:
Key
Plain
Control
Shift
Shift+Control
F1
145
209
177
241
F2
146
210
178
242
F3
147
211
179
243
F4
148
212
180
244
F5
149
213
181
245
F6
150
214
182
246
F7
151
215
183
247
F8
152
216
184
248
F9
153
217
185
249
F10
154
218
186
250
F11
155
219
187
251
F12
156
220
188
252






Set 2 returns these codes :
Key
Plain
Control
Up Arrow
128
192
Down Arrow
129
193
Left Arrow
130
194
Right Arrow
131
195
Space Bar
32
0
Page Up
136
200
Page Down
137
201
Enter
13
13
End
135
199
Home
134
198
Tab
9
9
Backspace
8
8


MMBasic interprets the Alt as a key by itself, not a modifier. The keycode for the Alt key is 139, Control-Alt is 203, Shift-Alt is 171, Control-Shift-Alt is 235. This program will return two key codes when Alt is used, first the Alt code, then the key code. Control-Shift-Alt-F1, for example, returns 235 241.












Purchase a CGMMSTICK1 Download of Maximite Integrated Development Environment: MMIDE


CGMMSTICK 1-Wire Interface Example


As an example of the operation of the 1-wire function of the CGMMSTICK1, this example interfaces to a DS1822 temperature device.
From the DS1822 datasheet:
The DS1822 digital thermometer provides 9- to 12-bit centigrade temperature measurements and has an alarm function with NV user-programmable upper and lower trigger points. The DS1822 communicates over a 1-Wire bus that by definition requires only one data line (and ground) for communication with a central microprocessor. It has an operating temperature range of –55°C to +125°C and is accurate to ±2.0°C over the range of –10°C to +85°C.
Unique 1-Wire® interface requires only one port pin for communication.
Each device has a unique 64-bit serial code stored in an on-board ROM.
The hardware couldn't be simpler.

The DS1822 pin 1 was connected to ground, pin 3 connected to 5V, and the center pin, pin 2, connected to the CGMMSTICK I/O pin 20. The center pin is the data pin of the 1-wire device. I/O pin 20 has a 5k ohm (two 10k in parallel) pullup.
From the software perspective reading from a 1-wire device isn't as simple as just sending a read command. You have to write to the device first to tell it you want to read.
Furthermore it takes a moment for the device to start and complete the temperature measurement process.
First the 'bus' should be reset. In this case the 1-wire bus is I/O Pin 20 and only contains the single DS1822 device.
' Reset the 1w bus, DS1822 device
OWRESET 20


The reset command selects the pin (bus) to reset and optionally can receive an indication that there are 1 or more devices present on the bus. This puts a reset pulse on the bus.
All devices have a serial number, so that if there are multiple devices on a single I/O Pin (bus), any individual device can be addressed for access.
In this example there is only a single device, so rather than talking to it by addressing it specifically, a command is used that skips the need for a serial number. This is called “Skip ROM” in the 1-wire terminology.
From the data sheet:
SKIP ROM [CCh]
The master can use this command to address all devices on the bus simultaneously without sending out any ROM code information. For example, the master can make all DS1822s on the bus perform simultaneous temperature conversions by issuing a Skip ROM command followed by a Convert T [44h] command.
Note that the Read Scratchpad [BEh] command can follow the Skip ROM command only if there is a single slave device on the bus. In this case time is saved by allowing the master to read from the slave without sending the device’s 64-bit ROM code. A Skip ROM command followed by a Read Scratchpad command will cause a data collision on the bus if there is more than one slave since multiple devices will attempt to transmit data simultaneously.
The DS1822 will be told to start a temperature conversion.
' Start temperature conversion
' Pin 20, send reset first, send two bytes
' &hCC - Skip ROM
' &h44 - Start conversion
OWWRITE 20, 1, 2, &hCC, &h44


The OWWRITE command selects a pin/bus to write to. A reset pulse again is sent to that bus and then two bytes are sent. &hCC is the command byte to skip the serial number, and &h44 tells the DS1822 to start the temperature conversion process.
The conversion process takes a little while to complete, so the program pauses to allow that conversion to finish.
' Wait a second for conversion process to finish
PAUSE 100


After that pause, a command is sent that tells the DS1822 that the next communication will be a read.
' Read data/temperature command
' Pin 20, send reset first, send two bytes
' &hCC - Skip ROM
' &hBE - read data command
OWWRITE 20, 1, 2, &hCC, &hBE


This again resets the bus and uses “Skip ROM” since this example uses only a single 1-wire device. &hBE is the command to read.
The read command is next to read the temperature value.
' Read data/temperature from DS1822
' Pin 20, send reset after, read two bytes
OWREAD 20, 2, 2, LowTemp, HighTemp


Note that the bus is NOT reset at the start of the read command. The DS1822 expects the read to follow the command to read without a reset between the commands.
OWREAD reads the selects bus line. The options to the command allow for a selected number of bytes to be read. In this case we need to read only the first two bytes of the multi-byte register, the registers that contain the temperature data. A bus reset happens after the OWREAD command.
Math is performed to combine the two bytes that were read from the temperature device according to the DS1822 data sheet.
' Combine and adjust according to data sheet
Cel = ((HighTemp And &b111) * 256 + LowTemp) / 16


The resulting Celsius temperature is printed, then converted to Fahrenheit and that is also printed.
' Print Celsius and convert/print Fahrenheit
Print "Celsius" Cel
Print "Fahrenheit" ( 9 / 5) * Cel + 32;











Purchase a CGMMSTICK1 Download of Maximite Integrated Development Environment: MMIDE