輕鬆學習 C++ 與 ESP32:WIFI Scan
簡介
在這篇文章中,我們將使用 C++ 與 ESP-IDF 來實現 ESP32 的 WIFI Scan 功能。透過面向物件的程式設計方式,我們可以讓程式碼更加模組化、可重用且結構清晰。最後,你將學會如何將 C++ 類別與 ESP32 開發結合,並且能使用 ESP32 模組來掃描附近的 WiFi 網路。
內容
開發環境設置
1. 安裝 Visual Studio Code,可從官方網站下載並且安裝。 2. 安裝 ESP-IDF 插件。
創建一個新項目
1. 在 VS Code 中,按下 Ctrl (Cmd) + Shift + P,然後輸入 ESP-IDF: New Project。
2. 選擇一個樣板專案(如 blink example),設定專案名稱(例如 WIFI_Scan),並選擇存儲路徑。
3. 此時,系統會自動為您生成一個新的 ESP-IDF 項目,其中包含基本的 CMake 文件和一個範例程式碼。
檔案結構
my_project/
├── CMakeLists.txt
├── main/
│ ├── CMakeLists.txt
│ └── main.cpp
└── ...
編寫 C++ 的 WIFI Scan 的類別
我們將創建一個名為 WiFiScanner 的 C++ 類別,用於處理 WiFi 的初始化和掃描操作。此類別會使用 ESP32 的 WiFi 驅動來啟動掃描並取得可用的 WiFi 網路清單,並透過 ESP-IDF 的日誌系統(ESP_LOG)將掃描結果列印至終端機。
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_log.h"
static const char* TAG = "WiFiScanner"; // Define log tag
class WiFiScanner {
public:
// Constructor: Initializes WiFi
WiFiScanner() {
init_wifi();
}
// Starts WiFi scanning
void scan() {
wifi_scan_config_t scan_config = {
.ssid = nullptr, // No specific SSID filter
.bssid = nullptr, // No specific BSSID filter
.channel = 0, // Scan all channels
.show_hidden = true // Show hidden networks
};
// Start WiFi scan
esp_err_t err = esp_wifi_scan_start(&scan_config, true);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to start WiFi scan: %s", esp_err_to_name(err));
return;
}
// Get the number of networks found
uint16_t num_networks = 0;
esp_wifi_scan_get_ap_num(&num_networks);
// Store scan results in an array
wifi_ap_record_t ap_records[num_networks];
esp_wifi_scan_get_ap_records(&num_networks, ap_records);
// Log the scan results
ESP_LOGI(TAG, "Found %d WiFi networks:", num_networks);
for (int i = 0; i < num_networks; ++i) {
ESP_LOGI(TAG, "SSID: %s, Signal strength (RSSI): %d, Auth mode: %d",
ap_records[i].ssid, ap_records[i].rssi, ap_records[i].authmode);
}
}
private:
// Initializes WiFi
void init_wifi() {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t ret = esp_wifi_init(&cfg);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize WiFi: %s", esp_err_to_name(ret));
return;
}
// Set WiFi to station (STA) mode
esp_wifi_set_mode(WIFI_MODE_STA);
// Start WiFi
esp_wifi_start();
}
};
// Main function, entry point of the program
extern "C" void app_main() {
// Initialize NVS (Non-Volatile Storage)
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Initialize event loop
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
// Create a WiFiScanner object and start scanning
WiFiScanner scanner;
scanner.scan();
}
程式碼說明
1. WiFiScanner 類別:
用途:封裝 WiFi 功能,將 WiFi 掃描任務模組化。
建構函數:WiFiScanner() 呼叫私有方法 init_wifi() 來初始化 WiFi 模組。
scan() 方法:該公有方法執行 WiFi 掃描,配置掃描參數、啟動掃描、取得結果並透過日誌系統列印 WiFi 網路資訊。
init_wifi() 方法:私有方法,用於初始化 WiFi 並設置為 WIFI_MODE_STA 模式。
2. app_main():
NVS 初始化:初始化 NVS(非易失性儲存),確保 WiFi 正常運作。如果 NVS 損毀或未格式化,則會先抹除再重新初始化。
事件迴圈:esp_event_loop_create_default() 用於初始化 ESP-IDF 的事件迴圈,處理系統和 WiFi 相關事件。
WiFiScanner 物件:app_main() 中創建 WiFiScanner 類別的實例,並呼叫其 scan() 方法啟動 WiFi 掃描。
3. ESP-IDF 的日誌系統(ESP_LOG):
ESP_LOGI(TAG, ...):列印資訊級別的日誌,例如發現的 WiFi 網路數量及其詳細資訊。
ESP_LOGE(TAG, ...):列印錯誤級別的日誌,例如 WiFi 掃描失敗時的錯誤資訊。
此日誌系統是為嵌入式系統設計的,能夠提供靈活的日誌級別調整,有助於除錯和系統追蹤。
編譯與燒錄
在 VSCode 視窗最下方中找到 "ESP32-IDF : Build, Flash and Monitor" ICON 執行和燒錄。
程式運行效果
運行程式後,您將在終端機中看到以下輸出:
I (1234) WiFiScanner: Found 3 WiFi networks:
I (1235) WiFiScanner: SSID: MyHomeWiFi, Signal strength (RSSI): -45, Auth mode: 3
I (1236) WiFiScanner: SSID: CoffeeShopWiFi, Signal strength (RSSI): -70, Auth mode: 0
I (1237) WiFiScanner: SSID: NeighborsWiFi, Signal strength (RSSI): -80, Auth mode: 3
結論
我們學習了如何使用 C++ 和 ESP-IDF 編寫 ESP32 的 WiFi 掃描功能。透過將 WiFi 功能封裝到 WiFiScanner 類別中,使得程式碼更加模組化、易於維護。我們利用 ESP-IDF 的日誌系統,將掃描結果清晰地打印到終端,這對嵌入式開發非常有幫助。
結合 C++ 和 ESP-IDF 的方式,讓我們能夠編寫出更乾淨且易於維護的程式碼,同時充分發揮 ESP32 強大的微控制器功能。現在,你可以嘗試進一步擴展該專案,添加更多功能,並繼續探索 ESP32 開發中的網路程式設計技巧。