赤外線リモコンの信号を受信しLEDを点灯させるプログラムです。
リモコンの「1」ボタンを押すと「LED1(RA2)」 が点灯します。
再び「1」を押すとLEDは消灯します。
同様に、リモコンの「2」「3」「4」が
それぞれ LED2(RC0)」「LED3(RC1)」「LED4(RC2)」に対応します。
PICのペリフェラルは以下の用途に使用しています。
この受信機は、JVCTVリモコンの使用を想定したプログラムになっています。JVCは、NECが設定した赤外線リモコン仕様に準拠しており、以下のフォーマット仕様です。
キャリア | 赤外線(λp = 940nm) | Data部 詳細 (T = 562μs) | |
サブキャリア | fsc = 38kHz, 1/3duty | Data の '1' | Mark 1T + Space 3T |
Leader 部 | Mark 9mSec Space 4.5mSec | Data の '0' | Mark 1T + Space 1T |
Data 部 | 固定長フレーム (16bit) 8bitのカスタマーコード + 8bitのコマンドデータ |
Stop bit | Mark 1T |
JVCの汎用リモコンをビクターに設定した時のキーと出力される16ビットコードの関係を示します。
出力される16bitコード | |||||||
---|---|---|---|---|---|---|---|
入力切換 | C0C8 | 大 | C078 | 1 | C084 | 7 | C0E4 |
電源 | C0E8 | 小 | C0F8 | 2 | C044 | 8 | C014 |
タイマー | C0C0 | 消音 | C038 | 3 | C0C4 | 9 | C094 |
BS/e2 | C030 | + | C098 | 4 | C024 | 10 | C054 |
地デジ | F0A8 | − | C018 | 5 | C0A4 | 11 | C0D4 |
機能 | 赤外線の出力なし | 6 | C064 | 12 | C034 |
2本のプログラム例を示します。
一番目は、赤外線コードが終了するまで、赤外線センサーの信号をメインプロブラムのフローで常時監視し、On/OffをTimer1で計測します。
2番目のプログラムは、センサーからの信号は、I-O-C (Interrupt-on-Change)を利用し、割り込み処理の中で処理し、データが正しく取得された時に、主プロブラムに通知し、LEDを点灯します。
/********************************************************************* * NECタイプの赤外線リモコン受信 * LED1 RA2, LED2 RC0, LED3 RC1, LED4 RC2 * Sencer RA5 * 1MHz (内部クロック) * * PIC16F18325 MPLAB X IDE with XC8 * Copyright (c) 2017 iwamoto All Rights Reserved * *******************************************************************/ #define _XTAL_FREQ 1000000 // delay_ms(x) のための定義 #define L_ON_Min 5000 // 5msec リーダーの最小継続時間 #define DataTH 1000 // 1msec データの「1」「0」境界時間 #define D_Off_Max 2000 // 2msec データ「0」の最大継続時間 #define IrIN RA5 // 赤外線センサー入力 #define LED1 LATA2 #define LED2 LATC0 #define LED3 LATC1 #define LED4 LATC2 #include <xc.h> //******************* コンフィグレーション **************************** #pragma config FEXTOSC = OFF,RSTOSC = HFINT1 // HFINTOSC (1MHz) #pragma config CLKOUTEN = OFF,CSWEN = ON,FCMEN = OFF #pragma config MCLRE = OFF,PWRTE = OFF,WDTE = OFF,LPBOREN = OFF #pragma config BOREN = OFF,BORV = LOW,PPS1WAY = OFF,STVREN = ON #pragma config DEBUG = OFF #pragma config WRT = OFF,LVP = OFF,CP = OFF,CPD = OFF unsigned int IrCmdRcv(void); // MAIN ******************************************************** void main(void){ unsigned int revdData; ANSELA = 0; // 全てデジタルI/O ANSELC = 0; // 全てデジタルI/O TRISA = 0b111011; // RA2 LED出力 他は入力 TRISC = 0b111000; // RC0-RC2 LED出力 他は入力 LATA = 0; // LED 初期化 LATC = 0; // LED 初期化 WPUA = 0b111111; // 入力は全て弱プルアップ WPUC = 0b111111; // 入力は全て弱プルアップ // Pin 状態変化 初期化 ------------------------------------- IOCANbits.IOCAN5 = 1; // 負極性の変位でWake-up PIE0bits.IOCIE = 1; // Wake-up 許可 // Timer 1 設定 ------------------------------------------- // リモコンパルス幅の計測に使用する Timer は、1カウント 1uS T1CON = 0b01000000; // Timer 1 FOSC 1/1(66mSecごと) T1GCON = 0b00000000; // Timer 1 Gate設定(使用せず) while(1){ // 繰り返しループ TMR1ON = 0; // Timer1 OFF IOCAFbits.IOCAF5 = 0; // 入力変位フラッグ クリア SLEEP(); // 無信号時はスリープ //-------------------- TMR1ON = 1; // Timer1 ON revdData = IrCmdRcv(); // データー取得 if(revdData == 0) continue; // データー無 // ---- 受信データーの処理 ----------------------------------- switch (revdData){ case 0xC084: LED1 ^= 1; break; // Key 1 LED1 反転 case 0xC044: LED2 ^= 1; break; // Key 2 LED2 反転 case 0xC0C4: LED3 ^= 1; break; // Key 3 LED3 反転 case 0xC024: LED4 ^= 1; break; // Key 4 LED4 反転 default: LATA = 0; LATC = 0; break; // 他のKey 全消灯 } } } //*************** 赤外線データーを受信する ***************************** // 正常にデーターを受信したときは、そのデーターを返り値とし // 無信号、エラー時は、0を返す。 // ビクターの信号体系(NEC系)を受信 // リーダ受信確認、データ受信(16bits)する //******************************************************************* unsigned int IrCmdRcv(void){ unsigned int rcvData = 0; if(IrIN) return 0; // 無信号「1」時は復帰 // ------- Start Bit (リーダー)の確認 ----------------------------- //OnおよびOFFの時間を確認しノイズか有効データか判断する // --------------------------------------------------------------- TMR1 = 0; // -- リーダーのON 時間測定 while(TMR1 < L_ON_Min){ // リーダーの最小継続に達しないのに if(IrIN)return 0; // IR Space「1」無信号になったら } // ノイズと判断し復帰 while(!IrIN); // IR Space 待ち TMR1 = 0; // -- リーダーのOFF時間測定 while(IrIN){ // リーダーの終了時間を越えても待ち if(TMR1 > L_ON_Min)return 0; // data開始(IrON)しなければ復帰 } // ------- dataの確認 ----------------------------------- for(char i = 0; i < 16; i++){ // 1ビットずつ16回繰り返す rcvData <<= 1; while(!IrIN); // space 開始を待つ TMR1 = 0; // Bitのspace時間測定開始 while(IrIN) // space 終了を待つ if(TMR1 > D_Off_Max) // 2mS以上ならStopなので return 0; // 復帰 if(TMR1 > DataTH) // 時間取得「1」「0」判定 rcvData |= 1; // 「1」を立てる } return rcvData; // 受信データを持って復帰 }
赤外線センサーからの信号を全て割り込み(I-O-C)で処理するプログラム
/********************************************************************* * NECタイプの赤外線リモコン受信 * LED1 RA2, LED2 RC0, LED3 RC1, LED4 RC2 * Sencer RA5 * 1MHz (内部クロック) I-O-C を使用して受信情報を割り込みで処理 * * PIC16F18325 MPLAB X IDE with XC8 * Copyright (c) 2017 iwamoto All Rights Reserved * *******************************************************************/ #define _XTAL_FREQ 1000000 // delay_ms(x) のための定義 // IR 閾値 *********************************************** #define L_ON_Min 5000 // 5msec リーダーの最小継続時間 #define DataTH 1000 // 1msec データの「1」「0」境界時間 #define D_Off_Max 2000 // 2msec データ「0」の最大継続時間 // Pin設定 *********************************************** #define IrIN RA5 // 赤外線センサー入力 #define LED1 LATA2 // LED #define LED2 LATC0 #define LED3 LATC1 #define LED4 LATC2 // ステート名 *********************************************** #define leaderStart 0 #define leaderMkEnd 1 #define dataStart 2 #define dataMkEnd 3 #define dataBitEnd 4 #define waitGap 5 #include <xc.h> #include <stdint.h> //******************* コンフィグレーション **************************** #pragma config FEXTOSC = OFF,RSTOSC = HFINT1 // HFINTOSC (1MHz) #pragma config CLKOUTEN = OFF,CSWEN = ON,FCMEN = OFF #pragma config MCLRE = OFF,PWRTE = OFF,WDTE = OFF,LPBOREN = OFF #pragma config BOREN = OFF,BORV = LOW,PPS1WAY = OFF,STVREN = ON #pragma config DEBUG = OFF #pragma config WRT = OFF,LVP = OFF,CP = OFF,CPD = OFF // プロトタイプ *********************************************** void IrCmdRcv(void); // 共通変数 *********************************************** uint8_t state = 0; uint8_t gapFlag = 0; uint16_t revdData = 0; // MAIN ******************************************************** void main(void){ ANSELA = 0; // 全てデジタルI/O ANSELC = 0; // 全てデジタルI/O TRISA = 0b111011; // RA2 LED出力 他は入力 TRISC = 0b111000; // RC0-RC2 LED出力 他は入力 LATA = 0; // LED 初期化 LATC = 0; // LED 初期化 WPUA = 0b111111; // 入力は全て弱プルアップ WPUC = 0b111111; // 入力は全て弱プルアップ // Pin 状態変化 I-O-C設定 ----------------------------------- IOCANbits.IOCAN5 = 1; // 立下がり検出 IOCAPbits.IOCAP5 = 1; // 立上がり検出 IOCAFbits.IOCAF5 = 0; // 入力変位フラッグ クリア PIE0bits.IOCIE = 1; // 割り込み許可 // Timer 1 設定 ------------------------------------------- // リモコンパルス幅の計測に使用する Timer は、1カウント 1uS T1CON = 0b01000000; // Timer 1 FOSC 1/1(66mSecごと) T1GCON = 0b00000000; // Timer 1 Gate設定(使用せず) PIE1bits.TMR1IE = 1; // Timer 1 割込みの許可 PEIE = 1; // 周辺機能割込みの使用許可 GIE = 1; // 全割込みの使用許可 gapFlag = 1; // Gap フラグ セット while(1){ // 繰り返しループ ------------------ if(gapFlag){ // Gap なら gapFlag = 0; // Ir信号受信まで // ------------ // ---------- SLEEP(); // Sleep // ------------ // ---------- } if(revdData == 0) continue; // 受信完了までループして待つ // ---- 受信データーの処理 ----------------------------------- switch (revdData){ case 0xC084: LED1 ^= 1; break; // Key 1 LED1 反転 case 0xC044: LED2 ^= 1; break; // Key 2 LED2 反転 case 0xC0C4: LED3 ^= 1; break; // Key 3 LED3 反転 case 0xC024: LED4 ^= 1; break; // Key 4 LED4 反転 default: LATC = 0; break; // 他のKey 全消灯 } revdData = 0; } } //----------------------割込み処理------------------------ void interrupt IOC_isr(void){ // Ir信号がOnOffした --------------------------------- if(IOCIF){ //IRsencerからの割込みを確認 IOCAF = 0; // 割込みフラッグをクリア IrCmdRcv(); // 受信処理 } // Gapを検出した -------------------------------------- if(TMR1IF){ //Timer1からの割込みを確認 TMR1IF = 0; // 割込みフラッグをクリア TMR1ON = 0; // Timer1 OFF gapFlag = 1; // Gap 検出 state = leaderStart; } } void IrCmdRcv(void){ static uint8_t num; // 受信Bit数を計測 static uint16_t IrData; // 受信データを蓄積 uint16_t timeIntvl = TMR1; // データ間隔 TMR1 = 0; // 次の間隔測定のため // ステート制御 ***************************************************** switch(state){ case leaderStart: // leader Mark 開始時 ⥥ ------- TMR1ON = 1; // Timer1 ON if(!IrIN) // Markなら state = leaderMkEnd; // leader Mark 終了 待ちへ break; case leaderMkEnd: // leader Mark 終了 ⥣ ---------- if(timeIntvl > L_ON_Min) // リーダー最小継続を超えるなら state = dataStart; // data Mark 開始 待ちへ else // 最小継続 未満なら state = waitGap; // Timer1 count up 待ちへ break; case dataStart: // data Mark 開始時 ⥥ ------------ num = 16; // 受信Bit数リセット IrData = 0; // 受信dataリセット state = dataMkEnd; // data Mark 終了 待ちへ break; case dataMkEnd: // data Mark 終了 ⥣ ------------ state = dataBitEnd; // data Bit 終了 待ちへ break; case dataBitEnd: // data Bit 終了 ⥥ ------------ if(timeIntvl > DataTH) // スペース時間で「1」「0」判定 IrData |= 1; // 長ければ「1」 num--; // 受信Bit数の確認 if(num){ // 途中なら IrData <<= 1; // 次 Bitの準備 state = dataMkEnd; // 次 data bit 受信へ }else{ // 終了なら revdData = IrData; // 結果を保存 state = waitGap; // Timer1 count up 待ちへ } break; case waitGap: // Gap 待ち ------------ break; // Timer1 timeUpを待つ } }