以前、ESP32を使ってドットマトリクスLED(MAX7219)に文字を表示させました。

 

 

表示させる文字列を、いちいちプログラムを変更せずに書き換えたい。

できればスマホから書き換えられたら出先でも色々と遊べそう。

 

そんなモチベーションで挑戦しました。

 

 

結果、うまくできました!

まずは動作確認の様子をご覧ください。

 

 

 

文字表示の部分は以前のプログラムで出来ていたので、これに通信手段を追加するだけ。

今回はBLEを使うことにしました。

 

Arduinoのライブラリで、「ESP32_BLE_Arduino」というのがありますが、実はこれは古いものらしく、インストールすると逆に動かなくなりました。

元々ArduinoIDEに標準で入っているものを使用すると動きました。

 

スマホとESP32の接続は「nRF Connect for Mobile」というアプリを使用することで簡単にできました。

ちなみにこのアプリはAndroidのものですが、iPhoneでも似たようなアプリはあるかと思います。

 

 

ESP32の電源を入れて少し待ってからSCANすると、プログラムで指定したデバイス名が表示されます。

 

 

TYPEをTEXT(UTF-8)に変更するのを忘れずに。

 

あとは文字を入れてSENDボタンを押せばOK

 

 

ドットマトリクスを使ってやりたいことは一通りできたので、あとはちゃんとしたケースなどを作れば完成。

何気にケース作りが一番面倒だったりするんですよね~。

 

プログラムは下記のようにしました。

もうChatGPTは手放せない存在です。

#include <MD_MAX72xx.h>
#include <MD_Parola.h>
#include <misaki.hpp>

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

// =====================================================
// MAX7219の設定
// =====================================================

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4

// CSピン
#define CS_PIN 5

// =====================================================
// 文字列設定
// =====================================================

// 受信文字列の最大長
#define MAX_LENGTH 256

// =====================================================
// MD_Parola用データ
// =====================================================

// MD_Parolaに登録する文字コード
char messageCode[MAX_LENGTH];

// 90度回転したフォントデータ
uint8_t rotatedFontData[9 * MAX_LENGTH];

// =====================================================
// MD_Parola
// =====================================================

MD_Parola parola(
  HARDWARE_TYPE,
  CS_PIN,
  MAX_DEVICES
);

// =====================================================
// BLE UUID
// =====================================================

#define SERVICE_UUID \
  "12345678-1234-1234-1234-123456789abc"

#define CHARACTERISTIC_UUID \
  "abcdefab-1234-1234-1234-123456789abc"

// =====================================================
// BLE変数
// =====================================================

BLECharacteristic* pCharacteristic = nullptr;
bool deviceConnected = false;

// =====================================================
// 関数プロトタイプ
// =====================================================

void addFontToParola(const char* text);
void displayMessage(const char* message);
void setupBLE();

// =====================================================
// BLE Server Callback
// =====================================================

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) override {
    deviceConnected = true;
    Serial.println();
    Serial.println("================================");
    Serial.println("BLE Connected");
    Serial.println("================================");
  }

  void onDisconnect(BLEServer* pServer) override {
    deviceConnected = false;
    Serial.println();
    Serial.println("================================");
    Serial.println("BLE Disconnected");
    Serial.println("================================");

    // 再接続待ち
    BLEDevice::startAdvertising();


    Serial.println("BLE Advertising Restarted");
  }
};

// =====================================================
// BLE Characteristic Callback
// =====================================================

class MyCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic* pCharacteristic) override {

    // =================================================
    // BLEから受信
    // =================================================
    String rxValue = pCharacteristic->getValue();

    // 何も受信していなければ終了
    if (rxValue.length() == 0) {
      return;
    }

    // =================================================
    // シリアルモニタへ表示
    // =================================================

    Serial.println();
    Serial.println("--------------------------------");
    Serial.println("BLE Received");
    Serial.print("Length : ");
    Serial.println(rxValue.length());
    Serial.print("Text   : ");
    Serial.println(rxValue);
    Serial.println("--------------------------------");


    // =================================================
    // 受信した文字列を表示
    // =================================================

    displayMessage(rxValue.c_str());
  }
};

// =====================================================
// フォントデータをMD_Parolaへ登録
// =====================================================

