There appears to be some interest in a MMBasic driven custom keyboard so here is an expanded version of the Keypad program.
It uses one or more 74HC595 serial-to-parallel chips to drive the rows, freeing up Pico pins for a bigger input Port for more columns.
12 columns x 8 rows would give you 96 keys.
Still not enough? Add another 74HC595 and go for 16 x 16 = 256 keys!
The next firmware release looks like it will have a two pin version of Device Bitstream (perhaps only on the RP2350?). If so the HC595 Sub can be simplified.
' KeyPad_RP2040_74HC595_v03.bas - Program for more than 4x4 Key Pad
' Rows scanned by a 74HC595 serial-to-parallel chip
' rows = number of rows. For more than 8 rows daisychain another 74HC595 chip.
' cols = number of columns
' RowPinGP = row GP pin number for the 74HC595
' ColPinGP = first of the column GP pin numbers
' Key = number of the key that has been pressed.
' eg. 0 to 63 for 8 columns x 8 rows. 1st row 0 to 7, last row 55 to 63.
' X x Y Keypad with buttons bridging column x to row y
Option base 0
Dim integer n, Key=-1, RowPinGP=0, Rows=8, ColPinGP=1, Cols=8
' Dim KeyMap$(rows * cols - 1)=("Q","W","E","R","T","Y", etc) 'map keys to characters with KeyMap$(Key) if req.
Dim integer RowPinNo = MM.Info(pinno "GP"+Str$(RowPinGP))
SetPin RowPinNo, DOUT 'set the output pin to the 74HC595 and set its outputs to 0
HC595 RowPinNo, Rows+7, 0 'Call Sub with DataPin, max. number of Rows, Word to send, 0=all low
'Rows+7 to ensure any unused pins are also set to 0
For n=ColPinGP To ColPinGP+Cols-1
SetPin MM.Info(pinno "GP"+Str$(n)), INTL, Key.Pad, PULLUP 'set the input Port pins and ISR
Next
Do
' Your main processing loop
If Key+1 Then Print "Key";Key, "&H";Hex$(Key,2), Timer-t;"mS" : key=-1
'to retain the value of Key set a flag in the sub and reset it here
Loop
Sub Key.Pad
t=Timer
Local integer y, x, x1, n
Pause 10 'contact bounce delay, set to minimum value that is reliable
For y = 0 To rows 'scan the rows
HC595 RowPinNo, Rows, 1<<y Xor (1<<Rows+1)-1 'Call Sub with DataPin, no. of Rows, Row to read, inverted
Execute "x1 = (1<<cols)-1 XOR Port(GP"+Str$(ColPinGP)+",cols)" 'read the columns
If x1 Then x=Log(x1)/Log(2)+1
If x>cols Or y>rows Then 'check for values out of range and abort this read
x=0 :y=0 : Key=-1
HC595 RowPinNo, Rows+7, 0 'prepare for next key input, 0=all low
Exit Sub
EndIf
Key = y * cols + x - 1 'get key no. from row no. and col. no., starting from 0
If x1 Then Exit For
Next
HC595 RowPinNo, Rows+1, (1 << Rows+1)-1 'all high, block further input to prevent double press
Pause 150 'set to minimum value that is reliable, or remove it and/or the HC595 Sub call above
HC595 RowPinNo, Rows+7, 0 'prepare for next key input, 0=all low
'Set a flag here if main prog. needs it
End Sub
Sub HC595 OutPin As integer, R As integer, Dat As integer 'Data output Pin, number of Rows, Word to output
Pin(OutPin)=1 'ensure correct polarity for Bitstream
Local integer n, el=R*2-1, B(el)
For n=0 To el Step 2 'prepare Bitstream array
B(n)=3-(Dat>>(el-n)\2 And 1)*2 'low data pulses, 3uS=0 ,1uS=1
B(n+1)=1 '1uS high spaces
Next
Device BITSTREAM OutPin, R*2, B() 'send it
Pin(OutPin)=1 : Pause 0.04 ' >20uS high = latch clock
End Sub
End
' 74HC595 connections
' 3V3 to pins 16, 10
' Gnd to pins 8, 13
' BitStream input to pin 11 (clock)
' pin 11 - 1k8 - pin 14 (data in) - 1n5 - Gnd
' pin 11 - A-diode-K - pin 14 (ser. data in) eg 1N914 or 1N4148
' pin 11 - 4k7 - pin 12 (latch) - 1n5 - Gnd
' pin 11 - K-diode-A - pin 14 (latch)
' pin 9 (ser. data out) to next 74HC595 (if used) pin 14 (ser. data in),
' parallel pin 11 to pin 11 and pin 12 to pin 12
' Row output pins:- 15, 1, 2, 3, 4, 5, 6, 7
Edited 2026-01-17 15:46 by phil99