フォト
2017年12月
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
無料ブログはココログ

« Nexx WT3020FをOpenWrt化しました | トップページ | 書籍「ボクのLPC810工作ノート」届きました »

2015年4月22日 (水)

arduinoでPS/2キーボードのエミュレーションを行う

IchigoJam用の仮想キーボードでも作ろうと思い、
まずはarduinoでPS/2キーボードのエミュレーションを行ってみました。

06

まずは、上の図の感じでパソコン上でIchigoJamのキーボードをパソコンで
完全操作できるようにしてみます。

arduinoでPS/2インタフェースのキーボードやマウスを実装は、
公開されている ps2dev というライブラリを利用することで比較的簡単に実現できます。
ps2devライブラリ PS2 mouse interface for Arduino

実装例を探してみると下記サイトでWiiのヌンチャクリモコンをarduinoに接続し、
パソコンでPS2/2キーボードとして利用する例がありました。
内容的は大変参考になりました。

また、PS/2インタフェース、JISキーボードのスキャンコード関連の情報として
下記の情報を参考にさせて頂きました。
  ・Sazanami Online PS/2 インターフェイスの研究
  ・PS/2キーボードインターフェース http://www.technoveins.co.jp/technical/keyboard/
  ・O-Family   JIS配列 PS/2 キーボード スキャンコード表

取りあえず、動作確認の試作として
TeraTermで入力した文字をシリアル通信経由でarduinoに送信し、
その文字に対応するキーコード(スキャンコード)をPS/2インタフェースで
IchigoJamに送信するプログラムを作ってみました。

結線はこんな感じです。IchigoJamoとの接続は3線(GND,KBD1,KBD2)です。
arduinoは3.3Vで稼働させています。

Dscn3758

KBD1、KBD2、GNDを接続

Dscn3759

実際に動かしてみると、簡単にエミュレーションできました。
取りあえず、半角英数記号と、バックスペース、Enterキー、ESCを使えるようにしました。
全てのキーには対応していませんが、いけそうです。

これならIchigoJam BASICのINKEY()にも対応できます。ゲームパッドも作成可能です。

20150422105156

ps2devライブラリを見ると、LPC810にも移植可能そうです。
最終的にはLPC810を使った小型モジュール化LPC810で動かしてみたいと思います。

ただし、TeraTermではALTキーなのど特殊キーのコードを拾うのは無理なので、
Windows上でキーイベントを拾ってシリアル通信でキーコードを送信する
アプリケーションの作成も必要になりますね。

ソースはこんな感じとなります。

#include "ps2dev.h"

#define TM_PRESS 2

// スキャンコード(A-Zのキー)
uint8_t kcode[]= {
  0x1c,0x32,0x21,0x23,0x24,0x2b,0x34,0x33,0x43,0x3b,
  0x42,0x4b,0x3a,0x31,0x44,0x4d,0x15,0x2d,0x1b,0x2c,
  0x3c,0x2a,0x1d,0x22,0x35,0x1a
};

// スキャンコード(0-9のキー or '!'-')'の文字)
uint8_t kcode_num[]= {
  0x45,0x16,0x1e,0x26,0x25,0x2e,0x36,0x3d,0x3e,0x46
};

PS2dev keyboard(3,2); 
int enabled =0; 
int code;

void ack() {
  while(keyboard.write(0xFA));
}

