メインコンテンツに移動

GR-COTTON 特設:リモコン受信(赤外線モジュール)

概要

赤外線モジュールをGR-COTTONに接続してリモコン受信してみます。

cotton-sp-remote-controller

準備

GR-COTTON、USBケーブル(マイクロBタイプ)、赤外線モジュールの3つを準備します。

GR-COTTONにはピンソケット(丸ピン)を取り付ける必要があります。赤外線モジュールの足は適当な長さに切ります。なお、赤外線モジュールの足が細いため、温湿度センサーや、デジタルコンパス用のソケットではきちんと接続されません。この場合、丸ピンタイプのソケットを重ねることで解決できます。

赤外線モジュールの購入についてはこちら(秋月電子通商Web)

ピンソケット(丸ピン)の購入についてはこちら(秋月電子通商Web)

cotton-sp-prepare-ir-receive-usb

下図のように赤外線モジュールを、GR-COTTONに接続します。

GR-COTTONの裏面にある白いジャンパーが3V3、USB側にします。BATT側にある場合は引き抜いて、USB側に差し込んでください。

cotton-sp-prepare-ir-receive
cotton-sp-prepare2

赤外線の受信を確かめる。

まずは赤外線モジュールがリモコンからの赤外線をキャッチしているか確認します。

赤外線のキャッチを青LEDにエコーするだけのサンプルプログラムです。


#include <arduino.h>
void setup() {
    pinMode(2, INPUT_PULLUP);   
    pinMode(24, OUTPUT); //blue led
    digitalWrite(24, HIGH);
}
    
void loop() {
    digitalWrite(24, digitalRead(2));
}    

赤外線を受信しない間、省電力にする。

リモコンから操作しない間はなるべく省電力にしたいですよね。

赤外線をキャッチするまで省電力にするサンプルです。このサンプルはボタンスイッチと似ており、ピン2に割り当たっている割り込みを使っています。


#include <arduino.h>

void ir_receive(){
    digitalWrite(23, LOW);
    setPowerManagementMode(PM_NORMAL_MODE); // for use delay
    delayMicroseconds(1000);
    digitalWrite(23, HIGH);
}
void setup() {
    pinMode(2, INPUT_PULLUP);
    attachInterrupt(0, ir_receive, FALLING);
    
    pinMode(23, OUTPUT); //green led
    digitalWrite(23, HIGH);
}
    
void loop() {
    setPowerManagementMode(PM_STOP_MODE);
    delay(0xffffffff); // into stop mode
}

        

リモコンのボタンに応じてLEDを光らせる。

このサンプルは、以下のリモコンのA, B, Cボタンを押したときにLEDを光らせます。

このリモコンはNECフォーマットに準拠しています。サンプルではNECフォーマットに合わせた信号の分析をしてLEDを光らせる他、シリアルモニターに信号の内容を表示しています。

リモコンの購入についてはこちら(秋月電子通商Web)

cotton-sp-prepare-remote
Cottonリモートシリアル

#include <arduino.h>

#define IR_PIN 2
#define IR_INTERRUPT 0

uint8_t g_ir_data = 0;
bool    g_ir_available = false;

void ir_receive_interrupt();
void ir_receive_start();
uint8_t ir_getData();
bool ir_available();

void setup() {
setPowerManagementMode(PM_STOP_MODE);
Serial.begin(9600);
pinMode(IR_PIN, INPUT_PULLUP);
ir_receive_start();

pinMode(22, OUTPUT);
pinMode(23, OUTPUT);
pinMode(24, OUTPUT);
digitalWrite(22, HIGH);
digitalWrite(23, HIGH);
digitalWrite(24, HIGH);

}

void loop() {
ir_receive_start();
delay(0xFFFFFFFF); // hold STOP mode until receiving IR signal.

if(ir_available()){
Serial.println(ir_getData(), HEX);
Serial.flush();
switch (ir_getData()) {
case 0xD8: // POWER BUTTON
digitalWrite(22, LOW);
delay(100);
digitalWrite(22, HIGH);
break;
case 0xF8: // A BUTTON
digitalWrite(23, LOW);
delay(100);
digitalWrite(23, HIGH);
break;
case 0x78: // B BUTTON
digitalWrite(24, LOW);
delay(100);
digitalWrite(24, HIGH);
break;
case 0x58: // C BUTTON
digitalWrite(22, LOW);
digitalWrite(24, LOW);
delay(100);
digitalWrite(22, HIGH);
digitalWrite(24, HIGH);
break;
default:
break;
}
}   
}

/************ IR utility function ***************/
void ir_receive_interrupt(){

unsigned long last_time;

detachInterrupt(IR_INTERRUPT);
last_time = micros();

// confirm if reader code is correct
uint8_t err = 0;
while(!digitalRead(IR_PIN)){ // until change from low to high
if((micros() - last_time) > 10000){ // interval low should be 9ms or less 
err = true;
break;
}
}
while(digitalRead(IR_PIN)){ // until change from high to low
if((micros() - last_time) > 15000){ // interval of reader code should be 13.5ms or less
err = true;
break;
}
}
if(((micros() - last_time) < 13000) || (err == true)){ // Unknown code
attachInterrupt(0, ir_receive_interrupt, FALLING);
g_ir_available = false;
return; // not available remote controller
}

// get data
uint8_t receive_count = 0;
uint8_t temp_ir_data[4] = {0};
g_ir_data = 0;
last_time = micros();
while((32 > receive_count) && ((micros() - last_time) < 80000)){
// interval of a frame data should be 76.5ms or less
last_time = micros();
while(!digitalRead(IR_PIN) && ((micros() - last_time) < 1000)){
// interval of low state is about 0.56ms. 
}
while(digitalRead(IR_PIN) && ((micros() - last_time) < 2500)){
// interval of a bit is between 1.125ms and 2.25ms
}
if((micros() - last_time) > 1500){
bitSet(temp_ir_data[receive_count / 8], receive_count % 8);
}
receive_count++;
}

if(temp_ir_data[2] == (uint8_t)~temp_ir_data[3]){
g_ir_data = temp_ir_data[2]; // set actual data
g_ir_available = true;
}

}

void ir_receive_start(){
attachInterrupt(IR_INTERRUPT, ir_receive_interrupt, FALLING);
}

uint8_t ir_getData(){
g_ir_available = false;
return g_ir_data;
}

bool ir_available(){
return g_ir_available;
}