Last active
October 23, 2018 06:33
-
-
Save b2ox/4d351086e6f3272052b5c0445a04e7e2 to your computer and use it in GitHub Desktop.
赤外線リモコンを受信してちょっとだけ解析してシリアルにjsonで流すやつ for arduino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 赤外線リモコンを受信し、シリアルに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(); | |
} | |
} |
解析結果を利用しやすくするために表示部分を切り出したり大整理。
確保する作業配列も解析結果の個数を元に縮小。
表示形式の切り替え機能を追加
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
解析結果の出力部分の変数jが被ってたので外に出した。
D11ピンだとISPピンにモジュール挿して使えて便利ね、とか、適宜HIGH,LOWを出力して連続した3ピンにモジュールを挿しても使えるねとかいうメモを追加。