秋月電子で、赤外線リモコンが\300であった。面白そうなので、PICマイコンで受信するプログラムを書いたが、意外と苦戦したので、備忘録として書いておこう。
卓球の練習マシンを作っていたが、上ローラー、下ローラー、発射角度、発射周期、首振りなど調整項目が多く、アナログボリュームだと配線が大変だし、なによりマイコンのアナログ入力のピン数が増える。赤外線リモコンが使えれば、入力はデジタル×1で済むし、パラメーターを記録しておける。
で、使用したPICは16F1503 14pinDIPパッケージ。PWMが4つあり、モーター制御に向いている。ただ、DCモーターとラジコンサーボでは、PWM周期が違いすぎて両立はできない。よって、サーボはタイマ割り込みを使うこととする。
上記のことから、赤外線の受信には16F1503を内蔵オシレーターでの最高周波数16MHzで使用、タイマ1のゲート機能を使うこととする。赤外線受信モジュールは、常時Highで受信するとLowと逆転するが、かえって都合がいい。Highの部分だけを見れば受信可能だ。
リーダーが4500us、0が560us、1が1600us、リピートが2300usということで、16ビットタイマの上位8ビットのみを使いカウントする。
//リモコン受信データ
unsigned char IRBUFF[4];
unsigned char read_state=0;
unsigned char ir_repeat;
void interrupt isr(void){
unsigned static char byte_pos;
unsigned static char bit_pos;
unsigned static char skip=0;
unsigned char cnt;
if (TMR1IF){ //タイマ1がオーバーフローした場合。
read_state = 0; //読み取り状態をリセットする。
ir_repeat = 0;
skip = 1; // タイマがオーバーフローしたら、そのときのパルスは無効。
TMR1IF = 0;
}
if (TMR1GIF){
cnt = TMR1H; //パルス High時間を取得 2us/count(L) 512us/count(H)
TMR1L = 200; //タイマの値を初期化。0.5ms程度のパルスでカウントできるよう下駄はかせ
TMR1H = 0;
if (skip) skip = 0;
else switch (read_state){
case 0: //ヘッダ待ちモード
if(7<cnt && 11>cnt){ //3.8ms~4.9ms ならヘッダ
IRBUFF[0]=IRBUFF[1]=IRBUFF[2]=IRBUFF[3]=0;
read_state = 1;
bit_pos = 0;
byte_pos = 0;
ir_repeat = 0;
}
break;
case 1: //ヘッダ完了。データ待ちモード
if(1 > cnt || 4 < cnt){
read_state = 0;
}else{
IRBUFF[byte_pos] |= (cnt > 2) << bit_pos++;
if (bit_pos==8){ //8bit読んだら、次のバイトへ
byte_pos++;
bit_pos = 0;
};
if (byte_pos == 4){ //4byte読んだら終了、次のパルスは無視
skip = 1;
read_state = 2;
}
}
break;
case 2: //読み込み完了。リピート待ち。
if (6 > cnt && cnt > 3){
skip=1;
ir_repeat = 1;
}else ir_repeat = 0;
break;
}
TMR1GIF = 0; //割り込みフラグを解除して
T1GGO_nDONE = 1;//ゲート待機モードに
}
}
ソースありがとうございます。参考にさせていただきます!