あそ~ぶUSB サンプルソース解説・その5

USBジョイスティックを作る

2010/11/26

Assembly Desk

1. 概要

ここでは、あそ~ぶUSB のサンプルプログラムを解説していきます。

ここではUSBジョイスティックを作成します。

外部に接続したスイッチを押すと、USBジョイスティックとして、予め決めておいたコマンドを入力するハードウェアマクロを作成します。

なお、本サンプルソースはMicrochip社のMCHPFSUSBver2.7を元にして作成しています。

この文章は、開発環境が既にインストールされている事を前提としてかかれています。

まだ、開発環境を整えて居ない方はこちらを参考にして、まずは開発環境を整えて下さい。

http://a-desk.jp/modules/forum_pic/index.php?cat_id=4

まだ、ファームウェアのビルドの仕方についてはこちらを参考にして下さい。

http://a-desk.jp/modules/forum_pic/index.php?cat_id=3

2. ソースコード解説

2.1 ファイルの構成

“joystick_sample”は次の様な、様々なファイルで構成されています。

これらのファイルには、USBの通信を行う為の様々な記述があります。

ここでは、手っ取り早くUSBマウスのソフトを作れる様になるための、最低限の説明を行います。

“main.c”このファイルを開いてください。

次の3つの関数を用いてコマンドマクロを実現しています。

2.2 void UserInit(void)関数

まずは、”mouse.c”の中のUserInit関数を見ていきます。

ここは、プログラムが動きだしてから最初に一回だけ実行されます。

色々な初期化ルーチンを書く事が出来ます。

また、USB関係の初期化はこの関数が実行された後にやってくれるので、よっぽど変な設定をしない限りは正常に動作してくれます。


/******************************************************************************

 * Function:        void UserInit(void)

 *****************************************************************************/

void UserInit(void)

{

        TRISA = 0x03;        //RA0,1を入力に

        TRISB = 0;

        LATB = 0;

//        タイマ0の設定

//        内部48MHz動作、1/60s毎に割り込みを発生させる

//        (1/60) / (4 / 48000000) / 8 = 25000

//        65536 - 25000 = 40536 = 0x9E58

        OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_8);

        WriteTimer0(WRITE_TIMER0);

//        割り込み開始

        INTCON2bits.TMR0IP = 0;                //タイマ0を低位レベル割り込みに設定

        INTCONbits.TMR0IE = 1;                //タイマ0割り込み許可

        INTCONbits.GIEL = 1;                //低位レベル割り込みの許可

        joystick_input[0] = 0x00;

        joystick_input[1] = 0x80;

        joystick_input[2] = 0x80;

lastTransmission = 0;

}//end UserInit


まず、ポートの初期化を行います。

RA0,1を入力に設定し、後は出力とします。

次にタイマ0の設定をします。

これは、1/60s毎に割り込みを発生させる為に使用します。

この割り込みのタイミングで、コマンド入力を変更していきます。

ここでは、タイマ0の割り込みを低位レベル割り込みに設定しています。

これは、USB通信が高位レベル割り込みで処理されるため、それを阻害しない為の処置です。

なお、Microchip社のMCHPFSUSBver2.7を元にして、USB通信と同時に割り込みを用いる場合には、usb_config.hの

#define USB_POLLING

をコメントアウトし、

#define USB_INTERRUPT

を記述します。(このジョイスティックのソフトはそのようになっています)

joystick_input[0]~[2]を初期化します。

この配列にはPCに送付するジョイスティック操作情報が入ります。

なお、配列の意味は次の様になっています。

joystick_input[0] ビット0

ボタン1

joystick_input[0] ビット1

ボタン2

joystick_input[0] ビット2

ボタン3

joystick_input[0] ビット3

ボタン4

joystick_input[0] ビット4

ボタン5

joystick_input[0] ビット5

ボタン6

joystick_input[0] ビット6

ボタン7

joystick_input[0] ビット7

ボタン8

joystick_input[1]

X軸

joystick_input[2]

Y軸

lastTransmissionは後で使うUSB通信の管理を行う為の変数です。

削除しないでください。

2.3 void Joystick(void)関数

Joystick関数では、ジョイスティックとして、PCにどのようなデータを送信するかを記述します。


/******************************************************************************

 * Function:        void Joystick(void)

 *****************************************************************************/

void Joystick(void)

{

if(!HIDTxHandleBusy(lastTransmission))

{

if(!PORTAbits.RA0)

{

if(command_state == 0)

                                command_state = COMMAND_MACRO_COUNT;

}

                lastTransmission = HIDTxPacket(HID_EP, (BYTE*)&joystick_input, sizeof(joystick_input));

}

return;                

}//end joystick()


if(HIDTxHandleBusy(lastTransmission) == 0)このif文の中に、ASOOVUからPCに送信するデータを入れます。

送信するデータはjoystick_input配列にいれます。

ここでは、PORT A0に繋いだスイッチが押されていたらcommand_stateをCOMMAND_MACRO_COUNTにしています。

command_stateの値にしたがって、後で述べる割り込み処理でキー入力を行っています。

2.4 void isr_high()関数

この関数は低位レベル割り込み処理関数です。

ここでは、UserInit関数で設定したタイマ0割り込みが1/60秒毎に呼び出されます。


void isr_low()

{

        if(INTCONbits.TMR0IF == 1)

        {

                INTCONbits.TMR0IF = 0;

                WriteTimer0(WRITE_TIMER0);

                if(command_state != 0)

                        command_state--;

                joystick_input[0] = command_macro[command_state][0];

                joystick_input[1] = command_macro[command_state][1];

                joystick_input[2] = command_macro[command_state][2];

        }

}        //This return will be a "retfie", since this is in a #pragma interruptlow section


この処理で予めcommand_macro配列に書きこんでおいたコマンドが後ろから順に1/60秒毎に入力される事になります。

サンプルでは、command_macroは次の様になっています。


//        ここにコマンドを入れる。

//        コマンドは後ろから順に実行される

#define COMMAND_MACRO_COUNT        4

BYTE command_macro[COMMAND_MACRO_COUNT][3] =

        {{0x00,0x80,0x80},        //ここはいじっちゃダメ

         {0x01,0xff,0xff},

         {0x00,0x80,0xff},

         {0x00,0xff,0x80}

        };


これで、最初の1/60秒は配列の最後{0x00,0xff,0x80}がjoystick_input[0]~[2]に代入され、次の1/60秒で{0x00,0x80,0xff}が代入され、と言う形でマクロが実行されて行く事になります。

この例では、「右」 ->「下」 -> 「右下+ボタン1」と言う順番で実行される事になります。