最終修正日:2020/6/18
ESP32のオリジナル開発モジュールを購入してみたいと思い立ったちました。Espressif 社オリジナルの入手を試みたのですが、なかなか入手しやすいものがないです。AliExpressから入手は可能なようですが、コロナ禍の中、中国からの輸入は躊躇します。
技適を取得しているかどうかは重要だと思っています。ESP-WROOM-32は技適を取得しておりマークも付いているので変な心配が一つ減ります。
スイッチサイエンスはESP-WROOM-32を独自モジュールに載せて販売しています。秋月はEspressif 社オリジナルを安価に扱っていました。それも38pinDIPタイプで自分が欲するモノでした。ところがアンテナ部がモジュールから飛び出しています。これ折れやすいという情報もあり避けたいと思っていました。DIP化キットは期待通りなのですが、この場合自分で半田付けしないといけません。結局Amazonに出店していた WayinTop社の ESP-WROOM-32 モジュールを購入しました。ピンアサイン等の情報公開はしているので使えるだろうという考えです。
既に確認している現象をリストアップして置きます。
- ESP-WROOM-32の消費電流は80mA程度とのことでした。しかし、USBハブを介すると全く認識しないです。
CP2102はUSBハブでも認識しているのでESP-WROOM-32のブート時の電流供給出来ないのかと考えています。- GPIO #1〜#3にデバイス等が接続された状態だとコンパイルに失敗することが多いです。使わないで済むのであればそうすべきです。
- SPI端子は1系統しかありません。ESP-WROOM-32モジュール内部のFlashメモリバスに使用しており、この端子にも他のデバイスが接続されていると期待通りの動作にならないことがあるとのことです。
初期ファームのまま使ってみる
- 初期ファームの状況を確認してみようと思いました。が、ESP-WROOM-32 モジュールはより情報が少ないと思いました。パスすることにします。
- ただ、電源は供給しているため電波はどうなっているのか確認したところ、『ESP_5EED7D』というSSIDを確認し、ログオン出来ました。
![]()
- この初期SSID文字列は何を参照して表示しているのか気になりました。
- ArduinoIDEから書込を試みてしまうとメーカが提供するファームが使えなくなります。
WayinTop社の ESP-WROOM-32 モジュール 初期ファームの情報を入手出来ていません。元に戻すことは諦めた方がいいのかと思います。- 初期ファームの書き出し(サルベージと云うそうです。)方法について、先人の方が紹介していました。自分もトライして見ました。
これを実現するには開発環境を整えてからで無いと出来ません。
- ライブラリマネージャ使用を使用してArduino core for the ESP3 をインストールする方法だとArduino IDEでESP-WROOM-32が開発できるようになるのですが、ツールの類いが期待通りの場所にありません。
- 手動でArduino core for the ESP32 のインストールします。
- https://github.com/espressif/arduino-esp32 から arduino-esp32-master.zip をダウンロードし、デスクトップなりに展開します。
- Arduino インストールフォルダの中の hardware フォルダに、espressif\esp32 サブフォルダを作成。
※C:\Users\[ユーザ]\Documents\Arduino\hardware でも良いかと思います。- 展開した中身一式をesp32 フォルダ内にコピーします。
- \hardware\espressif\esp32\tools\get.exe を右クリックし、[管理者として実行] で実行する。
- ESP-WROOM-32開発ボードをPCに接続してCOM番号を確認する。COM35とする。
- バッチファイルを作成する。ファイル名はとりあえずFirmware_Backup.cmdとする。内容は、
@echo off SET COM_PORT=COM35 esptool\esptool.exe --chip esp32 --port %COM_PORT% --baud 921600 read_flash 0 0x400000 esp32_firmware.bin
として、\hardware\espressif\esp32\tools\Firmware_Backup.cmd に保存します。- ESP-WROOM-32開発ボードのBOOTボタンを押しながら、Firmware_Backup.cmdを右クリックして管理者として実行します。結果として、コマンドプロンプトにメッセージが逐次発行され、ついにはesp32_firmware.binという4MBのファームウエアを吸い上げることが出来ます。
esptool.py v2.6 Serial port COM35 Connecting........_____. Chip is ESP32D0WDQ6 (revision 1) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None MAC: 24:0a:c4:61:1e:7c Uploading stub... Running stub... Stub running... Changing baud rate to 921600 Changed. 4096 (0 %) 8192 (0 %) ・・・・ 4194304 (100 %) Read 4194304 bytes at 0x0 in 58.7 seconds (571.2 kbit/s)... Hard resetting via RTS pin...- ちなみに@ BOOTボタンを押すのを忘れると、
Connecting........_____........_____........_____.
と云う時間が暫くあり、コマンドウインドが勝手に閉じられてしまいます。
逆に Connecting の- ちなみにA リストア用のスクリプトも紹介されていました。
@echo off SET COM_PORT=COM35 esptool\esptool.exe --chip esp32 --port %COM_PORT% --baud 921600 write_flash 0 esp32_firmware.bin- Pathの記述にご注意ください。自分の環境ではarduino-esp32-master.zipを展開した際に、
C:\Program Files (x86)\Arduino\hardware\espressif\esp32\tools\esptool\esptool.exe
となっています。- 初期ファームに使われているソースコードが見つかればSSIDのルールが判ります。ただ、このファームは暗号化しているようなので安易な解析は出来ない様で、先人の記事も踏み込んだモノが見当たらないです。
ESP-WROOM-32開発ボードをArduino IDEで開発する方法
によると、
- Settingタブ内のAdditional Boards Manager URLsに次のURLを入力して、Arduino IDEにESP32ボードを追加します。
https://arduino.esp8266.com/stable/package_esp8266com_index.json
2020.5.28現在のArduinoIDE最新バージョンは1.8.12です。
START![]()
- ツール>ボード>ボードマネージャーを選択してesp32環境をインストールします。
2020.6.8の時点での最新版は1.0.4でした。
![]()
- ArduinoIDEを再起動するとツール>ボードリストに追加したESP32 Module群がリストアップされているはずです。
ESP32 DEV Module を選択します。自分は以下のように設定しました。
@ ボード: ESP32 DEV Module A Upload Speed 921600 B CPU Frequency 240MHz C Flash Size 2M(FS1M) D Flash Mode QIO(fast) E Flash Frequency 80MHz F Reset Method dtr(aka nodemcu) G シリアルポート 実機に合わせて - GetChipIDというサンプルスケッチを書き込んでみました。
/* * 20200608 T.Wanibe * Amazon で扱っていた WayinTop ESP32開発ボード の使い方を勉強するために購入しました。 * 多分純正の ESP-WROOM32 の条件で使えると思っています。 * 最大1310720バイトのフラッシュメモリのうち、スケッチが214853バイト(16%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が15396バイト(4%)を使っていて、ローカル変数で312284バイト使うことができます。 */ uint64_t chipid; //---------------- void setup() { Serial.begin(115200); } //---------------- void loop() { chipid=ESP.getEfuseMac(); //The chip ID is essentially its MAC address(length: 6 bytes). Serial.printf("ESP32 Chip ID = %04X",(uint16_t)(chipid>>32)); //print High 2 bytes Serial.printf("%08X\n",(uint32_t)chipid); //print Low 4bytes. delay(3000); }
これまでのように書き込むと『A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header』というエラーが発生します。ESPのプログラム書込に際しては『BOOT』ボタンを押した状態で書込開始して、書込完了したらボタンを放せば良いです。ArduinoIDEには以下のようなメッセージが出て書き込めました。
esptool.py v2.6 Serial port COM35 Connecting.... Chip is ESP32D0WDQ6 (revision 1) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None MAC: 24:0a:c4:5e:ed:7c Uploading stub... Running stub... Stub running... Changing baud rate to 921600 Changed. Configuring flash size... Auto-detected Flash size: 4MB Compressed 8192 bytes to 47... Writing at 0x0000e000... (100 %) Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.0 seconds (effective 2340.6 kbit/s)... Hash of data verified. Compressed 17392 bytes to 11186... Writing at 0x00001000... (100 %) Wrote 17392 bytes (11186 compressed) at 0x00001000 in 0.2 seconds (effective 909.4 kbit/s)... Hash of data verified. Compressed 214976 bytes to 109251... Writing at 0x00010000... (14 %) Writing at 0x00014000... (28 %) Writing at 0x00018000... (42 %) Writing at 0x0001c000... (57 %) Writing at 0x00020000... (71 %) Writing at 0x00024000... (85 %) Writing at 0x00028000... (100 %) Wrote 214976 bytes (109251 compressed) at 0x00010000 in 1.8 seconds (effective 946.0 kbit/s)... Hash of data verified. Compressed 3072 bytes to 128... Writing at 0x00008000... (100 %) Wrote 3072 bytes (128 compressed) at 0x00008000 in 0.0 seconds (effective 877.7 kbit/s)... Hash of data verified. Leaving... Hard resetting via RTS pin...- 『RST』ボタンを押すとコンソールに以下のようなメッセージが返りました。
16:04:04.226 -> ets Jun 8 2016 00:22:57 16:04:04.226 -> 16:04:04.226 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 16:04:04.226 -> configsip: 0, SPIWP:0xee 16:04:04.226 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 16:04:04.226 -> mode:DIO, clock div:1 16:04:04.226 -> load:0x3fff0018,len:4 16:04:04.226 -> load:0x3fff001c,len:1216 16:04:04.226 -> ho 0 tail 12 room 4 16:04:04.260 -> load:0x40078000,len:9720 16:04:04.260 -> ho 0 tail 12 room 4 16:04:04.260 -> load:0x40080400,len:6352 16:04:04.260 -> entry 0x400806b8 16:04:04.396 -> ESP32 Chip ID = 7CED5EC40A24
Chip ID が 7CED5EC40A24 と云う事が判りましたがSSIDとの関連は不明です。なんとなく近い文字列なんですが。。
もう少し調査すれば何か判るかもしれません。
サンプルスケッチの実行例を挙げてゆきます。
ArduinoIDEには可成りのサンプルスケッチが登録されているのですが、いまいち目的とするスケッチが判らないと自分は感じています。そんな折、先人が紹介記事を書いていました。参考にさせて戴いております。
Arduino(ESP-WROOM-32)サンプルグログラム解説:https://garretlab.web.fc2.com/arduino/esp32/examples/
- Chipの情報及びMACアドレスを調査するサンプルスケッチ
- NTP時刻同期
- WebServerの実行
- Chipのリビジョンを確認する方法
- EEPROMClassの使用
- WiFiScan
- WiFi-Control-Car(DHCP)
- WiFi-Control-Car(AP)
- ESPでAJAXを試す
【Chipの情報及びMACアドレスを調査するサンプルスケッチ】
/* * 20200609 T.Wanibe * ESP32 Chip ID等更に情報取得する方法を探していたところ見つかったスケッチを実行してみます。 * 最大1310720バイトのフラッシュメモリのうち、スケッチが216977バイト(16%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が15388バイト(4%)を使っていて、ローカル変数で312292バイト使うことができます。 */ //----------------------- void setup(void) { Serial.begin(115200); Serial.println(F("-----------------------------")); uint64_t chipid; chipid=ESP.getEfuseMac(); //The chip ID is essentially its MAC address(length: 6 bytes). Serial.printf("ESP32 Chip ID = %04X\r\n",(uint16_t)(chipid>>32)); //print High 2 bytes Serial.printf("Chip Revision %d\r\n", ESP.getChipRevision()); esp_chip_info_t chip_info; esp_chip_info(&chip_info); Serial.printf("Number of Core: %d\r\n", chip_info.cores); Serial.printf("CPU Frequency: %d MHz\r\n", ESP.getCpuFreqMHz()); Serial.printf("Flash Chip Size = %d byte\r\n", ESP.getFlashChipSize()); Serial.printf("Flash Frequency = %d Hz\r\n", ESP.getFlashChipSpeed()); Serial.printf("ESP-IDF version = %s\r\n", esp_get_idf_version()); Serial.printf("Free Heap Size = %d\r\n", esp_get_free_heap_size()); Serial.printf("System Free Heap Size = %d\r\n", system_get_free_heap_size()); Serial.printf("Minimum Free Heap Size = %d\r\n", esp_get_minimum_free_heap_size()); Serial.println(); uint8_t mac0[6]; esp_efuse_mac_get_default(mac0); Serial.printf("Default Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac0[0], mac0[1], mac0[2], mac0[3], mac0[4], mac0[5]); uint8_t mac1[6]; esp_efuse_read_mac(mac1); Serial.printf("EFuse Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac1[0], mac1[1], mac1[2], mac1[3], mac1[4], mac1[5]); uint8_t mac2[6]; system_efuse_read_mac(mac2); Serial.printf("System Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac2[0], mac2[1], mac2[2], mac2[3], mac2[4], mac2[5]); uint8_t mac3[6]; esp_read_mac(mac3, ESP_MAC_WIFI_STA); Serial.printf("[Wi-Fi Station] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac3[0], mac3[1], mac3[2], mac3[3], mac3[4], mac3[5]); uint8_t mac4[7]; esp_read_mac(mac4, ESP_MAC_WIFI_SOFTAP); Serial.printf("[Wi-Fi SoftAP] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac4[0], mac4[1], mac4[2], mac4[3], mac4[4], mac4[5]); uint8_t mac5[6]; esp_read_mac(mac5, ESP_MAC_BT); Serial.printf("[Bluetooth] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac5[0], mac5[1], mac5[2], mac5[3], mac5[4], mac5[5]); uint8_t mac6[6]; esp_read_mac(mac6, ESP_MAC_ETH); Serial.printf("[Ethernet] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac6[0], mac6[1], mac6[2], mac6[3], mac6[4], mac6[5]); } //----------------------- void loop() { }[実行結果]
15:38:51.829 -> ets Jun 8 2016 00:22:57 15:38:51.829 -> 15:38:51.829 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 15:38:51.829 -> configsip: 0, SPIWP:0xee 15:38:51.863 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 15:38:51.863 -> mode:DIO, clock div:1 15:38:51.863 -> load:0x3fff0018,len:4 15:38:51.863 -> load:0x3fff001c,len:1216 15:38:51.863 -> ho 0 tail 12 room 4 15:38:51.863 -> load:0x40078000,len:9720 15:38:51.863 -> ho 0 tail 12 room 4 15:38:51.863 -> load:0x40080400,len:6352 15:38:51.863 -> entry 0x400806b8 15:38:51.999 -> ----------------------------- 15:38:51.999 -> ESP32 Chip ID = 7CED 15:38:51.999 -> Chip Revision 1 15:38:51.999 -> Number of Core: 2 15:38:51.999 -> CPU Frequency: 240 MHz 15:38:51.999 -> Flash Chip Size = 4194304 byte 15:38:52.033 -> Flash Frequency = 80000000 Hz 15:38:52.033 -> ESP-IDF version = v3.2.3-14-gd3e562907 15:38:52.033 -> Free Heap Size = 289780 15:38:52.033 -> System Free Heap Size = 289780 15:38:52.033 -> Minimum Free Heap Size = 283732 15:38:52.033 -> 15:38:52.033 -> Default Mac Address = 24:0A:C4:5E:ED:7C 15:38:52.033 -> EFuse Mac Address = 24:0A:C4:5E:ED:7C 15:38:52.033 -> System Mac Address = 24:0A:C4:5E:ED:7C 15:38:52.033 -> [Wi-Fi Station] Mac Address = 24:0A:C4:5E:ED:7C 15:38:52.033 -> [Wi-Fi SoftAP] Mac Address = 24:0A:C4:5E:ED:7D 15:38:52.067 -> [Bluetooth] Mac Address = 24:0A:C4:5E:ED:7E 15:38:52.067 -> [Ethernet] Mac Address = 24:0A:C4:5E:ED:7FSSIDの値は[Wi-Fi SoftAP] Mac Addressの下3バイトを使っていた事が明解になりました。
また、Chip IDはDefault Mac Addressのエンディアンが逆の6バイト値と云う事も判りました。そして、
Wi-Fi SoftAP = Default Mac Address +1
Bluetooth = Default Mac Address +2
Ethernet = Default Mac Address +3MACアドレスを検索したところ、24:0A:C4 cn - 中華人民共和国 Espressif Inc. が確認出来ました。
ということはESP-WROOM-32にはユニークなMACアドレスが付加されてリリースされているということはESP-WROOM-32には可能性が出てきました。CHIPIDから生成されていると推測できるためユニークだと信じたいところですが、IDが16bitなので衝突する番号を発行してしまっているのでは無いかと云う疑問が湧きます
興味深い議事の多い『Geekなページ』の 2020/06/16 のブログ記事に興味深いモノがありました。
2020-06-16 MACアドレスの再利用は、みんなが思っているよりもはるかに一般的
Derbycon 2102の発表の MACアドレスが示すベンダーごとに、重複したMACアドレスが検出された数が示されています。これを見るとHUWAI社が吐出しており30万件あります。
RFC 7707 にて MACアドレスの重複が確認されたら動的に調整する手順が示されていることからこのような事は事前に検討されていたのでしょう。MACアドレスはユニークに割り振る必要がある は 迷信なのでしょうか?多分HUWAI社が出荷するネットワーク機器は同一MACアドレス商品がたくさんあったのでしょう。
この記事から8年経っていますが、現在の状況はどうなのか判りませんが、Arduinoでコーディングしたネットワーク機器はbitイメージ書込時にユニークなMACアドレスを設定しないでしょうから更に面白い結果が得られるのでは無いかと思います。当然Privateなゾーンで使われていれば攻められないのでしょうが、Publicなゾーンに無意識に出て行く人が,,少なからずいるでしょう。
【NTP時刻同期】
ESP-WROOM-32 リセット後、WIFI経由でLANに入り、LAN内のNTPDにアクセスして時刻取得して時刻表示するというサンプルスケッチです。
表示にはI2CのOLCDを採用しました。追加が必要なライブラリ: <Adafruit_GFX.h> https://github.com/adafruit/Adafruit-GFX-Library <Adafruit_SSD1306.h>https://github.com/adafruit/Adafruit_SSD1306
/* * 20200610 T.Wanibe * 起動時にNTPサーバにアクセスして時刻取得したら以後1秒毎に時刻プリントするスケッチを実行します * オリジナルのコードはコンソールに時刻表示をしていたが、これをI2CのOLCDに表示するように変更した。 * 最大1310720バイトのフラッシュメモリのうち、スケッチが647730バイト(49%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が39680バイト(12%)を使っていて、ローカル変数で288000バイト使うことができます。 */ #include <WiFi.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "time.h" #include "time.h" #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define NUMFLAKES 10 // アニメーション例の雪片の数 #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 #define PLCDAres 0x3C //0x3Cか0x3D const char* ssid = "Kingsland"; const char* password = ""; const char* ntpServer = "192.168.0.206"; const long gmtOffset_sec = 32400; //GMT+9 const int daylightOffset_sec = 0; //夏時間はありません //I2C(SDA、SCLピン)に接続されたSSD1306ディスプレイの宣言 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //-------------------------- void printLocalTime(){ struct tm timeinfo; if(!getLocalTime(&timeinfo)){ Serial.println(F("Failed to obtain time")); return; } Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); display.clearDisplay(); display.setTextSize(1); // Draw 2X-scale text display.setTextColor(SSD1306_WHITE); display.setCursor(0, 5); //左上原点(0,5)開始点 display.println(&timeinfo,"%A, %B %d %Y"); display.setTextSize(2); display.setCursor(10, 20); display.println(&timeinfo,"%H:%M:%S"); display.display(); } //-------------------------- void setup() { Serial.begin(115200); //SSD1306_SWITCHCAPVCC =内部で3.3Vから表示電圧を生成 if(!display.begin(SSD1306_SWITCHCAPVCC, PLCDAres)) { // 128x64のスレーブアドレスオリジナル値は0x3Dでしたが手元の元は0x3Cでした。 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } // バッファをクリアします display.clearDisplay(); display.display(); //connect to WiFi Serial.printf("Connecting to %s ", ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(F(".")); } Serial.println(F(" CONNECTED")); //init and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); printLocalTime(); //disconnect WiFi as it's no longer needed WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } //-------------------------- void loop() { delay(1000); printLocalTime(); }[実行結果]
16:24:30.628 -> ets Jun 8 2016 00:22:57 16:24:30.628 -> 16:24:30.628 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 16:24:30.628 -> configsip: 0, SPIWP:0xee 16:24:30.628 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 16:24:30.628 -> mode:DIO, clock div:1 16:24:30.628 -> load:0x3fff0018,len:4 16:24:30.628 -> load:0x3fff001c,len:1216 16:24:30.628 -> ho 0 tail 12 room 4 16:24:30.628 -> load:0x40078000,len:9720 16:24:30.628 -> ho 0 tail 12 room 4 16:24:30.628 -> load:0x40080400,len:6352 16:24:30.662 -> entry 0x400806b8 16:24:30.899 -> Connecting to Kingsland . CONNECTED 16:24:31.477 -> Friday, June 12 2020 16:24:30 16:24:31.477 -> Guru Meditation Error: Core 1 panic'ed (Connecting to Kingsland . CONNECTED 16:26:51.391 -> Friday, June 12 2020 16:26:50 ・・・・・
【WebServerの実行】
ESP-WROOM-32 リセット後、WIFI経由でLANに入り、WebServerが公開されます。
IPアドレスが固定する方法が判りませんが、一応ブラウザでアクセス出来ました。
/* * 2020/06/10 T.Wanibe * ESP-WROOM32のサンプルスケッチを改造しました。 * オリジナルは、 * Copyright (c) 2015, Majenko Technologies All rights reserved. * ソースおよびバイナリ形式での再配布および使用は、変更の有無にかかわらず、次の条件を満たす場合に許可されます。 * ソースコードの再配布では、上記の著作権表示、この条件のリスト、および次の免責事項を保持する必要があります。 * バイナリ形式で再配布する場合は、上記の著作権表示、この条件のリスト、および次の免責事項を、配布物とともに * 提供されるドキュメントやその他の資料に複製する必要があります。 * Majenko Technologiesの名前もその貢献者の名前も、書面による事前の明確な許可なしに、このソフトウェア * から派生した製品を推奨または宣伝するために使用することはできません。 * * * このソフトウェアは、著作権者および寄稿者によって「現状のまま」提供され、商品性および特定の目的に対する適合性の * 黙示の保証を含むがこれに限定されない、明示または黙示の保証は否認されます。 いかなる場合においても、 * 著作権者または寄稿者は、直接的、間接的、偶発的、特別、例示的、または結果的損害に対して責任を負わないものとします。 * (これに限定されないが、代替商品またはサービスの調達、使用、データ、利益の喪失、または業務の中断)責任の理論、 * 責任、過失、または責任の不一致にかかわらず、 それ以外の場合)そのような損害の可能性について知らされていたとしても、 * 本ソフトウェアの使用からいかなる方法においても生じること。 * * 最大1310720バイトのフラッシュメモリのうち、スケッチが749050バイト(57%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が41264バイト(12%)を使っていて、ローカル変数で286416バイト使うことができます。 */ #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <ESPmDNS.h> #define HTTPPort 80 const char *ssid = "Kingsland"; //有効なSSIDにLOGONしてLANに入る const char *password = ""; const int led = 13; //BuiltInLEDというのがESPには無いようなのでcheck用のLEDを接続する。 //GPIO13を使うのが一般的とのこと //ON/OFFとかTRUE/FALSEという表記はマクロ定義されていない模様 WebServer server(HTTPPort); //-------------------- void handleRoot() { digitalWrite(led,1); char temp[400]; int sec = millis() / 1000; int min = sec / 60; int hr = min / 60; snprintf(temp, 400, "<html> <head> <meta http-equiv='refresh' content='5'/> <title>ESP32 Demo</title> <style> body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; } </style> </head> <body> <h1>Hello from ESP32!</h1> <p>Uptime: 00:01:38</p> <img src="/test.svg" /> </body> </html>", hr, min % 60, sec % 60); server.send(200, "text/html", temp); digitalWrite(led, 0); } //-------------------- void handleNotFound() { digitalWrite(led, 1); String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } server.send(404, "text/plain", message); digitalWrite(led, 0); } //-------------------- void drawGraph() { String out = ""; char temp[100]; out += "<svg xmlns=\"https://www.w3.org/2000/svg\" version=\"1.1\" width=\"400\" height=\"150\">\n"; out += "<rect width=\"400\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n"; out += "<g stroke=\"black\">\n"; int y = rand() % 130; for (int x = 10; x < 390; x += 10) { int y2 = rand() % 130; sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", x, 140 - y, x + 10, 140 - y2); out += temp; y = y2; } out += "</g>\n</svg>\n"; server.send(200, "image/svg+xml", out); } //-------------------- void setup(void) { pinMode(led, OUTPUT); digitalWrite(led, 0); Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.println(F("")); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.print(F(".")); } Serial.println(F("")); Serial.print(F("Connected to ")); Serial.println(ssid); Serial.print(F("IP address: ")); Serial.println(WiFi.localIP()); if (MDNS.begin("esp32")) { Serial.println(F("MDNS responder started")); } server.on("/", handleRoot); server.on("/test.svg", drawGraph); server.on("/inline", []() { server.send(200, "text/plain", "this works as well"); }); server.onNotFound(handleNotFound); server.begin(); Serial.println(F("HTTP server started")); } //-------------------- void loop(void) { server.handleClient(); }[実行結果]
17:35:47.566 -> ets Jun 8 2016 00:22:57 17:35:51.365 -> 17:35:51.365 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 17:35:51.365 -> configsip: 0, SPIWP:0xee 17:35:51.365 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 17:35:51.365 -> mode:DIO, clock div:1 17:35:51.365 -> load:0x3fff0018,len:4 17:35:51.365 -> load:0x3fff001c,len:1216 17:35:51.365 -> ho 0 tail 12 room 4 17:35:51.365 -> load:0x40078000,len:9720 17:35:51.365 -> ho 0 tail 12 room 4 17:35:51.365 -> load:0x40080400,len:6352 17:35:51.365 -> entry 0x400806b8 17:35:51.738 -> 17:35:52.246 -> ................................................ 17:38:36.516 -> . 17:38:36.516 -> Connected to Kingsland 17:38:36.516 -> IP address: 192.168.0.99 17:38:36.516 -> MDNS responder started 17:38:36.516 -> HTTP server startedコンソール画面にIP address: 192.168.0.99と云う表示が出てこれを確認出来ないと使えないのであれば問題有りですね。ブラウザでアクセスしてみると以下の結果になりました。
5秒毎のREFLESH グラフ自体は乱数です。
このサンプルスケッチは使えそうで使いにくいですね。
【Chipのリビジョンを確認する方法】
/* * 20200612 T.Wanibe * ESP-WROOM-32のRev0にはバグがあるそうです。そのバグとは、espressifがエラータを出しています。 * https://www.espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_en.pdf * なかなか解釈の難しいバグです。ただ、Rev1でもバグは残っているような雰囲気です。 * chipのリビジョンを確認する方法が掲載されていたので実行してみました。 * 最大1310720バイトのフラッシュメモリのうち、スケッチが214449バイト(16%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が15380バイト(4%)を使っていて、ローカル変数で312300バイト使うことができます。 */ //------------------ void setup() { Serial.begin(115200); while (!Serial); //シリアル接続されていないとここで無限LOOP Serial.printf("Revision: %d\r\n" , ESP.getChipRevision()); } //------------------ void loop() { }[実行結果]
09:56:20.575 -> ets Jun 8 2016 00:22:57 09:56:20.575 -> 09:56:20.575 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 09:56:20.575 -> configsip: 0, SPIWP:0xee 09:56:20.575 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 09:56:20.575 -> mode:DIO, clock div:1 09:56:20.575 -> load:0x3fff0018,len:4 09:56:20.575 -> load:0x3fff001c,len:1216 09:56:20.575 -> ho 0 tail 12 room 4 09:56:20.575 -> load:0x40078000,len:9720 09:56:20.575 -> ho 0 tail 12 room 4 09:56:20.575 -> load:0x40080400,len:6352 09:56:20.609 -> entry 0x400806b8 09:56:20.711 -> Revision: 1外観でも判るというお話がありました。シールドケースに『CE1313』の刻印があるのはRev0で古いバージョンである可能性が高いようです。一方『CE』のみはRev1のようです。自分の所有するESP-WROOM32はRev1でした。外観も『CE』のみでした。
【EEPROMClassの使用】
ESP-WROOM32のモジュール構成を見ても実EEPROMは載っていないように思います。多分STM32F1と同様Flash領域の一部を仮想的にEEPROMとして使用していると想像します※間違いがあれば後日訂正します。
EEPROMが使えるなら、接続するSSIDやPASSWORDをブラウザから登録出来るようなサンプルsketchを検討しました。
[実行結果]
【WiFiScan】
WiFiネットワークをスキャンし、見つかったSSID名、強度、暗号化の種別を表示します。
/* * 20200612 T.Wanibe * このスケッチは、WiFiネットワークをスキャンする方法を示しています。 * APIはWiFiシールドライブラリとほとんど同じですが、 * 最も明白な違いは、含める必要がある別のファイルです。 * 最大1310720バイトのフラッシュメモリのうち、スケッチが623662バイト(47%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が38744バイト(11%)を使っていて、ローカル変数で288936バイト使うことができます。 */ #include "WiFi.h" //---------------------------- void setup() { Serial.begin(115200); // WiFiをステーションモードに設定し、以前に接続されていた場合はAPから切断します WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); Serial.println(F("Setup done")); } //---------------------------- void loop() { Serial.println(F("scan start")); // WiFi.scanNetworksは見つかったネットワークの数を返します int n = WiFi.scanNetworks(); Serial.println(F("scan done")); if (n == 0) { Serial.println(F("no networks found")); } else { Serial.print(n); Serial.println(F(" networks found")); for (int i = 0; i < n; ++i) { // 見つかった各ネットワークのSSIDとRSSIを出力する Serial.print(i + 1); Serial.print(F(": ")); Serial.print(WiFi.SSID(i)); Serial.print(F(" (")); Serial.print(WiFi.RSSI(i)); Serial.print(F(")")); Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*"); delay(10); } } Serial.println(F("")); //もう一度スキャンする前に少し待ってください delay(5000); }[実行結果]
17:46:32.152 -> ets Jun 8 2016 00:22:57 17:46:32.152 -> 17:46:32.152 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 17:46:32.152 -> configsip: 0, SPIWP:0xee 17:46:32.152 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 17:46:32.185 -> mode:DIO, clock div:1 17:46:32.185 -> load:0x3fff0018,len:4 17:46:32.185 -> load:0x3fff001c,len:1216 17:46:32.185 -> ho 0 tail 12 room 4 17:46:32.185 -> load:0x40078000,len:9720 17:46:32.185 -> ho 0 tail 12 room 4 17:46:32.185 -> load:0x40080400,len:6352 17:46:32.185 -> entry 0x400806b8 17:46:32.593 -> Setup done 17:46:32.593 -> scan start 17:46:34.901 -> scan done 17:46:34.901 -> 8 networks found 17:46:34.901 -> 1: Kingland_Guest (-54)* 17:46:34.901 -> 2: Kingsland (-55)* 17:46:34.935 -> 3: SPWH_H33_61CE92 (-91)* 17:46:34.935 -> 4: Buffalo-G-2FC8 (-91)* 17:46:34.935 -> 5: elecom2g-bf4469 (-92)* 17:46:34.969 -> 6: 001D73B49DAC (-92)* 17:46:34.969 -> 7: Buffalo-G-3A80 (-95)* 17:46:34.969 -> 8: 001D73B49DAC-1 (-96)*このスケッチをレタッチしてOLCD(SSD1306)に表示するようにしました。モバイルバッテリから電源供給するようにすれば、簡易的な WiFi強度チェッカーに仕立てることが出来ます。
【WiFi-Control-Car】
無線ロボットカー制御のテストスケッチです
/* * 20200617 T.Wanibe * このスケッチは、WiFi-Control-Car という名で紹介されていたものです。 * 東芝のMOSFETを駆動して2基のモータを前後させ車を動かすというものです。ESPはWebServerを起動しており、ブラウザから制御出来ます。 * 最大1310720バイトのフラッシュメモリのうち、スケッチが641410バイト(48%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が38776バイト(11%)を使っていて、ローカル変数で288904バイト使うことができます。 */ #include <WiFi.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define NUMFLAKES 10 // アニメーション例の雪片の数 #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 #define PLCDAres 0x3C //0x3Cか0x3D #define HTTPport 80 #define P1 4 #define P2 0 #define P3 2 #define P4 15 const char* ssid = "Kingsland"; //アクセスポイントのSSID const char* password = "minawanibe"; //アクセスポイントのパスワード const char titleStr[] = "ESP32 WiFi_Car Controller"; WiFiServer server(HTTPport); //I2C(SDA、SCLピン)に接続されたSSD1306ディスプレイの宣言 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //--------------------------HTML出力 void PrintResponse200( WiFiClient client) { client.println(F("HTTP/1.1 200 OK")); client.println(F("Content-Type: text/html")); client.println(); } //-------------------------- void PrintResponse404( WiFiClient client ) { client.println(F("HTTP/1.1 404 Not Found")); client.println(F("Content-Type: text/html")); client.println(); } //--------------------------HTMLのコードを作成する場合は、HTMLエディタで構築した後、行毎にclient.println(F(""))に割り当てます。 void PrintNormalPage(WiFiClient client) { client.println(F("<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>")); client.println(F("<html lang='ja'>")); client.println(F("\t<head>")); client.println(F("\t\t<META name='GENERATOR' content='IBM WebSphere Studio Homepage Builder Version 10.0.0.0 for Windows'>")); client.println(F("\t\t<META http-equiv='Content-Type' content='text/html; charset=UTF-8'>")); client.println(F("\t\t<META http-equiv='Content-Style-Type' content='text/css'>")); client.println(F("\t\t<style>")); client.println(F("\t\t\t<!--")); client.println(F("\t\t\tinput {margin:8px;width:80px;}")); client.println(F("\t\t\tdiv {font-size:16pt;color:red;text-align:center;width:400px;border:groove 40px orange;}-->")); client.println(F("\t\t</style>")); client.print(F("\t\t<title>")); client.print(titleStr); client.println(F("</title>")); client.println(F("\t</head>")); client.println(F("\t<body>")); client.println(F("\t\t<div>")); client.println(F("\t\t\t<p>Controller</p>")); client.println(F("\t\t\t<form method='get'>")); client.println(F("\t\t\t<input type='submit' name='le' value='左' />")); client.println(F("\t\t\t<input type='submit' name='fo' value='前' />")); client.println(F("\t\t\t<input type='submit' name='ri' value='右' /><br>")); client.println(F("\t\t\t<input type='submit' name='st' value='停' /><br>")); client.println(F("\t\t\t<input type='submit' name='bl' value='左後' />")); client.println(F("\t\t\t<input type='submit' name='ba' value='後' />")); client.println(F("\t\t\t<input type='submit' name='br' value='右後' /><br><br>")); client.println(F("\t\t\t</form>")); client.println(F("\t\t</div>")); client.println(F("\t</body>")); client.println(F("</html>")); } //------------------------- void stop(){ digitalWrite(P1, LOW); digitalWrite(P2, LOW); digitalWrite(P3, LOW); digitalWrite(P4, LOW); } //------------------------- void clearTXT(Adafruit_SSD1306 display){ display.setTextColor(SSD1306_BLACK); display.setCursor(0, 8);display.print(F(" ")); display.setTextColor(SSD1306_WHITE); } //------------------------- void setup() { Serial.begin(115200); pinMode(P1, OUTPUT); pinMode(P2, OUTPUT); pinMode(P3, OUTPUT); pinMode(P4, OUTPUT); //SSD1306_SWITCHCAPVCC =内部で3.3Vから表示電圧を生成 if(!display.begin(SSD1306_SWITCHCAPVCC, PLCDAres)) { // 128x64のスレーブアドレスオリジナル値は0x3Dでしたが手元の元は0x3Cでした。 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } // バッファをクリアします display.clearDisplay(); delay(10); Serial.print(F("\nConnecting to "));Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(F(".")); } Serial.println(F("\nWiFi connected.")); Serial.print(F("IP address: "));Serial.println(WiFi.localIP()); display.setTextSize(1);display.setTextColor(SSD1306_WHITE);display.setCursor(0, 0); display.print(F("IP:"));display.println(WiFi.localIP());display.display(); server.begin(); } //------------------------- void loop(){ WiFiClient client = server.available(); if (client) { Serial.println(F("New Client.")); String currentLine = ""; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); if (c == '\n') { if (currentLine.length() == 0) { PrintResponse200(client); PrintNormalPage(client); client.println(); break; } else { currentLine = ""; } } else if (c != '\r') { currentLine += c; } if (currentLine.endsWith("GET /?fo")) { stop(); digitalWrite(P2, HIGH); digitalWrite(P1, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:FO"));display.display(); } if (currentLine.endsWith("GET /?le")) { stop(); digitalWrite(P2, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:LE"));display.display(); } if (currentLine.endsWith("GET /?ri")) { stop(); digitalWrite(P1, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:RI"));display.display(); } if (currentLine.endsWith("GET /?ba")) { stop(); digitalWrite(P3, HIGH); digitalWrite(P4, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:BA"));display.display(); } if (currentLine.endsWith("GET /?bl")) { stop(); digitalWrite(P3, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:BL"));display.display(); } if (currentLine.endsWith("GET /?br")) { stop(); digitalWrite(P4, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:BR"));display.display(); } if (currentLine.endsWith("GET /?st")) { stop(); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:ST"));display.display(); } } } client.stop(); Serial.println(F("Client Disconnected.")); } }[実行結果]
ボタンの反応は悪くないです。
IPアドレスの確認が必要でコンソールでの確認が必要です。それを避けるためにOLCDにIPアドレスを表示するようにしました。また、接続するSSIDをソースに固定しなくても良い方法を検討しておきたいです。
【WiFi-Control-Car(AP)】
ESPはアクセスポイントになるわけで、iPhoneから直接ESPに接続し、ブラウザを介して機器制御出来るはずです。それを実現出来るか確認すべくテストスケッチを書きました。
/* * 20200618 T.Wanibe * このスケッチは、WiFi-Control-Car という名で紹介されていたものです。 * 東芝のMOSFETを駆動して2基のモータを前後させ車を動かすというものです。ESPはWebServerを起動しており、ブラウザから制御出来ます。 * ESPをSoftAPとして立ち上げて直接iPhoneから制御出来ることを確認する。 * OLCDにSSIDと及びIPアドレスを表示します。 * 最大1310720バイトのフラッシュメモリのうち、スケッチが662090バイト(50%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が39688バイト(12%)を使っていて、ローカル変数で287992バイト使うことができます。 */ #include <WiFi.h> #include <WiFiClient.h> #include <WiFiAP.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define NUMFLAKES 10 // アニメーション例の雪片の数 #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 #define PLCDAres 0x3C //0x3Cか0x3D #define HTTPport 80 #define P1 4 #define P2 0 #define P3 2 #define P4 15 const char* ssid = "ESP"; //アクセスポイントのSSID const char* password = "password"; //アクセスポイントのパスワード const char titleStr[] = "ESP32 WiFi_Car Controller"; WiFiServer server(HTTPport); IPAddress ip(192,168,0,190); // Select ip and mask IPAddress mask(255, 255, 255, 0); //I2C(SDA、SCLピン)に接続されたSSD1306ディスプレイの宣言 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //--------------------------HTML出力 void PrintResponse200( WiFiClient client) { client.println(F("HTTP/1.1 200 OK")); client.println(F("Content-Type: text/html")); client.println(); } //-------------------------- void PrintResponse404( WiFiClient client ) { client.println(F("HTTP/1.1 404 Not Found")); client.println(F("Content-Type: text/html")); client.println(); } //--------------------------HTMLのコードを作成する場合は、HTMLエディタで構築した後、行毎にclient.println(F(""))に割り当てます。 void PrintNormalPage(WiFiClient client) { client.println(F("<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>")); client.println(F("<html lang='ja'>")); client.println(F("\t<head>")); client.println(F("\t\t<META name='GENERATOR' content='IBM WebSphere Studio Homepage Builder Version 10.0.0.0 for Windows'>")); client.println(F("\t\t<META http-equiv='Content-Type' content='text/html; charset=UTF-8'>")); client.println(F("\t\t<META http-equiv='Content-Style-Type' content='text/css'>")); client.println(F("\t\t<style>")); client.println(F("\t\t\t<!--")); client.println(F("\t\t\tinput {margin:8px;width:80px;}")); client.println(F("\t\t\tdiv {font-size:16pt;color:red;text-align:center;width:400px;border:groove 40px orange;}-->")); client.println(F("\t\t</style>")); client.print(F("\t\t<title>")); client.print(titleStr); client.println(F("</title>")); client.println(F("\t</head>")); client.println(F("\t<body>")); client.println(F("\t\t<div>")); client.println(F("\t\t\t<p>Controller</p>")); client.println(F("\t\t\t<form method='get'>")); client.println(F("\t\t\t<input type='submit' name='le' value='左' />")); client.println(F("\t\t\t<input type='submit' name='fo' value='前' />")); client.println(F("\t\t\t<input type='submit' name='ri' value='右' /><br>")); client.println(F("\t\t\t<input type='submit' name='st' value='停' /><br>")); client.println(F("\t\t\t<input type='submit' name='bl' value='左後' />")); client.println(F("\t\t\t<input type='submit' name='ba' value='後' />")); client.println(F("\t\t\t<input type='submit' name='br' value='右後' /><br><br>")); client.println(F("\t\t\t</form>")); client.println(F("\t\t</div>")); client.println(F("\t</body>")); client.println(F("</html>")); } //------------------------- void stop(){ digitalWrite(P1, LOW); digitalWrite(P2, LOW); digitalWrite(P3, LOW); digitalWrite(P4, LOW); } //------------------------- void clearTXT(Adafruit_SSD1306 display){ display.setTextColor(SSD1306_BLACK); display.setCursor(0, 8);display.print(F(" ")); display.setTextColor(SSD1306_WHITE); } //------------------------- void setup() { Serial.begin(115200); pinMode(P1, OUTPUT); pinMode(P2, OUTPUT); pinMode(P3, OUTPUT); pinMode(P4, OUTPUT); //SSD1306_SWITCHCAPVCC =内部で3.3Vから表示電圧を生成 if(!display.begin(SSD1306_SWITCHCAPVCC, PLCDAres)) { // 128x64のスレーブアドレスオリジナル値は0x3Dでしたが手元の元は0x3Cでした。 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } // バッファをクリアします display.clearDisplay(); delay(10); //APを開く場合は、パスワードパラメータを削除できます。 WiFi.softAP(ssid, password); WiFi.softAPConfig(ip,ip,mask); IPAddress myIP = WiFi.softAPIP(); Serial.print(F("AP IP address: "));Serial.println(myIP); display.setTextSize(1);display.setTextColor(SSD1306_WHITE);display.setCursor(0, 0); display.print(F("SSID:"));display.println(ssid); display.print(F("PASS:"));display.println(password); display.print(F("IP:"));display.println(myIP);display.display(); server.begin(); } //------------------------- void loop(){ WiFiClient client = server.available(); if (client) { Serial.println(F("New Client.")); String currentLine = ""; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); if (c == '\n') { if (currentLine.length() == 0) { PrintResponse200(client); PrintNormalPage(client); client.println(); break; } else { currentLine = ""; } } else if (c != '\r') { currentLine += c; } if (currentLine.endsWith("GET /?fo")) { stop(); digitalWrite(P2, HIGH); digitalWrite(P1, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:FO"));display.display(); } if (currentLine.endsWith("GET /?le")) { stop(); digitalWrite(P2, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:LE"));display.display(); } if (currentLine.endsWith("GET /?ri")) { stop(); digitalWrite(P1, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:RI"));display.display(); } if (currentLine.endsWith("GET /?ba")) { stop(); digitalWrite(P3, HIGH); digitalWrite(P4, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:BA"));display.display(); } if (currentLine.endsWith("GET /?bl")) { stop(); digitalWrite(P3, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:BL"));display.display(); } if (currentLine.endsWith("GET /?br")) { stop(); digitalWrite(P4, HIGH); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:BR"));display.display(); } if (currentLine.endsWith("GET /?st")) { stop(); display.clearDisplay(); display.setCursor(0, 8);display.print(F("Detect:ST"));display.display(); } } } client.stop(); Serial.println(F("Client Disconnected.")); } }[実行結果]
17:59:08.645 -> ets Jun 8 2016 00:22:57 17:59:08.645 -> 17:59:08.645 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 17:59:08.679 -> configsip: 0, SPIWP:0xee 17:59:08.679 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 17:59:08.679 -> mode:DIO, clock div:1 17:59:08.679 -> load:0x3fff0018,len:4 17:59:08.679 -> load:0x3fff001c,len:1216 17:59:08.679 -> ho 0 tail 12 room 4 17:59:08.679 -> load:0x40078000,len:9720 17:59:08.679 -> ho 0 tail 12 room 4 17:59:08.679 -> load:0x40080400,len:6352 17:59:08.679 -> entry 0x400806b8 17:59:09.017 -> AP IP address: 192.168.0.190
iPhoneからESPで構築したAPに接続し、表示されているIPアドレスにブラウザでアクセスするとESPのIPが制御出来ます。WindowsPCからであれば、PCに無線LANドングルを接続し、ESPに直接アクセスして接続。
TelnetツールのPuTTYを起動してコマンドラインから制御が可能です。
【ESPでAJAXを試す】
ESP32でAJAXでのWeb表示のサンプルスケッチを探しました。先人はいろいろ用意してくれています。参考にして書いてみました。
HTMLのコードは“index.h”の名前でinoと同じフォルダに書き込みます。
/* * 20200622 T.Wanibe * このコードはESP32をAJAXベースのWeb表示のテストスケッチです。 * オリジナルのスケッチは以下の通りESP8266用のものです。 * https://circuits4you.com/2018/02/04/esp8266-ajax-update-part-of-web-page-without-refreshing/ * ESP8266 NodeMCU AJAX Demo * Updates and Gets data from webpage without page refresh * AI入力はAI0(3pin)を使用しています。 * DIOはGPIO13(15pin)を使用しています。 * IPアドレス等はOLCDに表示する。 * 最大1310720バイトのフラッシュメモリのうち、スケッチが739042バイト(56%)を使っています。 * 最大327680バイトのRAMのうち、グローバル変数が40256バイト(12%)を使っていて、ローカル変数で287424バイト使うことができます。 */ #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <Wire.h> // I2C interface #include <Adafruit_SSD1306.h> // SSD1306 display #include <Adafruit_GFX.h> // SSD1306 display #include "index.h" //JavaScriptを使用したHTML Webページのコンテンツ #define LED 13 //ボード上のLEDは使えないのでGPIO13にLEDを接続 #define AIport A0 #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define NUMFLAKES 10 // アニメーション例の雪片の数 #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 #define PLCDAres 0x3C //0x3Cか0x3D #define HTTPport 80 #define P1 4 #define P2 0 #define P3 2 #define P4 15 //SSIDとパスワードを入力してください const char* ssid = "Kingsland"; const char* password = ""; WebServer WS(HTTPport); //I2C(SDA、SCLピン)に接続されたSSD1306ディスプレイの宣言 Adafruit_SSD1306 OLCD(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //-----------このルーチンは、ブラウザでIPを開いたときに実行されます。 void handleRoot() { String s = MAIN_page; //Read HTML contents WS.send(200, "text/html", s); //Send web page } //----------- void handleADC() { int a = analogRead(AIport); String adcValue = String(a); WS.send(200, "text/plane", adcValue); //Send ADC value only to client ajax request } //----------- void handleLED() { String ledState = "OFF"; String t_state = WS.arg("LEDstate"); //Refer xhttp.open("GET", "setLED?LEDstate="+led, true); Serial.println(t_state); if(t_state == "1"){ digitalWrite(LED,HIGH); //LED ON ledState = "ON"; //Feedback parameter }else{ digitalWrite(LED,LOW); //LED OFF ledState = "OFF"; //Feedback parameter } WS.send(200, "text/plane", ledState); //Send web page } //-----------SETUP void setup(void){ Serial.begin(115200); WiFi.begin(ssid, password); //Connect to your WiFi router Serial.println(""); pinMode(LED,OUTPUT); //Onboard LED port Direction output pinMode(P1,OUTPUT); digitalWrite(P1,LOW); pinMode(P2,OUTPUT); digitalWrite(P2,LOW); pinMode(P3,OUTPUT); digitalWrite(P3,LOW); pinMode(P4,OUTPUT); digitalWrite(P4,LOW); //SSD1306_SWITCHCAPVCC =内部で3.3Vから表示電圧を生成 if(!OLCD.begin(SSD1306_SWITCHCAPVCC, PLCDAres)) { // 128x64のスレーブアドレスオリジナル値は0x3Dでしたが手元の元は0x3Cでした。 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } // バッファをクリアします OLCD.clearDisplay(); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(F(".")); } IPAddress myIP = WiFi.localIP(); //If connection successful show IP address in serial monitor Serial.print(F("\nConnected to ")); Serial.println(ssid); Serial.print(F("IP address: ")); Serial.println(myIP); //IP address assigned to your ESP OLCD.setTextSize(1);OLCD.setTextColor(SSD1306_WHITE);OLCD.setCursor(0, 0); OLCD.print(F("IP:"));OLCD.println(myIP);OLCD.display(); WS.on("/", handleRoot); //Which routine to handle at root location. This is display page WS.on("/setLED", handleLED); WS.on("/readADC", handleADC); WS.begin(); //Start server Serial.println(F("HTTP server started")); } //-----------MAINLOOP void loop(void){ WS.handleClient(); //Handle client requests }
const char MAIN_page[] PROGMEM = R"=====( <!DOCTYPE html> <html> <body> <div id="demo"> <h1>The ESP32 Update web page By AJAX</h1> <button type="button" onclick="sendData(1)">LED ON</button> <button type="button" onclick="sendData(0)">LED OFF</button><BR> </div> <div> ADC Value is : <span id="ADCValue">0</span><br> LED State is : <span id="LEDState">NA</span> </div> <script> function sendData(led) { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("LEDState").innerHTML = this.responseText; } }; xhttp.open("GET", "setLED?LEDstate="+led, true); xhttp.send(); } setInterval(function() { // Call a function repetatively with 2 Second interval getData(); }, 1000); //2000mSeconds update rate function getData() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("ADCValue").innerHTML = this.responseText; } }; xhttp.open("GET", "readADC", true); xhttp.send(); } </script> <br><br><a href="https://toolsbox.biz">TOOLSBOX.BIZ</a> </body> </html> )=====";[実行結果]
17:18:38.836 -> ets Jun 8 2016 00:22:57 17:18:38.836 -> 17:18:38.836 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 17:18:38.836 -> configsip: 0, SPIWP:0xee 17:18:38.836 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 17:18:38.836 -> mode:DIO, clock div:1 17:18:38.870 -> load:0x3fff0018,len:4 17:18:38.870 -> load:0x3fff001c,len:1216 17:18:38.870 -> ho 0 tail 12 room 4 17:18:38.870 -> load:0x40078000,len:9720 17:18:38.870 -> ho 0 tail 12 room 4 17:18:38.870 -> load:0x40080400,len:6352 17:18:38.870 -> entry 0x400806b8 17:18:39.209 -> 17:18:39.717 -> . 17:18:39.717 -> Connected to Kingsland 17:18:39.717 -> IP address: 192.168.0.99 17:18:39.751 -> HTTP server started 17:18:59.276 -> 1ブラウザからhttps://192.168.0.99/にアクセスします。index.hに書かれているHTMLコードがレンダリングされています。
ボリュームを動かすとADC値が変わり、LEDON/OFFボタンでLEDも消点灯します。
ESP32のWebCodeの記述方法の一例を垣間見ました。
免責事項
本ソフトウエアは、あなたに対して何も保証しません。本ソフトウエアの関係者(他の利用者も含む)は、あなたに対して一切責任を負いません。
あなたが、本ソフトウエアを利用(コンパイル後の再利用など全てを含む)する場合は、自己責任で行う必要があります。本ソフトウエアの著作権はToolsBoxに帰属します。
本ソフトウエアをご利用の結果生じた損害について、ToolsBoxは一切責任を負いません。
ToolsBoxはコンテンツとして提供する全ての文章、画像等について、内容の合法性・正確性・安全性等、において最善の注意をし、作成していますが、保証するものではありません。
ToolsBoxはリンクをしている外部サイトについては、何ら保証しません。
ToolsBoxは事前の予告無く、本ソフトウエアの開発・提供を中止する可能性があります。
商標・登録商標
Microsoft、Windows、WindowsNTは米国Microsoft Corporationの米国およびその他の国における登録商標です。
Windows Vista、Windows XPは、米国Microsoft Corporation.の商品名称です。
LabVIEW、National Instruments、NI、ni.comはNational Instrumentsの登録商標です。
I2Cは、NXP Semiconductors社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。