マイコン独立大作戦
キーボードインターフェースの製作
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
WindowsパソコンにUSB接続して使う現行方式はそれなりに便利ではありますが、ときとしてWindows
のしがらみから開放されて、小さいながらも独立した一個のパソコンとして機能したいと思うこともあります。
独立大作戦の作戦その1はCRTインターフェースボードの製作です。
そして作戦その2は、やっぱりキーボードインターフェースしかありませんでしょう。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
[第12回]
●PICを使います
前回書きましたようにPS/2キーボードを82C55に直接接続する方法は[Ctrl]+[C]などのキーコードの入力に時間がかかってしまうという難点があるため、マイコン独立大作戦のキーボードインターフェースとしては使いません。
もっとも82C55に直結するという方法は簡便ですし、何より間に何もはさまないで信号を直接受信することができる、という利点がありますから、[第5回]や[第6回]で使った方法は、キーボードからのデータ信号を生の状態で解読しなければならないようなときにはこれからも活用したいと思っています。
さて。
それではマイコン独立大作戦のキーボードインターフェースとして何を使うのか、ということなのですが、ここはやっぱりPICを使う場面だと思います。
PICは16F87を使うことにしました。
こちらがジャノ目基板に組んだPIC16F87を使ったテスト回路の写真です。

といっても、PIC16F87とPS/2ミニDINコネクタと26pinフラットケーブルコネクタを手配線でつないだだけです。
基板の表側から見ただけでは、その3つが見えるだけです。
こちらが基板裏側の写真です。

下が回路図です。

82C55のCポートはPC0〜PC3を出力、PC4〜PC7を入力に設定します。
Bポートはパラレルデータの入力に使います。
Aポートは使いません。
PIC16F87の入出力について簡単に説明します。
PS/2信号のCLKはRB0(INT)で受けます。
前回説明しましたようにPS/2キーボードのCLKパルスは80μsとそれほど速いクロックではありませんから割込みを使わなくても処理できないことはありませんが、プログラムをすっきりまとめるために、ここは割込みを使うことにしました。
ホスト(CPU)側とのインターフェースですが、そこをどうするかかなり悩んであれこれ考えました。
よくよく考えてみましたら、もともとキーボードはCPUとハンドシェークをするような高度なものではなくて、ただのキースイッチに過ぎない、ということに気が付きました。
キーボードの中にIC回路が組み込まれていて、シリアルデータとしてキーコードが出力されているとしても、それは同じことです。
そう考えたらホスト(CPU)側のソフトもPIC側のソフトも簡単なものになってしまいました。
PIC16F87はキーボードからのデータを受信したら、それを解読して、その結果以下の動作をします。
1)キーが押されたら常に最後に押されたキーのスキャンコードをRB7〜RB1、RA0に出力したままにします。
RB0をINT端子としてCLK入力として使うのでRA0で代用します。
2バイトのスキャンコードについては工夫して未使用の8ビットコードを割り当てることにします。
キーが離れたら(1バイトのスキャンコードの場合にはF0+スキャンコードが送られてくる)、もしもそれが最後に押されたキーコードと一致したらRB7〜RA0に00を出力します。
2)もしも押されたキーが[Shift][Ctrl][Alt]だった場合には、各キーに対応してRA1(Shift)、RA2(Ctrl)、RA3(Alt)を1にします(このときはRB7〜RA0にはスキャンコードは出力しません)。
上記いずれかのキーが離れたら、それに対応してRA1〜RA3を0にする。
3)このようにすることで[Shift]〜[Alt]とそのほかのキーが同時に押された場合に、そのことをCPU側は82C55のポートBとポートCを読み込むだけで知ることができます(待っている必要はありません)。
最近はPICのプログラムもCコンパイラで書くのだそうですが、単なるI/O制御程度のものにCコンパイラを使うというのは、いかがなものかと思います。
アセンブラがいいじゃありませんか。
PICのアセンブラはわかりにくいことで定評がありますけれど、慣れてしまえばそれほどのものじゃありません。
なんたってたった35個の命令を覚えるだけでいいのですから、やる気になれば別にどうというほどのことはありませんでしょう(Mid−RangeクラスのPICの場合)。

