2023年11月30日木曜日

YAMAHA DSP-1のリモコンの製作

 

YAMAHA DSP-1のリモコンの製作

注意:このサイトの内容を鵜呑みにし、事故や損失を招いた場合でも当方は一切の責任は負いかねます。自己責任でお願いします。

YAMAHAのデジタル・サウンドフィールド・プロセッサ「DSP-1」は、リモコンが無いと操作が一切できません。

本体を手に入れてもリモコンが無くどうしようもなくなっている方もいるでしょう。

リモコンを入手しようとオークションサイトで探しても、本体よりリモコンの方が価格が高くなってしまっています。

そこで、DSP-1のリモコンを作ることにしました。


・DSP-1のリモコン仕様

型番 : RS-DSP-1
使用IC : μPD1943G
リモコンフォーマット : NECフォーマット
カスタムコード : 1バイトカスタムコード 0x7D
ボタン数 : 30


回路上の
ボタン番号
リモコン
コード
16進
ボタンの場所
(左上から0,0)
ボタン名
S0 00
S1 01 0,1 ACOUSTIC/SURROUND
S2 02 0,2 SOUND EFFECTOR
S3 03 0,3 USER PROGRAM
S4 04 1,0 1 (HALL 1/DELAY)
S5 05 1,1 2 (HALL 2/ST ECHO)
S6 06 1,2 3 (HALL 3/ST FLANGE A)
S7 07 1,3 4 (CHAMBER/ST FLANGE B)
S8 08 2,0 5 (MÜNSTER/CHORUS A)
S9 09 2,1 6 (CHURCH/CHORUS B)
S10 0A 2,2 7 (JAZZ CLUB/ST PHASING)
S11 0B 2,3 8 (ROCK CNCT/TREMOLO)
S12 0C 3,0 9 (DISCO/SYMPHONIC)
S13 0D 3,1 10 (PAVILION/ECHO ROOM)
S14 0E 3,2 11 (WHSE LOFT/PITCH CHANGE A)
S15 0F 3,3 12 (STADIUM/PITCH CHANGE B)
S16 10 4,0 13 (PRESENCE/L TURN)
S17 11 4,1 14 (SUR 1/R TURN)
S18 12 4,2 15 (SUR 2/F-R)
S19 13 4,3 16(Dolby SUR/L-R)
S20 14 5,0 PARAMETER
S_DGS 15 DIAGNOSTIC
S21 16 5,2 DEC
S22 17 5,3 INC
S23 18 6,0 TITLE EDIT
S24 19 0,0 MEMORY
S25 1A 6,2 BALANCE (FRONT)
S26 1B 6,3 LEVEL (UP)
S27 1C 7,0 MUTE (MAIN)
S28 1D 7,1 MUTE (EFFECT)
S29 1E 7,2 BALANCE (REAR)
S30 1F 7,3 LEVEL (DOWN)


μPD1943Gは32キーリモコン用送信用ICです。
機器メーカにそれぞれ割り当てられるカスタムコードをダイオードで設定できます。
ですので、別のリモコンを分解してμPD1943Gを手に入れればDSP-1を作ることができます。


今回はArduino(ATmega328p)でリモコンを作ってみます。




・回路図


Arduino UNO の場合


ATmrga328p、ATmrga168p、ATmrga88pを単体で使う場合


一部のボタン(S24:MEMORY)はRS-DSP-1と配置が異なるので注意してください。
また、RS-DSP-1にはないボタン(S0、S_DGS:診断)も一応配置しています。



・プログラム(Arduino ATmrga328p、ATmrga168p、ATmrga88p用)


// YAMAHA DSP-1 リモコン
// 詳細はμPD1943のデータシートを参照
// ©oy
// https://oykenkyu.blogspot.com/2023/07/psg-ssg.html

// UARTでも操作可('0'~'9'は0x00~0x09、'a'~は0x0A~に割り当て)
#define XTAL 16000000     // 水晶振動子の周波数
#define SERIALSPEED 38400 // UARTのボーレート

unsigned char data[8]; // ボタン状態保存

void setup()
{
    Serial.begin(SERIALSPEED * (16000000.0 / XTAL)); // シリアル通信開始

    DDRB |= 0x03;  // pin8~pin9_Ko6~Ko7 ボタンスキャン出力
    DDRD |= 0xFC;  // pin2~pin7_Ko0~Ko5 ボタンスキャン出力
    DDRC &= 0xF0;  // pin14~pin17_Ki0~Ki3 ボタンスキャン入力
    PORTC |= 0x0F; // pin14~pin17_Ki0~Ki3 ボタンスキャン入力プルアップ

    DDRB |= 0x04; // 赤外線LED

    for (int i = 0; i < 8; i++)
    {
        data[i] = 0x00;
    }
}

void loop()
{
    unsigned char scan_data = 0;
    int tx_time = 0;                 // 押しっぱなし時間カウント
    unsigned int custom_code = 0x827D; // DSP-1

    while (1)
    {
        // スキャンと送信
        for (unsigned char i = 0; i < 8; i++)
        {
            scan_data = scan_4bit_tr(key_scan(i));
            if ((scan_data >> 4) != 0x0F) // スキャンデータと保存しているデータを比較
            {
                tx_time += nec_frame_send(custom_code, (i << 2) | scan_data); // データ送信

                delay(70);//押しっぱなしで連打の場合有効
                while (scan_4bit_tr(key_scan(i)) != 0xF0)
                {
                    // 押しっぱなしの時
                    delay(1);
                    tx_time++;
                    // リピート
                    if (tx_time >= 108)
                    {
                        //準フォーマット
                        tx_time = 0;
                        tx_time += nec_repeat_send(); // 約11ms
                       
                        //押しっぱなしで連打の場合
                        //tx_time = 255;// 待機時間なし
                        //tx_time += nec_frame_send(custom_code, (i << 2) | scan_data); // データ送信

                    }
                }
                delay(30); // チャタリング防止
            }
        }
        // uartで操作
        if (Serial.available() > 0)
        {
            scan_data = Serial.read();
            if ((scan_data <= '9') && (scan_data >= '0'))
            {
                nec_frame_send(custom_code, scan_data - '0'); // データ送信
            }
            else if ((scan_data <= 'z') && (scan_data >= 'a'))
            {
                nec_frame_send(custom_code, scan_data - 'a' + 10); // データ送信
            }
        }
    }
}

