SSID、WPA2、STA/AP、DHCP、IP/Gateway/DNS、RSSI、I2C、NTP、時區 的基本概念你將完成兩個可展示的小作品:
1. Wi-Fi 連線成功偵測器:連線後把 IP 位址 顯示在 OLED 上(同時也在序列埠顯示)
2. 網路校時電子鐘:透過 NTP 取得時間,顯示在 OLED 上;延伸討論「沒網路怎麼辦?」(RTC)
U8g2(U8g2 by olikraus)多數 SSD1306 I2C 模組只有 4 腳:
GND / VCC / SCL / SDA
| OLED 腳位 | NodeMCU-32S(ESP32)建議腳位 | 說明 |
|---|---|---|
| GND | GND | 地 |
| VCC | 3V3 | 建議 3.3V(避免 5V 造成不穩) |
| SCL | GPIO 22 | I2C 時脈 |
| SDA | GPIO 21 | I2C 資料 |
IoT 裝置要「變聰明」,必須能把資料送到網路(或從網路取資料)。Wi-Fi 是最常見、最容易在教室實作的無線連線方式之一。
工程學習的重點:名詞不是背誦,而是理解「它在系統中負責什麼」與「如何驗證它有沒有正常工作」。
| 名詞 | 工程語意(它負責什麼) | 你要怎麼驗證(可觀測訊號) | 常見問題 |
|---|---|---|---|
SSID |
AP 對外廣播的網路識別(你要連到哪個系統) | 手機/電腦掃描到的名稱 | 連到錯的 SSID、SSID 含空白/特殊字元 |
Password |
加密連線授權(你是否被允許加入) | WiFi.status() 是否為 WL_CONNECTED |
密碼錯、路由器改密碼未更新 |
STA(Station) |
裝置端角色:當用戶端連到 AP | WiFi.mode(WIFI_STA) |
忘了設 STA、或同時 AP+STA 造成混淆 |
AP(Access Point) |
網路入口:提供無線連線與上網路徑 | 其他裝置能否上網 | AP 本身沒上網、或限制 UDP/NTP |
DHCP |
自動配置:分配 IP/Gateway/DNS(租約制) | WiFi.localIP() / WiFi.gatewayIP() / WiFi.dnsIP() |
取得 IP 失敗、租約到期、IP 衝突 |
IP |
你的位址:封包要找得到你 | WiFi.localIP() 是否非 0.0.0.0 |
有 IP 但無法上網(多半是 DNS/GW) |
Gateway |
出入口:往外網的下一跳(通常是路由器) | WiFi.gatewayIP() 是否合理 |
Gateway 錯會造成「有 IP 但出不去」 |
DNS |
名稱解析:把網域名轉成 IP | 測試能否解析/連網域 | DNS 錯:能連 IP 但連不了網域 |
RSSI |
無線鏈路品質指標(dBm,越接近 0 越強) | WiFi.RSSI() |
訊號弱導致斷線、封包重傳 |
MAC |
網卡硬體位址(L2 身分) | WiFi.macAddress() |
校園網路可能做 MAC 管制 |
你寫的程式只是在「應用層」下指令,但故障常發生在更底層,所以除錯要會往下追:程式 -> IP -> Wi-Fi -> 訊號。
原檔寫「WEP, WAP, 與 WAP2」,實際應為
WEP / WPA / WPA2(WAP 通常指 Wireless Application Protocol,與 Wi-Fi 安全性不同)
| 名稱 | 安全性 | 現況 | 教室建議 |
|---|---|---|---|
| WEP | 很弱(已可被快速破解) | 幾乎淘汰 | 不建議使用 |
| WPA | 比 WEP 好,但已過時 | 逐步淘汰 | 不建議使用 |
| WPA2 | 目前最常見且相對安全 | 主流 | 建議使用 |
| WPA3 | 更新、更安全 | 逐步普及 | 若環境支援可使用(但教室常以 WPA2 為主) |
本單元建議用「可驗證、可累加」的方式練習:先做出最小可行版本(MVP),再逐步加功能;每一圈都要保留可觀測的證據(Serial/OLED)。
每一圈都用同一套「AI 協作」方式:提出明確需求 -> 編譯/上傳 -> 觀測輸出 -> 用證據回饋 AI 修正。
ESP32 Dev Module(或你實際的 ESP32 板型)SSID 與 PASSWORD目標:先只要求「會連線、看得到狀態」;成功後再加限制(超時、重試、顯示更多資訊)。
請為 ESP32(NodeMCU-32S / ESP32 Dev Module)寫 Arduino IDE 完整程式(setup/loop)。
需求(最小可行版本):
1) 以 WiFi STA 模式連線到 SSID=____,PASSWORD=____(使用 DHCP)
2) Serial 速率 115200,印出:Connecting...、Connected、Local IP
3) 程式要可編譯可上傳,不要使用額外函式庫
請輸出完整程式。
請在你剛剛的 ESP32 WiFi 程式上加入「工程化連線策略」並輸出完整程式。
新增需求:
1) 連線等待最多 10 秒,若失敗要印出 FAIL
2) 失敗後每 3 秒重試一次(不要卡死在 while 迴圈)
3) 連線成功後印出 Local IP、Gateway IP、DNS IP
#include <WiFi.h>
// TODO: 改成你的 Wi-Fi
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
delay(500);
connectWiFi();
}
void loop() {
// 可延伸:定期顯示 RSSI、重連機制等
delay(1000);
}
核心流程(偽代碼)
初始化序列埠
設定 Wi-Fi 模式為 STA
開始連線 (SSID, 密碼)
重複檢查狀態直到連線成功
印出 DHCP 分配的 IP 位址
0x3C0x3D如果你不確定位址,可先用 I2C Scanner 掃描(見 5.2)。
提醒:I2C Scanner 顯示的是「7-bit 位址」。使用 U8g2 時,
setI2CAddress()需要 8-bit 位址,通常要做addr << 1。
| 名詞 | 它在系統中做什麼 | 你要怎麼驗證 | 常見錯誤 |
|---|---|---|---|
I2C |
兩線式匯流排:多個裝置共用同一組線 | I2C Scanner 能掃到裝置 | 線太長/接觸不良導致通訊不穩 |
SDA |
資料線(Data) | Scanner 能回應 | SDA/SCL 接反 |
SCL |
時脈線(Clock) | Scanner 掃描穩定 | 時脈太快/拉不動(通常線材問題) |
Address |
裝置的門牌號碼(同匯流排要唯一) | 掃描到 0x3C/0x3D |
程式用錯位址、或忘記 U8g2 左移 |
Pull-up |
I2C 使用開漏(open-drain),需要上拉電阻 | 多數模組自帶 | 罕見:上拉不足導致不穩(長線更明顯) |
#include <Wire.h>
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA, SCL
Serial.println("I2C scan start...");
for (uint8_t addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.print("Found I2C device at 0x");
Serial.println(addr, HEX);
}
}
Serial.println("I2C scan done.");
}
void loop() {}
目標:把「已驗證的 WiFi 連線」加上「可觀測的 OLED 顯示」,避免一次把所有需求混在一起。
請基於「已能成功連上 WiFi 並印出 IP 的 ESP32 程式」,加入 OLED 顯示功能並輸出完整程式。
硬體:SSD1306 I2C 128x64 OLED
接線:SDA=21,SCL=22,I2C 位址=0x3C
顯示需求:
1) OLED 第 1 行顯示 WiFi OK
2) OLED 第 2 行顯示 IP: x.x.x.x
限制:
- OLED 請使用 U8g2 by olikraus
- 請提醒並正確處理 U8g2 setI2CAddress 需要 addr 左移 1 位
請給我一個最小 OLED 測試程式(Arduino IDE,ESP32)。
條件:
1) 使用 U8g2
2) I2C:SDA=21、SCL=22、位址=0x3C
3) OLED 顯示 Hello 並在 Serial 印出「OLED OK」
請輸出完整程式,用來排除接線或位址問題。
#include <WiFi.h>
#include <Wire.h>
#include <U8g2lib.h>
// TODO: 改成你的 Wi-Fi
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";
// OLED(U8g2)
// - SSD1306 128x64 常見型號 NONAME
// - HW I2C:使用 Wire(ESP32 可先 Wire.begin(SDA,SCL))
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// I2C Scanner 看到的是「7-bit 位址」(0x3C / 0x3D)
// 但 U8g2 的 setI2CAddress() 需要「8-bit 位址」:所以要左移 1 位
static const uint8_t OLED_ADDR_7BIT = 0x3C; // 若掃描到 0x3D,請改成 0x3D
void show2Lines(const String& line1, const String& line2) {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(0, 12, line1.c_str());
u8g2.drawStr(0, 28, line2.c_str());
u8g2.sendBuffer();
}
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("Connecting to WiFi");
show2Lines("Connecting WiFi", "...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
show2Lines("WiFi OK", "IP: " + WiFi.localIP().toString());
}
void setup() {
Serial.begin(115200);
delay(500);
Wire.begin(21, 22); // SDA, SCL(依你的板子可調整)
u8g2.setI2CAddress(OLED_ADDR_7BIT << 1);
u8g2.begin();
show2Lines("OLED OK", "Booting...");
connectWiFi();
}
void loop() {
// 可延伸:顯示 RSSI、連線狀態、重新連線
delay(1000);
}
Wire.begin(21,22):指定 I2C 的 SDA/SCL 腳位(ESP32 可改)u8g2.setI2CAddress(OLED_ADDR_7BIT << 1):把 7-bit 位址轉成 U8g2 需要的 8-bit 位址u8g2.begin():初始化 OLED(位址錯常見症狀:黑屏)WiFi.begin(...):開始連線;連線成功後 WiFi.localIP() 才有意義u8g2.begin() + drawStr)NTP (Network Time Protocol) 是透過網路同步時間的協定。對微控制器來說,NTP 能讓裝置取得「可靠的現在時間」,例如做資料紀錄(log)、排程(schedule)、或顯示電子鐘。
| 名詞 | 它在系統中做什麼 | 你要怎麼驗證 | 常見錯誤 |
|---|---|---|---|
UTC |
世界協調時間(基準時間) | NTP 取得的是 UTC | 把 UTC 當本地時間,顯示差 8 小時 |
Time zone |
本地時間換算規則(例如台灣 UTC+8) | GMT_OFFSET_SEC=8*3600 |
時區設定錯、或誤用日光節約 |
SNTP/NTP |
NTP 的簡化使用(裝置端常用) | getLocalTime() 成功 |
路由器/校園網路阻擋 UDP |
UDP |
NTP 常用的傳輸協定(延遲較低) | 連網正常但 NTP 失敗要懷疑 UDP | 以為「能連 Wi-Fi」就一定能 NTP |
Stratum |
時間來源層級(越小越接近原子鐘) | 不必深究,但知道「來源品質」 | 使用不可靠伺服器導致時間飄移 |
工程提醒:不需要每秒跟 NTP 取時間,常見做法是「開機或每天校一次」,其餘時間由系統/RTC 維持。
tock.stdtime.gov.twwatch.stdtime.gov.twtime.stdtime.gov.twclock.stdtime.gov.twtick.stdtime.gov.tw目標:把「已能連網、OLED 正常」的作品升級成「可校時的時鐘」。
請在「ESP32 已能連 WiFi 並用 U8g2 OLED 顯示資訊」的基礎上,加入 NTP 校時並輸出完整程式。
需求:
1) NTP 伺服器依序使用:tock.stdtime.gov.tw、watch.stdtime.gov.tw、time.stdtime.gov.tw
2) 時區:台灣 UTC+8,DAYLIGHT=0
3) OLED 三行顯示:
- NTP Clock
- YYYY-MM-DD
- HH:MM:SS
4) 若 NTP 10 秒內失敗:OLED 顯示 NTP FAIL,並每 5 秒重試一次
限制:
- 使用 configTime() 與 getLocalTime()
- OLED 使用 U8g2(提醒:setI2CAddress 需 addr<<1)
請改寫你的 ESP32 NTP 時鐘程式,符合工程化需求並輸出完整程式:
1) NTP 只在開機成功連網時同步一次(或每 6 小時同步一次),不要每秒打 NTP
2) OLED 仍每秒更新顯示時間
3) Serial 印出:同步成功或失敗、下一次同步時間(用秒數或簡單計數即可)
這個版本使用 ESP32 內建的
configTime()+getLocalTime(),較簡潔。
#include <WiFi.h>
#include <Wire.h>
#include <U8g2lib.h>
// TODO: 改成你的 Wi-Fi
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";
// NTP 與時區(台灣 UTC+8)
static const long GMT_OFFSET_SEC = 8 * 3600;
static const int DAYLIGHT_OFFSET_SEC = 0;
// OLED(U8g2)
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
static const uint8_t OLED_ADDR_7BIT = 0x3C;
void drawClock(const String& title, const String& dateStr, const String& timeStr) {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(0, 12, title.c_str());
u8g2.drawStr(0, 28, dateStr.c_str());
u8g2.drawStr(0, 44, timeStr.c_str());
u8g2.sendBuffer();
}
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
drawClock("Connecting WiFi", "...", "");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
drawClock("WiFi OK", WiFi.localIP().toString(), "");
}
bool syncTimeByNTP() {
// 依序使用多台伺服器,提高成功率
configTime(
GMT_OFFSET_SEC,
DAYLIGHT_OFFSET_SEC,
"tock.stdtime.gov.tw",
"watch.stdtime.gov.tw",
"time.stdtime.gov.tw"
);
struct tm timeinfo;
if (!getLocalTime(&timeinfo, 10000)) { // 最多等 10 秒
return false;
}
return true;
}
String nowTimeString() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) return "Time N/A";
char buf[32];
// 格式:YYYY-MM-DD HH:MM:SS
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
return String(buf);
}
void setup() {
Wire.begin(21, 22);
u8g2.setI2CAddress(OLED_ADDR_7BIT << 1);
u8g2.begin();
connectWiFi();
if (!syncTimeByNTP()) {
drawClock("NTP FAIL", "Check network", "");
delay(2000);
}
}
void loop() {
String t = nowTimeString();
String dateStr = (t.length() >= 10) ? t.substring(0, 10) : "---- -- --";
String timeStr = (t.length() >= 19) ? t.substring(11, 19) : "--:--:--";
drawClock("NTP Clock", dateStr, timeStr);
delay(1000);
}
configTime(時區, 日光節約, server1, server2, server3):告訴系統去哪裡抓時間、如何換算成本地時間getLocalTime(&timeinfo):從系統取得目前時間(已套用時區)NTP 必須「能上網」才抓得到時間;但很多裝置要在離線環境仍能計時(例如校園角落感測器、停電後重啟)。RTC (Real-Time Clock) 模組(常見 DS3231)可用電池維持走時。
策略偽代碼
開機:
嘗試連 Wi-Fi
若 Wi-Fi 成功:
用 NTP 同步時間
把時間寫入 RTC
否則:
從 RTC 讀取時間
循環:
顯示時間(RTC 或系統時間)
目標:讓 AI 回答「可直接上傳」的完整程式,同時避免常見缺漏(腳位/函式庫/位址/序列埠速率)。
使用建議:前面實作階段(第 4~6 節)先用「Prompt 範例」帶學生跑完螺旋漸進;第 8 節模板則用於學生專題或變更需求時的快速套用。
請用 Arduino IDE(C++)為 ESP32(NodeMCU-32S / ESP32 Dev Module)寫一個完整可編譯的範例。
需求:
1) 連線到 Wi-Fi:SSID=______,PASSWORD=______,使用 DHCP 取得 IP
2) OLED:SSD1306 I2C 128x64,使用 U8g2(U8g2 by olikraus),SDA=GPIO21、SCL=GPIO22、I2C 位址 0x3C
3) 連線成功後在 OLED 顯示 IP 位址,同時 Serial(115200) 也印出狀態
4) 若連線失敗請顯示「Connecting...」並每 500ms 更新一次點點
補充要求:請注意 U8g2 的 setI2CAddress() 使用 8-bit 位址(0x3C 需左移 1 位)。
請附上需要安裝的函式庫名稱(U8g2 by olikraus)。
請用 Arduino IDE(C++)為 ESP32(NodeMCU-32S)寫一個完整可編譯的範例。
需求:
1) 連線到 Wi-Fi:SSID=______,PASSWORD=______(DHCP)
2) NTP 校時:使用 tock.stdtime.gov.tw / watch.stdtime.gov.tw / time.stdtime.gov.tw
3) 時區:台灣 UTC+8(不使用日光節約)
4) OLED:SSD1306 I2C 128x64,使用 U8g2(U8g2 by olikraus),SDA=GPIO21、SCL=GPIO22、位址 0x3C
5) OLED 每秒顯示目前時間(YYYY-MM-DD HH:MM:SS)
6) Serial(115200) 顯示除錯訊息
補充要求:請注意 U8g2 的 setI2CAddress() 使用 8-bit 位址(0x3C 需左移 1 位)。
請使用 configTime() 與 getLocalTime(),並列出需要的函式庫。
#include <WiFi.h> 與 #include <U8g2lib.h>Wire.begin(SDA, SCL)(ESP32 很重要)setI2CAddress(addr<<1))Serial.begin(115200) 方便除錯GMT_OFFSET_SEC = 8*3600教學用:讓學生知道「怎麼問」才會得到「能跑」的答案,並學會用回饋讓 AI 修正。
你是 Arduino/ESP32 助教。請輸出一個「可直接貼到 Arduino IDE 就能編譯上傳」的完整範例(含 setup/loop)。
硬體:ESP32 NodeMCU-32S + OLED SSD1306 I2C 128x64
接線:SDA=GPIO21,SCL=GPIO22,OLED I2C 位址=0x3C,供電=3V3
需求:
1) Wi-Fi STA 連線:SSID=你的SSID,PASSWORD=你的密碼(DHCP)
2) Serial(115200) 印出連線進度與最後的 IP
3) OLED 顯示兩行:第一行顯示 WiFi OK,第二行顯示 IP: x.x.x.x
4) 若 10 秒內連不上,請在 OLED 顯示 FAIL 並每 3 秒重試一次
5) 請使用 U8g2(U8g2 by olikraus),並列出必需安裝的函式庫名稱
6) 請注意 U8g2 I2C 位址使用 8-bit(0x3C 需左移 1 位)
請避免使用括號或特殊符號放在 Mermaid 圖內(本題不需要圖)。
請為 ESP32(NodeMCU-32S)寫 Arduino IDE 完整範例。
需求:
1) 連 Wi-Fi(STA/DHCP):SSID=____,PASSWORD=____
2) NTP:依序使用 tock.stdtime.gov.tw、watch.stdtime.gov.tw、time.stdtime.gov.tw
3) 時區:台灣 UTC+8,DAYLIGHT=0
4) OLED SSD1306 I2C 128x64:使用 U8g2,SDA=21、SCL=22、位址=0x3C(提醒:U8g2 setI2CAddress 需 addr<<1)
5) OLED 每秒顯示:
第 1 行:NTP Clock
第 2 行:YYYY-MM-DD
第 3 行:HH:MM:SS
6) 若 NTP 10 秒內失敗,OLED 顯示 NTP FAIL,並每 5 秒再試一次
請使用 configTime() 與 getLocalTime(),並加上必要的 Serial 除錯訊息。
請在你剛剛提供的 Wi-Fi + OLED 程式上做增強(保留原功能)。
新增需求:
1) 每 2 秒檢查 WiFi.status(),若斷線就自動重連
2) OLED 最底下一行顯示 RSSI(訊號強度,例如 RSSI:-55dBm)或顯示 DISCONNECTED
3) 請用函式分工:connectWiFi()、drawStatus(),避免把所有邏輯塞在 loop
請輸出完整程式(不要只給片段)。
規則:把「完整錯誤訊息」貼上,並告訴 AI 你的板子與你做過的嘗試。
我在 Arduino IDE 編譯失敗,請你根據錯誤訊息修改程式,並告訴我還缺哪個函式庫要安裝。
板子:ESP32 Dev Module
我已安裝:U8g2 by olikraus
錯誤訊息(請看這段原文):
---
fatal error: WiFi.h: No such file or directory
#include <WiFi.h>
^~~~~~~~
compilation terminated.
---
請給我:
1) 可能原因(用一句話)
2) 如何在 Arduino IDE 安裝/選到正確的 ESP32 Board package
3) 修正後的完整程式(若程式本身沒錯,也請確認相容的 include)
我照你的程式上傳後,Serial 看到 WiFi OK 也有 IP,但 OLED 仍然黑屏。
已知資訊:
1) I2C Scanner 掃描結果:Found I2C device at 0x3D
2) OLED 供電接 3V3
3) SDA=21、SCL=22
4) 我使用的是 U8g2(提醒:U8g2 setI2CAddress 需要 8-bit 位址)
請你:
1) 說明最可能的原因
2) 指出程式碼中哪個設定要改(給出具體值,例如 0x3D 與 setI2CAddress 左移)
3) 給我一個最小測試程式:只初始化 OLED 並印出 Hello
我需要你幫我除錯/改進 ESP32 程式。
環境:
- IDE:Arduino IDE
- Board:__________(例如 ESP32 Dev Module / NodeMCU-32S)
- ESP32 core version:__________(若知道再填)
硬體:
- OLED:SSD1306 I2C 128x64
- SDA:GPIO__
- SCL:GPIO__
- I2C address:0x__(用 I2C Scanner 測到的)
我做了什麼:
1) 我使用的程式版本:WiFi + OLED / WiFi + NTP / 其他:____
2) 我期待看到的結果:____
實際發生:
- Serial 輸出(原文貼上):____
- 編譯錯誤(原文貼上):____
請你輸出:
1) 你判斷的原因
2) 你要我做的 2 個驗證步驟
3) 修正後的完整程式
setI2CAddress(addr<<1),且 addr 與掃描到的位址一致pool.ntp.org)測試(若網路策略允許)UTC+8)0)SSID、IP、RSSI(訊號強度)WiFi.status())SSID / WPA2 / STA/AP / DHCP / IP-Gateway-DNS / RSSI / I2C / NTP / 時區 的用途