本体に内蔵している赤外線ユニットを利用してNECフォーマットの赤外線送信を実験しました。現時点の情報ですので最新情報はM5StickC非公式日本語リファレンスを確認してください。
概要
M5StickCにはGPIO9に赤外線リモコン用のIRが内蔵されており、汎用的なリモコンとして利用が可能です。
ローレベルな関数を利用して、直接送信することも可能ですが、一般的な利用を想定して外部ライブラリを利用しています。
利用ライブラリ(IRremoteESP8266)
IRremoteESP8266はArduinoの標準ライブラリからインポートして利用することができるライブラリで、IRremoteという有名な赤外線リモコンのライブラリをESP8266とESP32に特化した形でフォークしたものです。
元になったIRremoteは受信しかできませんが、IRremoteESP8266を利用することで送信も可能です。
受信テスト
送信できたのかを確認するためには、受信環境を用意したほうがテスト簡単です。テレビとそのリモコンがあれば、送信コードを調べることで最低限確認ができますが、前回利用した赤外線受信ユニットを利用して実験を行いました。
まずは、本物のリモコンを操作して、どんなコードが飛んでいるのかを確認して、そのコードと同じものを送信できるようにします。
受信側はIRremoteESP8266のサンプルスケッチであるIRrecvDumpV2を利用すると簡単に分析が可能です。受信ユニットを接続したPINの番号を変更するだけで動きました。もちろん前回実験したときと同じデータが受信できました。
送信側コード(GitHub)
#include <M5StickC.h> #include <IRremoteESP8266.h> #include <IRsend.h> #include <IRutils.h> const uint16_t kIrLed = 9; // M5StickCはGPIO9にIRが内蔵 IRsend irsend(kIrLed); // IR送信を宣言 const uint32_t CUSTOMER_CODE = 0x00ff; // カスタマーコードをセット // リモコンコード保存用構造体 struct REMOTE { char name[9]; uint8_t command; }; // リモコンコード一覧 REMOTE remote[] = { { "POWER" , 0x45 }, { "VOL+" , 0x46 }, { "VOL-" , 0x15 }, { "0" , 0x16 }, { "1" , 0x0c }, { "2" , 0x18 }, { "3" , 0x5e }, { "4" , 0x08 }, { "5" , 0x1c }, { "6" , 0x5a }, { "7" , 0x42 }, { "8" , 0x52 }, { "9" , 0x4a }, }; int cursor = 0; // カーソル位置 void setup() { M5.begin(); // M5StickC初期化 irsend.begin(); // IR初期化 // リモコン項目表示 M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(0, 8); for ( int i = 0 ; i < ( sizeof(remote) / sizeof(REMOTE) ) ; i++ ) { M5.Lcd.print((cursor == i) ? ">" : " "); M5.Lcd.println(remote[i].name); } } void loop() { M5.update(); // ボタン状態更新 // M5ボタンで送信 if ( M5.BtnA.wasPressed() ) { // 送信4Byte(カスタマーコード2Byte+リモコンコード+反転リモコンコード) uint64_t send = 0; send = (uint64_t)reverseBits(CUSTOMER_CODE >> 8, 8) << 24; // カスタマーコード(上位8bit) send += (uint64_t)reverseBits(CUSTOMER_CODE & 0xff, 8) << 16; // カスタマーコード(下位8bit) send += reverseBits(remote[cursor].command, 8) << 8; // リモコンコードを順番入れ替えて送信 send += reverseBits(remote[cursor].command, 8) ^ 0xff; // リモコンコードのビット反転(パリティ) irsend.sendNEC(send); // 送信 // デバッグ表示 Serial.printf("Send IR : 0x%08LX", send); Serial.printf("(customer=0x%04X, ", CUSTOMER_CODE); Serial.printf("command=0x%02X)\n", remote[cursor].command); } // 右ボタンでカーソル移動 if ( M5.BtnB.wasPressed() ) { cursor++; cursor = cursor % ( sizeof(remote) / sizeof(REMOTE) ); // カーソル描画 M5.Lcd.setCursor(0, 8); for ( int i = 0 ; i < ( sizeof(remote) / sizeof(REMOTE) ) ; i++ ) { M5.Lcd.println((cursor == i) ? ">" : " "); } } delay(100); }
上記を実行するとリモコンの一覧がでてきて、右ボタン(Bボタン)でカーソルが動き、下ボタン(Aボタン)で送信をします。
IRremoteESP8266のサンプルスケッチであるIRsendDemoのPINを9に変更してまずは動かしたほうがわかりやすいと思いますが、PIN番号を指定して宣言すればあとは実際に送信するコードを指定するだけで動きます。
赤外線リモコンのコードは会社によって複数フォーマットがあり、今回は一番有名なNECフォーマットで送信しています。
NECフォーマットの特徴としては2バイトのカスタマーコード(会社)があり、ここで自分が利用するコード以外が来たら無視する設定になっています。その後に送信するリモコンコードと、そのコードを反転したパリティの4バイトを送るのですが、ビットの並びが下位から上位の順番なのでreverseBits()関数を利用して順番を入れ替えています。
Send IR : 0x00FFA25D(customer=0x00FF, command=0x45)
上記が0x45(POWERボタン)のコードを送ったときのデータですが、ビットの並びが違うので、実際に送信されたデータを見ただけだとすぐに解析ができません。
実際に利用する場合には、実物のリモコンが送信している0x00FFA25DをPOWERボタンとしてデータ保持しているほうがシンプルなコードになります。
シンプル送信側コード(GitHub)
#include <M5StickC.h> #include <IRremoteESP8266.h> #include <IRsend.h> const uint16_t kIrLed = 9; // M5StickCはGPIO9にIRが内蔵 IRsend irsend(kIrLed); // IR送信を宣言 // リモコンコード保存用構造体 struct REMOTE { char name[9]; uint64_t command; }; // リモコンコード一覧 REMOTE remote[] = { { "POWER" , 0x00FFA25DUL }, { "VOL+" , 0x00FF629DUL }, { "VOL-" , 0x00FFA857UL }, { "0" , 0x00FF6897UL }, { "1" , 0x00FF30CFUL }, { "2" , 0x00FF18E7UL }, { "3" , 0x00FF7A85UL }, { "4" , 0x00FF10EFUL }, { "5" , 0x00FF38C7UL }, { "6" , 0x00FF5AA5UL }, { "7" , 0x00FF42BDUL }, { "8" , 0x00FF4AB5UL }, { "9" , 0x00FF52ADUL }, }; int cursor = 0; // カーソル位置 void setup() { M5.begin(); // M5StickC初期化 irsend.begin(); // IR初期化 // リモコン項目表示 M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(0, 8); for ( int i = 0 ; i < ( sizeof(remote) / sizeof(REMOTE) ) ; i++ ) { M5.Lcd.print((cursor == i) ? ">" : " "); M5.Lcd.println(remote[i].name); } } void loop() { M5.update(); // ボタン状態更新 // M5ボタンで送信 if ( M5.BtnA.wasPressed() ) { // 送信4Byte(カスタマーコード2Byte+リモコンコード+反転リモコンコード) irsend.sendNEC(remote[cursor].command); // デバッグ表示 Serial.printf("Send IR : 0x%08LX", remote[cursor].command); } // 右ボタンでカーソル移動 if ( M5.BtnB.wasPressed() ) { cursor++; cursor = cursor % ( sizeof(remote) / sizeof(REMOTE) ); // カーソル描画 M5.Lcd.setCursor(0, 8); for ( int i = 0 ; i < ( sizeof(remote) / sizeof(REMOTE) ) ; i++ ) { M5.Lcd.println((cursor == i) ? ">" : " "); } } delay(100); }
実物のリモコンが手元にある場合には、受信して確認したデータをそのまま送信したほうが楽だと思います。ネット上で送信データを調べた場合には内部的な数値なのか、送信時のデータなのかを確認してから利用してください。
まとめ
赤外線リモコンは、データ送信時にビット配列を入れ替えるところがちょっと面倒です。またM5StickCのリモコンデータは受信側の性能とあると思いますが、2メートルぐらいの範囲ぐらいまで安定して送信できました。
ただし、実験で利用したELEGOOのリモコンもほぼ同じ距離だったので、安いリモコンはこれぐらいの距離が限界なのかもしれません。
コメント