[M5StickS3入門] Arduinoで始める:バッテリー表示とボタン入力の最初の一歩
M5StickS3 を Arduino IDE で触り始めたときの流れを、環境設定から実際の表示コードまでまとめました。
この記事では、次の 3 つを手早く確認できます。
- 書き込み時の定番エラーの意味と対処
- バッテリー情報の表示(充電状態・残量・電圧)
- ボタン入力の表示(A / B / 同時押し)
公式の手順ページはこちらです。
M5StickS3 Arduino プログラムのコンパイルとアップロード
開発環境
- Arduino IDE
- ボード: M5StickS3(ESP32-S3)
- ライブラリ:
M5Unified,M5GFX
最初に出たエラー
書き込み時に以下のエラーが出ることがあります。
This chip is ESP32-S3, not ESP32-P4. Wrong chip argument?
これは、接続中の実機が ESP32-S3 なのに、アップロード設定が ESP32-P4 になっているという意味です。
ボード設定を M5StickS3(または ESP32-S3 系)に合わせると解消します。
ダウンロードモードの出入り
- 入る: リセットボタンを長押し(緑 LED 点滅)
- 出る: リセットボタンを短押し
通常は、書き込み完了後の再起動でも通常モードに戻ります。
バッテリー情報を表示する
まずは電源まわりの値を確認できるコードです。
充電中は緑、低電池(20%以下または3600mV以下)は赤で表示します。
このコードで使う主な要素は次のとおりです。
-
#include "M5Unified.h": M5デバイス本体、画面、電源情報などをまとめて扱うためのライブラリ -
setup(): 電源ON直後に1回だけ実行される初期化処理 -
loop(): 初期化後に繰り返し実行されるメイン処理 -
M5.Power.getBatteryLevel(): バッテリー残量(%)を取得 -
M5.Power.getBatteryVoltage(): バッテリー電圧(mV)を取得
// M5StickS3を含むM5シリーズ向けの基本ライブラリ。
// 画面、ボタン、電源情報などを M5.*** で扱えるようになる。
#include "M5Unified.h"
void setup() {
// M5デバイス初期化用の設定オブジェクトを作る
auto cfg = M5.config();
// 画面・ボタン・電源管理などを初期化する
M5.begin(cfg);
// 画面を横向き表示にする(数値は機種ごとに見やすい向きが異なる)
M5.Display.setRotation(1);
// 表示フォントを設定
M5.Display.setTextFont(&fonts::FreeMonoBold9pt7b);
// 文字サイズを1倍に設定
M5.Display.setTextSize(1);
}
void loop() {
// ボタンや内部状態を毎ループ更新する(M5Unifiedの基本)
M5.update();
// 前フレームの表示を消して描き直す
M5.Display.clear();
// 充電中かどうか(true/false)
bool isCharging = M5.Power.isCharging();
// バッテリー残量(0〜100の目安)
int level = M5.Power.getBatteryLevel();
// バッテリー電圧(mV)
int voltage = M5.Power.getBatteryVoltage();
// 低電池とみなす条件を定義
bool lowBattery = (level <= 20) || (voltage <= 3600);
// 1行目: 充電状態を表示
M5.Display.setCursor(0, 30);
// 充電中なら緑、それ以外は白
M5.Display.setTextColor(isCharging ? TFT_GREEN : TFT_WHITE, TFT_BLACK);
M5.Display.printf("Charging: %s", isCharging ? "Yes" : "No");
// 2行目: 残量を表示(低電池なら赤)
M5.Display.setCursor(0, 60);
M5.Display.setTextColor(lowBattery ? TFT_RED : TFT_WHITE, TFT_BLACK);
M5.Display.printf("Bat_level: %d%%", level);
// 3行目: 電圧を表示
M5.Display.setCursor(0, 90);
M5.Display.printf("Bat_voltage: %d mV", voltage);
// 2秒ごとに更新(変化が速すぎないので見やすい)
delay(2000);
}
ボタン状態を表示する
次に、A / B / 同時押し / 未押下を表示するコードです。
状態が変わったときだけ再描画するので、画面が安定します。
ここで押さえておくポイントです。
- 「ボタン状態」を数値で定義して管理すると、判定ロジックを整理しやすい
-
getButtonState()で入力(ボタン)を読む -
drawState()で出力(画面表示)を行う -
prevStateと比較して、変化したときだけ描画する
// M5Unifiedを使って、ボタンと画面をまとめて扱う
#include "M5Unified.h"
// ボタン状態を数値で定義(読みやすさと保守性のため)
static constexpr uint8_t STATE_RELEASED = 0;
static constexpr uint8_t STATE_PRESSED_A = 1;
static constexpr uint8_t STATE_PRESSED_B = 2;
static constexpr uint8_t STATE_PRESSED_BOTH = 3;
// 前回の状態を保存して、状態変化時だけ再描画するために使う
static uint8_t prevState = STATE_RELEASED;
// 現在のボタン状態(未押下/A/B/同時押し)を返す関数
static uint8_t getButtonState() {
// Aボタンの押下状態を取得
bool a = M5.BtnA.isPressed();
// Bボタンの押下状態を取得
bool b = M5.BtnB.isPressed();
// 押し方に応じて状態コードを返す
if (a && b) return STATE_PRESSED_BOTH;
if (a) return STATE_PRESSED_A;
if (b) return STATE_PRESSED_B;
return STATE_RELEASED;
}
// 状態に応じた画面表示を行う関数
static void drawState(uint8_t state) {
// まず画面をクリアして、表示の重なりを防ぐ
M5.Display.clear(TFT_BLACK);
M5.Display.setCursor(0, 0);
// 文字色(前景色)と背景色を設定
M5.Display.setTextColor(TFT_WHITE, TFT_BLACK);
// stateの値に応じて表示内容と色を変更
switch (state) {
case STATE_PRESSED_A:
M5.Display.println("Button Detail:");
M5.Display.setTextColor(TFT_GREEN, TFT_BLACK);
M5.Display.println("ButtonA Pressed");
break;
case STATE_PRESSED_B:
M5.Display.println("Button Detail:");
M5.Display.setTextColor(TFT_CYAN, TFT_BLACK);
M5.Display.println("ButtonB Pressed");
break;
case STATE_PRESSED_BOTH:
M5.Display.println("Button Detail:");
M5.Display.setTextColor(TFT_YELLOW, TFT_BLACK);
M5.Display.println("ButtonA + ButtonB");
break;
default:
M5.Display.println("Button Released");
break;
}
}
void setup() {
// 初期化設定を作成してM5を起動
auto cfg = M5.config();
M5.begin(cfg);
// 画面の向きとフォントを設定
M5.Display.setRotation(1);
M5.Display.setFont(&fonts::FreeMonoBold12pt7b);
// 起動時は未押下表示
drawState(STATE_RELEASED);
}
void loop() {
// ボタン状態を更新
M5.update();
// 現在のボタン状態を取得
uint8_t state = getButtonState();
// 前回と変化があったときだけ描画
if (state != prevState) {
drawState(state);
prevState = state;
}
// タスクにCPU時間を譲る(高頻度ループでの負荷軽減)
vTaskDelay(1);
}
つまずきやすいポイント
- 1つのスケッチフォルダに
.inoを複数置くと、setup()/loop()が重複してビルドエラーになる -
printfの書式は%d mVのように書く(%mVは無効) - ボード設定は実機のチップと合わせる(M5StickS3 は ESP32-S3)
次にやると面白い拡張
- ボタン短押し・長押しの判定表示
- バッテリー値のグラフ表示
- IMU 値(加速度)のリアルタイム表示
- ボタンで画面を切り替える簡単な UI
最初の一歩としては、電源情報表示とボタン判定が動けば十分です。
この2つができると、センサー表示やUI実装へ自然に進めます。