Hatena::ブログ(Diary)

nicotakuya

2008-10-28

[]NicoKeyboardのスイッチ同時読み

f:id:nicotakuya:20081028180053j:image

NicoKeyboardはスイッチの同時読みに対応しているかどうかについて、お問い合わせがあったので、ココに書いておきます。

まず、ハードの説明から、、

f:id:nicotakuya:20081028175413g:image

NicoKeyboardの回路図の一部です。8x8のキーマトリックスです。

ic側の出力は8行のうち、どれか1行がLowになります。

個々のスイッチにダイオードが入っていないので、3つ以上スイッチのを

「特殊な組み合わせ」で同時に押すと誤動作します。

f:id:nicotakuya:20081028175352g:image

たとえば、↑のような状態。

Q、A、Sを同時押しすると赤い部分がLowになり、押してないはずのDが押されてしまいます。

こういうのが「特殊な組み合わせ」です。

f:id:nicotakuya:20081028175412g:image

f:id:nicotakuya:20081028175353g:image

ただし、行や列がバラバラの場合には、3つ以上同時に押しても問題ありません。

たとえば、1列全部押すとか、1行を全部押すのは問題ありません。


ここまではハードの話で、今度はソフトの話。

NicoKeyboardのソフトはちょっと機能を節約してまして、

alt、ctrl、shiftの3つだけが同時押しに対応しています。

現時点のver.7のソースの一部、スイッチの読み取り部分です。

swnum=SWNUM_NONE;
sw2num=SWNUM_NONE;
for(rownum=0; rownum<8; rownum++)
{
	if(mode==MODE_PS2)
		ps2_recvbyte();

	//1行〜8行のうち1つをLow
	if(rownum==0){
		PORTD &= ~ID_DAT;	//(74HC164)DAT
	}else{
		PORTD |= ID_DAT;	//(74HC164)DAT
	}
	timer_wait(TCNT_50US);		//50uSec
	PORTD |=  IC_CLK;	//(74HC164)CLK
	PORTD &= ~IC_CLK;	//(74HC164)CLK
    	timer_wait(TCNT_50US);		//50uSec

	for(colnum=0; colnum<8; colnum++){
		if(((0x80 >> colnum)& PINB)==0){	//Lowを検出した場合、スイッチが押された
			PORTD |= MASK_LED;	//LED
			swnum = colnum+(rownum *8);

			if(swnum <= SWNUM_SHIFT){	//Alt/Shift/Ctrlは同時押し用変数に格納
				sw2num = swnum;
				swnum = SWNUM_NONE;
			}
			PORTD &= ~MASK_LED;	//LED
		}
	}
}

sw2numとswnumにスイッチ番号が入ります。

sw2numがAlt/Shift/Ctrl同時押し用です。

それ以外はスイッチ番号の大きいほうを優先して、swnumに上書きします。

たとえば、dとsを同時に押したらsしか検出しません。

これがイヤな場合は、swnumを64個全部のスイッチ分用意すれば解決できます。

8bitx8行、8バイトのバッファがあればいいだけです。

ソースはサイトで公開していますので、改造してみてください。

あと、チャタリング除去も簡単にできるので、よかったらやってみてください。

[]バージョンアップ2008/10/28版

細切れなアップデートが続きます、、、

nicobas20081028.zip

Video出力のプログラムアセンブラで書き直して(videodot.S)高速化させてみました。

f:id:nicotakuya:20081028173759j:image

2倍くらい速くなるかなと思ったんですが、

実際に増えたwidth方向のドット数は18ドット→23ドットでした。ちょっとだけマシになりました。

これ以上はもうスピードアップはできないみたいですが、beep処理を削ったらもっとドット数が増やせると思います。

f:id:nicotakuya:20081028173801j:image

外部発振20MHz時には78ドットまで増えました。