chrmlinux03のアイコン画像
chrmlinux03 2024年01月26日作成 (2024年02月29日更新)
製作品 製作品 Lチカ Lチカ 閲覧数 450
chrmlinux03 2024年01月26日作成 (2024年02月29日更新) 製作品 製作品 Lチカ Lチカ 閲覧数 450

【SPRESENSE2023】LoRaPagerを作ったよっ【簡易メッセンジャー】

【SPRESENSE2023】LoRaPagerを作ったよっ【簡易メッセンジャー】

はじめに

こんにちわっ

リナちゃん X@chrmlinux03 です

このページは SPRESENSE2023コンテストで作った製品を紹介するものです
最初に 開発まとめ をお読みいただければ幸いです

はじめは トランシーバーを作る気満々だった

当初は ESPNow や WiFi の速度 と転送容量を期待していたのですが

実際に実装してみるとなんと 200byte - 3byte の 197byteがせいぜい💦

しかも 転送に1秒ほどかかるようで

それでもエイヤっと組んでみるかと考えて

試しに計算してみると 10Kbyte のファイル転送に要する時間が半端ない💦

さらにこんなメッセージが

用意するもの

👉組込用のSPRESENSEモジュールを作ったよ

キャプションを入力できます

ある日 毎日欠かさず読んでいるサイトに

こんなデータがあることが分かった

これを使えば採寸しなくて良いのでは?

※って言うか 元旦💦

ケース作成要件

  • リチウムイオン電池を内蔵して
  • LEDミルフィーユを右側に搭載
  • アンテナは左側上部に設置する
  • 画面は 2.4インチのタッチパネル
  • タッチパネルは天面と同じ高さ

ケースの設計

天面

LED用透明パッド

側面部分

底面

印刷物

印刷物

実装

//=================================================== /* program name : LoRaPager.ino date/author : 2024/01/23 @chrmlinux03 update/author : 2024/01/23 @chrmlinux03 ----------------------------------------------------- MainCore : 512KByte */ //=================================================== #include <spre.Tools.hpp> #include <spre.Graphics.hpp> #include <tinyLoRa.hpp> #include <tinyTouch.hpp> #include <tinyTouchVrKey.hpp> #include <spre.Neo.hpp> SpreNeo neo; TouchVrKey VrKey; tinyLoRa tLoRa; #define VERSION "v0.1" const int historyBufferSize = 5; char recvHistory[historyBufferSize][SENDBUFLEN_MAX]; int recvHistoryIndex = 0; char sendHistory[historyBufferSize][SENDBUFLEN_MAX]; int sendHistoryIndex = 0; uint8_t recvBuf[SENDBUFLEN_MAX] = {0}; int16_t recvBufLen = SENDBUFLEN_MAX; int16_t rssi; uint8_t sendBuf[SENDBUFLEN_MAX] = {0}; int16_t sendBufLen = SENDBUFLEN_MAX; enum { LED_STAT_IDLE = 0, LED_STAT_SEND, LED_STAT_RECV }; int ledStat = LED_STAT_IDLE; void addToHistory(const char* data, char historyBuffer[][SENDBUFLEN_MAX], int& historyIndex) { strncpy(historyBuffer[historyIndex], data, SENDBUFLEN_MAX); historyIndex = (historyIndex + 1) % historyBufferSize; } void sendProc(void) { tLoRa.setSendData(sendBuf, sendBufLen); tLoRa.setSendFlag(); tLoRa.sendData(); addToHistory(reinterpret_cast<char*>(sendBuf), sendHistory, sendHistoryIndex); memset(sendBuf, 0x0, sendBufLen); ledStat = LED_STAT_SEND; } void recvProc(void) { if (tLoRa.recvData()) { memset(recvBuf, 0x0, recvBufLen); tLoRa.getRecvData(recvBuf, &recvBufLen, &rssi); tLoRa.dump(recvBuf, recvBufLen); addToHistory(reinterpret_cast<char*>(recvBuf), recvHistory, recvHistoryIndex); ledStat = LED_STAT_RECV; } } void setup() { Serial.begin(115200); int8_t rotation = ROT0; bool tft24inch = true; setupGraphics(rotation); setupTouch(_w, _h, rotation, tft24inch); tLoRa.setupLoRa(LORA_NORMAL_MODE); tLoRa.setDebugPrint(false); int bw = 21, bh = 20; VrKey.begin(bw, bh, 0, _h - (bh * 5)); neo.begin(); neo.set(LEDKIND_BRESS, 0, 0, 255, 64); neo.start(); } #define IDLE_TIMEOUT 500 unsigned long lastLedStatChangeTime = 0; void ledCtrl(void) { static unsigned long lastLEDUpdateTime = 0; const unsigned long LEDUpdateInterval = 500; if (millis() - lastLEDUpdateTime >= LEDUpdateInterval) { lastLEDUpdateTime = millis(); switch (ledStat) { case LED_STAT_SEND: neo.stop(); neo.set(LEDKIND_RIGHTSTAR, 0, 64, 0, 128); neo.start(); break; case LED_STAT_RECV: neo.stop(); neo.set(LEDKIND_LEFTSTAR, 64, 0, 0, 128); neo.start(); break; default: neo.stop(); neo.set(LEDKIND_BRESS, 0, 0, 64, 64); neo.start(); break; } if (ledStat != LED_STAT_IDLE && millis() - lastLedStatChangeTime >= IDLE_TIMEOUT) { ledStat = LED_STAT_IDLE; } } } void loop(void) { ledCtrl(); neo.update(); spr.startWrite(); spr.clear(TFT_BLACK); spr.setTextColor(TFT_CYAN); spr.setCursor(0, 0); for (int i = 0; i < historyBufferSize; ++i) { int index = (recvHistoryIndex + i) % historyBufferSize; spr.printf("%s\n", recvHistory[index]); } spr.setTextColor(TFT_GREEN); spr.setCursor(0, 104); for (int i = 0; i < historyBufferSize; ++i) { int index = (sendHistoryIndex + i) % historyBufferSize; spr.printf("%s\n", sendHistory[index]); } VrKey.scan(&spr, TFT_WHITE); if (VrKey.isEnter()) { VrKey.getData(sendBuf, &sendBufLen); VrKey.resetEnter(); sendProc(); } recvProc(); static int cnt = 0; char ast[4] = "|/-\\"; spr.setTextColor(TFT_WHITE); spr.setCursor(0, _h - 8); spr.printf(" [%c] %3d fps [%s]\n", ast[cnt], getfps(), VERSION); cnt = (cnt + 1) % 4; spr.pushSprite(&lcd, 0, 0); spr.endWrite(); }

