マイコン独立大作戦
キーボードインターフェースの製作
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
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
前へ
次へ
ホームページトップへ戻る