Arduinoで赤外線受信を割り込み処理

###概要
Arduinoで赤外線受信IC VS1831 を使って、割り込みを使って赤外線リモコンを受信します。
対象のリモコンはNECフォーマットのみ
他の受信プログラムとちょっと違うのは、都度解析するのでは無く、全文受信したら解析するようにしています。
micros()の約70分のオーバーフローは未考慮
IRremoteライブラリは重たいので使わない方法で実現。
他のSONYフォーマットや家電製品協会フォーマットも作れそうですがやらない(^^;
###レグザリモコン
電源ボタン
NEC:00000010111111010100100010110111:2FD48B7
音量＋
NEC:00000010111111010101100010100111:2FD58A7
音量-
NEC:00000010111111010111100010000111:2FD7887
チャンネル＋
NEC:00000010111111011101100000100111:2FDD827
チャンネル-
NEC:00000010111111011111100000000111:2FDF807
CH1
NEC:00000010111111011000000001111111:2FD807F
CH2
NEC:00000010111111010100000010111111:2FD40BF
CH3
NEC:00000010111111011100000000111111:2FDC03F
###回路図
![スクリーンショット 2019-10-16 14.52.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111210/cf33e7c7-847e-2036-2a43-a1168e8b6d9b.png)
###基板
![スクリーンショット 2019-10-16 14.53.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111210/d29fec42-2f3a-9beb-2e87-14722d3b2d31.png)
###引用
赤外線リモコン受信（Physical Computingに挑戦！）
http://physicom.digick.jp/
http://physicom.digick.jp/?p=3928

赤外線リモコンの通信フォーマット（elm-chanさん）
http://elm-chan.org/index_j.html
http://elm-chan.org/docs/ir_format.html

赤外線リモコンのフォーマット（電子工作の森さん）
http://www.asahi-net.or.jp/~gt3n-tnk/
http://www.asahi-net.or.jp/~gt3n-tnk/IR_TX1.html
***
```c++
// 赤外線リモコン 割り込み受信プログラム
// buffにIr割り込み時間を記録しておき、後に受信内容を解析
// NEC用リモコン専用
//http://elm-chan.org/docs/ir_format.html
//http://www.asahi-net.or.jp/~gt3n-tnk/IR_TX1.html
//

#define BUFF_SIZE 256
#define PIN_IRLED   2
#define PIN_RUNLED  4
#define PIN_IRIN    3

#define S_MAX(n,t)    (((n- 500) <= t) && (t < (n+ 500)))
#define V_MAX(n,t)    (((n- 100) <= t) && (t < (n+ 100)))

unsigned long prev;
unsigned long time;
int index = 0;
unsigned long buff[BUFF_SIZE];

//--------------------------------------------------------------------------------
// arduino初期化
//--------------------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  
  pinMode(PIN_RUNLED, OUTPUT);        // IR受信した時に光らせるLED
  pinMode(PIN_IRIN, INPUT);           // Ir受信ポート

  attachInterrupt(1, blink, CHANGE);  // Ir割り込みポート設定　※PIN_IRIN 3 だけど、1を設定
  prev = micros();
}

//--------------------------------------------------------------------------------
// arduinoメインループ
//--------------------------------------------------------------------------------
void loop() {
  enum{
      ST_LEADER1 = 0,
      ST_LEADER2,
      ST_DATA_M,
      ST_DATA_L,
      ST_REPEAT,
      ST_OFF_RUN,
  };

  unsigned long temp = 0;
  unsigned long dat = 0;
  
  unsigned char Ir_state = ST_LEADER1;

  time = micros();
  
  if ((index > 0) && (time-prev > 20000)) { // この処理は見直したほうがいいかも。
    Serial.println("");
    Serial.println("****************");
    Serial.println(index,HEX);

    for (int i = 1; i < index; i++) { // buff に記録されている時間間隔を表示
      Serial.print(buff[i]);
      Serial.print(",");
    }
      Serial.println("");

    for (int i = 1; i < index; i++) { // buff 解析
      temp = buff[i];
      switch(Ir_state){
        case ST_LEADER1:
              if(V_MAX(8992,temp)){ // 562us * 16T = 8.992ms
                Serial.print("NEC");
                Ir_state = ST_LEADER2;
              }
                break;
        case ST_LEADER2:
              if(V_MAX(4496,temp)){ // 562us * 8T = 4.496ms
                Serial.print(":");
                Ir_state = ST_DATA_M;
              } if(V_MAX(2248,temp)){  // 562us * 4T = 2.248ms
                Ir_state = ST_REPEAT;
              } 
                break;
        case ST_DATA_M:
              if(temp < 616){ // 0.56ms * 1.1 = 0.616ms
                Ir_state = ST_DATA_L;
              }
              break;
        case ST_DATA_L:
              if(temp < 616){ // 0.56ms * 1.1 = 0.616ms
                Serial.print("0");
                dat=dat<<1;
              }
              else if(temp < 2475){ // 2.25ms * 1.1 =2.475ms
                Serial.print("1");
                dat=dat<<1;
                dat=dat|0x0001;
              }              
              Ir_state = ST_DATA_M;
              break;
        case ST_REPEAT:
              if(temp < 616){ // 0.56ms * 1.1 = 0.616ms
                Serial.print("Repeat");
              }
              break;
        default:
              break;
      }
    }
    
    Serial.print(":");
    Serial.println(dat,HEX);
    dat = 0;
    index = 0;
    prev = time;
  }
  delay(10);
}


//--------------------------------------------------------------------------------
// 赤外線受信割り込み処理
// 立ち上がり、立ち下がり両方で割り込みがかかります。
//--------------------------------------------------------------------------------
void blink() {
  PORTD |= _BV(2);  // PIN_IRLED 点灯
  time = micros();

  buff[index] = time - prev;
  prev = time;
  index++;
  if (index >= BUFF_SIZE) {
    index = 0;
  }
  PORTD &= ~_BV(2);  // PIN_IRLED 消灯
}