#author("2023-04-24T12:23:02+09:00","","") * ボタン入力とデバッグ [#wec9383b] ボタン入力はアドレス0x4000130をu16単位で参照します。下位のビットから順番に、Aボタン、Bボタン、セレクトボタン、スタートボタン、十字キーの→、←、↑、↓、最後はRボタン、Lボタンとなっています。ビットが立っている時は押されていない状態、ビットが立っていない時は押されている状態です。どの程度の強さで押されているか、といった判定はできません。~ | ビット | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | ボタン | | | | | | | L | R | ↓ | ↑ | ← | → | ST | SL | B | A | - GBA Keypad Input The built-in GBA gamepad has 4 direction keys, and 6 buttons. 4000130h - KEYINPUT - Key Status (R) Bit Expl. 0 Button A (0=Pressed, 1=Released) 1 Button B (etc.) 2 Select (etc.) 3 Start (etc.) 4 Right (etc.) 5 Left (etc.) 6 Up (etc.) 7 Down (etc.) 8 Button R (etc.) 9 Button L (etc.) 10-15 Not used It'd be usually recommended to read-out this register only once per frame, and to store the current state in memory. As a side effect, this method avoids problems caused by switch bounce when a key is newly released or pressed. ** 取得方法 [#kaa95702] キー入力を取得するにはメインループ中で毎回状態をチェックするか、割り込み機能を使って取得します。今回は簡単な前者の方法を使ってみましょう。以下のマクロを用意します。~ #define REG_KEYINPUT *(vu16*)(REG_BASE + 0x130) // Key Input typedef enum KEYPAD_BITS { KEY_A = (1<<0), /*!< keypad A button */ KEY_B = (1<<1), /*!< keypad B button */ KEY_SELECT = (1<<2), /*!< keypad SELECT button */ KEY_START = (1<<3), /*!< keypad START button */ KEY_RIGHT = (1<<4), /*!< dpad RIGHT */ KEY_LEFT = (1<<5), /*!< dpad LEFT */ KEY_UP = (1<<6), /*!< dpad UP */ KEY_DOWN = (1<<7), /*!< dpad DOWN */ KEY_R = (1<<8), /*!< Right shoulder button */ KEY_L = (1<<9), /*!< Left shoulder button */ KEYIRQ_ENABLE = (1<<14), /*!< Enable keypad interrupt */ KEYIRQ_OR = (0<<15), /*!< interrupt logical OR mode */ KEYIRQ_AND = (1<<15), /*!< interrupt logical AND mode */ DPAD = (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT) /*!< mask all dpad buttons */ } KEYPAD_BITS; ** 横道な雑談 [#o24a73f2] 入力の説明が簡単すぎたので別の話をさせてもらいます。今まで何気なくビットマップモードから説明をしてきました。REG_DISPCNTなどのレジスタに設定したり、VRAMに色データを設定したり、そして今回のREG_KEYINPUTは値を読み取っています。もう少し短めにいうと、決められた設定を行い決められたデータを配置する、または決められたアドレスの値を調べる、という考え方に集約されます。設定を忘れたり、データを配置し忘れると当然うまくいきません。ここではプログラマーの意図した結果になっているのか?という確認方法をまとめてご紹介します。~ *** Tools -> Memory viewer [#dd06572d] エミュレータのMemory viewerです。Toolsからぶら下がっているものはすべて有用なので一度確認しておくことをおすすめします。~ *** gritの出力結果 [#bf328660] gritのオプションを間違うことはよくあることです。自分の意図したサイズかどうか、あと1、2バイト目のデータ構造ぐらいは確認した方がいいかもしれません。~ *** printfデバッグ [#e81dda08] 私のサンプルコード限定ですけれど、使い方は以下のとおりです。 u32 x = 1234; TRACE("%d %x\n", x, x); 出力結果はエミュレータのTools->Loggingで確認できます。この関数は自作したものなので標準ライブラリと関係ありません。原理については[[Doc.10 エミュレータのデバッグコンソール>doc.10]]を読んでください。ところで、そろそろ標準ライブラリは使えないのかという疑問も出てくると思います。~ #include <stdio.h> というように山括弧を使えばできますが入出力関係の関数は全滅です。fopen、fgetcはファイルシステムがないので使えず。scanfはキーボード入力が物理的にないので使えず。printfはそもそも日本語フォントが内蔵されておらず、表示手段もないので使えず。。OSないってなんて不便なんや、と文句いいたくなりますね。有用なのは数学関係の関数でしょうか。~ #include <math.h> ただ標準ライブラリは全部カードリッジ領域''固定''なのでスピードが出ません。あとROMのサイズも増大するのであまりおすすめしません。~ ** キー入力 [#rc24903c] #include "lib/gba.h" //--------------------------------------------------------------------------- void WaitForVsync(void) { while(*(vu16*)0x4000006 >= 160) {}; while(*(vu16*)0x4000006 < 160) {}; } //--------------------------------------------------------------------------- int main(void) { SetMode(MODE_3 | BG2_ENABLE); u32 x = 0; for(;;) { WaitForVsync(); if( !(REG_KEYINPUT & KEY_UP) ) TRACE("上 ボタン\n"); if( !(REG_KEYINPUT & KEY_DOWN) ) TRACE("下 ボタン\n"); if( !(REG_KEYINPUT & KEY_RIGHT)) TRACE("右 ボタン\n"); if( !(REG_KEYINPUT & KEY_LEFT) ) TRACE("左 ボタン\n"); if( !(REG_KEYINPUT & KEY_A) ) TRACE("10進=%d 16進=0x%x 16進4桁=0x%04x \n", x, x, x); if( !(REG_KEYINPUT & KEY_B) ) TRACE("変数x++ \n", x++); } } ボタン入力はパソコンの物理キーボードの性能に依存しています。たとえば上下右左の4つのボタンを同時にした結果、正しいデバック表示になるかというとかなり難しいです。個人的には安いキーボードほど同時ボタン処理が適当なイメージを持っています。ここでは実機の場合とでは動作が違うということを覚えておいてください。 *** デバッグ画面 [#z779c7ea] -[[github:https://github.com/akkera102/gbadev-ja/tree/main/tut06%20%E3%83%9C%E3%82%BF%E3%83%B3%E5%85%A5%E5%8A%9B%E3%81%A8%E3%83%87%E3%83%90%E3%83%83%E3%82%B0]] #ref(1.png,nolink) ** 履歴 [#n0e506bc] - 2023/04/24 - 2014/12/23