PIC16F1619の基本動作から応用プログラムまでを学びます。

ホーム
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
    
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
赤外線リモコンパルス幅計測
2020-11-01

赤外線リモコンの信号を受信し、PIC16F1619のSMTを利用して受信信号のパルス幅を測定します。測定結果はEUSARTからシリアルUSB変換器を経由してPCに送信します。

PICのペリフェラルは以下の用途に使用しています。

SMT1
信号の継続時間測定に使用
1MHzをカウントするので、1us単位となる。SMT High-Low modeを使用している
赤外線センサー (OSRB38C9AA)
RC7に接続してSMT1SIG入力でモニタしている。赤外線信号を受信すると出力が LOW になる負論理出力のセンサー
EUSART
測定結果をUSBシリアル変換モジュールに送信する。USBシリアル変換モジュールについては、別ページに記載してある

赤外線リモコンの波形

下の波形は、JVCリモコンのチャンネル1Keyを押し、赤外線受信モジュールの出力波形をロジックアナライザーで測定したものです。使用している赤外線受信モジュールは負論理出力なので赤外線パルスを受信している間出力は「0」となっています。リーダー(Header)部に続き 16 ビットのデータが観測できます。


リモコンKeyを長押しすると、下図のようにデータ部の後に20ms程度の間隔を開けて、データ部が再送されているのがわかります。この例では、データ部は合計3回送信されていました。


このプログラムでは、無信号時間が 10 ms 以上の場合、単位を us から ms に変更して送信しています。さらに、100 ms 以上の無信号は、Key が押されていないと判断し「---」と表示します。


プログラム

プログラムを示します。
赤外線送信が終了するまで、赤外線センサーの Mark信号(赤外線を送っている時間)、Space信号(赤外線を送っていない時間)をSMY1で計測します。信号受信中は、得られたデータをバッファー(200ビット分)に保存し、Spaceが 100 msを超えると送信が終了したと判断し、保存したデータをUSB経由でPCに送信します。

/*******************************************************
 * SMT Hight-Low mode で、赤外線リモコンのパルス幅をus単位で
 * 測定し、EUSART経由しUSBに変換してPCに送信する
 * PIC16F1619  MPLAB X IDE 5.45 with XC8 2.20
 * Copyright (c) 2017 iwamoto All Rights Reserved
 * ******************************************************/
#include <xc.h>
#include <stdint.h>
#include <stdio.h>

#define _XTAL_FREQ 4000000

#define maxdata 200         // 赤外線データー配列数

uint16_t PW[maxdata];       // Mark配列
int16_t PR[maxdata];        // Space配列
uint8_t  p_PW;              // Mark配列ポインタ
uint8_t  p_PR;              // Space配列ポインタ

// CONFIG
#pragma config FOSC = INTOSC, PWRTE = OFF, MCLRE = ON, CP = OFF
#pragma config BOREN = ON, CLKOUTEN = OFF, IESO = ON, FCMEN = ON
#pragma config WRT = OFF, PPS1WAY = ON, ZCD = OFF, PLLEN = OFF
#pragma config STVREN = ON, BORV = LO, LPBOR = OFF, LVP = ON
#pragma config WDTCPS = WDTCPS1F, WDTE = OFF, WDTCWS = WDTCWSSW, WDTCCS = SWC

void putch(char txData){        // Write the data byte to the USART.
    while(0 == PIR1bits.TXIF);
    TX1REG = txData;
}

/**********************  Main application  ***************/
void main(void){
    OSCCON = 0b01101000;	// PLL disabled; 4MHz_HF; FOSC;

    TRISB = 0xF0;           // 入力に設定
    TRISC = 0xFF;
    ANSELB = 0;             // デジタルに設定
    ANSELC = 0;

    BAUD1CON = 0x08;    // 16 bit SPBRG
    RC1STA = 0x90;      // 8 bit 連続受信
    TX1STA = 0x24;      // 非同期送受信 High Baud Rate選択
    SPBRGL = 0x67;      // 9600 Baud @ 4M Fosc
    SPBRGH = 0x00;

    SMT1CON0 = 0x88;    // SIG極性 low; Prescaler 1:1;
    SMT1CON1 = 0x43;    // Repeat; High and Low: SMT1GO = Off
    SMT1STAT = 0x00;    //
    SMT1CLK = 0x01;     // Clock FOSC/4;
    SMT1WIN = 0x00;     // WIN in SMTWINx
    SMT1SIG = 0x00;     // SEL in SMTxSIG
    SMT1PR = 99999;     // 100 ms 周期

    RXPPS = 0x0D;       //RB5->EUSART:RX;
    RB7PPS = 0x12;      //RB7->EUSART:TX;
    SMT1WINPPS = 0x05;  //RA5->SMT1:SMT1WIN;
    SMT1SIGPPS = 0x17;  //RC7->SMT1:SMT1SIG;

    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(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;                    // 測定終了
        printf(" -  mark  space (us)\r\n");         // タイトル送信
        for(char i=0;i<p_PW;i++){                   // 保存した時間を送信
//        for(char i=0;i<20;i++){                   // 保存した時間を送信
            printf("%2d %5d",i,(uint16_t)PW[i]);    // mark時間
            if(PR[i]==0) {                          // 無信号なら
              printf("    ---\r\n");                //  「---」を送信
            }else if(PR[i] > 0){                    // 10ms未満なら
              printf("  %5d\r\n",PR[i]);            //   us単位で送信
            }else{                                  // 10ms未満なら
              printf("%7d ms\r\n",-PR[i]);          //   ms単位で送信
            }
        }
        if(p_PW >= maxdata){                        // バッファ万杯なら
            printf("-- Buffer Full --\r\n");        //  Buffer Full 送信
        }
    }
}
/** End of File **/