Wokwi:免費的ESP32開發板Arduino, MicroPython線上模擬器(二)

Wokwi模擬器支援ESP32的Wi-Fi無線網路連線功能,本文將示範在ESP32模擬器中測試:

  • 掃描ESP32周遭的Wi-Fi無線網路名稱和訊號強度
  • 網站伺服器程式
  • 在OLED螢幕顯示即時氣象資料

掃描周遭的Wi-Fi網路

ESP32的WiFi.h程式庫的scanNetworks()可掃描周遭的Wi-Fi網路,並傳回找到的無線網路分享器數量。如果有找到無線網路分享器,可進一步透過下列函式讀取該分享器的資料:

  • WiFi.SSID():無線網路名稱
  • WiFi.RSSI():無線網路訊號強度,數值越接近0,代表訊號越強。
  • WiFi.encryptionType():通訊加密形式,WIFI_AUTH_OPEN代表無需連線密碼。

底下是掃描周遭Wi-Fi網路的ESP32 Arduino程式碼,改自WiFi.h程式庫內建的WiFiScan.ino範例

#include <WiFi.h>

void setup() {
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);  // 設置成STA(無線終端)模式
  WiFi.disconnect();    // 切斷現有的Wi-Fi連線
  delay(100);           // 先等一下
}

void loop() {
  Serial.println("掃描Wi-Fi熱點…");

  int n = WiFi.scanNetworks();
  if (n == 0) {
      Serial.println("找不到Wi-Fi熱點");
  } else {
    Serial.printf("找到 %d 個熱點\n", n);
    // 列舉熱點的SSID和訊號強度
    for (int i = 0; i < n; ++i) {
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");
      delay(10);
    }
  }
  Serial.println("");
  // 暫停5秒再重新掃描
  delay(5000);
}

把上面的程式碼貼入ESP32模擬環境的sketch.ino程式,再按下三角形「開始模擬」鈕,過一會兒,右下角的「序列埠監控窗格」將顯示找到一個名叫“Wokwi-GUEST”的熱點,不用連線密碼。

掃描Wi-Fi網路

以下在ESP32模擬器中執行的網路程式都要連線到“Wokwi-GUEST”。下圖是在ESP32模擬器測試《超圖解ESP32深度實作》動手做6-3「使用WebServer程式庫建立HTTP伺服器」的執行結果,程式雖可正常運作,但是我們連不上那個虛擬的ESP32,因為連線設備必須位在相同網域,也就是10.5.75.xxx。

ESP32網站伺服器

不知能否在模擬器環境中,透過另一個ESP32前端程式連接到虛擬的ESP32網站伺服器 😛 有興趣的朋友請自行實驗。

下文使用《超圖解ESP32深度實作》7-3節「在OLED螢幕顯示天氣概況」的範例,在模擬器中透過ESP32讀取OpenWeather的台北天氣資料,顯示在OLED螢幕。

新增SSD1306 OLED顯示器元件

首先替ESP32開發板連接一個OLED顯示器。點擊Simulation(模擬)窗格裡的「+」鈕:

新增元件

輸入“SSD1306”關鍵字,或直接點擊彈出式選單中的SSD1306 OLED顯示器元件。

SSD1306 OLED顯示器元件

透過I2C介面連接ESP32:

  • 顯示器的CLK(時脈)接ESP32的腳22(SCL)
  • 顯示器的Data(資料)接ESP32的腳21(SDA)
採用I2C介面連接ESP32

新增程式庫

本文採用書本7-3節的範例程式,需要安裝解析JSON格式資料的“ArduinoJSON”程式庫,以及驅動OLED顯示器的“U8g2”程式庫。

切換到Library Manager(程式庫管理員),點擊「+」鈕新增程式庫:

Library Manager(程式庫管理員)

在搜尋欄位輸入程式庫名稱“ArduinoJSON”,不用在乎大小寫,也不必全部輸入,找到之後,點擊名稱即可匯入它。

搜尋程式庫名稱“ArduinoJSON”

重複相同的步驟,新增U8g2程式庫

新增U8g2程式庫

以上兩個是Wokwi模擬器開發工具內建的程式庫,開發其他專案程式時,假如找不到需要的程式庫,成為付費會員,即可自由上傳程式庫和預先編譯的.bin檔。