// 4bit分スキャン
unsigned char key_scan(unsigned char line)
{
    unsigned char sel_temp = 0;
    sel_temp = 1 << line;

    PORTB = (PORTB & 0xFC) | 0x03; // すべてH
    PORTD = (PORTD & 0x03) | 0xFC; // すべてH
    DDRD = (PORTB & 0xFC);         // すべて入力(プルアップ)
    DDRD = (PORTD & 0x03);         // すべて入力(プルアップ)

    PORTB = (PORTB & 0xFC) | ((~(sel_temp>>6)) & 0x03); // pin8~pin9_D6~D7
    PORTD = (PORTD & 0x03) | ((~(sel_temp<<2)) & 0xFC); // pin2~pin7_D0~D5

    DDRD = (PORTB & 0xFC) | ((sel_temp>>6) & 0x03); // 指定した行のみ出力に設定
    DDRD = (PORTD & 0x03) | ((sel_temp<<2) & 0xFC); // 指定した行のみ出力に設定

    delayMicroseconds(10);
    return 0x0F & (~PINC);
}

// スキャンデータから押されたボタンの番号を返す(同時押し無効)
unsigned char scan_4bit_tr(unsigned char data)
{
    unsigned char ret_num = 0xFF; // 同時押しの場合
    if (data == 0x08)
    {
        ret_num = 3;
    }
    else if (data == 0x04)
    {
        ret_num = 2;
    }
    else if (data == 0x02)
    {
        ret_num = 1;
    }
    else if (data == 0x01)
    {
        ret_num = 0;
    }
    else if (data == 0x00)
    {
        // 押していない時
        ret_num = 0xF0;
    }
    return ret_num;
}
/////////////////////////////////////////////////////////////

// NECフォーマット_データ送信
int nec_frame_send(unsigned int custom, unsigned char data)
{
    // 50ms前後
    int ret_tim=0;
    ret_tim += nec_leader();               // リーダー送信
    ret_tim += nec_byte_send(custom);      // カスタムコードbit0~bit7
    ret_tim += nec_byte_send(custom >> 8); // カスタムコード(16bitカスタムコードの場合はbit8~bit15、8bitカスタムコードの場合はbit0~bit7の反転)
    ret_tim += nec_byte_send(data);        // データ
    ret_tim += nec_byte_send(~data);       // データ反転
    ret_tim += nec_bit_l();                // ストップビット

    Serial.print("custom: 0x");
    Serial.print(custom, HEX);

    Serial.print(" key: 0x");
    Serial.print(data, HEX);
    Serial.print("\r\n");
    return ret_tim;//送信時間
}
// NECフォーマット_リピート送信
int nec_repeat_send()
{
    // NECフォーマット_リピート
    // T=562μs、H:16T、L:4T
    //
    for (int i = 0; i < 356; i++) // 約9.27ms
    {
        ir_38khz_prd();
    }
    for (int i = 0; i < 4; i++) // 約2.25ms
    {
        delayMicroseconds(562);
    }
    nec_bit_h();
    Serial.print("repeat\r\n");
    return 11;//送信時間
}

int nec_byte_send(unsigned char data)
{
    // NECフォーマット_バイト送信
    int ret_tim=0;
    for (int i = 0; i < 8; i++)
    {
        if (((data >> i) & 0x01) == 1)
        {
            ret_tim += nec_bit_h();

        }
        else
        {
            ret_tim += nec_bit_l();
        }
    }
    return ret_tim;//送信時間
}

int nec_bit_h()
{
    // NECフォーマット_ビットH
    // T=562μs、H:T、L:3T
    //
    for (int i = 0; i < 21; i++) // 約546μs
    {
        ir_38khz_prd();
    }
    delayMicroseconds(15);

    delayMicroseconds(562);
    delayMicroseconds(562);
    delayMicroseconds(562);
    return 2;//送信時間
}

int nec_bit_l()
{
    // NECフォーマット_ビットL
    // T=562μs、H:T、L:T
    //
    for (int i = 0; i < 21; i++) // 約546μs
    {
        ir_38khz_prd();
    }
    delayMicroseconds(15);

    delayMicroseconds(562);
    return 1;//送信時間
}

int nec_leader()
{
    // NECフォーマット_リーダー
    // T=562μs、H:16T、L:8T
    //
    for (int i = 0; i < 356; i++) // 約9.27ms
    {
        ir_38khz_prd();
    }
    for (int i = 0; i < 8; i++) // 約4.50ms
    {
        delayMicroseconds(562);
    }
    return 11;//送信時間
}

// サブキャリア
inline void ir_38khz_prd()
{
    // 本当はタイマーで作ると良い
    // 38.46kHz
    PORTB |= 0x04;         // pin10=H
    delayMicroseconds(9);  // 本当は8.772μs
    PORTB &= ~0x04;        // pin102=L
    delayMicroseconds(17); // 本当は17.54μs
}




・制作例


















0 件のコメント:

コメントを投稿