Skip to content

Instantly share code, notes, and snippets.

@b2ox
Last active October 23, 2018 06:33
Show Gist options
  • Save b2ox/4d351086e6f3272052b5c0445a04e7e2 to your computer and use it in GitHub Desktop.
Save b2ox/4d351086e6f3272052b5c0445a04e7e2 to your computer and use it in GitHub Desktop.
赤外線リモコンを受信してちょっとだけ解析してシリアルにjsonで流すやつ for arduino
// 赤外線リモコンを受信し、シリアルにjson形式とかで出力する
#include <Arduino.h>
#define CODE_MAX 16 // 解析結果(8bit)の最大個数
#define NUM_MAX 160 // 作業容量 > (16+1)*8
#define TIMEOUT 20000 // 無受信時のタイムアウトμs
#define IR_PIN 11 // 受信モジュール出力の信号入力ピン
// D11:MOSI を使うとISP用ピンのVcc,MOSI,GNDにまたがって挿すことができる
void setup() {
Serial.begin(115200);
pinMode(IR_PIN, INPUT);
}
// readIRの結果格納用
int work[NUM_MAX]; // 作業領域
int works; // ↑の有効個数
int T, Tmin, Tmax; // 単位幅μs
byte code[CODE_MAX]; // 解析結果を格納
int codes; // ↑の有効個数
int readIR(char irPin) {
boolean mode = HIGH; //呼び出し時点で赤外線モジュール出力はHIGH(=リモコンLEDオフ)と仮定する
int i = 0;
Tmin = TIMEOUT; // LOW,HIGH継続時間の最小値の計測用
while(i < NUM_MAX) {
unsigned long st = micros();
unsigned long dur = TIMEOUT; //時間μs
// LOW,HIGHが変化するまでループで待機(timeoutを超えたら抜ける)
do {
dur = micros() - st;
} while (digitalRead(irPin) == mode && dur <= TIMEOUT);
if (dur > TIMEOUT) break;
mode = !mode;
int d = (int)dur;
work[i++] = d;
if (d < Tmin) Tmin = d; // 最小値を更新
}
works = i - 1;
if (works < 18) return -1; // リーダー(2)+8bitデータ(16)くらいはあるはずなので少ないのは読み取りミス
// 単位幅にはばらつきがあるので
// 最小値の2倍を超えない範囲で最大のものを求め
int Tmin2 = Tmin * 2;
Tmax = Tmin;
for(int j = 1; j <= works; j++){
int w = work[j];
if (w < Tmin2 && Tmax < w) Tmax = w;
}
if (Tmax == Tmin) return -2; // ばらつきが全く無いのは不自然なので読み取りミス
// 中央値を10μ単位で四捨五入して単位幅Tとする
T = (int)((10.0f + Tmin + Tmax) / 20) * 10;
// Tでクォンタイズ(上書きする)
for(int j = 1; j <= works; j++) work[j-1] = (int)(0.5f + (float)work[j] / T);
work[works-1] = 0;
// コード解析 NECとAEHAは 1T+1T:0 / 1T+3T:1 で8bit単位で構成される
// リーダー部分(NEC:16T+8T, AEHA:8T+4T)のチェックは省略
byte d = 0;
int k = 0;
for (int j = 2; j < works; j += 2) {
int a = work[j]; // LED onの時間(Tで量子化)
int b = work[j+1]; // LED offの時間
if (a == 1) { // (a,b): (1,1)->0, (1,3)->1
if (b == 1 || b == 3) {
d = d << 1;
if (b == 3) d += 1;
k++;
if (k % 8 == 0) {
code[k / 8 - 1] = d;
d = 0;
}
} else a = 0; // 1T+1T or 1T+3T以外は終端とみなす
} else if (7 < a && a < 11) { // 途中にリーダーが入って続きのコードを出力するものがある(東芝 WH-D9Gとか)
// 8Tジャストということはないので誤差を許容
code[k / 8] = 0; // ダミーデータとして0を入れておく
k += 8;
a = 1;
}
if (a != 1) break;
}
codes = (byte)(k / 8);
// コード解析 ここまで
return works;
}
void putJson() {
//受信データをjson形式でシリアル出力
Serial.print("{\"t\":");
Serial.print(T);
Serial.print(",\"w\":");
Serial.print(Tmax - Tmin);
Serial.print(",\"code\":[");
for (int i = 0; i < codes; i++) {
if (i > 0 && code[i] == (byte)~code[i-1])
Serial.print(-1); // 直前値の補数の場合
else
Serial.print(code[i]);
Serial.print(",");
}
Serial.print("0],\"q\":[");
for(int i = 0; i < works - 1; i++){
Serial.print(work[i]);
Serial.print(",");
}
Serial.println("0]}");
}
void putData() {
//受信データを Tus[Tmax-Tmin]code0,code1,...,0 (値は16進数、直前値の補数は'_')形式で表示
Serial.print(T);
Serial.print("us[");
Serial.print(Tmax - Tmin);
Serial.print("]");
for (int i = 0; i < codes; i++) {
if (i > 0 && code[i] == (byte)~code[i-1])
Serial.print("_"); // 直前値の補数の場合
else
Serial.print(code[i], HEX);
Serial.print(",");
}
Serial.println("0");
}
char mode = 'd'; // 'd' or 'j'のトグル
void loop()
{
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 'd' || c == 'j') { // シリアルに'd','j'が入力されたら表示モードを変更
mode = c;
Serial.print("mode change:");
Serial.println(mode);
}
}
if (readIR(IR_PIN) > 0) {
if (mode == 'j') putJson(); else putData();
}
}
@b2ox
Copy link
Author

b2ox commented Feb 6, 2018

ir_scan.inoを改造。シリアル出力部分もreadIRに詰め込んで、生データは上書きクォンタイズ。容量に余裕があるのでついでにNEC&AEHAとかその派生形式のコード解析を追加。

@b2ox
Copy link
Author

b2ox commented Feb 7, 2018

8bitデータの次はその補数を8bitという組になってるので、直後の補数は-1と出力することにした。
(byte)~dat[j-1]の(byte)を外すとうまく動かない。intで補数を計算しちゃう?

@b2ox
Copy link
Author

b2ox commented Feb 9, 2018

解析結果の出力部分の変数jが被ってたので外に出した。
D11ピンだとISPピンにモジュール挿して使えて便利ね、とか、適宜HIGH,LOWを出力して連続した3ピンにモジュールを挿しても使えるねとかいうメモを追加。

@b2ox
Copy link
Author

b2ox commented Oct 22, 2018

解析結果を利用しやすくするために表示部分を切り出したり大整理。
確保する作業配列も解析結果の個数を元に縮小。

@b2ox
Copy link
Author

b2ox commented Oct 23, 2018

表示形式の切り替え機能を追加

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment