PIC18f2550をジョイスティックにする
この記事は、
の補足記事です。
ある程度PICに慣れている方向けの説明となっています。ご了承ください。
また、私の環境はMPLAB X IDE v5.45 + XC8 v2.32です。
それでは、PICマイコンに書き込むプログラムを作っていきます
- 環境など
- ブレッドボードでテスト
- Microchip Libraries for Applications (MLA) のダウンロード
- プロジェクトの作成
- 書き込み時の注意
- 実際につないでみよう
- ピン配置を決める
- プログラムを書く
- テスト
環境など
使用マイコン PIC18f2550
理由
・ピン数が多い(28ピン、20ピンだとちょっと足りない)
・p18系しか使ったことなかった
・秋月に売ってたから(超重要!!)
データシート(日本語版なさそう)
https://ww1.microchip.com/downloads/en/DeviceDoc/39632e.pdf
ブレッドボードでテスト
主な部品表です
部品名 | 値段 | 個数 | 用途など |
---|---|---|---|
PIC18F2550 | 500 | 1 | マイコン |
水晶発振器20MHz | 30 | 1 | クロックの生成 |
積層セラミックコンデンサ15pF | 10 | 2 | 水晶発振子の負荷容量 |
セラコン0.1μF | 15 | 1 | パスコン |
セラコン0.22μF | 20 | 1 | VUSB端子につなぐ |
セラコン1μF | 20 | 1 | USB端子側につけてノイズ軽減 |
ミニB-USBコネクタDIP化キット | 200 | 1 | USB端子 |
PICkit用の端子無しですが、最小構成はこんな感じです。左下のコンデンサはパスコンなので、マイコンに近い位置に配置してください。
細かい話ですが、USBで接続したときの電源の取得方法で回路が変わります。これはバスパワーの場合の回路図になっています。
Microchip Libraries for Applications (MLA) のダウンロード
MLAとは、Microchipから公開されている、USBやLANなどといったものを使うためのサンプルコード集みたいなやつです(って認識でいました)。
ここからダウンロード
皆さんの環境に合わせたものをダウンロードしてください。
インストーラーがダウンロードされる(容量は意外と大きい、300MBほど)
Next
accept からの next
フォルダ指定してね~ってやつ
とりあえずC直下においています。今後、パスを書く際はC直下に置かれている前提で書きます。
入れるやつ選択してね~ってやつ
他のやつは使わないのでUSBだけを選択しました。
とりあえずnext
Nextでインストール開始
インストール完了後この画面になります。finishで終了
それでは今インストールしたライブラリをMPLABで開いてみましょう。
C直下にインストールした場合は
C:\microchip\mla\v2018_11_26\apps\usb\device\hid_joystick\firmware\picdem_fs_usb.x
を開いてください。
開くとこうなります。
ここで赤丸で囲んだ部分を見てください。
デバイス違うじゃん(今回は18f2550)
ということで
プロジェクトの作成
今回使用しているPIC18F2550用のライブラリはMLAに入っていません。
しかし、ピン数が増えているだけのPIC18F4550のライブラリが入っているため、それを使用していきます。
まずはサンプルプロジェクトをコピーしてみましょう。
と言いたいのですが、このMLAは様々なデバイスに対応しているため、共通化できる部分はめちゃくちゃ共通化されています。
その結果、プロジェクトをコピーしようにも、いろいろなところに散らばっているファイルをかき集めなければなりません。
少し面倒くさいですが、やっていきましょう。
まずは新規プロジェクトを作成してください。
何点か注意点があり、
デバイスはPIC18F2550
コンパイラはXC8
プロジェクトの名前などは任意でOKです。
それでは次に、MLAから必要なファイルを、今作ったプロジェクトのフォルダに入れていきます。
C:\microchip\mla\v2018_11_26\apps\usb\device\hid_joystick\firmware\picdem_fs_usb.x
から
fixed_address_memory.h
io_mapping.h
system.c
system.h
C:\microchip\mla\v2018_11_26\apps\usb\device\hid_joystick\firmware\demo_src
から
app_device_joystick.c
app_device_joystick.h
app_led_usb_status.c
app_led_usb_status.h
main.c
usb_config.h
usb_descriptors.c
usb_events.c
C:\microchip\mla\v2018_11_26\framework\usb\inc
から
usb.h
usb_ch9.h
usb_common.h
usb_device.h
usb_device_hid.h
usb_hal.h
usb_hal_pic18.h
C:\microchip\mla\v2018_11_26\framework\usb\src
から
usb_device.c
usb_dvice_hid.c
usb_device_local.h
C:\microchip\mla\v2018_11_26\bsp\picdem_fs_usb
から
buttons.c
buttons.h
leds.c
leds.h
すべて入れるとこのようになります。
ファイル数多かったのでヘッダファイルはフォルダに入れました
完成
それでは次に、今入れたファイルをプロジェクトに追加していきます。
Projectウィンドウから、Add Existing itemで追加
ちなみにこの時点でビルドをかけるとエラーが起きますので、気にしないでください。
また、ヘッダファイルなどを別フォルダにした場合include directoriesの設定を忘れずにしましょう。
続いて、ビルドを通すためにいくつか変更を加えます。
先ほど4550は2550にピン数を増やしただけと書きましたが、もろにその部分でエラーが起きています。
leds.cを開くとこのような部分があるはずです
2550には存在しないポートDを使用しているためエラーが起きていました。
ということでDをAに変更しておきましょう
例
#define LED_D1_LAT LATDbits.LATD0
↓
#define LED_D1_LAT LATAbits.LATA0
これで一応ビルドが通るはずです。
次にコンフィギュレーションビットの設定をしていきます。
コンフィギュレーションビットの説明はコンパイラをインストールしたフォルダの中にPDFがありますので、そちらを参考にしましょう。
ちなみに私の場合このディレクトリにありました。
C:\Program Files\Microchip\xc8\v2.32\docs\chips\18f2550.html
コンフィギュレーションビットはsystem.cに書かれています
2点だけ説明します。
1.PLLDIV
PLLDIV = 5にします。(変更なし)
今回は20MHzの水晶発振子をつないでいるため5のままで大丈夫です。それ以外の周波数の発振子を使う場合は変更してください。
クロックダイアグラムを見るとこのようになっており、現在の構成では、
20MHz→1/5に分周→4MHz→PLL→96MHz→1/2に分周→クロックとして利用
となっています。つける水晶発振子の周波数や、CPUクロックを変更する場合は、コンフィギュレーションビットやレジスタを変更しなければならないので気を付けてください。
2.MCLRE
リセットピン用の設定です。今回の回路ではリセットボタンは実装しないためOFFにしておきましょう。
MCLRE = OFF
書き込み時の注意
ここまで来たら実際に書き込むのですが、p18f2550において書き込みに失敗することが多いらしいです
実際に私もこの状況に遭遇したのですが、PICkitからの電源供給を3.375Vにしたところ書き込めました。
実際につないでみよう
PICにプログラムを書き込み、PICkitを外し、USBケーブルを付けます。
PICkitを付けたままUSBを付けると、電源関係が確かアレするのでアレです(よくわかってないけどダメなのはわかる)
コントロールパネル→ハードウェアとサウンド→デバイスとプリンター
で見てみると、PCから認識されています。
Joystick Demo を右クリックで選択しゲームコントローラーの設定を開きます。
Joystick Demo を選択し、プロパティを開きます。
なんかあらぶっていますがOKです。
それではプログラムを少し見ていきましょう。
実際にコントローラーの入力を設定している部分は、app_device_joystick.cのAPP_DeviceJoystickTasks関数にあります。
if文の条件式にある、BUTTON_USB_DEVICE_HID_JOYSTICKとはRB4のことです(io_mapping.h, buttons.h, buttons.cなど参照)
ということで、RB4にスイッチを取り付け(とりあえずプルダウン)ると
あらぶらなくなります
もう少し詳しく見ていきます。
この部分が、実際に入力を設定している部分です。
joystick_inputは上で宣言されており
INPUT_CONTROLS型の変数です。
INPUT_CONTROLSとは、同じファイルの上の方に書いてあり
構造体の共用体(?)ですね(なんて説明していいのかわからん)
ただここら辺はあんまり理解しなくともかけるので、なんとなくこんなのがあるんだな~程度でOKです。
ピン配置を決める
アケコン用にプログラムを作る前に、ピン配置を決めます
ポートA(0~3)→レバー
ポートB→メインボタン
ポートC(0,1,2,6)→スタート・セレクトとか
ということにしました。
ポートBだけ内蔵プルアップがあるので使い、ポートAとCは自力でプルアップします。
プログラムを書く
アケコン向けにプログラムを書く前に、すでに設定されてるピン設定を無効化します。
system.cにあるSYSTEM_Initialize関数のED_Enable関数、BUTTON_Enable関数呼び出しをコメントアウトします。
usb_events.cにある、APP_LEDUpdateUSBStatus関数呼び出し3つをコメントアウトします。
次に
app_led_usb_status.c
leds.c
buttons.c
の3ファイルをプロジェクトから外します。(右クリックからRemove From Project)
app_device_joystick.cの、167行目あたりのBUTTON_isPressed~~~みたいなところをとりあえずtrueにしておきます(ここはあとからすべて変えるのでとりあえずtrueでOK)
この変更をするととりあえずビルドが通るはずです。
(使ってないヘッダファイルとか残ってるけど気にしない...)
と、ここまではすでにある設定の削除でした。
ここからは新しいアケコン向けの設定を書いていきます。
いろいろ設定するために新しくヘッダファイルを作成します。(my_header.h)
/* * File: my_header.h * Author: kazu8823 * * Created on 2021/12/01, 23:16 */ #ifndef MY_HEADER_H #define MY_HEADER_H #ifdef __cplusplus extern "C" { #endif // 追加部分ここから******************************************** // レバー #define LEVER_UP !PORTAbits.RA0 #define LEVER_DOWN !PORTAbits.RA1 #define LEVER_RIGHT !PORTAbits.RA2 #define LEVER_LEFT !PORTAbits.RA3 #define LEVER (~PORTA & 0x0f) // メインボタン #define BUTTON1 !PORTBbits.RB0 #define BUTTON2 !PORTBbits.RB1 #define BUTTON3 !PORTBbits.RB2 #define BUTTON4 !PORTBbits.RB3 #define BUTTON5 !PORTBbits.RB4 #define BUTTON6 !PORTBbits.RB5 #define BUTTON7 !PORTBbits.RB6 #define BUTTON8 !PORTBbits.RB7 // スタートセレクト等 #define SUB_BUTTON1 !PORTCbits.RC0 #define SUB_BUTTON2 !PORTCbits.RC1 #define SUB_BUTTON3 !PORTCbits.RC2 #define SUB_BUTTON4 !PORTCbits.RC6 // ここまで**************************************************** #ifdef __cplusplus } #endif #endif /* MY_HEADER_H */
回路がプルアップのため、ON=0, OFF=1になってしまいます。そのため、!を付けてON=1, OFF=0にしています。(好み)
今度はそれをmain.cから呼び出します。
次に、main関数の前にinit関数を作って設定をしましょう。
// 設定など void init(){ // 入出力設定 0で出力 1で入力 TRISA = 0x0f; // 0~3までを入力 TRISB = 0xff; // 全部入力 TRISC = 0x47; // 0,1,2,6を入力 INTCON2bits.RBPU = 0; // ポートBの内蔵プルアップを有効にする(0で有効 1で無効) ADCON1bits.PCFG = 0b1111; // AD変換を無効化(全ピンデジタルに) }
main関数の最初で、今作成したinit関数を呼び出します
app_device_joystick.cからも自作ヘッダをインクルードします
同じくapp_device_joystick.cに、レバーの入力と出力の関係を表す配列を作っておきます。
unsigned char lever_con[] = { 0x8, 0x2, 0x6, 0x2, 0x4, 0x3, 0x5, 0x3, 0x0, 0x1, 0x7, 0x1, 0x8, 0x2, 0x6, 0x2 };
最後にAPP_DeviceJoystickTasks関数をこのようにします
(最後の閉じカッコ途切れています、すいません...)
void APP_DeviceJoystickTasks(void) { /* If the USB device isn't configured yet, we can't really do anything * else since we don't have a host to talk to. So jump back to the * top of the while loop. */ if( USBGetDeviceState() < CONFIGURED_STATE ) { /* Jump back to the top of the while loop. */ return; } /* If we are currently suspended, then we need to see if we need to * issue a remote wakeup. In either case, we shouldn't process any * keyboard commands since we aren't currently communicating to the host * thus just continue back to the start of the while loop. */ if( USBIsDeviceSuspended() == true ) { /* Jump back to the top of the while loop. */ return; } //If the last transmission is complete if(!HIDTxHandleBusy(lastTransmission)) { // ボタン joystick_input.members.buttons.square = BUTTON1; joystick_input.members.buttons.x = BUTTON3; joystick_input.members.buttons.o = BUTTON4; joystick_input.members.buttons.triangle = BUTTON2; joystick_input.members.buttons.L1 = BUTTON6; joystick_input.members.buttons.R1 = BUTTON5; joystick_input.members.buttons.L2 = BUTTON8; joystick_input.members.buttons.R2 = BUTTON7; joystick_input.members.buttons.select = SUB_BUTTON2; joystick_input.members.buttons.start = SUB_BUTTON1; joystick_input.members.buttons.left_stick = SUB_BUTTON3; joystick_input.members.buttons.right_stick = SUB_BUTTON4; joystick_input.members.buttons.home = 0; // レバー joystick_input.members.hat_switch.hat_switch = lever_con[LEVER]; // アナログスティック(無効) joystick_input.members.analog_stick.X = 0x80; joystick_input.members.analog_stick.Y = 0x80; joystick_input.members.analog_stick.Z = 0x80; joystick_input.members.analog_stick.Rz = 0x80; lastTransmission = HIDTxPacket(JOYSTICK_EP, (uint8_t*)&joystick_input, sizeof(joystick_input)); } }//end ProcessIO
テスト
ここまで出来たら実際にプログラムを書き込みましょう。
また、テストができるようにブレッドボードにスイッチを取り付けます。
回路図はこんな感じです。コネクタでかいていますが、普通のジャンパー線でつなぎました。
そしてボタン16つけたブレッドボードがこちら!!
結果
古いタクトスイッチを使っているため、入力がちょっと不安定です...
ということで完成です!!!!!
すごく駆け足で説明したため、わかりにくい部分もあったと思います。
何か質問等ありましたら、私のツイッター(@kazujdDR8823)にでもお願いします。
ここまでご覧いただきありがとうございました。