シリアル接続の赤外線送受信モジュール(YS-IRTM)


前回に続いて赤外線送受信ネタです。
シリアル(UART)接続の赤外線送受信モジュール(YS-IRTM)を入手しました。
このモジュールについては、こ ちらに詳しく紹介されています。
そこで、Arduino UNOで使えるかどうか試してみました。

最初に、このモジュールを使って{0xA1, 0xF1, 0x12, 0x34, 0x56}のコードを送信しました。
受信側にはこちらのライブラリのサンプル コード(dump.ino)を利用して、 受信コードを解析してみました。
結果は以下のようになります。

Ready to receive IR signals
Decoded Unknown(0): Value:0 Adrs:0
Decoded Unknown(0): Value:0 Adrs:0 (0 bits)
Raw samples(68): Gap:10594
  Head: m8850  s4500
0:m500 s650    1:m500 s1700         2:m500 s600    3:m500 s650         
4:m450 s1750    5:m450 s650         6:m450 s700    7:m400 s700         
8:m450 s650    9:m450 s650         10:m450 s1800    11:m450 s650         
12:m450 s1750    13:m450 s1800         14:m450 s650    15:m450 s700         

16:m400 s650    17:m450 s1800         18:m450 s1750    19:m500 s600         
20:m500 s1750    21:m500 s650         22:m450 s1750    23:m450 s650         
24:m450 s1800    25:m450 s600         26:m500 s650    27:m500 s1700         
28:m500 s600    29:m500 s1750         30:m450 s650    31:m500 s1700         

32:m500
Extent=63850
Mark  min:400     max:500
Space min:600     max:1800

送信したのは{0x12, 0x34, 0x56}ですが、受信したコードは

0100 1000 (=0x48)
0010 1100 (=0x2C)
0110 1010 (=0x6A)
1001 0101 (=0x95 0x6Aの反転コードをモジュール側で付加)

となっています。
最初は訳が分からなかったのですが、よくよく見るとビットがローテーションしています。
つまり、送信コードは
0x12 = 0001 0010
0x34 = 0011 0100
0x56 = 0101 0110
ですが、一番下のビット(一番右側のビット)から送信されています。

このモジュールの回路図がこ ちらに公開されていますが、オンボードにSTC11F02E-SOP16のマイコンが実装され
このマイコンがUART->IRの変換を行っているようです。
ATMegaとはバイナリーデータの扱い方(バイトオーダーとかエンディアンと呼ばれているものでもない)が違うみたいで
0x12 = 0001 0010は 0100 1000 (=0x48)として受け取られるようです。

そこでバイトの変換関数をかませて送信してみました。

Ready to receive IR signals
Decoded Unknown(0): Value:0 Adrs:0
Decoded Unknown(0): Value:0 Adrs:0 (0 bits)
Raw samples(68): Gap:29722
  Head: m8850  s4550
0:m450 s650    1:m450 s650         2:m500 s600    3:m500 s1750         
4:m450 s650    5:m450 s650         6:m500 s1750    7:m450 s650         
8:m450 s650    9:m500 s600         10:m500 s1750    11:m400 s1800         
12:m500 s600    13:m450 s1800         14:m400 s700    15:m450 s650         

16:m450 s700    17:m400 s1800         18:m450 s650    19:m450 s1800         
20:m400 s700    21:m400 s1800         22:m450 s1800    23:m400 s700         
24:m450 s1750    25:m450 s700         26:m400 s1800    27:m450 s650         
28:m450 s1800    29:m400 s700         30:m450 s650    31:m450 s1800         

32:m400
Extent=63800
Mark  min:400     max:500
Space min:600     max:1800

今度は以下のデータを受信していますが、Decorded Unknownとなっています。

0001 0010 (=0x12)
0011 0100 (=0x34)
0101 0110 (=0x56)
1010 1001 (=0xA9 0x56の反転コード)

使用したスケッチを公開しておきます。
#if defined(__AVR__)
#include <SoftwareSerial.h>
#define SERIAL_TX       2
#define SERIAL_RX       3
SoftwareSerial Serial3(SERIAL_RX, SERIAL_TX); // RX, TX
#define _MODEL_         "arduino"
#endif

#if defined(__STM32F1__)
#define _MODEL_         "stm32f103"
#endif


void irSend(char * buf,int len) {
  for(int i=0;i<len;i++) {
    Serial3.write(buf[i]);
  }
}

uint8_t bitConv(uint8_t val) {
  uint8_t mask = 1;
  uint8_t rval = 0;
  uint8_t bits[] = {0x8, 0x4, 0x2, 0x1};
 
  for(int i=0;i<4;i++) {
    if (val & mask) rval = rval + bits[i];
    mask=mask << 1;
  }
  return rval;
}


uint8_t irConv(uint8_t val) {
//  Serial.print("val=0x");
//  Serial.print(val,HEX);
  uint8_t high = (val >> 4) & 0x0f;
  uint8_t low = val & 0x0f;
//  Serial.print(" high=0x");
//  Serial.print(high,HEX);
//  Serial.print(" low=0x");
//  Serial.print(low,HEX);
  uint8_t rval1 = bitConv(high);
  uint8_t rval2 = bitConv(low);
//  Serial.print(" rval1=0x");
//  Serial.print(rval1,HEX);
//  Serial.print(" rval2=0x");
//  Serial.print(rval2,HEX);
//  Serial.println();
  return (rval2 << 4) + rval1;
}
 
