PSパッドのコンフィギュレーションモードを試す。
これまでは、Analogボタンでデジタルモード⇔アナログモードの切り替えをおこなっていたが、Analogボタンを無効にしてアナログ固定にできた。
アセンブラで作業していたときと比較して、ちょっと何か試すのにCは便利。

現状のソースは次のとおり。
なんじゃこれは!と思われる方はぜひコメント願います。

#include    <pic.h>
#include    <conio.h>
#include    "delay.h"

#define    DEBUG 1
//RCB-3への接続時:0     RA0をRCB-3の低速シリアル端子の信号線として使用
//動作確認時     :1     RA0をMAX232Cドライバなどを経由しPCのCOMポートへ接続
//                      パッド情報およびRCB-3への送信データをシリアル出力する

__CONFIG( HS & WDTDIS & PWRTEN & UNPROTECT);
//発振モード            :RC HS XT LP
//watchdogの有無        :WDTEN=O WDTDIS=OFF
//power up timerの有無  :PWRTEN=ON PWRTDIS=OFF
//コードプロテクトの有無:PROTECT=プロテクトあり UNPROTECT=プロテクトなし

#define    CDAT RA4
#define    CCMD RA3
#define    CSEL RA2
#define    CCLK RA1
/*
PLAYSTATION PAD 9PIN ASIGN
 1: DAT (PIC <- PAD)
 2: CMD (PIC -> PAD)
 3: 7.6V
 4: GND
 5: 3.6V
 6: SEL (PIC -> PAD)
 7: CLK (PIC -> PAD)
 8: NC
 9: ACK (PIC <- PAD) *接続せず

PIC <---> PS PAD
 VCC------5:Vcc 3.6V
          3:Vcc 7.6V
 RB.0*<---1:DAT     *PULL UP必要
 RB.1---->2:CMD
 RB.2---->6:SEL
 RB.3---->7:CLK
          9:ACK
 GND------4:GND
*/

persistent unsigned char pad_buf[10];
persistent unsigned char pad_byte;

/**
* 1バイト送受信
*/
unsigned char
pad_comm(unsigned char tx_chr) {
    unsigned char rx_chr, bitno;
    rx_chr = 0;
    bitno  = 8;
    do {
        //CCLKの立ち下がりで送信
        if(tx_chr & 1)    CCMD = 1;
        if(!(tx_chr & 1)) CCMD = 0;
        tx_chr = (tx_chr >> 1) | 0x80;
        CCLK = 0;
        DelayUs(12);
        //CCLKの立ち上がりで受信
        rx_chr = (rx_chr >> 1) | (CDAT << 7);
        CCLK = 1;
        DelayUs(12);
    } while(--bitno);
    //各BYTEの間隔を40us以上あける
    DelayUs(40);
    pad_buf[pad_byte] = rx_chr;
    pad_byte++;
    return rx_chr;
}


/*
* パッド情報取得
*/
void
pad_get(void) {
    unsigned char lastbyte;     //残りバイト数
    unsigned char rx_chr;       //受信データ
    pad_byte = 0;
    //SEL下げて、初めのCLK下げるまで2us待つ
    CSEL = 0;
    DelayUs(2);
    //1バイト送受信(送信[+0]=01h, 受信[+0]→不定(無視))
    rx_chr = pad_comm(0x01);
    //1バイト送受信(送信[+1]=42h, 受信[+1]→応答ID)
    rx_chr = pad_comm(0x42);
    if (rx_chr!=0 && rx_chr!=0xff) {
        //応答ID(下位4bit*2+1)→受信残りバイト数
        lastbyte = (rx_chr & 0x0f) << 1;
        //1バイト送受信(送信[+2]=00h), 受信データ[+2]→Z
        pad_comm(0x00);
        do {
            //1バイト送受信(送信[+3〜]=00h), 受信データ1バイトを格納
            pad_comm(0x00);
        } while(--lastbyte);
    }
    CSEL = 1;
}


#if DEBUG
//動作確認用 10進数で1バイトを表示
void
put1byte(unsigned char c)
{
    putch(((c /100)%10)+0x30);    //100の位を計算してアスキーコード0x30を足す
    putch(((c / 10)%10)+0x30);    // 10の位を計算してアスキーコード0x30を足す
    putch(((c     )%10)+0x30);    //  1の位を計算してアスキーコード0x30を足す
    return;
}

//動作確認用 16進数で1バイトを表示
void
put1hex(unsigned char c)
{
    unsigned char c0;
    unsigned char c1;
    c0 = c & 0b00001111;
    c1 = c & 0b11110000;
    c1 = c1 >> 4;
    if (c1 < 10) {
        putch(c1 + 0x30);
    } else {
        putch(c1 + 0x37);
    }
    if (c0 < 10) {
        putch(c0 + 0x30);
    } else {
        putch(c0 + 0x37);
    }
    return;
}
#endif

/**
 * ハンドル値0-0xffを0-0x7fに変換する
 * ハンドル値中心0x80付近に不感帯(0x68-0x97)を設ける
 */
unsigned char
marume(unsigned char c) {
    if (c >= 0x68 && c <= 0x97) {
        c = 0x80;
    }
    return (c >> 1) & 0x7f;
}

/**
 * パッドをアナログモードに固定化する
 */
