LoRa無線ユニット「LoRaE220-JP」を使用して「M5StickC Plus2」で長距離無線通信(遠隔操作でLチカ)する方法をサンプルプログラムを使って詳しく紹介します。
標準化された「LoRaWAN」ではないため、自由度は高いですがモジュールごとに通信仕様が異なり「E220」以外のモジュールを搭載した機器との互換性がありません(通信仕様を合わせるのが大変)。
このため、今回は同じ無線ユニット「LoRaE220-JP」を2つ使って動作確認しています。
「M5StickC Plus2」の使い方は以下のリンクで詳しく紹介しています。

1.LoRaとは
2.無線ユニットLoRa E220-JPについて
・外観
・通信仕様
3.開発環境の準備
・M5StickC Plus2の準備
・Arduino IDEのインストール
・ライブラリについて
4.動作確認
・動作紹介
・サンプルプログラム(ライブラリ使用)
・サンプルプログラム(ライブラリ未使用)
5.まとめ
1.LoRaとは
「LoRa」とは、「semtech社」が開発した変調方式(電波の飛ばし方)です。
長距離無線(Long Range Radio)を実現することから「Long Range」を略して「LoRa」と呼ばれています。
「LoRa」はWi-Fiのような高速通信はできませんが、遠くまで電波が届くのに省電力であることが特徴です。
通信距離は、壁の無い見通しの良い条件では「数km〜数十km」の通信が可能で、「数m〜数十m」のWi-FiやBluetoothより、はるかに遠くへの無線通信が可能で、ノイズにも強く障害物の影響も受けにくい変調方式です。
しかし、通信速度は「数百bps〜数kbps程度」と遅いため、動画や音声の通信には不向きです。
その代わり消費電力は少ないので、電池で駆動するデバイスで小さなデータを送信する用途には最適で以下のような用途で使用されます。
2.無線ユニットLoRa E220-JPについて
無線ユニット「LoRa E220-JP」について、外観や通信仕様について詳しく紹介します。
詳細仕様は使用されているモジュール「E220-900T22S(JP) 」の以下のデータシートを参照してください。
・外観

梱包状態は上写真のようになります。
アンテナもコンパクトに収まっています。

中身は「本体」と「専用アンテナ」、「Groveコネクタ配線」です。

アンテナはネジ式で、取り付けると全長は約18cmになります。

アンテナは45°と90°に折りたためて回転もできるため、電波状況に合わせて調節できます。

制御デバイス(今回はM5StickC Plus2)との接続には「Groveコネクタ配線」で行い、「UART通信」で制御されます。
・通信仕様
今回使用する「M5Stack」社製の「LoRaE220-JP」の仕様について詳しく紹介します。
このユニットには「220-900T22S(JP)」 という技適取得済みのLoRaモジュールを搭載しており、内部で最低限の配線済みで「UART通信」を行うための「Groveコネクタ配線」をデバイスに接続するだけで使用することができる「LoRa無線通信ユニット」です。
主な使用は以下表のようになります。
| 項目 | 内容 |
|---|---|
| 搭載モジュール | E220-900T22S(JP) |
| 技適 | Telec 認証(001-P01730) |
| 周波数帯 | 920MHz(920.6〜928.0 MHz) |
| 変調方式 | LoRa(Semtech LLCC68) |
| 最大送信出力 | 13 dBm(約20mW) |
| 受信感度 | 標準 約 −124 dBm(SF/BW条件により異なる) |
| 通信距離 | 最大約5km(障害物なし条件、環境による) |
| 通信方式 | UART(シリアル通信) |
| 動作モード | 4種類(DIPスイッチで切替) |
| 電源電圧 | 5V(5.5V超で破損の可能性あり注意) |
| サイズ | 71.4 × 24.0 × 8.0 mm |
| 重量 | 19.2 g |
通信方式は「P2P(固定通信)モード」と「TT(透過)モード」の2つが設定可能です。
この2つの違い、使い方は以下表のようになります。
| モード | 役割 | どんなときに使う? |
|---|---|---|
| P2Pモード (固定通信モード) | LoRa無線のパラメータ(周波数・SF・BWなど)を固定して、 決めた相手(アドレス&チャンネル&暗号化キー:ヘッダー情報として送信)を 選択して複数デバイスと通信できるモード | センサー同士のP2P通信 固定ネットワーク |
| TTモード (透過モード) | UARTで受け取ったデータをそのまま無線に流す。 シンプルなシリアル無線通信モードで、自身のアドレス&チャンネル&暗号化キー (ヘッダー情報不要なデータ送信)と同じデバイスと通信するモード | 小規模な構成で手軽に簡単に 無線通信したい場合 |
無線ユニット「LoRa E220-JP」は使用前に単体で通信設定を行っておく必要があります。
出荷時に初期設定済みですが、自由に使用するためには設定方法について知っておく必要があるため、設定方法について紹介します。
無線ユニットの通信設定のレジスタ構成は以下表のようになります。
ライブラリを使用しない場合は、各レジスタの内容を「UART通信」で書き換えて設定します。

