ATキーボードのCLOCKとDATAは双方向通信で、ホスト側からコマンドを送ることで、Num Lock、
Caps Lock、Scroll Lockランプを点けたり、キーリーピーと速度の設定が行えます。
今回は、この機能を使わないと決め、キーデータの読み込みだけを行う回路にします。
片方向通信であれば回路も単純です。CLOCKは割り込みで受ける必要があるのでP9-4を使います。
いつものようにポート設定。キーデータは複数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のデータと、パリティビットを
取得し、リングバッファに貯めていきます。
ここで取得されるのはスキャンコードで、そのままのデータでは使い物になりません。
通信仕様(プロトコル)とスキャンコードは、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 ぐらいでした。