ATキーボード(PS2)を繋ぐ

回路図

ATキーボードのCLOCKとDATAは双方向通信で、ホスト側からコマンドを送ることで、Num Lock、
Caps Lock、Scroll Lockランプを点けたり、キーリーピーと速度の設定が行えます。
今回は、この機能を使わないと決め、キーデータの読み込みだけを行う回路にします。
片方向通信であれば回路も単純です。CLOCKは割り込みで受ける必要があるのでP9-4を使います。

完成図

チップ抵抗を使ってしまったので、基板の表にはコネクタだけです。裏も配線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のデータと、パリティビットを
取得し、リングバッファに貯めていきます。
ここで取得されるのはスキャンコードで、そのままのデータでは使い物になりません。
通信仕様(プロトコル)とスキャンコードは、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 ぐらいでした。

h8/atキーボード_ps2_を繋ぐ.txt · 最終更新: 2018/03/18 09:56 (外部編集)
 
特に明示されていない限り、本Wikiの内容は次のライセンスに従います: CC Attribution-Share Alike 4.0 International
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki