2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

赤外線リモコンを解析してネットワーク経由で送信する!- その2「信号解析」

Last updated at Posted at 2018-09-18

こんにちは、前回のその1から引き続き「赤外線リモコンを解析してネットワーク経由で送信する!」について書いて行こうと思います。今回は「赤外線信号の解析」について書いていきます。

信号解析を始めよう、、、だけど

まずはセオリーどおりArduinoのライブラリ「IRRemote」を入れて「IRRecvDumpV2」を使って赤外線信号を解析してみました。調べるとすぐに出てきますね。結果は、、、

Encoding UNKNOWN

。。。こうなると同ライブラリのsendNECだったり、sendSony等が使えない。。。
ちなみに使っているリモコンは、SHARP 液晶テレビ(AQUOS) 純正リモコン GB228SA RRMCGB228WJSAです。

ライブラリを使わずに赤外線を解析しよう!

またライブラリをそのまま使うと解析しづらそうなので、ライブラリを使わない方法を調べてみました。
Arduinoで赤外線リモコンの信号を解析する

このコードでは受信した赤外線のON時間とLOW時間を記録して出力します。
このままでも送信することは可能ですが、とても長いので16進数で保存しておきたい!
そこでArduino上で書いてもよいですが、簡単にProcessingで解析してみましょう。

以下にArduinoとProcessingのコードをおいておきます。使い方は起動し、画面上を何度かクリックすることで、シリアル通信が始まります。送信し、受信成功するとプロンプトに16進数の信号が表示されます。

Arduino

#define IRRECV_PIN 12

unsigned long now = micros();
unsigned long lastStateChagedMicros = micros();
int state = HIGH;

void setup(){
  Serial.begin(115200UL);
  pinMode(IRRECV_PIN, INPUT);
  establishedContact();
}

void loop(){
  if (Serial.available() <= 0) return;
  readSignal();
}

void readSignal(){
  if (state == LOW) waitLow();
  else if (waitHigh() == 1) return;

  now = micros();
  int pulse_width = (now-lastStateChagedMicros)/10;
  if (abs(pulse_width) > 1000) {
    Serial.print("\n");
  }
  Serial.print(pulse_width, DEC);
  Serial.print(",");
  lastStateChagedMicros = now;
  state = !state;
}

void waitLow(){
  while (digitalRead(IRRECV_PIN) == LOW){
    ;
  }
}

int waitHigh(){
  unsigned long start = micros();
  while (digitalRead(IRRECV_PIN) == HIGH){
    if (micros() - start > 1000){
      // wait over 1000us
      return 1;
    }
  }
  return 0;
}

void establishedContact(){
  while (Serial.available() <= 0){
    //Serial.println("0,0");
    delay(300);
  }
}

Processing

import processing.serial.*;
Serial myPort;

int[] recv_data = new int[200];
float x, pre_x;
boolean state = true;
boolean requested = false;
boolean received = false;
float t_margin, b_margin, r_margin, l_margin;
int base_t = 0;

void setup(){
  myPort = new Serial(this, Serial.list()[0], 115200);
  size(1800, 200);
  configure();
  initial();
}

void draw(){
  drawWave();
  drawFrame();
}

void drawWave(){
  if (!requested || !received) return;
  initial();
  evalBaseTime();
  strokeWeight(3);
  for (int i = 1; i < recv_data.length; i++){
    stroke(0,200,100);
    x += recv_data[i] / 4.5;
    if(state) line(pre_x+l_margin, t_margin+5, x+l_margin, t_margin+5);  // HIGH
    else line(pre_x+l_margin, height-b_margin-5, x+l_margin, height-b_margin-5);  //LOW
    line(x+l_margin, t_margin+5, x+l_margin, height-b_margin-5); 
    pre_x = x;
    state = !state;  // HIGH <=> LOW
    if (i==1) {
      fill(255, 0, 0);
      textSize(20);
      text(recv_data[1], x+l_margin-20, height-b_margin+20);
    }
  }
}

void evalBaseTime(){
  int sum = 0;
  int cnt_t = 0;
  for (int i = 3; i < recv_data.length; i+=2){
    sum += recv_data[i];
    cnt_t ++;
  }
  if (cnt_t <= 0) return;
  base_t = sum/cnt_t;
  evalBinary();
}

void evalBinary(){
  String bin ="";
  for (int i = 4; i < recv_data.length; i+=2){
    bin += (recv_data[i] > 2*base_t) ? "1" : "0";
  }
  bin = "1" + bin;
  long dec = Long.parseLong(bin, 2);
  String hex = Long.toHexString(dec);
  println(hex);
}

void configure(){
  t_margin = 30;
  b_margin = 70;
  l_margin = 50;
  r_margin = 200;
}

void initial(){
  background(0);
  x = 0;
  pre_x = 0;
  //requested = false;
  received = false;
}

void drawFrame(){
  strokeWeight(1);
  stroke(255,0,0);
  DisplayGraphFrame();
  DisplayInfo();
}

void DisplayGraphFrame(){
  // vertical axis |
  line(l_margin, t_margin, l_margin, height-b_margin);
  line(width-r_margin, t_margin, width-r_margin, height-b_margin);
  // horizontal axis -
  line(l_margin, t_margin, width-r_margin, t_margin);
  line(l_margin, height-b_margin, width-r_margin, height-b_margin);
}

void DisplayInfo(){
  fill(0);
  stroke(255);
  rect(width-r_margin+20, t_margin, 100, 30);
  fill(255);
  textSize(25);
  text("T="+base_t, width-r_margin+25, t_margin+23);
}

void serialEvent(Serial myPort){
  if (!requested) return;
  String recvString = myPort.readStringUntil('\n');
  recvString = trim(recvString);
  if (!received && recvString != null){
    recv_data = int(split(recvString, ","));
    received = true;
  }
}

void mousePressed(){
  myPort.write("REQUEST");
  requested = true;
}

まず基本となる「T」を解析します。
赤外線信号の詳しいことはボクにもわかる地上デジタル 地デジ方式編 - 赤外線リモコン方式を参考にしました。
かいつまんで説明すると、赤外線信号は、
[リーダーON], [リーダーOFF]、[ON時間]、[OFF時間]、[ON時間]、[OFF時間]、、、
となります。
ON時間は全てほぼ同じで、ON時間をTとします。
[リーダーON]、[リーダーOFF]は信号の始まりを表します。同じリモコンであればこれらはすべて同じで、Tの何倍かを記録しておきます。
ON時間はTとなので、OFF時間1Tであれば"0"、**OFF時間が3Tであれば"1"**となります。
それで得た2進数信号はリーダー信号は含まれていないのでビットの始まりがわからないので、先頭に"1"をつけて16進数に変換することで信号が得られます。

こうして「Tの値」「リーダー信号がTの何倍か」「16進数の信号」が得られます。

#次回は
今回得られた「Tの値」「リーダー信号がTの何倍か」「16進数の信号」を使って赤外線の送信用の関数を作っていきます。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?