Arduinoで、KURO-RS(PC-OP-RS1)とIRIO88(Electric House)の互換で動作するリモコンデバイスを作成してみました。
arduino用のリモコン・ライブラリーをいくつか見つけましたが、どのライブラリーもKURO-RS互換で動作させるのは難しいようなので、今回はそれらのライブラリーを参考にしながら一から作成しました。
注意:KURO-RS互換ですが、実際にKURO-RS用のアプリが動作するのか確認した訳ではありません。
作り方
回路図通り配線を行い、ソースプログラムをarduinoに書き込めば完成です。
上の写真では、ブレッドボード上で配線を行っています。 一番右端のLEDは通電確認用の物で、実際の動作には必要の無いものです。
作成に必要な部品
– | Arduino Duemilanove | 1 |
U1 | リモコン受信モジュール | 1 |
D1 | 赤外線LED | 1 |
R1 | 抵抗 300Ω (橙黒茶金) | 1 |
- Arduinoとは、AVRを搭載したCPUボードです。 今回利用したのはArduino Duemilanoveと言う、現在最も標準的なArduinoです。
- リモコン受信モジュールは、赤外線を受信する為のセンサーで、リモコンのキャリア周波数である38kHz前後の赤外線のみを受信出来るようにモジュール化されたものです。 秋月電子で100円程で売られています。 参考:PL-IRM0101 / PL-IRM2121
- 赤外線LED。 秋月電子で100個パックで売られている物を今回は利用しました。
- 抵抗は300Ω(橙黒茶金)の物を利用ました。もう少し小さい値の物を使えば、赤外線LEDが強く光ると思います。
配線
この回路図は、BSch +arduinoライブラリ を利用して作成しました。
ソース
#define USB_BAUD 115200UL // USB Serial Baudrate #define IR_OUT 3 // IR LED (Arduino 3pin) #define IR_IN 2 // IR Receiver(Arduino 2pin) #define L_LED 13 #define MAX_DATA_LENGTH 960 #ifndef cbi #define cbi(PORT, BIT) (_SFR_BYTE(PORT) &= ~_BV(BIT)) #endif #ifndef sbi #define sbi(PORT, BIT) (_SFR_BYTE(PORT) |= _BV(BIT)) #endif volatile struct { uint8_t rec_check: 1; uint8_t rec_start: 1; } intflags; volatile uint8_t ir_bit; volatile uint8_t ir_data[MAX_DATA_LENGTH]; volatile uint16_t i16,send_max; volatile uint8_t rbuf; volatile uint8_t tcnt2; volatile uint8_t smp_rate; unsigned int count; ISR(TIMER2_OVF_vect) { TCNT2 = tcnt2; if( intflags.rec_start ) { // 受信処理中 if( !(PIND & _BV(2)) ) { ir_data[i16] |= ir_bit; } ir_bit <<= 1; if( ir_bit == 0 ) { ir_bit = 1; i16++; if( i16 >= MAX_DATA_LENGTH ) { intflags.rec_start = 0; } } } else if( intflags.rec_check ) { if( !(PIND & _BV(2)) ) { i16=0; ir_data[i16] |= 1; ir_bit = 2; intflags.rec_check = 0; intflags.rec_start = 1; } } // L-LED点滅 digitalWrite(L_LED, (count&0x0800)?HIGH:LOW); count++; } void IROutSetup(int kHz,int duty) { pinMode(IR_OUT, OUTPUT); digitalWrite(IR_OUT, LOW); TCCR2A &= ~(_BV(COM2B1)); TCCR2A = _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS20); OCR2A = F_CPU / 2 / kHz / 100; OCR2B = OCR2A / duty; } void IRInSetup(int smp_rate) { TCCR2A = 0; // normal mode cbi(TCCR2B,CS22); sbi(TCCR2B,CS21); cbi(TCCR2B,CS20); sbi(TIMSK2,TOIE2); tcnt2 = 256 - ((F_CPU/8/10000*smp_rate)/100) +5; TCNT2 = tcnt2; sei(); pinMode(IR_IN, INPUT); PORTD|=_BV(2); } void IRInStop() { cbi(TIMSK2,TOIE2); } void crearBuf() { for(i16=0; i16<MAX_DATA_LENGTH; i16++ ) { ir_data[i16] = 0x00; } } void waitSerialAvailable() { while(Serial.available() <= 0) { __asm("nop"); } } void setup() { pinMode(L_LED, OUTPUT); digitalWrite(L_LED, HIGH); // Serial setup Serial.begin(USB_BAUD); Serial.flush(); count=0; smp_rate=50; digitalWrite(L_LED, LOW); } void loop() { // if(Serial.available() > 0) { digitalWrite(L_LED, HIGH); rbuf = Serial.read(); if(rbuf == 'r') // Receive IR (compatible KURO-RS) { Serial.write('Y'); intflags.rec_start = 0; intflags.rec_check = 0; crearBuf(); intflags.rec_check = 1; IRInSetup(100); for(;;) { if(Serial.available() > 0) { rbuf = Serial.read(); if(rbuf=='c') { IRInStop(); Serial.write('Y'); break; } } if( intflags.rec_check == 0 && intflags.rec_start == 0 ) { IRInStop(); Serial.write('S'); for(i16=0; i16<240; i16++ ) { Serial.write(ir_data[i16]); } Serial.write('E'); break; } } } else if(rbuf == 'R') // Receive IR (compatible IRIO88) { Serial.write('Y'); intflags.rec_start = 0; intflags.rec_check = 0; crearBuf(); intflags.rec_check = 1; IRInSetup(smp_rate); for(;;) { if(Serial.available() > 0) { rbuf = Serial.read(); if(rbuf=='c') { IRInStop(); Serial.write('Y'); break; } } if( intflags.rec_check == 0 && intflags.rec_start == 0 ) { IRInStop(); // 最大格納データ長計算 for(send_max=(MAX_DATA_LENGTH-1); send_max>=0; send_max--) { if( ir_data[send_max] ) { send_max++; break; } } Serial.write('S'); Serial.write(smp_rate); Serial.write((byte)(send_max>>8)); Serial.write((byte)(send_max&0xFF)); for(i16=0; i16<send_max; i16++ ) { Serial.write(ir_data[i16]); } Serial.write('E'); break; } } } else if(rbuf == 'S') // Send IR (compatible IRIO88) { // smp_rate receive Serial.write('Y'); waitSerialAvailable(); smp_rate = Serial.read(); waitSerialAvailable(); send_max = (Serial.read()<<8); waitSerialAvailable(); send_max += Serial.read(); if(send_max>0 && send_max<=MAX_DATA_LENGTH) { // data receive i16=0; while(i16<send_max) { waitSerialAvailable(); ir_data[i16] = Serial.read(); i16++; } // send byte sbuf; byte c; IROutSetup(382,3); // 38.2kHz 1/3duty for(i16=0; i16<send_max; i16++ ) { sbuf=ir_data[i16]; for(c=0;c<8;c++) { if(sbuf&1) { digitalWrite(L_LED, HIGH); sbi(TCCR2A,COM2B1); } else { digitalWrite(L_LED, LOW); cbi(TCCR2A,COM2B1); } sbuf>>=1; delayMicroseconds(smp_rate); } } cbi(TCCR2A,COM2B1); } Serial.write('E'); } else if(rbuf == 't') // Send IR (compatible KURO-RS) { // ch receive Serial.write('Y'); waitSerialAvailable(); rbuf = Serial.read(); // data receive Serial.write('Y'); i16=0; while(i16<240) { waitSerialAvailable(); ir_data[i16] = Serial.read(); i16++; } // send byte sbuf; byte c; IROutSetup(382,3); // 38.2kHz 1/3duty for(i16=0; i16<240; i16++ ) { sbuf=ir_data[i16]; for(c=0;c<8;c++) { if(sbuf&1) { digitalWrite(L_LED, HIGH); sbi(TCCR2A,COM2B1); } else { digitalWrite(L_LED, LOW); cbi(TCCR2A,COM2B1); } sbuf>>=1; delayMicroseconds(100); } } cbi(TCCR2A,COM2B1); Serial.write('E'); } else if(rbuf == 'T') // Set Sampling Rate (compatible IRIO88) { Serial.write('Y'); waitSerialAvailable(); rbuf = Serial.read(); if(rbuf>100) rbuf=100; else if(rbuf<20) rbuf=20; smp_rate=rbuf; Serial.write('E'); } else if(rbuf == 'i') // LED (compatible KURO-RS) { Serial.write('O'); } else if(rbuf == 'c') // Cancel (compatible KURO-RS) { Serial.write('Y'); } digitalWrite(L_LED, LOW); } }
※2009/1/13 受信待機中のキャンセルの応答が’E’になっていたのを、’Y’に修正しました。
使い方
winlirc用のpioservrmtggf1381.cfをコピペしてwinlircで使おうとしたところ、初期化に失敗してしまいます。XPや、2000、7でも試してみましたが、いずれもダメです。winlirc に最初から入っているsample.cfは問題なく使用できますが・・・どこが問題でしょうか?
コメントありがとうございます。
普通に考えて、pioservrmtggf1381.cfが問題なんじゃ無いかと思いますが・・・
Arduinoのキット販売で学習リモコンを計画しています。そこでこのライブラリを利用させていただきたいのですが、何か問題がありますでしょうか、宜しくお願いいたします。
コメント有り難うございます。
返信遅れてもうしわけありません。
ソースの利用はご自由にどうぞ。
ただし、回路の方が、このままだと動作が不安定になるので注意が必要です。
Arduino Unoでも動作しました!素晴らしいコードの公開ありがとうございます!