実装のポイント

LEDミルフィーユの光り方を苦悩した

recvFlag や sendFlag は 一瞬で変わってしまうので

一旦 ledStat で受けて その ledStat を自分自身で on/off するように構成

#define IDLE_TIMEOUT 500 unsigned long lastLedStatChangeTime = 0; void ledCtrl(void) { static unsigned long lastLEDUpdateTime = 0; const unsigned long LEDUpdateInterval = 500; if (millis() - lastLEDUpdateTime >= LEDUpdateInterval) { lastLEDUpdateTime = millis(); switch (ledStat) { case LED_STAT_SEND: neo.stop(); neo.set(LEDKIND_RIGHTSTAR, 0, 64, 0, 128); neo.start(); break; case LED_STAT_RECV: neo.stop(); neo.set(LEDKIND_LEFTSTAR, 64, 0, 0, 128); neo.start(); break; default: neo.stop(); neo.set(LEDKIND_BRESS, 0, 0, 64, 64); neo.start(); break; } if (ledStat != LED_STAT_IDLE && millis() - lastLedStatChangeTime >= IDLE_TIMEOUT) { ledStat = LED_STAT_IDLE; } } }

この作業により以下のエフェクトが実装できた

状態 エフェクト
アイドル時 呼吸をするイメージで青くぼーっと光る
受信時 流れる緑の光が飛び出すイメージ
送信時 流れる赤の光が入ってくるイメージ

動かしてみた

残務と今後の考察

これ シリアル用の穴をあけてUSBマイクロの差し込み口を付けるだけで

LoRa端末として良い形になりそう

PC に接続するとか用途は無限大ですね

さいごに

デザインは大事なんだなぁとか今更考えちゃいましたっ

っていうか製品感満載٩(ˊᗜˋ*)و

このページは SPRESENSE2023コンテストで作った部品を紹介するものです
最初に 開発まとめ をお読みいただければ幸いです

chrmlinux03のアイコン画像
今は現場大好きセンサ屋さん C/php/SQLしか書きません https://arduinolibraries.info/authors/chrmlinux https://github.com/chrmlinux #リナちゃん食堂 店主 #シン・プログラマ
ログインしてコメントを投稿する