void setup() {
  delay(1000);
  Serial.begin(9600);
  Serial3.begin(9600);

  unsigned char buf[5];
  buf[0] = 0xA1;
  buf[1] = 0xF1;
//  buf[2] = 0x12;
//  buf[3] = 0x34;
//  buf[4] = 0x56;
//  irSend(buf,5);

  buf[2] = irConv(0x21);
  Serial.println(buf[2],HEX);
  buf[3] = irConv(0x07);
  Serial.println(buf[3],HEX);
  buf[4] = irConv(0x04);
  Serial.println(buf[4],HEX);

  irSend(buf,5);
 
}

void loop() {
  uint8_t incomingByte = 0;   // for incoming serial data
 
  // send data only when you receive data:
  if (Serial3.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial3.read();

    // say what you got:
    Serial.print("I received: ");
    Serial.print(incomingByte, HEX);
    uint8_t convertByte = irConv(incomingByte);
    Serial.print("(");
    Serial.print(convertByte, HEX);
    Serial.print(")");
    Serial.println();
  }
}



次にTVの電源ONのコード(0x210704FB)を発射してみました。
以下が本物のリモコンから発射した時のコードです。
Ready to receive IR signals
Decoded NEC(1): Value:210704FB Adrs:0
Decoded NEC(1): Value:210704FB Adrs:0 (32 bits)
Raw samples(68): Gap:18148
  Head: m8850  s4450
0:m550 s600    1:m500 s600         2:m550 s1700    3:m500 s600         
4:m500 s650    5:m500 s600         6:m500 s600    7:m500 s1750         
8:m500 s600    9:m500 s600         10:m500 s600    11:m550 s600         
12:m500 s600    13:m500 s1750         14:m500 s1700    15:m500 s1750         

16:m450 s650    17:m500 s600         18:m500 s600    19:m500 s650         
20:m500 s650    21:m450 s1700         22:m500 s650    23:m500 s650         
24:m450 s1700    25:m550 s1700         26:m500 s1700    27:m500 s1750         
28:m500 s1750    29:m450 s650         30:m500 s1700    31:m500 s1700         

32:m550
Extent=63950
Mark  min:450     max:550
Space min:600     max:1750

次に、こちらがこのモジュールを使って発射した時のコードです。
Ready to receive IR signals
Decoded Unknown(0): Value:0 Adrs:0
Decoded Unknown(0): Value:0 Adrs:0 (0 bits)
Raw samples(68): Gap:61444
  Head: m8850  s4550
0:m450 s650    1:m450 s650         2:m500 s1750    3:m450 s600         
4:m500 s650    5:m500 s600         6:m500 s600    7:m500 s1750         
8:m450 s650    9:m500 s600         10:m450 s700    11:m400 s700         
12:m400 s700    13:m450 s1800         14:m400 s1800    15:m400 s1800         

16:m450 s700    17:m400 s700         18:m400 s700    19:m450 s650         
20:m450 s700    21:m400 s1800         22:m450 s650    23:m450 s650         
24:m450 s1800    25:m400 s1800         26:m450 s1800    27:m400 s1800         
28:m450 s1800    29:m400 s700         30:m400 s1800    31:m450 s1800         

32:m400
Extent=63800
Mark  min:400     max:500
Space min:600     max:1800

0010 0001 (=0x21)
0000 0111 (=0x07)
0000 0100 (=0x04)
1111 1011 (=0xFB)

一見よさそうですが、Decoded Unknownとなっています。



このリモコンコードはNECフォーマットのコードです。
NECフォーマットについては、こちらに 詳しく紹介されています。
Mark時間(電波を発射している時間)とSpace時間(電波を発射していない時間)でビットの0/1を表現します。

規格ではDataBit=0は1TのMark+1TのSpace(562μSec+562μSec)、DataBit=1は 1TのMark+3TのSpace(562μSec+1686μSec)です。
今回、受信データの解析に使用したライブラリは、25%までの誤差を許しています。
つまり、1T=562μ秒±25%(421.5μ秒〜702.5μ秒)、 3T=1686μ秒±25%(1514.5μ秒〜1857.5μ秒)として判定しますが、
この範囲に収まらない(それ以上に誤差が大きい)のでコードを解析できません
m400(Mark時間が400μ秒)の箇所が何か所かありますが、これは25%以上の誤差となっていて、1Tと判定しません。
s700(Space時間が700μ秒)の箇所もいくつかあります。これもかなりきわどい値です。

ちなみにTVに向けて発射してみましたがTVの電源は入りませんでした。



リモコンの受信を試してみました。
送信時に使用したTVの電源ONのコード(0x210704FB)を受信してみます。
ビットがローテーションすることが分かったので、受信データもローテーションしています。

I received: 0x84---> 0x21
I received: 0xE0---> 0x07
I received: 0x20---> 0x04

0x84 1000 0100 -> 0010 0001 = 0x21
0xE0 1110 0000 -> 0000 0111 = 0x07
0x20 0010 0000 -> 0000 0100 = 0x04

データがローテーションすることを考慮すれば、受信は正しくできるようです。

このモジュールを使って、TVなどを操作することはできませんが、市販の赤外線リモコンでマイコンを操作することはできます。