こんにちは、前回のその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進数の信号」を使って赤外線の送信用の関数を作っていきます。