以下表右の「Setting」は今回動作確認に使用したサンプルプログラムの設定内容です。
「Default」は無線ユニットの出荷時の初期設定の内容です。

動作確認に使用した設定内容の詳細は、初期設定の内容と比較して以下表のようになります。
| 設定内容 | 動作確認設定 Setting | 工場出荷時設定 Default |
|---|---|---|
| デバイスアドレス | → | 0x0000h |
| UARTボーレート パリティ | → | 9600 bps 8N1 (固定) |
| Air Data Rate | → | 62,500bps |
| SF (拡散率) | SF9 | SF5 |
| BW (帯域幅) | 125kHz | 500kHz |
| サブパケット長 | → | 200byte |
| RSSI 環境ノイズの有効化 | 有効 | 無効 |
| 送信出力 | → | 13dBm |
| 周波数チャンネル | 920.6MHz | 923.8MHz |
| RSSI バイトの有効化 | 有効 | 無効 |
| WORサイクル | → | 2000ms |
| 暗号化キー | → | 0x0000h |
ライブラリを使用せずに「UART通信」で設定するための書き込みコマンドは以下になります。
前半3byteで「書込みコマンド」と「書き込み開始アドレス」、「レジスタ数」を指定して、続けて各アドレスの設定内容を記述してUARTで送信することで設定を行うことができます。
C0 00 08 = [書き込みコマンド] [書き込み開始レジスタ] [書き込みレジスタ数]
70 20 00 C3 00 00 = レジスタアドレス00h〜07hの内容

無線ユニットの裏側には設定を行うためのディップスイッチ「M0、M1」の設定内容が記載されています。

設定は「M0、M1」スイッチの組み合わせで上画像のように行いますが、これだけでは少々分かりにくいです・・・。
通信設定を行う「M0、M1」スイッチの内容は以下になります。

ノーマル(通信)モード
設定完了後はこのモードで通信可能

WOR受信モード
WOR有効、送信不可

WOR送信モード
WOR有効、送受信可能

Config(設定)モード
設定の書込みや読み出し時はこの設定で行う。
3.開発環境の準備
サンプルプログラムを使用して動作確認するためのデバイスの準備や開発環境の準備、初期設定について紹介します。
・M5StickC Plus2の準備
「M5StickC Plus2」については以下のリンクで詳しく紹介していますので、参考にして初期設定を行なってください。

・Arduino IDEのインストール
「Arduino IDE」はプログラムの作成、書き込みを行う開発環境です。
インストール方法や使い方については、以下のリンクで詳しく紹介しています。


・ライブラリについて
今回使用するライブラリは下表のようになります。
開発環境「ArduinoIDE」でインストールしておいてください。
| ライブラリ名 | 用途 | バージョン | 検索名 |
|---|---|---|---|
| M5Unified | M5Stack共通ライブラリ | 0.2.11 | M5Unif |
| M5GFX | 液晶画面制御用 | 0.2.17 | M5G |
| M5-LoRa-E220-JP | LoRaユニット制御用 | 1.0.1 | m5-lora-e220 |
4.動作確認
サンプルプログラムを使用したLoRa無線相互通信の動作について紹介します。
お互いのLEDランプのON/OFFを、ボタン操作によって遠隔操作します。
・動作紹介
サンプルプログラムを書き込んだ時の動作について詳しく紹介します。
「M5StickC Plus2」と無線ユニット「LoRaE220-JP」は下画像のように「Groveコネクタ」配線で接続します。

送受信テストのために、下写真のように同じ組み合わせが2セット必要です。

サンプルプログラムを書き込む前に、無線ユニット「LoRaE220-JP」は初期設定が必要です。
下画像のように無線ユニット本体のディップスイッチを切り替えて、初期設定を行なってください。


電源ON時には上記のように「int error」が表示されます。初期設定がまだの場合は本体のスイッチ「M0、M1」をOFFにして初期設定を行なってください。
初期設定済みの場合は本体ボタンを押してスキップしてください。

本体のスイッチ「M0、M1」が「Configモード」で初期設定が完了すると上写真のように「Init succeeded」が表示されます。
初期設定後は本体スイッチを「ノーマルモード」に切換えておいてください。

上写真下側の「M5StickC」の正面ボタンAを押すと上側の「M5StickC」側面の赤色LEDが点灯します。

上写真下側の「M5StickC」の側面ボタンBを押すと上側の「M5StickC」側面の赤色LEDが消灯します。

同様に上写真上側の「M5StickC」の正面ボタンAを押すと下側の「M5StickC」側面の赤色LEDが点灯します。

同様に上写真上側の「M5StickC」の側面ボタンBを押すと下側の「M5StickC」側面の赤色LEDが消灯します。
・サンプルプログラム(ライブラリ使用)
ライブラリ(M5-LoRa-E220-JP)を使用したサンプルプログラムは以下になります。
コピペで貼り付けて実行してください。コピーは下の黒塗り部右上のアイコンクリックでもできます。
#include <M5Unified.h> // M5Unified ライブラリ
#include "M5_LoRa_E220_JP.h" // LoRa E220 JP ライブラリ
#define LED 19 // 本体LED
M5Canvas canvas(&M5.Display); // メモリ描画領域表示(スプライト)のインスタンス作成
LoRa_E220_JP lora; // LoRa E220 インスタンス作成
struct LoRaConfigItem_t config; // LoRa E220 設定構造体
struct RecvFrame_t data; // 受信データ構造体
// 関数プロトタイプ宣言
void LoRaRecvTask(void *pvParameters); // 受信タスク
// グローバル変数宣言
String data_str = ""; // 受信データ保存用文字列
// ログ表示関数(メモリ描画領域とシリアル出力両方に表示)
void print_log(String info) {
canvas.println(info); // メモリ描画領域にログ追記
canvas.pushSprite(0, 0); // 画面に反映
Serial.println(info); // シリアル出力
}
// メッセージ送信関数
void send_message(String msg) {
if (lora.SendFrame(config, (uint8_t *)msg.c_str(), msg.length()) == 0) { // メッセージ送信を実行して成功なら
print_log("Send msg: " + msg); // 送信ログ表示
} else {
print_log("Send failed."); // 送信失敗ログ表示
}
}
// 初期設定 ***********************************************
void setup() {
auto cfg = M5.config(); // M5Unified設定取得
cfg.serial_baudrate = 115200; // シリアル出力初期化
M5.begin(cfg); // M5Unified初期化
// 出力端子設定
pinMode(LED, OUTPUT); // 本体LED赤
digitalWrite(LED, LOW); // 本体LED初期値OFF(LOW)
// 液晶画面の初期設定
M5.Display.begin(); // M5.Display初期化
M5.Display.fillScreen(BLACK); // 背景色
M5.Display.setRotation(1); // 画面向き設定(USB位置基準 0:下/ 1:右/ 2:上/ 3:左)
canvas.createSprite(M5.Display.width(), M5.Display.height()); // canvasサイズ(メモリ描画領域)設定(画面サイズに設定)
canvas.setFont(&fonts::Font2); // フォント指定
canvas.setTextScroll(true); // 文字スクロール有効化
canvas.println(">>LoRa E220 JP TEST"); // タイトル表示
canvas.pushSprite(0, 0); // 画面に反映
delay(1000); // シリアル通信安定化待ち
// LoRa E220 の UART 設定(Grove: RX=33, TX=32)
lora.Init(&Serial2, 9600, SERIAL_8N1, 33, 32);
lora.SetDefaultConfigValue(config); // デフォルト設定値読み込み
// LoRa E220 初期設定値(日本国内向け推奨設定)
config.own_address = 0x0000; // 自分のアドレス
config.baud_rate = BAUD_9600; // 通信速度(9600bps推奨)
config.air_data_rate = BW125K_SF9; // 空中伝送速度(SF7〜11、大きいほど長距離だが遅い。9が安定)
config.subpacket_size = SUBPACKET_200_BYTE; // サブパケットサイズ(200byte MAX)
config.rssi_ambient_noise_flag = RSSI_AMBIENT_NOISE_ENABLE; // RSSI環境雑音表示有効
config.transmitting_power = TX_POWER_13dBm; // 送信出力(13dBmは日本の法規に準拠した最大値)
config.own_channel = 0x00; // 自分のチャンネル
config.rssi_byte_flag = RSSI_BYTE_ENABLE; // RSSIバイト表示(ENABLEで受信データ末尾にRSSI値を含める)
config.transmission_method_type = UART_P2P_MODE; // 通信方式 P2Pモード(UART_TT_MODE:トランスペアレントモード)
config.lbt_flag = LBT_DISABLE; // LBT無効
config.wor_cycle = WOR_2000MS; // WORサイクル(WOR通信未使用ならなんでもOK)
config.encryption_key = 0x0000; // 暗号化キー ※同じ暗号化キー同士でのみ通信可能
config.target_address = 0x0000; // 相手のアドレス
config.target_channel = 0x00; // 相手のチャネル
// 初期化処理
if (lora.InitLoRaSetting(config) != 0) { // 初期化失敗なら
print_log("Init error, SW M0,M1 to OFF"); // 設定モード切換え案内
print_log("or click Btn to skip"); // ボタン押下で初期化スキップ案内
while (lora.InitLoRaSetting(config) != 0) { // 初期化失敗
M5.update(); // ボタン状態更新
if (M5.BtnA.wasPressed() || M5.BtnB.wasPressed()) {
break;
}
}
}
print_log("Init succeeded, SW M0,M1 to ON");
print_log("Click Btn to Send Data");
// マルチタスク処理開始
xTaskCreateUniversal(LoRaRecvTask, "LoRaRecvTask", 8192, NULL, 1, NULL, APP_CPU_NUM); // 受信タスク
}
// メインループ ***********************************************
void loop() {
M5.update(); // ボタン状態更新
// ボタンA処理
if (M5.BtnA.wasPressed()) {
send_message("ON"); // LED点灯コマンド送信
}
// ボタンB処理
if (M5.BtnB.wasPressed()) {
send_message("OFF"); // LED消灯コマンド送信
}
// 受信データ処理
if (data_str == "ON") { // LED点灯コマンド受信なら
digitalWrite(LED, HIGH); // 本体LED赤点灯
send_message("LED_ON_OK!"); // 返信メッセージ送信
data_str = ""; // 受信データクリア
} else if (data_str == "OFF") { // LED消灯コマンド受信なら
digitalWrite(LED, LOW); // 本体LED赤消灯
send_message("LED_OFF_OK!"); // 返信メッセージ送信
data_str = ""; // 受信データクリア
}
delay(100);
}
// 受信タスク
void LoRaRecvTask(void *pvParameters) {
while (1) {
if (lora.RecieveFrame(&data) == 0) { // 受信成功なら
// 受信データを文字列として格納
String msg = "";
for (int i = 0; i < data.recv_data_len; i++) { // 受信データ表示
msg += (char)data.recv_data[i];
// Serial.printf("%c", data.recv_data[i]);
}
data_str = msg; // 受信データをグローバル変数に保存
print_log("recv data: " + msg); // 受信データ表示
print_log("RSSI: " + String(data.rssi) + " dBm"); // RSSI表示
Serial.flush(); // シリアル出力フラッシュ
canvas.pushSprite(0, 0);
}
delay(1);
}
}・サンプルプログラム(ライブラリ未使用)
ライブラリ未使用のサンプルプログラムは以下になります。
コピペで貼り付けて実行してください。コピーは下の黒塗り部右上のアイコンクリックでもできます。
#include <M5Unified.h> // M5Unifiedライブラリ
#define LED 19 // 本体LED
HardwareSerial LoraSerial(2); // UART2を使用(RX=33, TX=32)
// 固定送信モードの宛先アドレスとチャンネル設定
uint8_t header[3] = {0x00, 0x00, 0x00}; // 送信先アドレスH,L + チャンネル ※アドレス0xFFFFならブロードキャスト
// グローバル変数宣言
String data_str = ""; // 受信データ保存用文字列
// ログ表示関数(液晶画面とシリアル出力両方に表示)
void print_log(String info) {
M5.Lcd.println(info); // 画面出力
Serial.println(info); // シリアル出力
}
// メッセージ送信関数
void send_message(const String& msg) {
LoraSerial.write(header, 3); // 固定送信モードの宛先アドレスとチャンネル(ヘッダー)送信
LoraSerial.print(msg); // メッセージ本体を送信
print_log("Send: " + msg); // ログ表示
}
// 初期設定 *********************************************
void setup() {
auto cfg = M5.config(); // M5Unified設定取得
cfg.serial_baudrate = 115200; // シリアル出力初期化
M5.begin(cfg); // M5Unified初期化
// 出力端子設定
pinMode(LED, OUTPUT); // 本体LED赤
digitalWrite(LED, LOW); // 本体LED初期値OFF(LOW)
// UART2初期化(LoRa E220用)
LoraSerial.begin(9600, SERIAL_8N1, 33, 32); // RX=33, TX=32 ※Groveコネクタ端子指定
delay(1000); // シリアル通信安定化待ち
// 画面表示設定
M5.Lcd.setRotation(1); // 画面回転設定
M5.Lcd.setFont(&fonts::Font2); // フォント設定
M5.Lcd.setTextScroll(true); // 文字スクロール有効化
print_log("LoRa E220 JP TEST"); // ログ表示
print_log("Init Start");
// LoRa通信 設定書込み(日本国内向け推奨設定)
uint8_t writeCmd[11] = {0xC0, 0x00, 0x08, // 書込みコマンドC0, 開始Add, 書込みByte数
0x00, 0x00, // ADD_H, ADD_L ※自分のアドレス
0x70, // 7-5bit:UART設定 9600bps(推奨) / 4-0bit:空中伝送速度 125kHz_SF9(安定通信向け)
0x20, // 7-6bit:パケットサイズ 200byte(最大) / 5bit:RSSI環境ノイズ有効 / 4-2bit:none / 1-0bit:送信出力電力 13dBm(最大)
0x00, // 周波数チャンネル 920.6MHz(BW125kHzの時)
0xC3, // 7bit:RSSIバイト有効 / 6bit:固定送信(P2P)モード /5-3bit:none / 2-0bit:WORサイクル2000ms ※トランスペアレントモードは0x83
0x00, 0x00}; // KEY_H, KEY_L ※同じ暗号化キー同士でのみ通信可能
LoraSerial.write(writeCmd, 11); // 書込みコマンド送信
delay(1000); // 書込み完了待ち
// 設定モード(M0,M1スイッチOFF)なら設定完了結果を表示(FF FF FFはエラー)
if (LoraSerial.available()) { // 返答があれば
while (LoraSerial.available()) { // 返答を読み取る
uint8_t b = LoraSerial.read(); // 受信バイト取得
Serial.printf("%02X ", b); // シリアル出力
M5.Lcd.printf("%02X ", b); // 画面出力
}
Serial.println();
M5.Lcd.println();
} else { // 返答がない場合、スイッチ確認を促す
print_log("No Response. Check M0/M1 Switch.");
}
}
// メインループ *********************************************
void loop() {
M5.update(); // M5ボタン状態更新
// ボタンA処理
if (M5.BtnA.wasPressed()) {
send_message("ON"); // LED点灯コマンド送信
}
// ボタンB処理
if (M5.BtnB.wasPressed()) {
send_message("OFF"); // LED消灯コマンド送信
}
// 受信データ処理
if (LoraSerial.available()) { // 受信データがあれば
uint8_t buf[200]; // 受信バッファ
int len = 0; // 受信データ長
// 受信データをバッファに格納
while (LoraSerial.available()) {
buf[len++] = LoraSerial.read();
}
// 最後の1バイトからRSSI値を取得
uint8_t rssi_raw = buf[len - 1]; // RSSI生データ取得
len--; // データ本体の長さを調整
int rssi_dbm = -(256 - rssi_raw); // RSSI換算値計算(データシートより)
// 受信データ本体を文字列に変換して表示
char msg[201]; // 終端文字分 +1
for (int i = 0; i < len; i++) {
msg[i] = (char)buf[i]; // バイトを文字に変換
}
msg[len] = '\0'; // 終端文字を付ける
data_str = msg; // 受信データをグローバル変数に保存
print_log("Recv data: " + String(msg)); // ログ表示
print_log("RSSI: " + String(rssi_dbm) + " dBm"); // ログ表示
}
// 受信データ処理
if (data_str == "ON") { // LED点灯コマンド受信なら
digitalWrite(LED, HIGH); // 本体LED赤点灯
send_message("LED_ON_OK!"); // 完了メッセージ送信
data_str = ""; // 受信データクリア
} else if (data_str == "OFF") { // LED消灯コマンド受信なら
digitalWrite(LED, LOW); // 本体LED赤消灯
send_message("LED_OFF_OK!"); // 完了メッセージ送信
data_str = ""; // 受信データクリア
}
delay(100);
}5.まとめ
LoRa無線ユニット「LoRaE220-JP」を使用して「M5StickC Plus2」で長距離無線通信(遠隔操作でLチカ)する方法をサンプルプログラムを使って詳しく紹介しました。
「LoRaE220-JP」を使った長距離無線通信は、プライベートLoRa(P2P)の仕組みを理解しながら実践できる絶好の教材です。
本記事では、プライベートLoRaの基礎、LoRaE220-JP の仕様、P2P/TT通信モードの違い、設定方法、DIPスイッチによる動作モード切替、そして実際の遠隔Lチカまでを一連の流れで詳しく紹介しました。
「LoRaWAN」とは異なり、「プライベート(独自)LoRa」は自由度が高く、設定次第で用途に最適化できる反面、互換性確保には注意が必要ですが、手軽に省電力な長距離無線通信する手段としては最適と思います。
今回のサンプルプログラムを通じて、LoRa通信の基本構造や設定の重要性、RSSIによる通信品質の判断など、実運用に役立つ知識を身につけることができたと思います。
これを基に、より高度なLoRa通信の応用機器やIoTデバイスの開発にも挑戦してみましょう。












コメント