ATtinyの赤外線受信


ArduinoではIRremote ライブラリを使って赤外線の送受信ができます。
IRremoteライブラリのページにはATtiny84/85もサポートしていると書かれていますが、
環境に依存するようで、私の環境ではコンパイルエラーとなります。

開発環境をいじると何かと面倒なので、
しばらくあきらめていたのですが、このページで ライブラリを一切使わずに
ATtiny85で赤外線の受信ができることが分かりましたので紹介します。

ATtinyでは受信した赤外線データを表示することができないので、シリアル通信で
受信した赤外線データをUNOに送って、UNO側で表示しています。

なお、こ ちらにも似たようなサンプルがありますが、Oscillator callibration valueを調整しているので
ソフトウェアシリアル通信が併用して動きません。

全体の結線は以下の様になります。



使用した赤外線レシーバーは TSOP4838 と TL1838 で、どちらも正常に動きました。

まずUNO側のスケッチは以下の通りです。
ソフトウェアシリアルを使って受信したデータをシリアルモニターに表示しているだけです。
ソフトウェアシリアルのボーレートは安全を見て、4800Bpsにしています。

/*
 * Software Serial Receiver Sample
 */
#include <SoftwareSerial.h>

#define rxPin 2    // PD2
#define txPin 3    // PD3
#define BaudRate   4800

SoftwareSerial mySerial(rxPin, txPin); // RX, TX

void setup() {
  Serial.begin(9600);
  Serial.print("Software Serial Receiver Start BaudRate=");
  Serial.println(BaudRate);
  mySerial.begin(BaudRate);
}

void loop() {
  char buf[60];
  int pos=0;
  buf[pos]=0;
 
  while(1) {
    if (mySerial.available()){
      char c = mySerial.read();
//      Serial.print (" c=");
//      Serial.print(c,HEX);

      if (c == 0x0d) {
      
      } else if ( c == 0x0a) {
        Serial.print ("buf=");
        Serial.println(buf);
        pos=0;
      } else {
        buf[pos++]=c;
        buf[pos]=0;
      }
    }
  }
}

次にATtiny85側に以下のスケッチを書き込みます。
赤外線で受信したデータをそのまま、ソフトウェアシリアルを使って送信しているだけです。

/* ATtiny85 IR Remote Control Receiver

   David Johnson-Davies - www.technoblogy.com - 3rd April 2015
   ATtiny85 @ 1 MHz (internal oscillator; BOD disabled)
   
   CC BY 4.0
   Licensed under a Creative Commons Attribution 4.0 International license:
   http://creativecommons.org/licenses/by/4.0/

   http://www.technoblogy.com/show?V6F
   
*/
#include <SoftwareSerial.h>

#define rxPin 0    // PB0
#define txPin 1    // PB1

SoftwareSerial mySerial(rxPin, txPin); // RX, TX

volatile int NextBit;
volatile unsigned long RecdData;
int Brightness;

// Demo routine
void ReceivedCode(boolean Repeat) {
//  char buff[64];
//  sprintf(buff,"%d,%x",Repeat,RecdData);
//  mySerial.println(buff);
  mySerial.print(Repeat);
  mySerial.print(",");
  mySerial.println(RecdData,HEX);
}


// Interrupt service routine - called on every falling edge of PB2
ISR(INT0_vect) {
  int Time = TCNT0;
  int Overflow = TIFR & 1<<TOV0;
  // Keep looking for AGC pulse and gap
  if (NextBit == 32) {
    if ((Time >= 194) && (Time <= 228) && (Overflow == 0)) {
      RecdData = 0; NextBit = 0;
    } else if ((Time >= 159) && (Time <= 193) && (Overflow == 0)) ReceivedCode(1);
  // Data bit
  } else {
    if ((Time > 44) || (Overflow != 0)) NextBit = 32; // Invalid - restart
    else {
      if (Time > 26) RecdData = RecdData | ((unsigned long) 1<<NextBit);
      if (NextBit == 31) ReceivedCode(0);
      NextBit++;
    }
  }
  TCNT0 = 0;                  // Clear counter
  TIFR = TIFR | 1<<TOV0;      // Clear overflow
  GIFR = GIFR | 1<<INTF0;     // Clear INT0 flag
}

// Setup **********************************************
 
void setup() {
  // Set up Timer/Counter0 (assumes 1MHz clock)
  TCCR0A = 0;                 // No compare matches
  TCCR0B = 3<<CS00;           // Prescaler /64
  // Set up INT0 interrupt on PB2
  MCUCR = MCUCR | 2<<ISC00;   // Interrupt on falling edge
  GIMSK = GIMSK | 1<<INT0;    // Enable INT0
  NextBit = 32;               // Wait for AGC start pulse

  mySerial.begin(4800);
  mySerial.println("IR demo start");
}

void loop() {
}


ATtiny側のスケッチを実行して、赤外線受信機に向けてリモコンを発射すると、
UNO側のシリアルモニターに以下の様に表示されます。



1番目の数字がリピートかどうかのフラグ、2番目の数字が受信したリモコンコードで、押したリモコンボタンによりコードは変わります。
上記はテレビのリモコンの1から12のボタンを押したときですが、2バイト目(3文字目4文字目)でなんとなく分かります。
なお、このリモコンコードはNECフォーマットなので、32ビット(4バイト)のコードで、1バイト目がデータコード、
2バイト目は1バイト目の反転コード、3バイト目と4バイト目がメーカ識別コードです。
0xFE01=1111 1110 0000 0001
0xF30C=1111 0011 0000 1100

32ビット(4バイト)のコードで、1バイト目と2バイト目が反転していることで、NECフォーマットであると判別できますが、
フォーマットの識別などしなくても、複数のリモコンを使わなければ、十分どのボタンが押されたのか識別することができます。

なお、ATtiny85以外のモデルではコンパイルエラーとなります。
詳しい方なら、ほかのモデルにも移植できると思いますが、私には無理です。