LoRa通信をLRA1のBASICで、たった1行で環境モニター実装!
この記事について
こんにちは、ぽんたです🐾
今回は前回からの進化版として──
LRA1のBASICでLoRa通信を本格的に運用するための 「バイナリ送信+非同期受信」テクを1行BASICで 試してみます!
文字列ベースで送信できるのは手軽だけど、実際に使ってみると文字列のままだと扱いにくい。
そこで、文字列と違って、数値を効率的にやり取りできるのがバイナリの魅力。
最後は センサー値をバイナリで送信し、LCDにすっきり表示する環境モニターを構築していきます。
🎀 いよいよLoRa通信が“実用仕様”に近づいてきたよ〜っ!
バイナリでの送受信とは?
LoRa通信では「送信する内容」が何より大事。
これまでは人が読みやすい“文字列”で送ってきましたが、実はそれ、通信としてはちょっと遠回りなんです。
- 数値を文字列にして送ると、どうしても1バイトずつ文字データーになる
- 送るデーターが多くなるほど、パケットが長くなって送信時間がかかる
- 電波の制限(送信時間・DutyCycle)にも引っかかりやすくなる
つまり、手軽さと引き換えに、無駄が増えてしまうわけです。
🎀 “ABCD”って送るのも、12345を2バイトで送るのも、電波に乗るサイズが全然ちがうんだよ〜!
PCやPythonなどの高機能な環境であれば、受信側で文字列をパースするのはそこまで難しくありません。
でも、マイコン環境では文字列処理は意外と大変で、ちょっとした数値変換でもメモリやコード量に響いてきます。
🎀 文字列を数値に直すだけで、けっこうゴリゴリ処理しないといけないんだよ〜💦
一方で“バイナリ”なら、
- 1バイトで255までの整数を送れる(桁数に関係なく)
- 2バイトでセンサーデーター(0.1単位の気温とか)も余裕で収まる
- 必要な長さだけ送るから、通信時間も短く、省エネ!
特に、センサーから得た「温度・湿度・気圧」のようなデーターは、定型の数値としてやりとりするのがいちばん効率的。
そしてLRA1では、BYTE(1バイト)、WORD(2バイト)、LONG(4バイト) の各サイズで数値を送受信できる機能が備わっています。
🎀 用途に合わせて、“ちょうどいいサイズ”でデーターを送れるのが便利なんだよ〜!
送信バッファ
LRA1でバイナリ送信を行う前に、まずはLoRa通信で使う送信バッファについて説明します。
送信バッファは #
または txd
変数で参照することができます。
📒 送信バッファと受信バッファは独立しています。
`#` 変数を使う場合、参照時は受信バッファ(`rxd`)、設定時は送信バッファ(`txd`)となります。
以下のようにすると、送信バッファに文字列を設定することができます。
そのまま、引数無しで send
コマンドを実行すると、send
コマンドに文字列を指定したことと同じになります。
>#="Hello":send
このとき、送信バッファに文字列が設定されるとともに、送信パケットの LoRaの制御情報(gid
,own
,dst
,データ長
)が自動的に設定されます。gid
にはgid変数
が、own
にはown変数
が、dst
にはdst変数
が、データー長
は文字列長が設定されます
それ以外の方法では自動的に設定されません。起動時のデフォルトではすべて 0 になっています。
そのため、次章で説明するバイナリ送信の前に、以下のように #=null
とするのが便利です。
>#=null
送信バッファ #
に空文字列を設定して、送信パケットの LoRaの制御情報も自動設定されます。
このとき、送信データ長は0に設定されるので、バイナリデーター送信時には、手動で送信バイト数の設定が必要です。
send
コマンドに引数を与えない場合、事前に #=文字列
を行わないと正しく送信できないことがあります。
バイナリで送信する時は、このコマンドで初期設定することをおススメします。
※すべてを手動で設定することもできますが、この方法が一番簡単です。
🎀 “送信準備、よーいドン!”っていう感じの合図だよっ!
バイナリで送信してみよう
LRA1では送信データーのバッファに直接数値を書き込むことで、バイナリ形式での通信が可能になります。
#[index]=n
のようにして、送信バッファに1バイト単位で値を設定します。
実際に送信するデーターを格納するエリアを「ペイロード」と言います。
#[8]
(送信バッファの8バイト目)以降がペイロードです。送信したいデーターはここ設定します。
#[7]
(送信バッファの7バイト目)には、送信データー長を指定します。
📒 補足:`#[0],#[1]`はgid、`#[2],#[3]`はdts、`#[4],#[5]`はown、`#[6]`はSystemで使用
send
コマンドを引数無しで実行すると、上記の設定で送信バッファを送信します。
>#=null:#[7]=2:#[8]=65:#[9]=66:send
上記は「”AB”」という2バイトのデーターをバイナリで送信する例です。
より複雑なデーター(16ビット・32ビット)を送るには、txdw[]
や txdl[]
を使って次のように指定します:
>#=null:#[7]=6:txdw[8]=25185:txdl[10]=2054780975:send
受信側では “ab/xyz” と表示されるはずです。
🎀 “txdw”はWORD型、“txdl”はLONG型のデーターを入れるときに使うよ〜
バイナリで受信するには?
受信バッファは #
または rxd
を使って参照します。
ただし #
や rxd
を添え字無しで参照すると、自動的に文字列として解釈されます。
バイナリとして扱いたい場合は、送信と同様に以下のようにします。
>? #[8] 66
ペイロードやその他の情報も送信バッファと同じ構成です。
🎀 受け取るときも、“文字”じゃなくて“数値”で読むのがバイナリのポイントなんだよ〜!
バイナリとして16ビットや32ビットの値を受け取るときは、以下のようにrxdw
、rxdl
変数を使います。
>? #[7],rxdw[8],rxdl[10] 6 25185 2054780975
#[7]
は受信したバイナリの長さ(バイト数)です。rxdw[8]
は#[8]
から2バイトを整数(16bit)として読み出したもの。rxdl[10]
は#[10]
から4バイトを整数(32bit)として読み出したもの。
🎀 “文字列”じゃなくて“数値”として扱えるのが、バイナリの強みなんだよ〜っ!
バックグランド受信
ここまでの説明では、recvコマンドは受信があったかタイムアウトするまではそのコマンドが終了しませんでした。
recv の引数に 0 を指定すると、バックグラウンド受信を開始して、コマンドからはすぐに戻ってきます。
>recv 0 >OK
インタラクティブモードでは、コマンド入力待ちのときも受信しています。
もちろん、BASICのコマンドが次々に実行されても継続して受信します。
受信があったかどうかは statコマンドで知ることができます。
>? stat >10 >OK >? # Hello!!
このとき、stat
変数 に0を設定するまでは次のパケットを受信しても破棄されます。
受信データーの処理が完了したらすぐに stat=0
を実行して次のパケット受信に備えてください。
🎀 “statを0にしないと、次が来ても無視されちゃう”ってちょっとツンデレ仕様かも〜っ💦
バックグラウンド受信を終了するには rxstop
コマンドを使用します。
>rxstop
rxstop
はあまり使う場面が無いかもしれません。
バックグラウンド受信は、基本的に次のような使い方となります。
>recv 0:do:if stat then if stat=10 then ? # endif:stat=0 endif:loop
※stat
変数は 10 以外になる場合もあるため、念のため 10 以外でも 0 にするコードにしています。
このように、LRA1では同期受信だけでなく、非同期受信も簡単にできるようになります。
🎀 “受信しながら動く”って、まるでマルチタスクっぽくてちょっとカッコいいよね〜っ✨
1行で環境モニターを作ってみよう!
ここまで紹介してきたセンサー取得・LCD表示・LoRa送受信の要素を組み合わせて、1行で環境モニターを構築してみましょう。
なお、バイナリで送信する場合は、変数のサイズ(BYTE/WORD/LONG)に合わせたスケーリングが必要です。
たとえば温度なら「0.1℃単位の値を10倍して整数にしてからWORD型で送る」など、
“どのくらいの精度で送るか”を考えて事前にスケーリングしておくことが前提となります。
🎀 あとで受け取ったときに“元の値”に戻せるようにしておくのがポイントだよ〜っ!
送信側は、BME280で取得した温度・湿度・気圧の値を16ビット整数としてバイナリでLoRa送信します。
送信間隔は5分おきです。表示はしないで、LoRa送信のみ行います。
>#=null:do:bme t,h,p:#[7]=6:txdw[8]=t:txdw[10]=h:txdw[12]=p:send:delay 300000:loop
この1行だけで、「気温・湿度・気圧の取得 → バイナリ格納 → 送信 → 5分待機」がすべて完結しています。
※delay 300000
の代わりに sleep 300
とすることができますが、sleep中はUART入力が無視されるため、ここでは中断可能な delay
コマンドを使用しました。
受信側は、送信されてきたバイナリデーターを受け取り、LCDに表示するだけの構成です。
タイムアウト時間は十分に大き目な値を設定しています。
タイムアウト処理は省略し、受信があったときだけ表示するシンプルな構成です。
>recv 0:do:if stat then if stat=10 then lclr:lprint rxdw[8]:lpos=4:lprint rxdw[10]:lpos=64:lprint rxdw[12] endif:stat=0 endif:loop
それぞれ10倍の値になっていることと、単位の表示が無いので、見栄えは悪いですが、
これで、LCDの指定位置に気温、湿度、気圧が表示されるようになりました。
🎀 温度27.2℃、湿度53.5%、気圧1008.2hPaって出てるね〜っ!
こんなにシンプルなのに、環境モニターになるなんて…感動しちゃう〜✨
⚠️ gidとdst,ownが合ってると、LRA1同士ならば全く関係のないパケットも受信してしまう事に注意してください。
長いスクリプトを保存するには?
このように1行で完結する環境モニターはとても手軽で便利ですが、注意点もあります。
このBASICコードはインタラクティブモードで書いたものなので、電源を切ると内容はすべて消えてしまいます。
もし電源を入れたときに自動でこの処理を開始させたい場合は、auto
変数に1行スクリプトを設定して、ssave
で保存しておく方法があります。
>auto="#=null:do:bme t,h,p:...":ssave
ただし auto
に設定できる文字列は最大63文字までなので、今回紹介したような長い1行コードは入りきらないのが難点です。
🎀 う〜ん、ちょっと惜しいっ!こんなに便利なのに、長すぎて保存できないなんて〜💦
そこで次のステップでは、行番号を使った“複数行プログラム”の書き方をご紹介します!
行番号を使えば、もっと複雑で長いプログラムも組めてFlashにも保存できるし、起動時の自動実行も可能になります。
🎀 “1行派”から“本格派”へステップアップするチャンスかも〜っ✨
おわりに
今回は、1行BASICだけでLoRaの送受信、LCD表示、センサーデーターの処理までやってみました!
LRA1は、よくあるLoRaモジュールのように外部MCUや特別なIDEは必要ありません。
シリアルポートのターミナルがあれば、たった1行のBASICだけで結構色々なことができると思いませんでしたか?
次は行番号を使った複数行プログラムにも挑戦してみましょう!
🎀 “行番号付きプログラム”では、もっと自由に動かしてみようね〜っ!
📪 お問い合わせなど
技術的なご相談やご質問などありましたら、
📩お問い合わせフォーム
または、
📮info@shachi-lab.com までお気軽にどうぞ。
🎀 ろらたん、返信ボタンのそばでずっとスタンバってるからね〜っ📮💨
🔗 関連リンク
しゃちらぼの最新情報や開発の様子は、こちらでも発信しています:
- 🌐しゃちらぼ公式サイト
- 🐦 X(旧Twitter):@shachi_lab
- 📗 Qiita:@shachi-lab
- 🐙 GitHub:@shachi-lab
- 📸 Instagram:@shachi_lab
ほんとは「しゃちらぼ(Shachi-lab)」なんだけど、見つけてくれてありがとう🐬
コメント