PIC18f2550をジョイスティックにする

この記事は、

kazu8823.hatenablog.jp

の補足記事です。

 

ある程度PICに慣れている方向けの説明となっています。ご了承ください。

 

また、私の環境はMPLAB X IDE v5.45 + XC8 v2.32です。

 

 

 

 

それでは、PICマイコンに書き込むプログラムを作っていきます

 

 

 

 

環境など

 

使用マイコン PIC18f2550 

akizukidenshi.com

 

理由

・ピン数が多い(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端子

 

 

f:id:kazujdDR8823:20211201022615j:plain

最小構成

f:id:kazujdDR8823:20211201022700j:plain

PICkit用の線追加

 

f:id:kazujdDR8823:20211212175230p:plain

PICkit用の端子無しですが、最小構成はこんな感じです。左下のコンデンサパスコンなので、マイコンに近い位置に配置してください。

 

細かい話ですが、USBで接続したときの電源の取得方法で回路が変わります。これはバスパワーの場合の回路図になっています。

 

Microchip Libraries for Applications (MLA) のダウンロード

MLAとは、Microchipから公開されている、USBやLANなどといったものを使うためのサンプルコード集みたいなやつです(って認識でいました)。

 

 

ここからダウンロード

https://www.microchip.com/en-us/development-tools-tools-and-software/libraries-code-examples-and-more/microchip-libraries-for-applications#

 

皆さんの環境に合わせたものをダウンロードしてください。

 

f:id:kazujdDR8823:20211201211315p:plain

MLAのダウンロード

インストーラーがダウンロードされる(容量は意外と大きい、300MBほど)

f:id:kazujdDR8823:20211201211936p:plain

Next

 

f:id:kazujdDR8823:20211201211951p:plain

accept からの next

 

f:id:kazujdDR8823:20211201212013p:plain

フォルダ指定してね~ってやつ

とりあえずC直下においています。今後、パスを書く際はC直下に置かれている前提で書きます。

 

f:id:kazujdDR8823:20211201212100p:plain

入れるやつ選択してね~ってやつ

他のやつは使わないのでUSBだけを選択しました。

 

 

f:id:kazujdDR8823:20211201212119p:plain

とりあえずnext

 

f:id:kazujdDR8823:20211201212132p:plain

Nextでインストール開始

 

f:id:kazujdDR8823:20211201212236p:plain

インストール完了後この画面になります。finishで終了

 

 

 

それでは今インストールしたライブラリをMPLABで開いてみましょう。

f:id:kazujdDR8823:20211201212540p:plain

C直下にインストールした場合は

C:\microchip\mla\v2018_11_26\apps\usb\device\hid_joystick\firmware\picdem_fs_usb.x

を開いてください。

 

開くとこうなります。

f:id:kazujdDR8823:20211201212735p:plain

 

ここで赤丸で囲んだ部分を見てください。

f:id:kazujdDR8823:20211212180447p:plain

 

 

 

 

f:id:kazujdDR8823:20211201212916p:plain

バイス違うじゃん(今回は18f2550)

 

ということで

 

 

プロジェクトの作成

今回使用しているPIC18F2550用のライブラリはMLAに入っていません。

しかし、ピン数が増えているだけのPIC18F4550のライブラリが入っているため、それを使用していきます。

 

まずはサンプルプロジェクトをコピーしてみましょう。

 

と言いたいのですが、このMLAは様々なデバイスに対応しているため、共通化できる部分はめちゃくちゃ共通化されています。

その結果、プロジェクトをコピーしようにも、いろいろなところに散らばっているファイルをかき集めなければなりません。

 

少し面倒くさいですが、やっていきましょう。

 

 

まずは新規プロジェクトを作成してください。

 

何点か注意点があり、

 

バイスはPIC18F2550

f:id:kazujdDR8823:20211201213023p:plain

 

コンパイラはXC8

f:id:kazujdDR8823:20211201213041p:plain

 

プロジェクトの名前などは任意でOKです。

f:id:kazujdDR8823:20211212181133p:plain



 

それでは次に、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

 

 

すべて入れるとこのようになります。

f:id:kazujdDR8823:20211212181415p:plain



ファイル数多かったのでヘッダファイルはフォルダに入れました

f:id:kazujdDR8823:20211212181458p:plain

完成

 

 

それでは次に、今入れたファイルをプロジェクトに追加していきます。

 

Projectウィンドウから、Add Existing itemで追加

f:id:kazujdDR8823:20211201215050p:plain

f:id:kazujdDR8823:20211201215102p:plain

 

ちなみにこの時点でビルドをかけるとエラーが起きますので、気にしないでください。

f:id:kazujdDR8823:20211212191649p:plain



 

 

また、ヘッダファイルなどを別フォルダにした場合include directoriesの設定を忘れずにしましょう。

f:id:kazujdDR8823:20211201215349p:plain

 

 

続いて、ビルドを通すためにいくつか変更を加えます。

先ほど4550は2550にピン数を増やしただけと書きましたが、もろにその部分でエラーが起きています。

leds.cを開くとこのような部分があるはずです

f:id:kazujdDR8823:20211201220130p:plain

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に書かれています

f:id:kazujdDR8823:20211201221001p:plain

 

 

2点だけ説明します。

 

1.PLLDIV

f:id:kazujdDR8823:20211201222408p:plain

PLLDIV = 5にします。(変更なし)

今回は20MHzの水晶発振子をつないでいるため5のままで大丈夫です。それ以外の周波数の発振子を使う場合は変更してください。

 

 

f:id:kazujdDR8823:20211201221156p:plain

クロックダイアグラム(データシートより)

クロックダイアグラムを見るとこのようになっており、現在の構成では、

 

20MHz→1/5に分周→4MHz→PLL→96MHz→1/2に分周→クロックとして利用

 

となっています。つける水晶発振子の周波数や、CPUクロックを変更する場合は、コンフィギュレーションビットやレジスタを変更しなければならないので気を付けてください。

 

2.MCLRE

リセットピン用の設定です。今回の回路ではリセットボタンは実装しないためOFFにしておきましょう。

MCLRE = OFF 

 

 

 

書き込み時の注意

ここまで来たら実際に書き込むのですが、p18f2550において書き込みに失敗することが多いらしいです

akizukidenshi.com

実際に私もこの状況に遭遇したのですが、PICkitからの電源供給を3.375Vにしたところ書き込めました。

 

実際につないでみよう

PICにプログラムを書き込み、PICkitを外しUSBケーブルを付けます

PICkitを付けたままUSBを付けると、電源関係が確かアレするのでアレです(よくわかってないけどダメなのはわかる)

 

コントロールパネル→ハードウェアとサウンド→デバイスとプリンター

で見てみると、PCから認識されています。

f:id:kazujdDR8823:20211212191815p:plain



Joystick Demo を右クリックで選択しゲームコントローラーの設定を開きます。

f:id:kazujdDR8823:20211201223656p:plain

 

Joystick Demo を選択し、プロパティを開きます。

f:id:kazujdDR8823:20211201223716p:plain

 

 

なんかあらぶっていますがOKです。

 

 

それではプログラムを少し見ていきましょう。

実際にコントローラーの入力を設定している部分は、app_device_joystick.cのAPP_DeviceJoystickTasks関数にあります。

 

f:id:kazujdDR8823:20211201224931p:plain

 

f:id:kazujdDR8823:20211212183447p:plain

 

if文の条件式にある、BUTTON_USB_DEVICE_HID_JOYSTICKとはRB4のことです(io_mapping.h, buttons.h, buttons.cなど参照)

 

ということで、RB4にスイッチを取り付け(とりあえずプルダウン)ると

f:id:kazujdDR8823:20211207011554j:plain

 

あらぶらなくなります

 

 

もう少し詳しく見ていきます。

 

 

f:id:kazujdDR8823:20211212183718p:plain

この部分が、実際に入力を設定している部分です。

 

joystick_inputは上で宣言されており

f:id:kazujdDR8823:20211201231312p:plain

INPUT_CONTROLS型の変数です。

 

INPUT_CONTROLSとは、同じファイルの上の方に書いてあり

f:id:kazujdDR8823:20211201231459p:plain

構造体の共用体(?)ですね(なんて説明していいのかわからん)

 

ただここら辺はあんまり理解しなくともかけるので、なんとなくこんなのがあるんだな~程度でOKです。

 

 

ピン配置を決める

アケコン用にプログラムを作る前に、ピン配置を決めます

 

ポートA(0~3)→レバー

ポートB→メインボタン

ポートC(0,1,2,6)→スタート・セレクトとか

 

ということにしました。

 

ポートBだけ内蔵プルアップがあるので使い、ポートAとCは自力でプルアップします。

 

 

プログラムを書く

 

アケコン向けにプログラムを書く前に、すでに設定されてるピン設定を無効化します。

 

system.cにあるSYSTEM_Initialize関数のED_Enable関数、BUTTON_Enable関数呼び出しをコメントアウトします。

f:id:kazujdDR8823:20211201232751p:plain

 

 

usb_events.cにある、APP_LEDUpdateUSBStatus関数呼び出し3つをコメントアウトします。

f:id:kazujdDR8823:20211201233809p:plain

 

次に

app_led_usb_status.c

leds.c

buttons.c

の3ファイルをプロジェクトから外します。(右クリックからRemove From Project)

 

app_device_joystick.cの、167行目あたりのBUTTON_isPressed~~~みたいなところをとりあえずtrueにしておきます(ここはあとからすべて変えるのでとりあえずtrueでOK)

f:id:kazujdDR8823:20211201234053p:plain

 

この変更をするととりあえずビルドが通るはずです。

(使ってないヘッダファイルとか残ってるけど気にしない...)

 

 

 

と、ここまではすでにある設定の削除でした。

ここからは新しいアケコン向けの設定を書いていきます。

 

 

 

いろいろ設定するために新しくヘッダファイルを作成します。(my_header.h)

f:id:kazujdDR8823:20211212184846p:plain

/* 
 * 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から呼び出します。

f:id:kazujdDR8823:20211201235324p:plain

 

次に、main関数の前にinit関数を作って設定をしましょう。

f:id:kazujdDR8823:20211202005510p:plain

// 設定など
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関数を呼び出します

f:id:kazujdDR8823:20211202001211p:plain



 

app_device_joystick.cからも自作ヘッダをインクルードします

f:id:kazujdDR8823:20211202000335p:plain

 

 

同じくapp_device_joystick.cに、レバーの入力と出力の関係を表す配列を作っておきます。

f:id:kazujdDR8823:20211212185239p:plain

unsigned char lever_con[] = {
  0x8, 0x2, 0x6, 0x2, 0x4, 0x3, 0x5, 0x3, 0x0, 0x1, 0x7, 0x1, 0x8, 0x2, 0x6, 0x2
};

 

 

 

最後にAPP_DeviceJoystickTasks関数をこのようにします

f:id:kazujdDR8823:20211212185529p:plain

(最後の閉じカッコ途切れています、すいません...)

 

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

 

 

 

 

テスト

ここまで出来たら実際にプログラムを書き込みましょう。

 

また、テストができるようにブレッドボードにスイッチを取り付けます。

 

回路図はこんな感じです。コネクタでかいていますが、普通のジャンパー線でつなぎました。

f:id:kazujdDR8823:20211205021423p:plain

 

 

そしてボタン16つけたブレッドボードがこちら!!

f:id:kazujdDR8823:20211207011744j:plain

 

 

 

結果

古いタクトスイッチを使っているため、入力がちょっと不安定です...

 

 

 

ということで完成です!!!!!

 

すごく駆け足で説明したため、わかりにくい部分もあったと思います。

何か質問等ありましたら、私のツイッター(@kazujdDR8823)にでもお願いします。

 

ここまでご覧いただきありがとうございました。