====== ATキーボード(PS2)を繋ぐ ======
===== 回路図 =====
ATキーボードのCLOCKとDATAは双方向通信で、ホスト側からコマンドを送ることで、Num Lock、\\
Caps Lock、Scroll Lockランプを点けたり、キーリーピーと速度の設定が行えます。\\
今回は、この機能を使わないと決め、キーデータの読み込みだけを行う回路にします。\\
片方向通信であれば回路も単純です。CLOCKは割り込みで受ける必要があるのでP9-4を使います。
{{atkey00.gif}}
===== 完成図 =====
チップ抵抗を使ってしまったので、基板の表にはコネクタだけです。裏も配線2本で作るのは\\
簡単でした。ソフトのほうが何倍も大変になるとは、この時は思いもしませんでした。\\
{{atkey01.jpg}}
===== プログラムの作成 =====
いつものようにポート設定。キーデータは複数Byteの場合もあるので、リングバッファが必要です。
AT_KEY_PORT EQU P9 ; DATA が繋がっているポート
AT_KEY_CLOCK EQU 4 ; IRQ 番号
AT_KEY_DATA EQU 5 ; DATA のビット位置
AT_KEY_BUFFSIZE EQU 32 ; リングバッファのサイズ(16,32,64,128,256)
RAMにワークの作成。
;******************************************************************************
; RAM 上のデータ(初期化あり)
;******************************************************************************
SEGMENT DATA
public _AtKeyStatus
_AtKeyStatus: DC.W 0 ; キーステータス
ATKEY_BIT: DC.B 0 ; 読み出しているビット位置
ATKEY_DATA: DC.B 0 ; キーボードデータ
ATKEY_BUFF_R: DC.B 0 ; リングバッファの読み出し位置
ATKEY_BUFF_W: DC.B 0 ; リングバッファの書き込み位置
ATKEY_BUFF_NUM: DC.B 0 ; リングバッファにあるデータ数
ATKEY_WORK_END:
;******************************************************************************
; RAM 上のデータ(初期化なし)
;******************************************************************************
SEGMENT BSS
ATKEY_BUFF: DS.B AT_KEY_BUFFSIZE ; リングバッファ
初期化ルーチンでは割り込みの設定と、ワークのクリアを行います。
;******************************************************************************
; AT キーボードの初期化
;
; _AtKeyInit
; 2005/01/12 : 初期バージョン完成
;
; [書式] void AtKeyInit(void) ;
;
; [IN] なし
;
; [OUT] なし
;
; [DED] R0,ER1
;******************************************************************************
public _AtKeyInit
_AtKeyInit: BCLR.B #AT_KEY_CLOCK,@ISR ; CLOCK 割り込み要因のクリア
BSET.B #AT_KEY_CLOCK,@ISCR ; 立ち下がりエッジで割り込み
BSET.B #AT_KEY_CLOCK,@IER ; CLOCK 割り込み有効
; ワークのクリア
MOV.B #ATKEY_WORK_END - _AtKeyStatus,R0H
SUB.B R0L,R0L
MOV.L #_AtKeyStatus,ER1
WORK_CLEAR: MOV.B R0L,@ER1
INC.L #1,ER1
DEC.B R0H
BNE WORK_CLEAR:8
RTS
次に終了ルーチン。割り込みを止めるだけの単純な物です。
;******************************************************************************
; AT キーボードの終了
;
; _AtKeyEnd
; 2005/01/13 : 初期バージョン完成
;
; [書式] void AtKeyEnd(void) ;
;
; [IN] なし
;
; [OUT] なし
;
; [DED] なし
;******************************************************************************
public _AtKeyEnd
_AtKeyEnd: BCLR.B #AT_KEY_CLOCK,@IER ; CLOCK 割り込み無効
RTS
割り込みルーチンは結構な行数になります。やっていることは単純で、スタートビットを待ち、\\
スタートビットが来たら、割り込みカウンタを進めながら8Bitのデータと、パリティビットを\\
取得し、リングバッファに貯めていきます。\\
ここで取得されるのはスキャンコードで、そのままのデータでは使い物になりません。\\
通信仕様(プロトコル)とスキャンコードは、[[http://www.computer-engineering.org/|Computer-Engineering.org]]のページが参考になります。
;******************************************************************************
; AT キーボード割り込み
;
; AT_KEYBOARD_INT
; 2005/01/12 : 初期バージョン完成
;
; [IN] なし
;
; [OUT] なし
;
; [DED] なし
;******************************************************************************
public AT_KEYBOARD_INT
AT_KEYBOARD_INT:PUSH.W R0
PUSH.L ER1
MOV.B @ATKEY_BIT,R0L ; R0L = 読み出しビット位置
CMP.B #9,R0L ; パリティ(9)?
BEQ KEYDATA_PARITY:8
CMP.B #1,R0L ; データ(1~8)?
BCC KEYDATA_DATA:8
;------------------------------------------------------------------------------
; スタートビットを待つ
;------------------------------------------------------------------------------
; スタートビットじゃない?
KEYDATA_START: BLD.B #AT_KEY_DATA,@AT_KEY_PORT
BCS AT_KEYBOARD_END:8
INC.B R0L ; カウンタを進める
BRA AT_KEYBOARD_END:8
;------------------------------------------------------------------------------
; 下位ビットから 8bit 取得
;------------------------------------------------------------------------------
KEYDATA_DATA: MOV.B @ATKEY_DATA,R0H ; 1bit 取得
BLD.B #AT_KEY_DATA,@AT_KEY_PORT
ROTXR.B R0H
MOV.B R0H,@ATKEY_DATA
INC.B R0L ; カウンタを進める
BRA AT_KEYBOARD_END:8
;------------------------------------------------------------------------------
; パリティ、ストップビットの破棄
;------------------------------------------------------------------------------
KEYDATA_PARITY: SUB.B R0L,R0L ; カウンタを 0 に戻す
;------------------------------------------------------------------------------
; リングバッファにデータ格納
;------------------------------------------------------------------------------
MOV.B @ATKEY_BUFF_W,R1L ; リングバッファは空いている?
MOV.B @ATKEY_BUFF_R,R1H
DEC.B R1H
AND.B #AT_KEY_BUFFSIZE-1,R1H
CMP.B R1H,R1L
BEQ AT_KEYBOARD_END:8
MOV.B @ATKEY_DATA,R0H ; リングバッファにデータを積む
EXTU.W R1
EXTU.L ER1
MOV.B R0H,@(ATKEY_BUFF,ER1)
INC.B R1L ; リングバッファを進める
AND.B #AT_KEY_BUFFSIZE-1,R1L
MOV.B R1L,@ATKEY_BUFF_W
MOV.B @ATKEY_BUFF_NUM,R1L ; データ数 + 1
INC.B R1L
MOV.B R1L,@ATKEY_BUFF_NUM
;------------------------------------------------------------------------------
; 終了
;------------------------------------------------------------------------------
AT_KEYBOARD_END:MOV.B R0L,@ATKEY_BIT
POP.L ER1
POP.W R0
BCLR.B #AT_KEY_CLOCK,@ISR ; CLOCK 割り込み要因のクリア
RTE
ここまで作れば、キーデータ(まだスキャンコードですが)が読み出せるかテストできるので、\\
データ読み出しルーチンを作成します。スキャンコードが解からないキーのチェックにも使えます。\\
リングバッファからデータを取得し、リングバッファを進めるルーチンは良く使うので、\\ サブルーチンにしておきます。
;******************************************************************************
; AT キーボードの読み込み(スキャンコード)
;
; _AtKeyGetScanCode
; 2005/01/12 : 初期バージョン完成
;
; [書式] Uint8 AtKeyGetScanCode(void) ;
;
; [IN] なし
;
; [OUT] Uint8 = スキャンコード
;
; [DED] R0H,ER1,R2L,R3L
;******************************************************************************
public _AtKeyGetScanCode
_AtKeyGetScanCode:
SUB.B R0L,R0L ; 戻り値
MOV.B @ATKEY_BUFF_NUM,R3L ; R3L = データ数
BEQ KEY_SCAN_END:8 ; リングバッファにデータはある?
SUB.L ER1,ER1 ; ER1 = リングバッファ読み出し位置
MOV.B @ATKEY_BUFF_R,R1L
BSR AT_KEYBOARD_GET ; データを取得しリングバッファを進める
MOV.B R2L,R0L
MOV.B R1L,@ATKEY_BUFF_R ; リングバッファの更新
MOV.B R3L,@ATKEY_BUFF_NUM
KEY_SCAN_END: RTS
;******************************************************************************
; データを取得しリングバッファを進める
;
; AT_KEYBOARD_GET
; 2005/01/13 : 初期バージョン完成
;
; [IN] ER1 = リングバッファ読み出し位置
; R3L = リングバッファのデータ数
;
; [OUT] ER1 = 次のリングバッファ読み出し位置
; R3L = 残りのリングバッファのデータ数
; R2L = 読み出したデータ
;
; [DED] なし
;******************************************************************************
AT_KEYBOARD_GET:MOV.B @(ATKEY_BUFF,ER1),R2L
INC.B R1L ; リングバッファを進める
AND.B #AT_KEY_BUFFSIZE-1,R1L
ADD.B #-1,R3L ; データ数 - 1
RTS
プログラマなら後は判ると思いますので、ソースつき解説は、ここまでに留めて置きます。\\
あとは、以下のような関数を追加していきます。\\
\\
この関数では押されたキーを、キーコードに変換します。キーコードはOADG準拠。\\
キーボードステータス(Shift,Alt,Winキーの状態と、Caps,Num,Scroll Lock の状態)の更新も行う。
;******************************************************************************
; AT キーボードの読み込み(キーコード)
;
; _AtKeyGetKeyCode
; 2005/01/12 : 初期バージョン完成
;
; [書式] Uint16 AtKeyGetKeyCode(void) ;
;
; [IN] なし
;
; [OUT] Uint16 = キーコード(b15 = 0:離された 1:押された)
;
; [DED] R0H,ER1,ER2,R3,ER4,R5
;******************************************************************************
public _AtKeyGetKeyCode
_AtKeyGetKeyCode:
省略
この関数は、キーコードを文字に変換します。Caps Lockの状態と、Shiftの押し下げもサポートします。\\
改行や、Tab等は0を返し、ユーザ処理に任せるようにします。
;******************************************************************************
; AT キーボードのキーコードを文字コードに変換
;
; _AtKeyCodeToChara
; 2005/01/14 : 初期バージョン完成
;
; [書式] Uint8 AtKeyCodeToChara(Uint8 code) ;
;
; [IN] Uint8 code = キーコード
;
; [OUT] Uint8 = 文字コード(文字以外なら 0)
;
; [DED] E0,ER1
;******************************************************************************
public _AtKeyCodeToChara
_AtKeyCodeToChara:
省略
H8にATキーボードを繋ぐ記事は多いのに、通信部分の作り方の解説ページがないのでこの記事を\\
書きました。結構面倒だったが、はんだ付け込みで2日で終わり、プログラムもテーブル込みで\\
1K ぐらいでした。