SSブログ

Arduinoで赤外線リモコンコードを読み出す 家庭でできるIoT! 4パルス目 [ESP32]

odelic_seen_01.png前回ちらっと書いたリモコンコードの受信です。

秋月電子で売られている赤外線受光素子( http://akizukidenshi.com/catalog/g/gI-04659/ )をデータシート通りに抵抗、コンデンサ等を接続し、OUT端子をESP8266に接続します。
この受光素子はサブキャリアを検出するとLowを出力、サブキャリアが無ければHigh(HI-Z)です。
ESP8266側では端子割込みを使ってLowやHighの時間を測定し、時間をビットに換算します。
比較的簡単な処理ですが、悩むのがフレームの終了検出で、NECフォーマットであればビット数は固定長ですが、AEHAフォーマットの場合はビット数は可変長となるので、どこまで取り込んで良いのか判りません。
ですがフレーム間の間隔は必ず空く仕様なので、時間でフレームの終端を強制的に決めてしまう事としました。
とは言え三菱のエアコンのリモコンコードはデータ部が18byte有り、もし全ビットが1であればフレーム長は250msを超えてしますので、いかがなものか?と思わないでもないですが、、、

まぁリモコンコードを見るだけの処理なので、細かい事は気にしません。


aquos_odelic_power_on_off.png実際にスケッチを組んで読み出したものです。オーデリックのリモコンとアクオスのリモコンを受信しています。
オーデリックは前出の様にNECフォーマットです。アクオスはAEHAフォーマットでした。このリモコンコードはメーカーが仕様で示したものではなく、あくまでも自分で解析したコードである事に十分注意して下さい。仮に他のプログラムでこのコードを送信しても上手くは行かないと思います。学習リモコンの様にする場合は、受信したコードを送信可能なプログラムが別途必要です。なお、前回のプログラムでは使えます。


#include  <ESP8266WiFi.h>

void ICACHE_RAM_ATTR irRemocon_interrupt( void );

#define  IR_CONT  12 /* Ir LED ON/OFF */
#define  IR_RECV  13 /* Ir receive */

#define  Max_IR_Bits_NEC  32
#define  Max_IR_Bits_AEHA 256

#define  NEC_HEADER_LOW_MIN_PERIOD  462UL
#define  NEC_HEADER_LOW_MAX_PERIOD  662UL

#define  AEHA_HEADER_LOW_MIN_PERIOD 350UL
#define  AEHA_HEADER_LOW_MAX_PERIOD 500UL

unsigned long IR_Low_Time;    // holds IR bursting time
unsigned long IR_High_Time;   // holds IR high idling time
unsigned long Latest_Time_ms;
unsigned short IR_Data[Max_IR_Bits_AEHA] = {0,};  // holds the bit length of each data bit by micro-sec.
int IR_State;
int IR_Bit_Count;
bool IR_Active = false;  // when true, the capturing IR data stream is valid
char IR_formatType;

void setup()
{
  Serial.begin( 115200UL );
  Serial.println( "\r\n\r\nIR recieve code print out." );
  pinMode( IR_RECV, INPUT_PULLUP );
  attachInterrupt( IR_RECV, irRemocon_interrupt, CHANGE );
}

void loop()
{
  if( IR_Active )
  {
    if( IR_formatType == 'N' && (millis() - Latest_Time_ms) >= 18UL )
    {
      if( irRemocon_available() >= 4 ) IR_nec();
      irRemocon_init();
    }
    else if( IR_formatType == 'A' && (millis() - Latest_Time_ms) >= 10UL )
    {
      if( irRemocon_available() >= 6 ) IR_aeha();
      irRemocon_init();
    }
  }
}

/*************************************************************************/
/* int to hexadecimal                                                    */
/*************************************************************************/
char *itoh( char *dst, unsigned int value )
{
  sprintf( dst, "%02x", value );
  
  return dst;
}

/*************************************************************************/
/* IR_REMOCON初期化                                                      */
/*************************************************************************/
void irRemocon_init( void )
{
  IR_Active = false;       // when 1, the capturing IR data stream is valid
  IR_formatType = 0;
  IR_State = 0;
}

/*************************************************************************/
/* データ数確認                                                          */
/*************************************************************************/
int irRemocon_available( void )
{
  if( IR_Active ) return IR_State / 8;

  return 0;
}

/*************************************************************************/
/* NECタイプのデータ受信                                                 */
/*************************************************************************/
int irRemocon_rxNEC( byte dst[], int size )
{
  int index = 0;

  for( int i = 0; i < Max_IR_Bits_NEC; i++ )
  {
    dst[index] >>= 1;
    if ( IR_Data[i] > ((NEC_HEADER_LOW_MIN_PERIOD + NEC_HEADER_LOW_MAX_PERIOD) / 2) * 3 )
      dst[index] |= 0x80;
    if( (i % 8) == 7 ) index++;
  }

  return index;
}

/*************************************************************************/
/* AEHAタイプのデータ受信                                                */
/*************************************************************************/
int irRemocon_rxAEHA( byte dst[], int size )
{
  volatile int limit = IR_State;
  int index = 0;

  for( int i = 0; i < limit; i++ )
  {
    dst[index] >>= 1;
    if ( IR_Data[i] > ((AEHA_HEADER_LOW_MIN_PERIOD + AEHA_HEADER_LOW_MAX_PERIOD) / 2) * 3 )
      dst[index] |= 0x80;
    if( (i % 8) == 7 ) index++;
  }

  return index;
}

/****************************************************************************/
/* IR RECEIVE for NEC format                                                */
/****************************************************************************/
void IR_nec( void )
{
  int sz = irRemocon_available();
  byte *iRData = new byte[sz];
  sz = irRemocon_rxNEC( iRData, sz );

  String str = "";
  char asc[8];
  for(int i = 0; i < sz; i++)
  {
    str += itoh(asc,(unsigned int)iRData[i]);
    str += ",";
  }
  delete[] iRData;

  if( str.length() > 0 )
  {
    Serial.print( "type NEC:sz = " ); Serial.print( sz, DEC );
    Serial.print( " code:" ); Serial.println( str );
  }
}

/****************************************************************************/
/* IR RECEIVE for AEHA format                                               */
/****************************************************************************/
void IR_aeha( void )
{
  int sz = irRemocon_available();
  byte *iRData = new byte[sz];
  sz = irRemocon_rxAEHA( iRData, sz );

  char buf[8];
  String str = "";
  for(int i = 0; i < sz; i++)
  {
    str += itoh(buf,(unsigned int)iRData[i]);
    str += ",";
  }
  delete[] iRData;

  if( str.length() > 0 )
  {
    Serial.print( "type AEHA: sz=" ); Serial.print( sz, DEC );
    Serial.print( " code:" ); Serial.println( str );
  }
}

/*************************************************************************/
/* IR_REMOCON割り込み                                                    */
/*************************************************************************/
void ICACHE_RAM_ATTR irRemocon_interrupt( void )
{
  if( digitalRead( IR_RECV ) == LOW )  // edge is low.
  {
    if( IR_Active )  //LOWからLOWまでの時間を計測して配列に保存する
    {
      unsigned long period = micros() - IR_Low_Time;

      if( IR_formatType == 'N' &&
        period >= NEC_HEADER_LOW_MIN_PERIOD * 2 && period <= NEC_HEADER_LOW_MAX_PERIOD * 4 )
      {
        if( IR_State < Max_IR_Bits_NEC )
        {
          IR_Data[IR_State++] = (unsigned short)period;
          IR_Bit_Count = IR_State;
          Latest_Time_ms = millis();
        }
        else irRemocon_init();
      }
      else if( IR_formatType == 'A' &&
        period >= AEHA_HEADER_LOW_MIN_PERIOD * 2 && period <= AEHA_HEADER_LOW_MAX_PERIOD * 4 )
      {
        if( IR_State < Max_IR_Bits_AEHA )
        {
          IR_Data[IR_State++] = (unsigned short)period;
          IR_Bit_Count = IR_State;
          Latest_Time_ms = millis();
        }
        else irRemocon_init();
      }
    }
    IR_Low_Time = micros();
  }
  else  // edge is high.
  {
    unsigned long period = micros() - IR_Low_Time;

    if( period >= NEC_HEADER_LOW_MIN_PERIOD * 8 )  // NECフォーマット
    {
      IR_Active = true;
      IR_State = 0;
      IR_High_Time = millis();  //先頭フレームの後半の時間となる
      IR_formatType = 'N';
      Latest_Time_ms = millis();
    }
    else if( period >= AEHA_HEADER_LOW_MIN_PERIOD * 8 )  // 家製協(AEHA)フォーマット
    {
      IR_Active = true;
      IR_State = 0;
      IR_High_Time = millis();  //先頭フレームの後半の時間となる
      IR_formatType = 'A';
      Latest_Time_ms = millis();
    }
    else {}
  }
}




ESP-WROOM-02開発ボード

ESP-WROOM-02開発ボード

  • 出版社/メーカー: スイッチサイエンス(Switch Science)
  • メディア: おもちゃ&ホビー









nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。