YS電子工作ラボ

USBキーボードのキー出力表示
(ホストモード HIDクラス)
(→プロジェクトファイル(Harmony Ver.2.04版 ) ダウンロード


 USBキーボードの各キーの出力を キャラクタ液晶 及びTeraTermに出力表示した例を紹介します。 HarmonyのUSB(ホストモード) HIDクラスを使っています。 尚、PIC32MZとキャラクタ液晶間はI2C、またPIC32MZとTeraTerm(PC)間はUARTです。

 本プログラムは マイクロチップのHarmonyのhid_basic_keyboardを参考にして作成しています。hid_basic_keyboardは、下記のパスにあります。
   "C:\microchip\harmony\v2_04\apps\usb\host\hid_basic_keyboard"

 

<仕様>
 ・PIC32MZにUSBキーボードを接続して各キーの出力情報をキャラクタ液晶とTeraTermに表示すること。
 ・接続するキーボードは、日本語109キーボードとする。
 ・PICに接続するキャラクタ液晶はI2Cインターフェースの液晶とする。
 ・PIC-PC間のUARTは以下とする。
   通信速度:9600bps、データ長:8ビット、パリティ:なし、ストップビット:1、フロー制御:なし
 ・キャラクタ液晶には下記を表示のこと。
  ①PIC立ち上がり完了:
      1行目: USB device HID
      2行目: Keyboard demo
  ②USB初期化完了: 
      1行目: Please Connect
      2行目: Keyboard !!
  ③各キーデータ取得時:
      1行目: 取得キーコード(0x + 16進数表示)   例: 0x04  0xFFFFFF89
      2行目: 
        図形表示キーの場合: 既定の図形  例: abcd... ABCD... 1234 !"#$<>?\...      
        機能キーの場合: キーボードに記載してある文字 または機能がわかる文字
                      例: Esc Kanji(半角/全角 漢字キー) PrintScreen Enter 10key Enter F1

 ・TeraTermには下記を実施のこと。
  ①USB初期化完了: ***Connect Keyboard*** を表示する
  ②USBキーボードの接続を検出した場合: ---Keyboard Connected--- を表示する。
  ③図形表示キー: 打鍵されたキーに対応する図形 (例:  abcd... ABCD... 1234 !"#$<>?\...) 
  ④メインキーのEnterが打鍵された場合: 改行と復帰を行う
  ⑤ ④を除く機能キー: キーボードに記載してある文字 または機能がわかる文字(代用文字)を表示すること 
                  (例: Esc Kanji(半角/全角 漢字キー) PrintScreen Enter 10key Enter F1)
        





<回路図>(→PDFファイル)






<外観>PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。
       汎用モジュール評価ボード(段積みボード)には本テーマと関係ない部品が多々実装されています


<キーボード用USBコネクタ接続部の詳細>





<動作結果>(→  動画 :1080pのHD動画を見ることができます。) 

  分類 シフト
操作
例    備考
表示図形
(代用文字)
キーコード
keyCode
 TeraTerm と キャラクタ液晶の画像例  
アルファベットの
   小文字 
abcdefghijklmn
opqrstuvwxyz
 無  0x04  
 ② アルファベットの
   大文字
ABCDEFGHIJKLMN
OPQRSTUVWXYZ
 有 A 0x04
 ③  数字
12456789
1  0x1E  
 ④  記号
!"#$%&'()
 !  0x1E  
 ⑤  機能
Esc、Tab、Caps Lock、
Back Space、Insert
Delete、End、Page Up、
Page Down、Print Screen 他
無関係 Esc 0x29  
 ⑥ テンキー系
NumLock、1234567890
/*-+. Enter
10Key Enter 0x58
 ⑦ 日本語系
半角/全角 漢字
無変換、変換
カタカナ ひらがな ローマ字
無関係 Muhenkan 0xFFFFFF8B  




 以下は、サンプルプログラムで使用した各キーのキーコード(keyCode)一覧表です。 尚、灰色のセルはサンプルプログラム
(Harmony v.2.04のライブラリ)の中の変数keyCodeでは呼び出せなかったキーです。 
  下表のキーボードは日本語109キーボードです。 英語101キーボードをはじめキーボードにはたくさんの種類があります。キーボードにより
 キーコードはかなり異なるので他のキーボードを使用する場合は注意が必要です。

キーボード(本体)部 テン キーパッド部
キーの
文字
記号
呼称
keyCode キーの
文字
記号
呼称
keyCode キーの
文字
記号
呼称
keyCode キーの
文字
記号
呼称
keyCode キーの
文字
記号
呼称
keyCode キーの
文字
記号
呼称
keyCode
A 0x04 1 0x1E F1 0x3A Menu 0x65 Alt Left 0xE2 / 0x54
B 0x05 2 0x1F F2 0x3B _ 0xFFFFFF87 Alt Right 0xE6 * 0x55
C 0x06 3 0x20 F3 0x3C カタカナ
ひらがな
ローマ字
0xFFFFFF88 Ctrl Right - 0x56
D 0x07 4 0x21 F4 0x3D \ 0xFFFFFF89 Ctrl Left + 0x57
E 0x08 5 0x22 F5 0x3E 変換 0xFFFFFF8A Shift Right Enter 0x58
F 0x09 6 0x23 F6 0x3F 無変換 0xFFFFFF8B Shift Left 1 0x59
G 0x0A 7 0x24 F7 0x40 Windows
Right
2 0x5A
H 0x0B 8 0x25 F8 0x41 Windows
Left
3 0x5B
I 0x0C 9 0x26 F9 0x42 4 0x5C
J 0x0D 0 0x27 F10 0x43 5 0x5D
K 0x0E Enter 0x28 F11 0x44 6 0x5E
L 0x0F Escape 0x29 F12 0x45 7 0x5F
M 0x10 Back Space 0x2A Print Screen 0x46 8 0x60
N 0x11 Tab 0x2B Scroll Lock 0x47 9 0x61
O 0x12 Space Bar 0x2C Pause/Break 0x48 0 0x62
P 0x13 - 0x2D Insert 0x49 . 0x63
Q 0x14 ^ 0x2E Home 0x4A
R 0x15 @ 0x2F Page Up 0x4B
S 0x16 [ 0x30 Delete 0x4C
T 0x17 End 0x4D
U 0x18 ] 0x32 Page Down 0x4E
V 0x19 ; 0x33 Arrow Right 0x4F
W 0x1A : 0x34 Arrow Left 0x50
X 0x1B 半角/全角
漢字
0x35 Arrow Down 0x51
Y 0x1C , 0x36 Arrow Up 0x52
Z 0x1D . 0x37 Num Lock 0x53
/ 0x38
Caps Lock 0x39





<解説> 以下に、記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います
       (以下は、Harmony v2.04 をもとに作成しています。最新のバージョンとは異なることがあるかもしれませんので注意してください。)
  
■ MHC設定
  ■ Options 

項目 ①Config設定
Device & Project Configuration
  > PIC32MZ2048 Device Configuration   
②Heap Size設定
Device & Project Configuration
 >Project Configuration >XC32(Global Opton)
 >XC32-ld >General  
③USB Library設定
Harmony Framework Configuration
 > USB Library 
MHC  
備考 デフォルトからの変更要領:
 FPLLIDIV: DIV3
 FPLLICLK: PLL_POSC
 POSCMOD: EC

システムクロック周波数: 200MHz
外部
 主発振器: 24MHz

#pragma config FNOSC = SPLL
#pragma config POSCMOD = EC
#pragma config FPLLIDIV = DIV_3
#pragma config FPLLICLK = PLL_POSC
#pragma config FPLLMULT = MUL_50
#pragma config FPLLODIV = DIV_2
デフォルトからの変更要領:
 Heap Size(byte): 4096
デフォルトからの変更要領:
 □Use USB Stack? チェック追加
 □USB Host  チェック追加
 Host Max Interface Per Deice
: 5
 □USE HID Host Client Driver: チェック追加

 □Use HID Host keyboard driver: チェック追加
項目 ④I2C設定
Harmony Framework Configuration
 > Drivers
   
MHC    
備考 デフォルトからの変更要領:
 □USE I2C Driver? チェック追加
 I2C Module ID: I2C_ID_2
 I2C CLOCK FREQUENCY(Hz): 100000
   



  Pin Settings

項目  ポート設定(その1)  ポート設定(その2) 
MHC
備考 デフォルトからの変更要領:
UARTポート設定
RC2: U6TX
RG9: U6RX
デフォルトからの変更要領:
I2Cポート設定
RA2: SCL2
RA3: SCLA 




I2Cインターフェースのキャラクタ液晶表示ライブラリの追加要領
  キャラクタ液晶表示のライブラリ lcd_ACM1602_lib_i2c.h と lcd_ACM1602_lib_i2c.cを main.cと同じフォルダにコピーして、
 プロジェクトに追加します。
                                       (使い方 → I2Cインターフェースキャラクタ液晶表示制御 参照

  プロジェクトへの追加は以下のようにします。



app.hに、青字部の修正、追加をします

 ①APP_STATESの列挙型変数を以下のように変更します。
  typedef enum
  {
    /* Application pixels put*/
    APP_STATE_INIT=0,
    APP_STATE_OPEN_HOST_LAYER,
    APP_STATE_WAIT_FOR_HOST_ENABLE,
    APP_STATE_HOST_ENABLE_DONE,
    APP_STATE_WAIT_FOR_DEVICE_ATTACH,
    APP_STATE_DEVICE_ATTACHED,
    APP_STATE_READ_HID,
    APP_STATE_DEVICE_DETACHED,
    APP_STATE_CHANGE_DEVICE_PARAMETERS,
    APP_USART_STATE_DRIVER_OPEN,
    APP_USART_STATE_CHECK_FOR_STRING_TO_SEND,
    APP_USART_STATE_DRIVER_WRITE,
    APP_STATE_ERROR
  } APP_STATE
S;

 ②構造体APP_DATAのメンバーを以下のように変更します。
  typedef struct
  {
    /* USB Application's current state*/
    APP_STATES state;

    /* USART Application task state */
    APP_STATES usartTaskState;

    /* Unique handle to USB HID Host Keyboard driver */
    USB_HOST_HID_KEYBOARD_HANDLE handle;

    /* Unique handle to USART driver */
    DRV_HANDLE usartDriverHandle;

    /* Number of bytes written by the USART write*/
    uint32_t nBytesWritten;

    /* Size of the buffer to be written */
    uint32_t stringSize;

    /* Buffer used for USART writing */
    uint8_t string[64];

    /* Holds the current offset in the string buffer */
    uint16_t currentOffset;

    /* Flag used to determine if data is to be written to USART */
    bool stringReady;

    /* Flag used to select CAPSLOCK sequence */
    bool capsLockPressed;

    /* Flag used to select SCROLLLOCK sequence */
    bool scrollLockPressed;

    /* Flag used to select NUMLOCK sequence */
    bool numLockPressed;

    /* Holds the output Report*/
    uint8_t outputReport;

    /* Application current data buffer */
    USB_HOST_HID_KEYBOARD_DATA data;

    /* Application last data buffer */
    APP_DATA_LAST_DATA lastData;

    } APP_DATA;



  以下、app.h




app.cに、青字部の修正、追加をします。

  ① MHCが作成したapp.cを修正するより、マイクロチップのサンプルソフトhid_basic_keyboardのapp.c
   ( "C:\microchip\harmony\v2_04\apps\usb\host\hid_basic_keyboard")を修正した方が
   簡単なので app.cを入れ替えます。


  ②インクルードファイルを追加します。stdio.hがないと、sprintf( )がコンパイラのバージョンによってコンパイルでエラーが
    でることがあります。
  #include "stdio.h"


  ③キャラクタ液晶制御のバッファーを定義します。 またキャラクタ液晶とTeraTermに表示する文字列も定義します。
  char Buf[32];
  char strUART[16];
  char moji_Esc[] = "Esc";
  char moji_Tab[] = "Tab";
  char moji_Enter[] = "Enter";
  char moji_BackSpace[] = "Back Space";
  char moji_CapsLock[] = "Caps Lock"
;
  ……
  ……
  char moji_F10[] = "F10";
  char moji_F11[] = "F11";
  char moji_F12[] = "F12";
  char moji_10keyEnter[] = "10key Enter";



  ④NOP()による遅延関数 delay_us( )、delay_ms( )を定義しておきます。
  int delay_Clock = 200000000; //200MHz

  void delay_us(volatile unsigned int usec) //1μsec遅延
  {
    volatile int count;

    count = (int)(delay_Clock/20000000)*usec
;
  ……
  ……


  ⑤ keyValueに係るコメントを追加しただけです。 PICの制御には無関係です。
  /* Usage ID to Key map table */
  const char *keyValue[] =
  {
    ……
    ……
  }


 
  ⑥ USB初期化に際して、APP_Tasks( )から呼び出されます。
  void APP_USBHostHIDKeyboardEventHandler(USB_HOST_HID_KEYBOARD_HANDLE handle,
  USB_HOST_HID_KEYBOARD_EVENT event, void * pData)
  {
    switch ( event)
    {
      case USB_HOST_HID_KEYBOARD_EVENT_ATTACH:
      appData.handle = handle;
      appData.state = APP_STATE_DEVICE_ATTACHED;

  ……
  ……
  }


  ⑦ 英数字が打鍵された場合、キャラクタ液晶やTeraTermに文字を表示するための補助関数です。 
  void ys_Char(USB_HID_KEYBOARD_KEYPAD _keyCode) //英数文字キー
  {
    //I2Cキャラクタ液晶表示
    lcd_ACM1602_cmd_i2c(0x80); //1行目の先頭へ
    sprintf(Buf,"key=0x%02X ",_keyCode);
    lcd_ACM1602_str_i2c(Buf);

    lcd_ACM1602_cmd_i2c(0xC0); //2行目の先頭へ
    sprintf(Buf,"%c ",appData.string[appData.currentOffset]);
    lcd_ACM1602_str_i2c(Buf);
  }


  ⑧ 記号が打鍵された場合、キャラクタ液晶やTeraTermに文字を表示するための補助関数です。
    対象の記号キーは keyCodeが 16進表示で0x〇〇と表示できるキーです。
  void ys_Char_0xXX(USB_HID_KEYBOARD_KEYPAD _keyCode, char myChar) //一般記号文字キー
  {
    ……
    ……
  }



  ⑨記号が打鍵された場合、キャラクタ液晶やTeraTermに文字を表示するための補助関数です。
    対象の記号キーは keyCodeが 16進表示で0xFFFFFF〇〇と表示できるキーです。 具体的には \ と _ の場合です。
  void ys_Char_0xFFFF(USB_HID_KEYBOARD_KEYPAD _keyCode, char myChar) //特別扱い文字キー:  \ _
  {
    ……
    ……
  }



  ⑩エンターキーが打鍵された場合、キャラクタ液晶やTeraTermに文字を表示するための補助関数です。
  void ys_Function_Enter(USB_HID_KEYBOARD_KEYPAD _keyCode) //エンターキー
  {
    ……
    ……
  }



  ⑪一般機能キー(Esc、Tab、ファンクションキーなど)が打鍵された場合、キャラクタ液晶やTeraTermに文字を
  表示するための補助関数です。
  void ys_Function_0xXX(USB_HID_KEYBOARD_KEYPAD _keyCode, char* str0) //一般機能キー
  {
    ……
    ……
  }


  ⑫特別扱い機能キー("カタカナ" "変換" "無変換"キー)が打鍵された場合、キャラクタ液晶やTeraTermに文字を
   表示するための補助関数です。
   void ys_Function_0xFFFF(USB_HID_KEYBOARD_KEYPAD _keyCode, char* str0) //特別扱い機能キー //"カタカナ" "変換" "無変換"
  {
    ……
    ……
  }



  ⑬シフトしない場合の 各キー毎の分岐をおこなう関数です。
  void ys_NonShift_MapKey(USB_HID_KEYBOARD_KEYPAD keyCode, uint8_t outputReport) //非シフトモードのキーマップ関数
  {
    ……
    ……
  }



  ⑭シフトした場合の 各キー毎の分岐を行う関数です。
  void ys_Shift_MapKey(USB_HID_KEYBOARD_KEYPAD keyCode, uint8_t outputReport) //シフトモードのキーマップ関数
  {

    ……
    ……
  }


  ⑮取得したキーコードを最初に分岐させる関数です。
  void APP_MapKeyToUsage(USB_HID_KEYBOARD_KEYPAD keyCode) //keyCode: 打鍵キーコード
  {
    ……
    ……
  }



  ⑯PICが立ち上がったらキャラクタ液晶に"USB device HID" と "Keyboard demo" を表示しています。
   void APP_Initialize ( void )
  {
   ……
   ……
   lcd_ACM1602_cmd_i2c(0x80); //1行目の先頭へ
   lcd_ACM1602_str_i2c("USB device HID ");

   delay_ms(1000);

   cd_ACM1602_cmd_i2c(0xC0); //2行目の先頭へ
   lcd_ACM1602_str_i2c(" Keyboard demo ");



  ⑰UARTに 表示データを送信しています。 APP_Tasks( ) 1サイクル毎に最後で呼ばれています。
  void APP_USART_Tasks(void)
  {
    ……
    ……
  }

  ⑱ APP_STATE_INIT は、USB初期化に際し一度だけ呼ばれます。
  void APP_Tasks ( void )
  {
     switch ( appData.state )
    {
      /* Application's initial state.
*/
      case APP_STATE_INIT:


  ⑲ USBの初期化が完了して、キーボード用USBコネクタの接続待ちのステートです。 キーボード用のUSBコネクタが
    途中で抜かれた場合 このステートでの待ちとなります。
    case APP_STATE_HOST_ENABLE_DONE:


  ⑳ キーボード用のUSBが接続された時に通過するステートです。この後キーボードとの送受信ステートAPP_STATE_READ_HIDに
    移行します。
    case APP_STATE_DEVICE_ATTACHED:


  (21) キーボードとの送受信ステートです。 このステート内で複数回キーボード情報を取得します。 すなわち APP_Tasks( )
     1サイクルの中で複数回のキーボード情報が取得されます。
    case APP_STATE_READ_HID:

  (22)APP_Tasks( ) 1サイクルの最後に APP_USART_Tasks( )が呼ばれ UARTへの送信が行われます。
     /* Call the USART task routine */
    APP_USART_Tasks(); //UART]側に送信



以下、app.c