Vol.886 12.Jan.2024

1台4役カークリーナー 赤外線リモコン(9)SONYリモコン

C 1台4役カークリーナー

by fjk

 キャンピングカーのシュピーレンにはDC12Vのカークリーナーを常備しているが、空気枕用のポンプ(電池式)とタイヤ用コンプレッサ(DC12V)は別で、万が一を考慮し、旅行時のみ車に乗せている。
 正月早々、ソースネクストからのメールで、「1台4役カークリーナー」(池商)が、タイムセールで65%引きの4,980円で売られていることを知り、1台で掃除機@だけでなく、空気枕やタイヤの空気入れAにも使えるとあり、ついポチり。
 地震の発生前に注文していたが、地震により配達が遅れるかと思っていたが、当初の予定日の前日には到着した。早速、DC12Vのシガーソケットに繋いで動作を確認したところ、クリーナーの吸引力はまあまあで音もそれなり。フレキシブルなロングノズルもついているので狭いところでも使えそう。また、コンプレッサは目安となるエアーゲージBがついているので便利だが音はかなり大きい(空気枕は約1分、タイヤ・自転車の空気入れもOK)。さらに、DC12V電源ケーブルは4.2mあるので装着タイヤまで届きそう。そして、LEDライトCもついているので夜間でも使えそう。ただし、連続使用時間は10分以内となっている。


クリーナーセット

空気枕にエアー充填中


R 赤外線リモコン (9)   〜SONYリモコン

by fjk

 abc869までで、変形NECフォーマットリモコンであるIODataリモコンをPICで実現した。これを参考に類似のNECフォーマットリモコンもチョット変更するだけで実現できそうである。
 しかしNEC系では space(0)の長さ(時間)が変わるが、SONY系は mark(1)の長さ(時間)が変わるフォーマットで、abc856で紹介した解読器では正しいビットデータが得られない。また、SONYフォーマットでは、ボタンを押している間中、同じリモコンコード(フレーム)を45ms毎に繰り返し送信している。
【SONYフォーマット】
・サブキャリア = 40 kHz(キャリア=950nm)
・T = 600uS(0:T、1:2T[マーク部])
・データ: 7ビット
・アドレス:5/8/13ビット

NECフォーマットでSONY信号解析

 そこで、PICを使ってSONYリモコンコードを解読し、リモコンとして作ることにした。解読に使用する受信用のハードはabc856のものをそのまま使っても良いが、いずれ送信にも使いたいので、赤外線送受信機能を持つコンパクトな物を新たに作ることにした(今回は受信のみ利用)。なお、I2CによるLCD表示部は汎用利用出来るよう、別ブロックで作成することにし、今回は実装していない。


リモコン回路図(PIC16F18424)

ブレッドボードで作成した回路

 PICの設定はabc856とほぼ同じだが、LCD表示部がないのでI2Cは設定していない。念のためにMCCの設定も紹介しておく。
 なお、DSMとCLCも設定したが、送信用なので今回は使っていない(今回は設定しなくても良い)。


TMR2

PWM6

STM1

EUSAT1

DSM

CLC1

 プログラムはabc856をベースに、SONY信号解析部を追加した。当初、NECとSONYの解析切替にはスイッチ入力を使用したが、リーダー部の長さが異なる(NEC:約9000 uS/SONY:2400 uS)ことを利用して、自動でフォーマットを判断することにした(あくまでNECとSONYだけ識別)。
 プログラム開発で苦労したのは、PIC16F18424メモリの少なさである。ROMで4バイト(4092/4096)、RAMで1バイト(511/512)しか残っていない。当初はSONY解析部をNEC部と同様の内容で追加したところ「メモリ不足エラー」がでたので、共通で使える部分をまとめたところ、なんとかメモリ容量内におさめることができた。さらに、プログラムエリアを増やそうとサブルーチンを作成したところ、今度は「RAMが足りない」とエラーが出る。コードデータサイズを減らすとRAM不足エラーが出なくなるが、今度はリモコンデータ読取時にデータメモリ不足となる可能性がある。まだ修正できるが余地があるが、面倒なので、サブルーチンを使うことをあきらめた。当初のスイッチ入力によるフォーマットの指定も、今後の改良時に使うかも知れないので、ソースファイルにはそれらの痕跡をコメントとして残した。
 最終的に、赤外線リモコンのNEC(IO)フォーマットとSONYフォーマットを自動で判断し、その赤外線コードを解析し、表示することが出来た。
 なお、Sonyフォーマットの場合、ボタンを押している時間が長いと「Buffer Full」エラー(データは取得済み)となるので注意!。

 [USB接続パソコンのテラターム画面]

NEC(IO)信号を自動解析

SONY信号(12)を自動解析

SONY信号(15)を自動解析

SONY信号(20)を自動解析

【プログラム】 abc886-main.c(zip)
/***************************************************************
 * SMT Hight-Low mode で、赤外線リモコンのパルス幅をus単位で
 * 測定し、EUSARTからUSB変換器経由でPCに送信する
 **************************************************************/
#include "mcc_generated_files/mcc.h"				
#define maxdata 75                                      // 赤外線データー配列数

uint16_t PW[maxdata];                                   // Mark配列
int16_t  PR[maxdata];                                   // Space配列
uint8_t  p_PW;                                          // Mark配列ポインタ
uint8_t  p_PR;                                          // Space配列ポインタ
uint8_t  Sony;                                          // Sonyフォーマット?

/*======================================================
                         Main application
 ======================================================*/