新增程式庫之後,開發環境會自動新增一個libraries.txt檔,紀錄此專案採用的程式庫名稱。

上傳Arduino原始檔

OLED顯示器呈現的天氣圖案和文字,定義在weatherFont.h檔,讀者可直接使用“diy7-2-OLED-font”範例資料夾中的檔案,或者按此連結下載OLED天氣情報範例檔

點擊下圖選單中的Upload file(上傳檔案)選項,上傳weatherFont.h檔。

點擊Upload file(上傳檔案)

上傳的檔案會顯示在新的標籤頁,這部份的程式碼不用改。

上傳的weatherFont.h檔

最後,在sketch.ino主程式的編輯畫面,貼入底下的程式碼並且修改其中的OpenWeather API碼

#include <map>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <U8g2lib.h>
#include "weatherFont.h"

U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

std::map<String, char> icon_map{
  {"01d", 'B'}, {"02d", 'H'}, {"03d", 'N'}, {"04d", 'Y'} , {"09d", 'R'},
  {"10d", 'Q'}, {"11d", 'P'}, {"13d", 'W'}, {"50d", 'J'}, {"01n", 'C'} ,
  {"02n", 'I'} , {"03n", '5'}, {"04n", '%'} , {"09n", '8'} , {"10n", '7'},
  {"11n", '6'} , {"13n", '#'} , {"50n", 'K'}
};

const char* ssid = "Wokwi-GUEST";  // Wokwi提供的Wi-Fi網路名稱
const char* password = "";
String API_KEY = "請輸入你的openWeather API碼";
String city = "Taipei,TW";

HTTPClient http;

void connectWiFi() {
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nIP位址:");
  Serial.println(WiFi.localIP());
}

String openWeather() {
  String url = "http://api.openweathermap.org/data/2.5/weather?q=" +
               city + "&appid=" + API_KEY;
  String payload = "";

  if ((WiFi.status() != WL_CONNECTED)) {
    connectWiFi();
  } else {
    http.begin(url);
    int httpCode = http.GET();

    if (httpCode > 0) {
      payload = http.getString();
      Serial.printf("回應本體:%s\n", payload.c_str());
    } else {
      Serial.println("HTTP請求出錯了~");
    }

    http.end();
  }
  return payload;
}

void displayWeather(String json) {
  DynamicJsonDocument doc(1024);

  deserializeJson(doc, json);
  JsonObject weather = doc["weather"][0];
  const char* icon = weather["icon"];
  const char* city = doc["name"];

  JsonObject main = doc["main"];
  // 取得絕對溫度,然後轉成攝氏溫度。
  float temp = (float)main["temp"] - 273.15;
  int humid = (int)main["humidity"];

  Serial.printf("天氣圖示:%s\n", icon);
  Serial.printf("攝氏溫度:%.1f\n", temp);

  // 在OLED螢幕顯示天氣資訊
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_profont12_mr);
    u8g2.drawUTF8(0, 8, city);
    u8g2.setFont(u8g2_font_inr16_mf);
    u8g2.setCursor(60, 36);
    u8g2.print(String(temp, 1)+ "\xb0");
    u8g2.setCursor(60, 62);
    u8g2.print(String(humid) + "%");
    u8g2.setFont(weatherFont);
    u8g2.setCursor(0, 62);
    u8g2.print(icon_map[icon]);
  } while ( u8g2.nextPage() );
}

void setup() {
  Serial.begin(115200);
  connectWiFi();
  u8g2.begin();
}

void loop() {
  String payload = openWeather();

  if (payload != "") {
    displayWeather(payload);
  }

  delay(50000);
}

按下Simulation(模擬)頁面中的三角形(開始模擬)鈕,過一會兒,將能取得台北的即時天氣情報並呈現在OLED顯示器。

台北的即時天氣情報
Posts created 470

One thought on “Wokwi:免費的ESP32開發板Arduino, MicroPython線上模擬器(二)

  1. #include
    sketch.ino
    1 of 1 problem
    /libraries/U8g2/src/clib/mui_u8g2.c:560: /libraries/U8g2/src/clib/mui_u8g2.c: In function ‘mui_u8g2_u8_vmm_draw_wm_pi’:
    initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top