void addFontToParola(const char* text) {
  uint16_t charIndex = 1;
  uint8_t charWidth;

  // ===================================================
  // 文字列を1文字ずつ処理
  // ===================================================

  while (*text && charIndex < MAX_LENGTH) {

    uint16_t unicode =
      utf8ToUnicode(text, &charWidth);

    // =================================================
    // フォントデータを取得
    // =================================================

    const uint8_t* fontData =
      getFontData(unicode);

    // =================================================
    // フォントデータを90度回転して保存
    // =================================================

    // 1バイト目は文字幅
    rotatedFontData[
      (charIndex - 1) * 9
    ] = charWidth;

    // 8列分を処理
    for (uint8_t col = 0; col < 8; col++) {
      uint8_t rotatedByte = 0;

      // 8行分を処理
      for (uint8_t row = 0; row < 8; row++) {
        if (
          fontData[row] &
          (1 << (7 - col))
        ) {
          rotatedByte |= (1 << row);
        }
      }

      // 回転後のデータを保存
      rotatedFontData[
        (charIndex - 1) * 9 + col + 1
      ] = rotatedByte;
    }

    // =================================================
    // MD_Parolaへフォント登録
    // =================================================

    parola.addChar(
      charIndex,
      &rotatedFontData[
        (charIndex - 1) * 9
      ]
    );

    // =================================================
    // MD_Parola用の文字コードを作成
    // =================================================

    messageCode[
      charIndex - 1
    ] = charIndex;

    charIndex++;
  }

  // ===================================================
  // 文字列終端
  // ===================================================

  messageCode[
    charIndex - 1
  ] = '\0';
}

// =====================================================
// 文字列をドットマトリクスに表示
// =====================================================

void displayMessage(const char* message) {

  // ===================================================
  // デバッグ表示
  // ===================================================

  Serial.println();
  Serial.println("================================");
  Serial.println("Display Message");
  Serial.println("================================");
  Serial.print("Message: ");
  Serial.println(message);


  // ===================================================
  // 現在の表示をクリア
  // ===================================================

  parola.displayClear();

  // ===================================================
  // フォントを登録
  // ===================================================

  addFontToParola(message);

  // ===================================================
  // スクロール表示
  // ===================================================

  parola.displayScroll(
    messageCode,
    PA_LEFT,
    PA_SCROLL_LEFT,
    50
  );
}

// =====================================================
// BLE初期化
// =====================================================

void setupBLE() {

  // ===================================================
  // BLEデバイス名
  // ===================================================

  BLEDevice::init(
    "ESP32_DotMatrix"
  );

  // ===================================================
  // BLE Server作成
  // ===================================================

  BLEServer* pServer =
    BLEDevice::createServer();

  pServer->setCallbacks(
    new MyServerCallbacks()
  );

  // ===================================================
  // BLE Service作成
  // ===================================================

  BLEService* pService =
    pServer->createService(
      SERVICE_UUID
    );

  // ===================================================
  // BLE Characteristic作成
  // ===================================================

  pCharacteristic =
    pService->createCharacteristic(
      CHARACTERISTIC_UUID,
      BLECharacteristic::PROPERTY_WRITE
    );

  // Callback登録
  pCharacteristic->setCallbacks(
    new MyCallbacks()
  );

  // ===================================================
  // BLE Service開始
  // ===================================================

  pService->start();

  // ===================================================
  // Advertising設定
  // ===================================================

  BLEAdvertising* pAdvertising =
    BLEDevice::getAdvertising();

  pAdvertising->addServiceUUID(
    SERVICE_UUID
  );

  pAdvertising->setScanResponse(true);

  // ===================================================
  // Advertising開始
  // ===================================================

  BLEDevice::startAdvertising();

  // ===================================================
  // シリアルモニタ
  // ===================================================

  Serial.println();
  Serial.println("================================");
  Serial.println("BLE Server Started");
  Serial.println("================================");
  Serial.println(
    "Device Name : ESP32_DotMatrix"
  );
  Serial.println(
    "Service UUID:");
  Serial.println(
    SERVICE_UUID
  );
  Serial.println(
    "Characteristic UUID:"
  );
  Serial.println(
    CHARACTERISTIC_UUID
  );
  Serial.println(
    "Waiting for BLE connection..."
  );
  Serial.println("================================");
}

// =====================================================
// setup
// =====================================================

void setup() {

  // ===================================================
  // シリアル通信開始
  // ===================================================

  Serial.begin(115200);
  delay(500);

  // ===================================================
  // 起動メッセージ
  // ===================================================

  Serial.println();
  Serial.println();
  Serial.println("================================");
  Serial.println("ESP32 Dot Matrix BLE");
  Serial.println("================================");

  // ===================================================
  // MD_Parola初期化
  // ===================================================

  parola.begin();
  parola.displayClear();

  // ===================================================
  // BLE初期化
  // ===================================================

  setupBLE();

  // ===================================================
  // 起動時のテスト表示
  // ===================================================

  displayMessage("真野あゆみ");
}

// =====================================================
// loop
// =====================================================

void loop() {

  // ===================================================
  // MD_Parolaのアニメーション更新
  // ===================================================

  if (parola.displayAnimate()) {
    parola.displayReset();
    delay(1500);
  }
}