赤外線リモコンの信号を受信し、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 **/