自作CPU「CalicoCPU」で、Pmod KYPD 上で押されたキーの認識をしてみた。
Pmod KYPD
Pmod KYPD は、列に対応する4本の入力端子と、行に対応する4本の出力端子を持つ。
そして、4×4で16個のキーがある。
出力端子はプルアップされており、LOWが入力された列のキーが押されるとLOWになる。
そのため、キーは一度に1個しか押されないと仮定すれば、1列ずつLOWを入力し、出力がLOWになる位置を探すことで、どのキーが押されたかを判定できる。
プログラム
ポート1に接続された Pmod KYPD で押されたキーの番号を、ポート0の下位4ビットに出力する。
以下のプログラムは、MikeAssembler でアセンブルできる。
target calico
; PORT0 lower : read result
; PORT1 : Pmod KYPD
MOVI A, 0xf
DRIVE 0, A
DRIVE 1, A
main_loop:
; スキャンを行うキーの番号
MOVI A, 0
; スキャンを行う列を表すビット
MOVI B, 8
scan_loop:
; 列のビットを反転して、出力する
MOV C, B
NOT C
OUT 1, C
NOP
; 行のスキャン結果を読み込み、反転する
IN C, 1
NOT C
SHR C, 4
; 押されているボタンがあれば、判別処理に進む
MOVI D, key_pressed
JNZ C, D
; 次の列のスキャンに進む
ADDI A, 4
SHR B, 1
MOVI D, scan_loop
JNZ B, D
; 全ての列のスキャンが終わったので、最初に戻る
MOVI D, main_loop
JNZ D, D
; 行のどのビットが1かを調べる
key_pressed:
; 1のビットが無くなるまでシフトする
SHR C, 1
MOVI D, find_row_loop
JNZ C, D
MOVI D, key_concluded
JNZ D, D
find_row_loop:
; シフトした回数を数える
ADDI A, 1
MOVI D, key_pressed
JNZ D, D
; どのキーが押されたのかの調査が完了した
key_concluded:
; テーブルを引いて押されたキーに対応する数値を求める
MOVI3 C, key_table
ADD C, A
ADD C, A
MOVI D, key_out
JNZ C, C
key_table:
MOVI C, 0
JNZ D, D
MOVI C, 7
JNZ D, D
MOVI C, 4
JNZ D, D
MOVI C, 1
JNZ D, D
MOVI C, 0xF
JNZ D, D
MOVI C, 8
JNZ D, D
MOVI C, 5
JNZ D, D
MOVI C, 2
JNZ D, D
MOVI C, 0xE
JNZ D, D
MOVI C, 9
JNZ D, D
MOVI C, 6
JNZ D, D
MOVI C, 3
JNZ D, D
MOVI C, 0xD
JNZ D, D
MOVI C, 0xC
JNZ D, D
MOVI C, 0xB
JNZ D, D
MOVI C, 0xA
JNZ D, D
key_out:
OUT 0, C
MOVI D, main_loop
JNZ D, D
以下は、このプログラムをHEX形式で表したものである。
:100000002F161E2068848A9A00988A8F8FEBCD9FC6
:10001000344BE55FE3DF8BE2C7FF9FE2C7F3DF31DD
:10002000EBCDDFAB83008181E5C7FC9BA0DFA7DFC1
:10003000A4DFA1DFAFDFA8DFA5DFA2DFAEDFA9DF8E
:0F004000A6DFA3DFADDFACDFABDFAADF92E3DF2C
:00000001FF
解説
Pmod KYPD の入力や出力は「1ビットをLOWにする」が基本であるが、
「0になったかどうか」でループの終了を判定するため1ビットをHIGHにする形でデータを持ち、入出力時に反転する形にした。
また、右シフトで下位へ抜けて0になるようにするため、上位ビットから下位ビットの順で判定する。
まず、キーの番号を4ずつ増やしながら、列のスキャンを行う。
よって、Pmod KYPD の列は左ほど上位のビットになっているので、左ほど若い番号になる。
なお、CalicoCPU では入力を一旦 D-FF で受けているため、OUT
命令の直後に IN
命令を実行すると、OUT
命令の結果が反映される前の状態が読み込まれてしまい、スキャンがうまくいかない。
そこで、OUT
と IN
の間に NOP
を挟んだ。
ある列についていずれかの行のキーが押されていることがわかったら、キーの番号を1ずつ増やしながら右シフトを行い、行のどのキーが押されているかを調べる。
このときは、下位ビットから先に抜けるので、同じ列の中では下位ビットほど若い番号になる。
すなわち、Pmod KYPD の行は下ほど下位のビットになってるので、下ほど若い番号になる。
まとめると、キーに対して以下のように番号を割り当てたことになる。
3 7 11 15
2 6 10 14
1 5 9 13
0 4 8 12
一方、Pmod KYPD のキーは以下のように配置されている。
1 2 3 A
4 5 6 B
7 8 9 C
0 F E D
単純な計算式で変換するのは難しそうなので、変換テーブルを用意することにした。
変換テーブルの1項目は、「変換結果の値を格納する命令」と「次の処理に移るためのジャンプ命令」で構成する。
そして、「変換テーブルの最初の項目のアドレス」に「変換テーブルの1項目のサイズ×変換する値」を足したアドレスにジャンプすることで、テーブルを引く。
最後に、変換したキーの番号を出力し、次のスキャンに移る。
実行結果
ポート0の下位ビットに 1-Digit 7seg Board を、ポート1に Pmod KYPD を接続して実行した。
押したキーの番号が正しく表示に反映されている。