int keyboardcommand(int command) {
  unsigned char val;
  switch (command) {
  case 0xFF:  ack();
    while(keyboard.write(0xAA)!=0);
    break;
  case 0xFE: // Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。その後キーボードはセルフテストを実行する。
    ack();
    break;
  case 0xF6: // set defaults: 起動時の状態へ戻す
    //enter stream mode
    ack();
    break;
  case 0xF5: //disable data reporting: 起動時の状態へ戻し、キースキャンを停止する
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //enable data reporting : キースキャンを開始する
    //FM
    enabled = 1;
    ack();
    break;
  case 0xF3: //set typematic rate/delay : 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xF2: //get device id : 
    ack();
    keyboard.write(0xAB);
    keyboard.write(0x83);
    break;
  case 0xF0: //set scan code set
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xEE: //echo :キーボードが接続されている場合、キーボードはパソコンへ応答(ECHO Responce)を返す。
    //ack();
    keyboard.write(0xEE);
    break;
  case 0xED: //set/reset LEDs :キーボードのLEDの点灯/消灯要求。これに続くオプションバイトでLEDを指定する。 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  }
}

void setup() {
  Serial.begin(115200);
  // send the keyboard start up
  while(keyboard.write(0xAA)!=0);
}

void loop() {

  unsigned char c;  // PCからの送信データ
  uint8_t inkey;    // シリアルポートからの取得文字コード
  uint8_t code;     // シーケンスコード 
  uint8_t shifton;  // シフトキーの状態

  if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
    while(keyboard.read(&c)) ;
    Serial.println(c,HEX);
    keyboardcommand(c);
  } else {
    if (Serial.available()>0 ) {
      code = 0;
      inkey = Serial.read();
      Serial.write(inkey);
      Serial.write(':');      
      Serial.println(inkey,HEX);
    if ( inkey >='a' && inkey <='z') {
        // a-zの文字
        shifton = 0;
        code = kcode[inkey - 'a'];
      } else if (inkey >='A' && inkey <='Z') {
        // A-Zの文字
        shifton = 1;
        code = kcode[inkey - 'A'];        
      } else if (inkey >='0' && inkey <='9') {
        // 0-9の文字
        shifton = 0;
        code = kcode_num[inkey - '0'];
      } else if (inkey >='!' && inkey <=')') {
        // '!'-')'の文字
        shifton = 1;
        code = kcode_num[inkey - '!'+1];
      } else {
        code = 0;
        shifton = 0;
        switch(inkey) {
          case 0x2d: code = 0x4e; break; // -
          case 0x5e: code = 0x55; break; // ^
          case 0x5c: code = 0x6a; break; // \
          case 0x40: code = 0x54; break; // @
          case 0x5b: code = 0x5b; break; // [
          case 0x3b: code = 0x4c; break; // ;
          case 0x3a: code = 0x52; break; // :
          case 0x5d: code = 0x5d; break; // ]          
          case 0x2c: code = 0x41; break; // ]
          case 0x2e: code = 0x49; break; // ` 
          case 0x2f: code = 0x4a; break; // /
          //case 0x5c: code = 0x51; break; // \ '
          case 0x20: code = 0x29; break; // \ ' 
          case 0x08: code = 0x66; break; // Bksp
          case 0x0d: code = 0x5a; break; // enter
          case 0x1b: code = 0x76; break; // ESC
        }
        if (!code) {
          shifton = 1;
          switch(inkey) {
          case 0x3d: code = 0x4e; break; // =
          case 0x7e: code = 0x55; break; // ~
          case 0x7c: code = 0x6a; break; // |
          case 0x60: code = 0x54; break; // `
          case 0x7b: code = 0x5b; break; // {
          case 0x2b: code = 0x4c; break; // +
          case 0x2a: code = 0x52; break; // *
          case 0x7d: code = 0x5d; break; // ]
          case 0x3c: code = 0x41; break; // } 
          case 0x3e: code = 0x49; break; // <
          case 0x3f: code = 0x4a; break; // >
          case 0x5f: code = 0x51; break; // _
         }
      }
    } 
      // PCに押したキーのシーケンスコードを送信
      if (code) {
        if (shifton) {
          keyboard.write(0x12);  // シフトキーを押した
        } else {
          keyboard.write(0xF0);  // シフトキーを離した 
          keyboard.write(0x12);  
        }          
        keyboard.write(code);    // キーを押した
        delay(TM_PRESS);
        keyboard.write(0xF0);    // キーを離した 
        keyboard.write(code);        
      }
    }
  }
}

関連記事

« Nexx WT3020FをOpenWrt化しました | トップページ | 書籍「ボクのLPC810工作ノート」届きました »

arduino」カテゴリの記事

IchigoJam」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/571408/61476780

この記事へのトラックバック一覧です: arduinoでPS/2キーボードのエミュレーションを行う:

« Nexx WT3020FをOpenWrt化しました | トップページ | 書籍「ボクのLPC810工作ノート」届きました »