[出典]Microchip Tecnology Inc. PIC16F87/88 Data Sheet
私はアセンブラのほうがずっとずっと楽だと思いますよ。
ということで、下がとりあえずテストとして作ったPS/2キーボードインターフェースプログラムです。
;;;PIC 16F87 keyboard interface
;
;16/10/4 10/7 10/8 10/22
;internal clock 8mhz
;
#include <p16f87.inc> ; processor specific variable definitions
;
;Program Configuration Register 1
__CONFIG _CONFIG1,_CP_OFF & _LVP_OFF & _MCLR_ON & _PWRTE_ON & _WDT_ON & _INTRC_CLKOUT
;Program Configuration Register 2
__CONFIG _CONFIG2,
;
cf=0
zf=2
f=1
w=0
;
bitcntr11 equ 20
bitcntr8 equ 21
keycode equ 22
outdata equ 23
dataokmk equ 24
keyoffmk equ 25
savew equ 26
savests equ 27
;
org 00
st0
goto start
;
org 04
goto int
;
org 05
start
bsf STATUS,5 ;bank 1
movlw 7c;=8MHz
movwf OSCCON
movlw 01;RB0=in(int) CLK
movwf TRISB
movlw 10;a4=in DT
movwf TRISA
bcf OPTION_REG,6;int edge is falling edge
bcf STATUS,5 ;bank 0
;
movlw 0b;=11
movwf bitcntr11
movlw 8
movwf bitcntr8
clrf keycode
clrf outdata
clrf dataokmk
clrf keyoffmk
clrf PORTB
clrf PORTA
;int enable
movlw 0d0
movwf INTCON
;
;start
;
loop
clrwdt
btfss dataokmk,0
goto loop
;
;F0(keyoff) ckeck
movlw 0f0
subwf keycode,w
btfsc STATUS,zf
goto keyoffmkset
;
btfsc keyoffmk,0;keyoff?
goto keyoff
;
;if shift,ctrl,alt
movlw 12;left shift
subwf keycode,w
btfsc STATUS,zf
goto shiftset
movlw 14;left ctrl
subwf keycode,w
btfsc STATUS,zf
goto ctrlset
movlw 11;left alt
subwf keycode,w
btfsc STATUS,zf
goto altset
;else
movf keycode,w
call dataout
dataokclr
clrf dataokmk
goto loop
;
shiftset
bsf PORTA,1
goto dataokclr
ctrlset
bsf PORTA,2
goto dataokclr
altset
bsf PORTA,3
goto dataokclr
;
keyoffmkset
bsf keyoffmk,0
clrf dataokmk
goto loop
;
keyoff
;shift,ctrl,alt check
movlw 12;left shift
subwf keycode,w
btfsc STATUS,zf
goto shiftoff
movlw 14;left ctrl
subwf keycode,w
btfsc STATUS,zf
goto ctrloff
movlw 11;left alt
subwf keycode,w
btfsc STATUS,zf
goto altoff
;else
movf keycode,w
subwf outdata,w
btfss STATUS,zf;equal?
goto keyoffmkclr
movlw 0
call dataout
keyoffmkclr
bcf keyoffmk,0
clrf dataokmk
goto loop
;
shiftoff
bcf PORTA,1
goto keyoffmkclr
ctrloff
bcf PORTA,2
goto keyoffmkclr
altoff
bcf PORTA,3
goto keyoffmkclr
;
; subroutine
;
dataout
movwf outdata
movwf PORTB
btfsc outdata,0
goto set0
bcf PORTA,0
goto next
set0
bsf PORTA,0
next
clrf dataokmk
return
;
int
movwf savew
swapf STATUS,w
movwf savests
bcf STATUS,5;bank 0
movlw 80
xorwf PORTA,f;for test
movlw 0b
subwf bitcntr11,w
btfsc STATUS,zf
goto skipbit
movf bitcntr8,w
btfsc STATUS,zf
goto skipbit
btfsc PORTA,4;DT
bsf STATUS,cf
btfss PORTA,4;DT
bcf STATUS,cf
rrf keycode,f
decf bitcntr8,f
skipbit
decfsz bitcntr11,f
goto intend2
bsf dataokmk,0
movlw 8
movwf bitcntr8
movlw 0b
movwf bitcntr11
intend2
bcf INTCON,1
swapf savests,w
movwf STATUS
swapf savew,f
swapf savew,w
retfie
;
end
;
|
アセンブラのほうが簡単です、と書きましたが、結構長いプログラムになってしまいました。
最初は短かったのですけれど、デバッグをして直していくうちにだんだん長くなってしまいました。
まあ、いつものことなのですけれど。
参考までに、簡単にプログラムの説明をします。
まず最初は割込みルーチンの説明です。
int以下が割込みルーチンです。
PS/2キーボードのCLKの下がりエッジで割込みが発生します。
int以下の最初の3行と終わりのintend2以下はPICの割込み処理のお約束事です。
movlw 80
xorwf PORTA,f
は何をやってるの?ということなのですが、ここではテストのために割込みが正しく行なわれているかRA7出力で確認しています。
動作が確認できればここは不要です。
PICプログラムがうまく動いてくれないときなどに、ちょいとこのような仕掛けをしておくと、プログラムのバグ取りに有効だったりします。
さて。
この割込みルーチンは簡単なものです。
割り込みはCLK毎に下がりエッジで発生します。
2個のビットカウンタbitcntr8とbitcntr11の値によって、スタートビット、パリティビット、ストップビットを判定し、読み飛ばします。
それ以外のクロックのときはDTをkeycodeにシフト入力します。
ストップビットを受信すると、スキャンコードを受信したことをメインプログラムに知らせるために、dataokmkのビット0を1にして処理を終ります。
ここで最初に発生した割り込みがスタートビットではなくて途中のクロックだったらどうなるか?ということなのですが、まずはテストですからそれは考えないことにします。
PICはホスト(CPU)側のプログラムがスタートしたときにリセットがかかって、そこからスタートします(CPU側のプログラムは最初にPC0からL→Hを出力してからスタートします)。
その時点ではPS/2キーボードは押されていないことを前提とします。
ここまでで割込みルーチンの説明は終わりです。
以下メインプログラムの説明に入ります。
メインプログラムはdataokmkのビット0が1になるのをループして待ちます。
テストですからE0,xxの2バイトコードは除外します。
しかし厄介なことにキーが離れたときはF0とスキャンコードの2バイトを判定しなければなりません。
そのために最初にF0かどうかをチェックしてF0ならばkeyoffmkのビット0を1にします(goto keyoffmkset)。
その次の
btfsc keyoffmk,0
のところで今判定したばかりのはずのキーオフのチェックをしていますが、このあたりのところが割込みプログラムに慣れていないとよく理解できないところだと思います。
ここは先にF0を受信した場合のその次のサイクルを意識しています(またはF0が来ないで普通にキーが押されている場合を考えています)。
keyoffmkのビット0が1ならばキーオフの処理をします(goto keyoff)。
keyoffの処理です。
まず[Shift]以下のチェックに入ります。
[Shift][Ctrl][Alt]のコードかどうかをチェックして、一致したら該当する出力を0にします。
それ以外のキーの場合には、これ以前に押されていたキーが離れたのかどうかをチェックします。
今回受信したkeycodeと先に出力したoutdataを比較して一致したら出力データを00にします(movlw 0/call dataoutを実行します)。
キーオフではなかった場合には
;if shift,ctrl,alt
から下の処理をします。
まずは[Shift][Ctrl][Alt]のコードかどうかをチェックして、一致したら該当する出力を1にします。
そうでなかった場合には、受信したキーコードをoutdataに入れるとともにRB7〜RA0に出力します(call dataout)。
これでとりあえずのPS/2キーボードインターフェースとして働いてくれるはずです。
次回はこのプログラムをPIC16F87に書いて、動作させてみることにします。
キーボードインターフェースの製作[第12回]
2016.10.22upload
前へ
次へ
ホームページトップへ戻る