以前、Arduinoでリモコンで紹介したリモコンデバイスに、Bluetoothモジュールを繋いでBluetoothで赤外線リモコンの操作を出来るようにしましたのでご紹介。
BluetoothのSPP(シリアルプロファイル)に対応したモバイル端末やスマートフォン等でリモコン操作が行えるようになります。 ただし、まだ対応したアプリはまだ出来ていませんが・・・
必要な部品
| - | Arduino Duemilanove | 1 |
| - | BT-MOD100R(Bluetoothモジュール) | 1 |
| - | 80FG970(BT-MOD100R用アダプタ) | 1 |
| U1 | リモコン受信モジュール | 1 |
| R1 | 抵抗 1KΩ | 1 |
| R2 | 抵抗 75Ω | 1 |
| R3 | 抵抗 1KΩ | 1 |
| Q1 | 2SC1815(NPNトランジスタ) | 1 |
| D1 | 赤外線LED | 1 |
| D2 | LED | 1 |
- Arduino
利用しているのは、Arduino Duemilanoveで 3200円程で売られています。
- BT-MOD100R + 80FG970
今回利用したBluetoothモジュールは、BT-MOD100Rと言うモジュールで、携帯電話(Android)で利用してみたレポートをこちらで紹介しています。
僕が購入したのは、BT-MOD100Rと80FG970で、約1万円程でした。
- リモコン受信モジュール
秋月電子で100円程で売られている物を利用。
参考:PL-IRM0101 / PL-IRM2121
- 抵抗
秋月電子で100本入り100円で売られています。
参考:75Ω 1KΩ
- 2SC1815
秋月電子で20個入り100円で売られています。
参考:2SC1815GR
- 赤外線LED
今回利用したのは、秋月電子で5個100円で売られている50mAまで流せる赤外線LED。
配線
基本的には、前回の配線と同じで、4番・5番のピンにBluetoothモジュールを接続したものです。
出力アップ用のトランジスタや、動作確認用LEDの外付けは、必要に応じて実装してください。
Arduinoソース
#include <NewSoftSerial.h>
#define USB_BAUD 115200UL // USB Serial Baudrate
#define BT_BAUD 9600UL // Bluetooth Connection Baudrate
#define IR_OUT 3 // IR LED (Arduino 3pin)
#define IR_IN 2 // IR Receiver(Arduino 3pin)
#define L_LED 13
#define FROM_USB 0
#define FROM_BT 1
#define BT_TPIN 4
#define BT_RPIN 5
#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;
volatile uint8_t dataFrom;
unsigned int count;
NewSoftSerial BTSerial(BT_RPIN,BT_TPIN);
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;
}
}
// 動作確認用
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));
// COM2A = 00: disconnect OC2A
// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
// WGM2 = 101: phase-correct PWM with OCRA as top
// CS2 = 000: no prescaling
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 setup()
{
pinMode(L_LED, OUTPUT);
digitalWrite(L_LED, HIGH);
// Serial setup
Serial.begin(USB_BAUD);
Serial.flush();
// Bluetooth側
BTSerial.begin(BT_BAUD);
BTSerial.flush();
count=0;
smp_rate=50;
digitalWrite(L_LED, LOW);
dataFrom=0;
}
void waitSerialAvailable()
{
while(Serial.available() <= 0)
{
__asm("nop");
}
}
int readData()
{
for(;;)
{
if(dataFrom==FROM_USB)
{
if(Serial.available()>0)
{
return Serial.read();
}
}
else
{
if(BTSerial.available()>0)
{
return BTSerial.read();
}
}
}
}
void writeData(uint8_t data)
{
if(dataFrom==FROM_USB) Serial.write(data);
else BTSerial.print(data);
}
void writeIRData(int length)
{
int i;
for(i=0; i<length; i++ )
{
writeData(ir_data[i]);
}
}
/////////////////////////////////////
// Receive IR (compatible KURO-RS)
void command_r()
{
writeData('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();
writeData('Y');
break;
}
}
if(BTSerial.available() > 0)
{
rbuf = BTSerial.read();
if(rbuf=='c')
{
IRInStop();
break;
}
}
if( intflags.rec_check == 0 && intflags.rec_start == 0 )
{
IRInStop();
writeData('S');
writeIRData(240);
writeData('E');
break;
}
}
}
///////////////////////////////////
// Receive IR (compatible IRIO88)
void command_R()
{
writeData('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();
break;
}
}
if(BTSerial.available() > 0)
{
rbuf = BTSerial.read();
if(rbuf=='c')
{
IRInStop();
writeData('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;
}
}
writeData('S');
writeData(smp_rate);
writeData((byte)(send_max>>8));
writeData((byte)(send_max&0xFF));
writeIRData(send_max);
writeData('E');
break;
}
}
}
/////////////////////////////////
// Send IR (compatible KURO-RS)
void command_t()
{
// ch receive
writeData('Y');
rbuf = readData();
// data receive
writeData('Y');
i16=0;
while(i16<240)
{
ir_data[i16] = readData();
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);
writeData('E');
}
////////////////////////////////
// Send IR (compatible IRIO88)
void command_S()
{
// ch receive
writeData('Y');
smp_rate = readData();
send_max = (readData()<<8);
send_max += readData();
// data receive
if(send_max>0 && send_max<=MAX_DATA_LENGTH)
{
i16=0;
while(i16<send_max)
{
ir_data[i16] = readData();
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);
writeData('E');
}
////////////////////////////////
// Set Sampling Rate (compatible IRIO88)
void command_T()
{
writeData('Y');
rbuf = readData();
if(rbuf>100) rbuf=100;
else if(rbuf<20) rbuf=20;
smp_rate=rbuf;
writeData('E');
}
void loop()
{
//
if(Serial.available() > 0)
{
digitalWrite(L_LED, HIGH);
dataFrom=FROM_USB;
rbuf = Serial.read();
if(rbuf == 'r') command_r(); // Receive IR (compatible KURO-RS)
else if(rbuf == 'R') command_R(); // Receive IR (compatible IRIO88)
else if(rbuf == 'S') command_S(); // Send IR (compatible IRIO88)
else if(rbuf == 't') command_t(); // Send IR (compatible KURO-RS)
else if(rbuf == 'T') command_T(); // Set Sampling Rate (compatible IRIO88)
else if(rbuf == 'i') writeData('O'); // LED (compatible KURO-RS)
else if(rbuf == 'c') writeData('Y'); // Cancel (compatible KURO-RS)
else
{
delay(100);
Serial.flush();
BTSerial.flush();
}
digitalWrite(L_LED, LOW);
}
if(BTSerial.available() > 0)
{
digitalWrite(L_LED, HIGH);
dataFrom=FROM_BT;
rbuf = BTSerial.read();
if(rbuf == 'r') command_r();
else if(rbuf == 'R') command_R();
else if(rbuf == 'S') command_S();
else if(rbuf == 't') command_t();
else if(rbuf == 'T') command_T();
else if(rbuf == 'i') writeData('O');
else if(rbuf == 'c') writeData('Y');
else
{
delay(100);
Serial.flush();
BTSerial.flush();
}
digitalWrite(L_LED, LOW);
}
}
このプログラムではNewSoftSerial(Arduinoライブラリ)を利用しています。
内部の処理としては、シリアル入力を2系統に対応させているので、今回利用したBluetoothモジュール以外のUSART対応モジュールを接続することも可能です。
他のモジュールを接続する場合、ソースの冒頭の
#define BT_BAUD 9600UL
を変更して、通信速度を調整してください。
使い方
デバイスは、上の配線通り接続して、ソースをコンパイルしてArduinoに書き込めば出来上がりです。
PCがBluetoothに対応している場合、RFCOMMを設定してコマンドを送ると、リモコン操作が行えるようになります。このデバイスを操作する為のコマンドはこちらのページを ご覧下さい。
RFCOMMで接続できれば、KURO-RS用のアプリなんかが動く・・・はずです(未確認)




RSS Feed