void
set_analog() {
    unsigned char rx_chr;       //受信データ
    //コンフィギュレーションモードエンター
    pad_byte = 0;
    CSEL = 0;
    DelayUs(2);
    pad_comm(0x01);
    rx_chr = pad_comm(0x43);
    pad_comm(0x00);
    pad_comm(0x01);
    pad_comm(0x00);
    if (rx_chr == 0x73) {
        pad_comm(0x00);
        pad_comm(0x00);
        pad_comm(0x00);
        pad_comm(0x00);
    }
    CSEL = 1;
    DelayMs(16);
    //セットモード&ロック
    pad_byte = 0;
    CSEL = 0;
    DelayUs(2);
    pad_comm(0x01);
    pad_comm(0x44);
    pad_comm(0x00);
    pad_comm(0x01); // アナログモード
    pad_comm(0x03); // モード固定/ボタンにより切り替え不能
    pad_comm(0x00);
    pad_comm(0x00);
    pad_comm(0x00);
    pad_comm(0x00);
    CSEL = 1;
    DelayMs(16);
    //コンフィギュレーションモードイクジット
    pad_byte = 0;
    CSEL = 0;
    DelayUs(2);
    pad_comm(0x01);
    pad_comm(0x43);
    pad_comm(0x00);
    pad_comm(0x00);
    pad_comm(0x00);
    pad_comm(0x00);
    pad_comm(0x00);
    pad_comm(0x00);
    pad_comm(0x00);
    CSEL = 1;
    DelayMs(16);
}

/*
* メイン
*/
void
main(void){
    unsigned char i;            //ループ用
    unsigned char j = 0;        //活性監視LED点滅用
    unsigned char pad_mode;     //コントローラのタイプ
    unsigned char rcb_buf[8];   //RCB-3への送信データ

    //ポート初期化
    TRISA = 0b00010000; //(in)RA4:CDAT
    TRISB = 0b00000000;
    //処理開始
    DelayMs(16);
    CSEL = 1;
    CCLK = 1;

    while(1){
#if DEBUG
        //DEBUG情報
        putch(0x0d); //改行
        putch(0x0a); //改行
        put1byte(j);
        putch(0x20); //空白
        putch(0x20); //空白
#endif
        //パッド情報の取得
        DelayMs(16);
        pad_get();
        pad_mode = (pad_buf[1] & 0xf0) >> 4;
        //デジタルモードなら強制的にアナログモードへ
        if (pad_mode == 4) {
            DelayMs(16);
            set_analog();
            pad_get();
        }
        //アナログモードなら処理続行
        if (pad_mode == 7) {
#if DEBUG
            //パッド情報の表示
            for(i=0; i<pad_byte; i++) {
                put1hex(pad_buf[i]);
                putch(0x20); //空白
            }
            putch(0x20); //空白
            putch(0x20); //空白
#endif
            rcb_buf[0] = 0x80; //固定
            rcb_buf[1] = 0;
            if ((pad_buf[3] & 0x01) == 0) rcb_buf[1] += 0x40; //PS:SL
            if ((pad_buf[3] & 0x08) == 0) rcb_buf[1] += 0x20; //PS:ST
            if ((pad_buf[4] & 0x02) == 0) rcb_buf[1] += 0x10; //PS:R2
            if ((pad_buf[4] & 0x08) == 0) rcb_buf[1] += 0x08; //PS:R1
            if ((pad_buf[4] & 0x01) == 0) rcb_buf[1] += 0x04; //PS:L2
            if ((pad_buf[4] & 0x04) == 0) rcb_buf[1] += 0x02; //PS:L1
            if ((pad_buf[4] & 0x80) == 0) rcb_buf[1] += 0x01; //PS:□
            rcb_buf[2] = 0;
            if ((pad_buf[4] & 0x20) == 0) rcb_buf[2] += 0x40; //PS:○
            if ((pad_buf[4] & 0x40) == 0) rcb_buf[2] += 0x20; //PS:×
            if ((pad_buf[4] & 0x10) == 0) rcb_buf[2] += 0x10; //PS:△
            if ((pad_buf[3] & 0x80) == 0) rcb_buf[2] += 0x08; //PS:左
            if ((pad_buf[3] & 0x20) == 0) rcb_buf[2] += 0x04; //PS:右
            if ((pad_buf[3] & 0x40) == 0) rcb_buf[2] += 0x02; //PS:下
            if ((pad_buf[3] & 0x10) == 0) rcb_buf[2] += 0x01; //PS:上
            rcb_buf[3] = marume(pad_buf[7]); //左ハンドル左右
            rcb_buf[4] = marume(pad_buf[8]); //左ハンドル上下
            rcb_buf[5] = marume(pad_buf[5]); //右ハンドル左右
            rcb_buf[6] = marume(pad_buf[6]); //右ハンドル上下
            rcb_buf[7] = (rcb_buf[1] + rcb_buf[2] + rcb_buf[3] + rcb_buf[4] + rcb_buf[5] + rcb_buf[6]) & 0x7f;
            for(i=0; i<8; i++) {
#if DEBUG
                put1hex(rcb_buf[i]);
                putch(0x20); //空白
#else
                putch(rcb_buf[i]);
#endif
            }
            //活性監視LED点滅
            j++;
            if ((j & 0x04)!=0) RB0=1;
            if ((j & 0x04)==0) RB0=0;
        }
    }

}