赤外線リモコンの信号を受信し、PIC16F1619のSMTを利用して受信信号のパルス幅を測定します。測定結果はEUSARTからシリアルUSB変換器を経由してPCに送信します。
PICのペリフェラルは以下の用途に使用しています。
下の波形は、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 **/