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 3pin)
#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'に修正しました。
使い方



RSS Feed
winlirc用のpioservrmtggf1381.cfをコピペしてwinlircで使おうとしたところ、初期化に失敗してしまいます。XPや、2000、7でも試してみましたが、いずれもダメです。winlirc に最初から入っているsample.cfは問題なく使用できますが・・・どこが問題でしょうか?
コメントありがとうございます。
普通に考えて、pioservrmtggf1381.cfが問題なんじゃ無いかと思いますが・・・
Arduinoのキット販売で学習リモコンを計画しています。そこでこのライブラリを利用させていただきたいのですが、何か問題がありますでしょうか、宜しくお願いいたします。
コメント有り難うございます。
返信遅れてもうしわけありません。
ソースの利用はご自由にどうぞ。
ただし、回路の方が、このままだと動作が不安定になるので注意が必要です。