このスケッチは、Seeed Studio XIAO ESP32S3 を使用し、 ✅ USB HIDマウス ✅ Wi-Fiアクセスポイント経由のWeb設定画面 ✅ GPIO入力によるマウス操作 を組み合わせたシステムです。 🎯 主な目的 USB HIDマウスとしてCHCNAVに接続され、GPIO入力でマウス操作を実行する 設定用スイッチを押しながら起動することで Wi-Fiアクセスポイントを立ち上げ、ブラウザからマウス操作の座標設定ができる 設定内容は不揮発メモリ(Preferences/NVS)に保存され、電源OFFしても保持される 設定モード中はLEDが点灯し、状態がわかる 🔍 動作の流れ XIAO ESP32S3をUSBでCHCNAVに接続すると、マウスとして認識される。 GPIO2に接続した「設定用スイッチ」を押したまま電源ONまたはリセットすると: Wi-Fiアクセスポイントモードが起動 スマホやPCを ESP32S3-AP というWi-Fiに接続 ブラウザから 192.168.4.1 にアクセス マウス座標設定ページが表示 LED(GPIO3接続)が点灯し、設定モード中であることを示す 設定ページから座標を入力・保存すると内部メモリに保存され、即時有効。 保存後は「テストクリック」ボタンで設定値に基づくマウス動作のテストが可能 GPIO2の設定用スイッチを押さずに起動した場合: Wi-Fiは起動せず LEDは消灯 USBマウスとGPIO入力のみ動作 GPIO0, GPIO1 に接続したタクトスイッチを押すと: GPIO0 → 自動操舵ONOFF GPIO1 → MOVE_FILL座標へ移動 → 塗りつぶしボタン等ONOFF → MOVE_RETURN座標へ戻る ✅ 特徴・利点 設定操作と通常動作をスイッチ1つで分離 設定値はPreferencesに保存されるため、電源OFFしても再設定不要 Wi-Fi設定中はLEDが点灯し、状態が一目でわかる マウス座標の変更がPC不要・スマホだけで可能(Webブラウザ経由) 小型のXIAO ESP32S3で完結、外付け部品はタクトスイッチとLEDのみ
#include <WiFi.h> #include <WebServer.h> #include <Preferences.h> #include "Adafruit_TinyUSB.h" // GPIO定義 const int tactA = 0; // 操作用タクトスイッチA const int tactB = 1; // 操作用タクトスイッチB const int setupSwitch = 2; // 設定用スイッチ const int LED_PIN = 3; // 設定モード表示用LED // Wi-Fi設定 const char* ssid = "ESP32S3-AP"; const char* password = "12345678"; // Webサーバ WebServer server(80); // USB HIDマウス Adafruit_USBD_HID usb_hid; uint8_t mouse_report[4] = {0}; // 座標変数 int CURSOR_X = 238; int CURSOR_Y = 150; int MOVE_FILL_X = 0; int MOVE_FILL_Y = -90; int MOVE_RETURN_X = 0; int MOVE_RETURN_Y = 90; // Preferences Preferences prefs; // フラグ bool setupMode = false; // HTMLページ String htmlPage = R"rawliteral( <!DOCTYPE html> <html> <head><title>ESP32S3設定</title></head> <body> <h2>座標設定</h2> <form action="/set" method="POST"> CURSOR_X: <input name="CURSOR_X" value="%CURSOR_X%"><br> CURSOR_Y: <input name="CURSOR_Y" value="%CURSOR_Y%"><br> MOVE_FILL_X: <input name="MOVE_FILL_X" value="%MOVE_FILL_X%"><br> MOVE_FILL_Y: <input name="MOVE_FILL_Y" value="%MOVE_FILL_Y%"><br> MOVE_RETURN_X: <input name="MOVE_RETURN_X" value="%MOVE_RETURN_X%"><br> MOVE_RETURN_Y: <input name="MOVE_RETURN_Y" value="%MOVE_RETURN_Y%"><br> <input type="submit" value="保存"> </form> <form action="/test" method="GET"> <input type="submit" value="テストクリック"> </form> </body> </html> )rawliteral"; String processor(const String& var) { if (var == "CURSOR_X") return String(CURSOR_X); if (var == "CURSOR_Y") return String(CURSOR_Y); if (var == "MOVE_FILL_X") return String(MOVE_FILL_X); if (var == "MOVE_FILL_Y") return String(MOVE_FILL_Y); if (var == "MOVE_RETURN_X") return String(MOVE_RETURN_X); if (var == "MOVE_RETURN_Y") return String(MOVE_RETURN_Y); return ""; } void handleRoot() { String page = htmlPage; page.replace("%CURSOR_X%", String(CURSOR_X)); page.replace("%CURSOR_Y%", String(CURSOR_Y)); page.replace("%MOVE_FILL_X%", String(MOVE_FILL_X)); page.replace("%MOVE_FILL_Y%", String(MOVE_FILL_Y)); page.replace("%MOVE_RETURN_X%", String(MOVE_RETURN_X)); page.replace("%MOVE_RETURN_Y%", String(MOVE_RETURN_Y)); server.send(200, "text/html", page); } void handleSet() { if (server.hasArg("CURSOR_X")) CURSOR_X = server.arg("CURSOR_X").toInt(); if (server.hasArg("CURSOR_Y")) CURSOR_Y = server.arg("CURSOR_Y").toInt(); if (server.hasArg("MOVE_FILL_X")) MOVE_FILL_X = server.arg("MOVE_FILL_X").toInt(); if (server.hasArg("MOVE_FILL_Y")) MOVE_FILL_Y = server.arg("MOVE_FILL_Y").toInt(); if (server.hasArg("MOVE_RETURN_X")) MOVE_RETURN_X = server.arg("MOVE_RETURN_X").toInt(); if (server.hasArg("MOVE_RETURN_Y")) MOVE_RETURN_Y = server.arg("MOVE_RETURN_Y").toInt(); prefs.putInt("CURSOR_X", CURSOR_X); prefs.putInt("CURSOR_Y", CURSOR_Y); prefs.putInt("MOVE_FILL_X", MOVE_FILL_X); prefs.putInt("MOVE_FILL_Y", MOVE_FILL_Y); prefs.putInt("MOVE_RETURN_X", MOVE_RETURN_X); prefs.putInt("MOVE_RETURN_Y", MOVE_RETURN_Y); server.sendHeader("Location", "/"); server.send(303); } void handleTest() { mouse_report[0] = 0; mouse_report[1] = CURSOR_X; mouse_report[2] = CURSOR_Y; mouse_report[3] = 0; usb_hid.sendReport(1, mouse_report, 4); delay(100); mouse_report[0] = 1; mouse_report[1] = 0; mouse_report[2] = 0; mouse_report[3] = 0; usb_hid.sendReport(1, mouse_report, 4); delay(100); mouse_report[0] = 0; usb_hid.sendReport(1, mouse_report, 4); server.sendHeader("Location", "/"); server.send(303); } void setup() { pinMode(tactA, INPUT_PULLDOWN); pinMode(tactB, INPUT_PULLDOWN); pinMode(setupSwitch, INPUT_PULLUP); // 設定用スイッチ(プルアップ) pinMode(LED_PIN, OUTPUT); // LED出力 digitalWrite(LED_PIN, LOW); // 初期は消灯 usb_hid.begin(); prefs.begin("config", false); // 設定値読み込み CURSOR_X = prefs.getInt("CURSOR_X", CURSOR_X); CURSOR_Y = prefs.getInt("CURSOR_Y", CURSOR_Y); MOVE_FILL_X = prefs.getInt("MOVE_FILL_X", MOVE_FILL_X); MOVE_FILL_Y = prefs.getInt("MOVE_FILL_Y", MOVE_FILL_Y); MOVE_RETURN_X = prefs.getInt("MOVE_RETURN_X", MOVE_RETURN_X); MOVE_RETURN_Y = prefs.getInt("MOVE_RETURN_Y", MOVE_RETURN_Y); // === 設定スイッチ判定 === unsigned long pressTime = 0; const unsigned long threshold = 2000; // 2秒 if (digitalRead(setupSwitch) == LOW) { pressTime = millis(); while (digitalRead(setupSwitch) == LOW) { if (millis() - pressTime >= threshold) { setupMode = true; break; } } } if (setupMode) { digitalWrite(LED_PIN, HIGH); // LED点灯 WiFi.softAP(ssid, password); Serial.print("APモード IP: "); Serial.println(WiFi.softAPIP()); server.on("/", handleRoot); server.on("/set", HTTP_POST, handleSet); server.on("/test", HTTP_GET, handleTest); server.begin(); } else { digitalWrite(LED_PIN, LOW); // 設定モードじゃなければLED消灯 } while (!TinyUSBDevice.mounted()) delay(10); } void loop() { if (setupMode) { server.handleClient(); } bool nowA = digitalRead(tactA); bool nowB = digitalRead(tactB); if (nowA) { mouse_report[0] = 1; mouse_report[1] = 0; mouse_report[2] = 0; mouse_report[3] = 0; usb_hid.sendReport(1, mouse_report, 4); delay(100); mouse_report[0] = 0; usb_hid.sendReport(1, mouse_report, 4); } if (nowB) { mouse_report[0] = 0; mouse_report[1] = MOVE_FILL_X; mouse_report[2] = MOVE_FILL_Y; mouse_report[3] = 0; usb_hid.sendReport(1, mouse_report, 4); delay(100); mouse_report[0] = 1; mouse_report[1] = 0; mouse_report[2] = 0; mouse_report[3] = 0; usb_hid.sendReport(1, mouse_report, 4); delay(100); mouse_report[0] = 0; mouse_report[1] = MOVE_RETURN_X; mouse_report[2] = MOVE_RETURN_Y; mouse_report[3] = 0; usb_hid.sendReport(1, mouse_report, 4); } delay(10); }
コメント
この記事へのトラックバックはありません。
この記事へのコメントはありません。