2010年11月12日金曜日

赤外線リモコンの受信

概要:赤外線リモコンの信号受信
使用PIC:PIC16F88
赤外線リモコン受信モジュール:PL-IRM-2161-C438(秋月電子通商で購入)
使用リモコン:NECのテレビリモコン

参考サイト
PICとMikroCのTVリモコン信号の受信機 のコーナーは非常に参考になりました。
リモコンのフォーマットは 秋月電子通商のダウンロードコーナーの資料も大いに役立ちます。
手元にNECのテレビリモコンがあってラッキーでした。



タイマTMR0を使用しての時間の計測
内部クロックの周期は(1/4MHz)*4=1usとなる。
TMR0は8bitのカウンタであるため,
TMR0は,256us(1us * 256)までの時間を計測することができる。
これではリーダー部の9msを計測できないのでプリスケーラを設定する。

プリスケーラ1/64に設定
(1/4MHz)*4*64=64us=0.0664ms
TMR0は,16.384ms(64us * 256)までの時間を計測することができるようになる.
0.064msから16.384ms の間の時間を計測できる。

リーダ部の9ms を計測したい場合に必要なタイマーカウント、
9ms = 0.064ms * x
x = 9ms/0.064ms
x = 140.625 = 141回
  1. /** 
  2. 概要:TVリモコン信号(赤外線)受信器 
  3. (ボタンと押している間だけLED点灯、ボタンをはなすとLED消灯) 
  4.  
  5. Device Flags: _BODEN_OFF _BOREN_OFF _CP_OFF _PWRTE_ON _WDT_OFF 
  6.        _LVP_OFF _MCLRE_OFF _INTRC_OSC_NOCLKOUT 
  7.  
  8. PICとMikroCさん(http://kuri6005.sakura.ne.jp/pic/)のソースを 
  9. PIC16F88  内蔵4MHzに変更 
  10. RB0:赤外線リモコン受信モジュール PL-TRM2161-C438 二個で100円 
  11. LED: RB2, RB3, RB4, RB5 動作確認用 
  12. 電源:乾電池2本(3V) 
  13. コンパイラ:MikroC 8.2.0.0 
  14. */  
  15. unsigned short int flag = 0;  
  16. unsigned short int custom_a = 0;  
  17. unsigned short int custom_b = 0;  
  18. unsigned short int data_a = 0;  
  19. unsigned short int data_b = 0;  
  20. unsigned short int old_F2 = 0;  
  21. unsigned short int old_F3 = 0;  
  22. unsigned short int old_F4 = 0;  
  23. unsigned short int old_F5 = 0;  
  24.   
  25. void interrupt() {            //割込み関数  
  26.     unsigned short int i, b;  
  27.   
  28.     if(INTCON.INTF) {         //割込み種がRB0/INT割込みの場合  
  29.         INTCON.INTE = 0;      //RB0/INT割込みの禁止  
  30.   
  31.         //リーダ部の確認        時間の計測にはタイマー0を割込みなしで使用  
  32.         TMR0 = 0;            //timer0リセット、タイマーは常に動作  
  33.           
  34.         while(PORTB.F0 == 0);   //0Vの状態をカウント、5Vになるまでループ  
  35.                                 //カウンタの比較  
  36.         if(TMR0 < 120) {       // < 141 (=9.0ms * 4MHz/4 /64) 誤差を見越して120  
  37.             flag = 1;           //120より少なかったらヘッダではないので受信を終了し、  
  38.             return;             //メインルーチンに戻り、受信待ち状態にします  
  39.         }                       //120以上であれば次に進みます。  
  40.   
  41.                    //リーダー部の残りの部分を判定  
  42.         TMR0 = 0;            //timer0リセット  
  43.         while(PORTB.F0 == 1);   //5Vの状態をカウント  
  44.         if(TMR0 < 27) {        // < 35 (=2.250ms * 4MHz/4 /64)  
  45.             flag = 1;  
  46.             return;  
  47.         }else if(TMR0 < 60) { // < 71 (=4.5ms * 4MHz/4 /64)  
  48.             //リピートリーダを受信した時  
  49.             PORTB.F2 = old_F2;  
  50.             PORTB.F3 = old_F3;  
  51.             PORTB.F4 = old_F4;  
  52.             PORTB.F5 = old_F5;  
  53.             Delay_ms(96);  
  54.             flag = 1;  
  55.             return;  
  56.         }  
  57.         //リーダー部の確認終了  
  58.   
  59.         //custom codeの取得  
  60.         custom_a = 0;  
  61.         for (i = 0; i < 8; i++) {   //繰返し0-7になるまで  
  62.             TMR0 = 0;         //timer0リセット  
  63.             while(PORTB.F0 == 0);     //0Vの期間をカウント  
  64.             while(PORTB.F0 == 1);     //5Vの期間をカウント  
  65.             if(TMR0 < 27)       // < 18 (=1.125ms * 4MHz/4 /64) 誤差を見越して27(35より小さい値)  
  66.                 b = 0;  
  67.             else                // < 35 (=2.250ms * 4MHz/4 /64)  
  68.                 b = 1;  
  69.             custom_a |= (b << i);     //custom_aと(b << i)の論理和をcustom_aに代入する  
  70.                      //bを左にiビットずらす  
  71.         }  
  72.         custom_b = 0;  
  73.         for (i = 0; i < 8; i++) {  
  74.             TMR0 = 0; //timer0リセット  
  75.             while(PORTB.F0 == 0);  
  76.             while(PORTB.F0 == 1);  
  77.             if(TMR0 < 27) // < 18 (=1.125ms * 4MHz/4 /64)  
  78.                 b = 0;  
  79.             else          // < 35 (=2.250ms * 4MHz/4 /64)  
  80.                 b = 1;  
  81.             custom_b |= (b << i);  
  82.         }  
  83.         //custom codeの取得終了  
  84.   
  85.         //data codeの取得  
  86.         data_a = 0;  
  87.         for (i = 0; i < 8; i++) {  
  88.             TMR0 = 0; //timer0リセット  
  89.             while(PORTB.F0 == 0);  
  90.             while(PORTB.F0 == 1);  
  91.             if(TMR0 < 27) // < 18 (=1.125ms * 4MHz/4 /64)  
  92.                 b = 0;  
  93.             else          // < 35 (=2.250ms * 4MHz/4 /64)  
  94.                 b = 1;  
  95.             data_a |= (b << i);  
  96.         }  
  97.   
  98.     data_b = 0;  
  99.         for (i = 0; i < 8; i++) {  
  100.             TMR0 = 0; //timer0リセット  
  101.             while(PORTB.F0 == 0);  
  102.             while(PORTB.F0 == 1);  
  103.             if(TMR0 < 27) // < 18 (=1.125ms * 4MHz/4 /64)  
  104.                 b = 0;  
  105.             else          // < 35 (=2.250ms * 4MHz/4 /64)  
  106.                 b = 1;  
  107.             data_b |= (b << i);  
  108.         }  
  109.         //while(PORTB.F0 == 0); //ストップビット受信  
  110.   
  111.         //data_aとdata_bの各ビットを反転しその結果が同じか比較  
  112.         if (data_a == ~data_b) {  //data誤りのチェックOKの場合  
  113.             switch (data_a) {  
  114.                 case 0x11:     //2チャンネルのボタンが押されている場合  
  115.                     PORTB.F2 = 1;   //RB2ポートのLEDを点灯する。  
  116.                     PORTB.F3 = 0;  
  117.                     PORTB.F4 = 0;  
  118.                     PORTB.F5 = 0;  
  119.                     break;  
  120.   
  121.                 case 0x13:      //4チャンネルのボタンが押されている場合  
  122.                     PORTB.F2 = 0;  
  123.                     PORTB.F3 = 1;  
  124.                     PORTB.F4 = 0;  
  125.                     PORTB.F5 = 0;  
  126.                     break;  
  127.   
  128.                 case 0x15:      //6チャンネルのボタンが押されている場合  
  129.                     PORTB.F2 = 0;  
  130.                     PORTB.F3 = 0;  
  131.                     PORTB.F4 = 1;  
  132.                     PORTB.F5 = 0;  
  133.                     break;  
  134.   
  135.                 case 0x17:      //8チャンネルのボタンが押されている場合  
  136.                     PORTB.F2 = 0;  
  137.                     PORTB.F3 = 0;  
  138.                     PORTB.F4 = 0;  
  139.                     PORTB.F5 = 1;  
  140.                     break;  
  141.   
  142.                 default:  
  143.                     PORTB.F2 = 0;  
  144.                     PORTB.F3 = 0;  
  145.                     PORTB.F4 = 0;  
  146.                     PORTB.F5 = 0;  
  147.                     break;  
  148.             }  
  149.             old_F2 = PORTB.F2;  
  150.             old_F3 = PORTB.F3;  
  151.             old_F4 = PORTB.F4;  
  152.             old_F5 = PORTB.F5;  
  153.         }  
  154.     }  
  155.     Delay_ms(40);  
  156.     flag = 1;  
  157. }  
  158.   
  159. void main() {  
  160.     //使用変数の定義  
  161.     unsigned short int i;  
  162.   
  163.     PORTB  = 0b00000000;  //PORTBの中身をきれいにする  
  164.   OSCCON = 0b01100000;  //内臓クロック4MHzに設定  
  165.     TRISB  = 0b00000001;  //RB0を1:入力、他は0:出力に設定  
  166.   
  167.     //PIC稼働確認(LED点滅)  
  168.     for (i=0; i < 5; i++) {  
  169.         PORTB = 0b11111110;  
  170.         Delay_ms(50);  
  171.         PORTB = 0b00000000;;  
  172.         Delay_ms(50);  
  173.     }  
  174.   
  175.     //timer0プリスケーラ64回に設定  
  176.     OPTION_REG = 0b10000101;  
  177.   
  178.     INTCON.INTE = 1;    //RB0/INT割込みの許可  
  179.     INTCON.GIE = 1;    //全体割込み許可  
  180.   
  181.     do {  
  182.         if(flag == 1) {  
  183.             flag = 0;  
  184.             PORTB.F2 = 0;  
  185.             PORTB.F3 = 0;  
  186.             PORTB.F4 = 0;  
  187.             PORTB.F5 = 0;  
  188.             INTCON.INTE = 1; //RB0/INT割込みの許可  
  189.         }  
  190.     }while(1);  
  191. }  

参考:5Vになるまでと表現していますが、実際には、受信センサーからの出力される電圧です。

0 件のコメント:

コメントを投稿