void main(void)
{
    uint8_t ird;                                        // 赤外線データ
    uint8_t sbt;                                        // ビットセット用シフトバイト 
    uint8_t bct;                                        // 有効ビットデータカウンタ
    uint8_t sgf;

    SYSTEM_Initialize();                                // デバイス初期化
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    
    while (1)                                           // 赤外線信号受信 繰り返し
    {
        p_PW = 0;                                       // データポインタ初期化
        p_PR = 0;
        SMT1PWAIF = 0;                                  // フラグクリア
        SMT1PRAIF = 0;
        SMT1IF = 0;
        SMT1CON1bits.SMT1GO = 1;                        // 測定開始
        printf("\r\nready\r\n");                        // 準備完了メッセージ送信

        // ---------- 赤外線信号を受信する --------
        while((p_PR < maxdata)){                        // バッファ満杯まで繰返
/*        // ---- スイッチでモード設定(テスト用)
            if(IO_RC2_PORT){                            // キー入力チェック
                Sony = 7;                               //  -> SONY Mode
                IO_RC4_SetHigh();
            }else{
                Sony = 0;                               //  -> NEC Mode
                IO_RC4_SetLow();
            }
*/
            if(SMT1PWAIF){                              // mark終了なら
                SMT1PWAIF = 0;                          //   フラグクリア
                PW[p_PW++]=SMT1CPW;                     //   High時間を保存
            }
            if(SMT1PRAIF){                              // space終了なら
                SMT1PRAIF = 0;                          //   フラグクリア
                if(SMT1CPR < 10000){                    //   10ms未満なら
                    PR[p_PR++]=SMT1CPR;                 //     Low時間を保存
                }else{                                  //   10ms以上なら
                    PR[p_PR++]=-(SMT1CPR / 1000);       //     msに変換し負数で保存
                }
            }
            if(SMT1IF){                                 // 無信号が100ms続いたら
                SMT1IF = 0;                             //   フラグクリア
                PR[p_PR++]=0;                           //   無信号記号「0」を保存
                break;
            }
        }
        SMT1CON1bits.SMT1GO = 0;                        // 測定終了

        //---------- 受信結果を解析・送信する -------
        ird = 0;
        sbt = 1;
        bct = 0;
        sgf = 0;
     
        if(PW[0]<3000){                                 // リーダーが3000uS未満なら
            Sony = 7;                                   //  -> SONY Mode
            IO_RC4_SetHigh();
            printf(">SONY, %d\r\n",p_PW);
        }else{
            Sony = 0;                                   //  -> NEC Mode
            IO_RC4_SetLow();
            printf(">NEC, %d\r\n",p_PW);
        }
        
        printf(" -  mark  space (us)\r\n");             // タイトル送信
       
        for(char i=0;i < p_PW;i++){                     // 保存した時間を送信
            printf("%2d %5d",i,(uint16_t)PW[i]);        // mark時間
            if(PR[i]==0) {                              // 無信号なら
                printf("    ---");                      //  「---」を送信
            }else if(PR[i] > 0){                        // 10ms未満なら
                printf("  %5d",PR[i]);                  //   us単位で送信(改行を外す)
                if (Sony){                              // == SONY Code (Mark) ==     
                    if(PW[i] < 1500){                   // markが1500us未満なら
                        sgf = 1;                        // 有効データ 
                        if(PW[i] > 900){                // markが900us超なら
                            ird |= sbt;                 //   シフトバイトを加える
                            printf("  1");
                        }else{
                            printf("  0"); 
                        }
                    }
                }else{                                  // == NEC Code (Space) ==
                    if(PW[i] < 1500){                   // markが1500未満なら
                        if(PR[i]<2000){                 //   spaceが2000未満なら
                            sgf = 1;                    //     有効データ
                            if(PR[i]>900){              // spaceが900以上なら
                                ird |= sbt;             //   シフトバイトを加える
                                printf("  1");
                            }else{
                                printf("  0");
                            }
                        }
                    }
                }
                if(sgf){                                // 有効データなら 
                    sbt <<= 1;                          // シフトバイトを左へシフト
                    bct++;                              //   有効データ数を1増やす
                    if(Sony){
                        if(bct == Sony){
                            printf("  >> %02XH",ird);   // 16進数で送信
                            ird = 0;                    // 赤外データをクリア 
                            sbt = 1;                    // シフトバイトも初期化  
                            Sony = bct + 8;
                        }
                    }else{
                        if((bct % 8) == 0){             // データ数が8の倍数?
                            printf("  >> %02XH",ird);   //  16進数で送信
                            ird = 0;                    //  赤外データをクリア 
                            sbt = 1;                    //  シフトバイトも初期化  
                        }
                    }
                    sgf = 0;
                }
            }else{                                      // 10ms超なら
                printf("%7d (ms)",-PR[i]);              //   ms単位で送信
                if(Sony){                               // SONYモードで
                    if(PW[i] < 1500){                   // markが1500us未満なら
                        bct++;
                        if(PW[i] > 900){                // markが900us超なら
                            ird |= sbt;                 //   シフトバイトを加える
                            printf("  1");
                        }else{
                            printf("  0");
                        }
                        printf("  >> %02XH",ird);       // 16進数で送信
                        ird = 0;                        // 赤外データをクリア 
                        sbt = 1;                        // シフトバイトも初期化 
                        Sony = bct + 7;
                    }
                }
            }
            printf("\r\n");
        }

        if(p_PW >= maxdata){                           	// バッファ満杯なら
            printf("-- Buffer Full --\r\n");            //   Buffer Full 送信
        }
    }
}

/********  End of File ******/

※ 本プログラム作成にあたり、赤外線コード取得方法を参考にさせていただいた「初めてのPIC」さんに感謝。


※ 本レポートの参考・利用は、あくまでも自己責任でお願いします。


1台4役カークリーナー 赤外線リモコン(9)SONYリモコン