ええ、約束通り自分で ESP8266 の開発ボードのファームウェアを書くと言った私が戻ってきました。
20 年に約束した、今日は戻ってきて願いを果たしました ESP8266 シリアル WiFi モジュール - WiFi キラー
今日は OLED ディスプレイも接続しました。今回購入したのは 4 ピンの OLED(128*64)で、カラー表示には対応していません。
NodeMCU 開発ボード#
NodeMCU はオープンソースの IoT ハードウェア開発ボードで、WIFI 機能をサポートし、Arduino 開発ボードと非常に似た使い方をするため、近年、世界中のクリエイターたちにますます人気を集めています。NodeMCU のサイズは Arduino Nano に似ています。これは Arduino チームが開発したものではありませんが、Arduino IDE を使用して開発することもできます。
あらゆるものがつながる IoT の基盤として、まず IoT 制御ボードのコストは高すぎてはいけません。高価な IoT 制御部品はプロジェクトのコスト管理に不利であり、多くのクリエイター愛好者が学び、使用することにも不利です。この点で、NodeMCU は Raspberry Pi や Arduino ファミリーの IoT プラットフォームよりも優位性があります。
注意深い友人はすでに気づいているかもしれませんが、私の開発ボードは ESP8266-NodeMCU と呼ばれています。しかし、他のウェブサイトや資料では、時々ESP8266 と呼ばれ、時々NodeMCU と呼ばれています。では、ESP8266 と NodeMCU の関係は何でしょうか?
ESP8266 はチップ(鉄のケースに保護された四角いもの)であり、NodeMCU は ESP8266 チップを中心にした開発ボードです。以下の図を参照してください。

ESP8266 チップを実験操作するのは非常に難しいです。なぜなら、小さなチップのピンをコンピュータに接続してプログラムをアップロードするなどの操作を行うのが難しいからです。そこで、ESP8266 チップを中心にしたさまざまな開発ボードが誕生しました。NodeMCU はこれらの開発ボードの一つです。
NodeMCU 開発ボードの 2 列のピンは ESP8266 チップのピンに接続されています。開発ボードの 2 列のピンを使うことで、ジャンパーワイヤーを使ってチップのピンを実験回路に簡単に接続できます。NodeMCU 開発ボードには USB インターフェースと電圧変換回路も搭載されています。これにより、私たちは大きな便利さを得ることができます。USB データケーブル 1 本で ESP8266 に電力を供給し、プログラムをアップロードする操作を簡単に実現できます。もちろん、NodeMCU 開発ボードの回路機能はこれだけではありませんので、これ以上は続けません。
ドライバのインストール#
以前に開発ボードのドライバのインストールについて説明しましたが、詳細ではありませんでした。
現在、市場にはさまざまな ESP8266 ドライバがあり、同じ NodeMcu の開発ボードのドライバも異なる場合があります。現在の主流は CH340 と CP210X のドライバです。
ドライバのダウンロードは、チップの製造元の公式ウェブサイトから直接行ってください。
CP210X:https://cn.silabs.com/developers/usb-to-uart-bridge-vcp-drivers
CH340C:https://www.wch.cn/downloads/CH341SER_EXE.html
自分のプラットフォームに適したドライバインストーラをダウンロードしてください。
自分のシリアルポートチップのモデルがドライバのサポート範囲内にあるかどうかを確認する必要があります。
自分の開発ボードに必要なドライバを確認する方法#
- 直接見る。下の図の縦長の黒い長方形が USB - シリアルチップです。上にチップのモデル名が書かれています。

 - 購入した業者に尋ねる。
 
ディスプレイのハンダ付け#
間違ってハンダ付けしないでください。そうしないとチップが壊れてしまいます。
OLED 接続:
- GND - GND
 - VCC - VCC
 - SCL - GPIO5(D1)
 - SDA - GPIO4(D2)
 
ロウ付け中

以下はハンダ付けが完了したものです。接続に注意してください。必ずしもこの順序である必要はなく、名前を確認する必要があります。

Arduino IDE のインストール#
- 
Arduino IDE をダウンロード
https://www.arduino.cc/en/software - 
インストール
インストールを教える必要がありますか? - 
設定
ツール - ボード - ボードマネージャをクリックし、設定にボードのアドレスを記入します:http://arduino.esp8266.com/stable/package_esp8266com_index.json
その後、自動的に対応するライブラリファイルがダウンロードされます。その間、ネットワークの科学性を保証する必要があります。 - 
ボードを選択
NodeMCU1.0(ESP-12EModule) - 
ポートを選択
コンピュータのデバイスマネージャで開発ボードの COM ポートを見つけます。 
Arduino コード#
時々、私は長々と話すよりも直接コードを見せた方が良いと思います。あなたも私が無駄話をするのではなく、直接コードを見たいと思っているに違いありません。
私はできるだけコードにコメントを付けました(Arduino コードを書く際は C/C++ 言語の規範に従ってください)。
以下の例では、WiFi 接続には <WiFiManager.h> ライブラリを使用し、初回接続時にはスマートフォンを使って ESP8266 が発信する WiFi に接続して設定を行う必要があります。画面に表示するには < U8g2lib.h > ライブラリを使用し、中国語を直接表示できます。
- これは WiFi に接続し、画面に画像を表示する簡単な例です。
 
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiManager.h>
#include <U8g2lib.h>
#define SDA 4  // SDAピン、デフォルトgpio4(D2)
#define SCL 5  // SCLピン、デフォルトgpio5(D1)
Adafruit_SSD1306 oled(128, 64, &Wire,-1);   //OLEDスクリーンのインスタンス化
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP,"pool.ntp.org", 8*3600, 60000);
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE);           // スクリーンを選択
// 1回だけ実行
void setup() {
  u8g2.begin();            // 初期化
  u8g2.enableUTF8Print();  // UTF8を許可
  u8g2.setFont(u8g2_font_wqy12_t_gb2312b); //フォントサイズ   u8g2_font_wqy15_t_gb2312b  
  
  // スクリーンの初期化
  OLED_Init();
  
  OLED_Showchin(1,13,"WiFiに接続中....",0);
  WiFiManager wifiManager;
  wifiManager.autoConnect("ESP8266");
  OLED_Showchin(1,27,"WiFi接続成功!",0);
  OLED_Showchin(1,41,"名称: " + WiFi.SSID(),0);
  OLED_Showchin(1,55,"IP: " + WiFi.localIP().toString(),1);
  // 時間を取得
  timeClient.begin();
  u8g2.setFont(u8g2_font_wqy15_t_gb2312b); //フォントサイズ   u8g2_font_wqy15_t_gb2312b  
  
  OLED_Showchin(1,13,"寧小建",0);
  OLED_Showchin(1,27,"hhhhhhhhhhhh",0);
  OLED_Showchin(1,55,"大バカハハハ",1);
  timeClient.update();
  OLED_Showchin(1,20,"現在の北京時間: ",0);
  OLED_Showchin(1,41,timeClient.getFormattedTime(),1);
  delay(1000);
  OLED_img();
}
// プログラムを繰り返し実行
void loop() {
  // 時間を更新
  // timeClient.update();
  // OLED_Showchin(1,27,"現在の北京時間: ",0);
  // OLED_Showchin(1,41,timeClient.getFormattedTime(),0);
}
// スクリーンに出力(中国語をサポート)
void OLED_Showchin(uint8_t x, uint8_t y, String string, uint8_t boot) {
  u8g2.setCursor(x, y);  //表示座標を設定
  u8g2.print(string);  // 指定されたバッファに印刷する文字列
  u8g2.sendBuffer();          // 位置情報をバッファに送信
  if(boot == 1){
    delay(1000);
    u8g2.clearBuffer();     // バッファをクリア、実際には初期化時にクリアされるが、ループ時には必ず追加する必要がある
  }
}
// スクリーンの初期化
void OLED_Init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);     //"SSD1306_SWITCHCAPVCC"はディスプレイがOLEDであることを示し、"0x3C"はOLEDスクリーンのデフォルト通信アドレス
  oled.setTextColor(WHITE);//ピクセルを点灯
  oled.clearDisplay();//クリア
}
// スクリーンに出力
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t font_size, String string) {
  oled.setTextSize(font_size);    //フォントサイズを設定 (>=1)
  oled.setCursor(x, y);           //表示座標を設定
  oled.println(string);           //表示内容
  oled.display();                 //表示を開始
}
// 描画
void OLED_img() {
  //  画像データ
    const unsigned char gImage_1[518] = { 0X00,0X01,0X40,0X00,0X40,0X00,
  0X00,0X40,0X00,0X00,0X00,0X3E,0XF0,0X00,0X00,0X80,0X00,0X00,0X00,0X1F,0XE0,0X00,
  0X00,0X00,0X00,0X00,0X00,0X06,0XB0,0X00,0X01,0X00,0X00,0X00,0X00,0X03,0XF8,0X00,
  0X00,0X00,0X00,0X00,0X00,0X03,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XDC,0X00,
  0X04,0X00,0X00,0X00,0X00,0X01,0XC0,0X00,0X0E,0X00,0X00,0X00,0X00,0X00,0X80,0X00,
  0X06,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0X00,0X00,0X00,0X10,0X00,0X00,0X00,
  0X08,0X00,0X00,0X00,0X0E,0X00,0X00,0X00,0X08,0X00,0X00,0X00,0X8F,0X00,0X00,0X00,
  0X00,0X00,0X02,0X02,0X47,0X00,0X00,0X00,0X00,0X00,0X01,0X10,0X63,0X80,0X00,0X00,
  0X00,0X00,0X01,0XC9,0X73,0XC0,0X00,0X00,0X00,0X00,0X00,0XE4,0X79,0XE0,0X00,0X00,
  0X00,0X02,0X00,0XFA,0XF9,0XE0,0X00,0X00,0X10,0X02,0X00,0X7D,0X8C,0XF0,0X00,0X00,
  0X10,0X03,0X01,0X7E,0X90,0XF1,0X80,0X00,0X10,0X01,0X20,0XFD,0X1C,0X7B,0XE0,0X00,
  0X00,0X01,0XA0,0X7D,0X03,0X7B,0X20,0X00,0X10,0X01,0XD8,0XFF,0X8B,0X7E,0X30,0X00,
  0X00,0X01,0XFC,0X7F,0X83,0XB6,0X10,0X00,0X00,0X00,0XF7,0XFF,0XC7,0XBE,0X10,0X00,
  0X00,0X01,0X8F,0XFF,0XE3,0XF6,0X10,0X00,0X01,0X01,0X4F,0XFF,0XFF,0XFF,0X10,0X00,
  0X00,0X01,0XCF,0XFF,0XFF,0XDF,0X10,0X00,0X00,0X01,0XC3,0XFF,0XFF,0XDF,0X70,0X00,
  0X01,0X03,0XE3,0XFF,0XFF,0XDF,0XE0,0X00,0X04,0X01,0XE7,0XFF,0XFF,0XDF,0XE4,0X00,
  0X07,0X00,0XFB,0XFF,0XFF,0XDF,0XC0,0X00,0X07,0X00,0XFB,0XFF,0XFF,0XFE,0X00,0X00,
  0X13,0X00,0X7F,0XFF,0XFF,0XFC,0X00,0X00,0X01,0X20,0X3F,0XFF,0XFF,0XFC,0X00,0X00,
  0X00,0X00,0X3F,0XFF,0XFF,0XF8,0X00,0X0B,0X00,0X00,0X1F,0XFE,0X0F,0XF8,0X00,0X1F,
  0X00,0X00,0X1F,0XF8,0X6F,0XF0,0X00,0XFF,0X00,0X00,0X1F,0XE1,0XFF,0XF0,0X05,0XFF,
  0X00,0X00,0X0F,0XF3,0XFF,0XE0,0X03,0XFF,0X00,0X40,0X0F,0XF7,0XFF,0XC0,0X07,0XFF,
  0X00,0X00,0X07,0XFF,0XFF,0X80,0X07,0XFF,0X08,0X00,0X07,0XFF,0XFF,0X00,0X0F,0XFF,
  0X00,0X00,0X23,0XFF,0XFE,0X00,0X0F,0XFF,0X00,0X08,0X60,0XFF,0XFE,0X00,0X0F,0XFF,
  0X00,0X40,0X20,0X3F,0XFE,0X00,0X1F,0XFF,0X00,0X00,0X10,0X0B,0XFF,0X80,0X1F,0XFF,
  0X00,0X00,0X40,0X00,0X3F,0X00,0X1F,0XFF,0X00,0X00,0X10,0X00,0X3F,0X00,0X1F,0XFF,
  0X20,0X00,0X02,0X00,0X3F,0X00,0X3F,0XFF,0X00,0X00,0X00,0X00,0X7F,0X80,0X3F,0XFF,
  0X00,0X00,0X00,0X10,0X7F,0X80,0X7F,0XFF,0X00,0X00,0X00,0X80,0X7F,0X80,0X7F,0XFF,
  0X10,0X00,0X00,0X00,0X7F,0X80,0XFF,0XFF,0X30,0X00,0X00,0X00,0X7F,0X80,0XFF,0XFF,
  0X10,0X10,0X00,0X00,0X7F,0XC1,0XFF,0XFF,0X00,0X00,0X00,0X00,0X7F,0XF3,0XFF,0XFF,
  0X00,0X00,0X01,0X00,0X3F,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X04,0X3F,0XFF,0XFF,0XFF,
  0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0X00,0X00,0X10,0X80,0X1F,0XFF,0XFF,0XFF,
  0X01,0X00,0X00,0X05,0X1F,0XFF,0XFF,0XFB,0X00,0X00,0X00,0X00,0X1F,0XF7,0XFF,0XFC,
  0X00,0X00,0X00,0X00,0X1F,0XFB,0XFF,0XFF,0X00,0X00,0X40,0X00,0X19,0XFF,0XFF,0XFF,
  };
  oled.clearDisplay();
  oled.drawBitmap(3, 1, gImage_1, 64, 64, WHITE);
  oled.display();
}

2. これは HTTP リクエストを発起し、画面に近 4 日間の天気情報を表示するものです。
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiManager.h> // WiFiManagerライブラリをインポート
#include <ArduinoJson.h> // ArduinoJsonライブラリをインポート
#include <U8g2lib.h> // U8g2ライブラリをインポート
#define SDA 4  // SDAピン、デフォルトgpio4(D2)
#define SCL 5  // SCLピン、デフォルトgpio5(D1)
// スクリーンを選択
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE);
// リクエストするURL
const char* url = "http://t.weather.itboy.net/api/weather/city/101230308";
// Wi-Fi自動接続
void connectToWiFi() {
  WiFiManager wifiManager;
  wifiManager.autoConnect("ESP8266"); // 保存されたWi-Fiネットワークに自動接続、または指定された名前のアクセスポイントを設定
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("Wi-Fiに接続されました");
  } else {
    Serial.println("Wi-Fiに接続されていません");
  }
}
// HTTP GETリクエストを発起し、レスポンスを返す
String httpRequest(const char* url) {
  WiFiClient client;
  HTTPClient http;
  http.begin(client, url); // WiFiClientとURLを使用
  int httpCode = http.GET(); // リクエストを発起
  String payload;
  if (httpCode > 0) {
    Serial.printf("HTTP GETリクエストが送信されました、レスポンスコード: %d\n", httpCode);
    if (httpCode == HTTP_CODE_OK) {
      payload = http.getString(); // レスポンス内容を取得
      Serial.println("レスポンス内容:");
      Serial.println(payload); // レスポンス内容を印刷
    }
  } else {
    Serial.printf("HTTP GETリクエストが失敗しました、エラー: %s\n", http.errorToString(httpCode).c_str());
  }
  http.end(); // 接続を閉じる
  return payload;
}
// 天気データを保存するグローバル変数
StaticJsonDocument<2048> doc;
int dayIndex = 0;
unsigned long previousMillis = 0;
const long interval = 5000; // 5秒ごとに表示を切り替える
// JSONを解析し、天気情報を保存
bool parseWeather(const String& payload) {
  DeserializationError error = deserializeJson(doc, payload); // JSONを逆シリアル化
  if (!error) {
    Serial.println("JSON解析成功!");
    return true;
  } else {
    Serial.print("JSON解析失敗: ");
    Serial.println(error.c_str());
    return false;
  }
}
// 天気情報を表示
void displayWeather(int index) {
  if (!doc["data"]["forecast"][index]) return; // JSONデータが存在するか確認
  char buffer[128];
  const char* high = doc["data"]["forecast"][index]["high"].as<const char*>();
  const char* low = doc["data"]["forecast"][index]["low"].as<const char*>();
  const char* ymd = doc["data"]["forecast"][index]["ymd"].as<const char*>();
  const char* week = doc["data"]["forecast"][index]["week"].as<const char*>();
  const char* type = doc["data"]["forecast"][index]["type"].as<const char*>();
  const char* notice = doc["data"]["forecast"][index]["notice"].as<const char*>();
  u8g2.clearBuffer();  // バッファをクリア
  // 日付と曜日を1行に表示
  snprintf(buffer, sizeof(buffer), "%s %s", ymd, week);
  OLED_Showchin(0, 15, buffer, 2); // テキストサイズを1に調整
  // 高温と低温を1行に表示
  snprintf(buffer, sizeof(buffer), "%s %s", high, low);
  OLED_Showchin(0, 35, buffer, 2); // テキストサイズを1に調整
  // 天気の種類を表示
  snprintf(buffer, sizeof(buffer), "%s", type);
  OLED_Showchin(0, 55, buffer, 3); // テキストサイズを1に調整
  // 提示情報を表示
  // snprintf(buffer, sizeof(buffer), "%s", notice);
  // OLED_Showchin(0, 55, buffer, 1); // テキストサイズを1に調整
  
  u8g2.sendBuffer(); // バッファの内容をディスプレイに送信
}
// スクリーンに出力(中国語とフォントサイズの設定をサポート)
void OLED_Showchin(uint8_t x, uint8_t y, const char* string, uint8_t textSize) {
  u8g2.setCursor(x, y);  // 表示座標を設定
  switch (textSize) {
    case 1:
      u8g2.setFont(u8g2_font_wqy12_t_gb2312b); // 最小フォントを設定
      break;
    case 2:
      u8g2.setFont(u8g2_font_wqy13_t_gb2312b); // 大フォントを設定
      break;
    case 3:
      u8g2.setFont(u8g2_font_wqy15_t_gb2312b); // 最大フォントを設定
      break;
  }
  u8g2.print(string); // 指定されたバッファに印刷する文字列
}
void setup() {
  Serial.begin(115200);
  delay(1000);
  u8g2.begin(); // U8g2を初期化
  u8g2.enableUTF8Print(); // UTF8を許可
  connectToWiFi(); // Wi-Fiに接続
  if (WiFi.status() == WL_CONNECTED) {
    String payload = httpRequest(url); // HTTPリクエストを発起
    if (!payload.isEmpty()) {
      if (parseWeather(payload)) { // 天気データを解析
        displayWeather(dayIndex); // 初期天気データを表示
      }
    }
  } else {
    Serial.println("Wi-Fiに接続できません");
  }
}
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    dayIndex = (dayIndex + 1) % 4; // 次の日のデータに切り替え
    displayWeather(dayIndex); // 天気情報を表示
  }
  // WiFi接続状態を確認し、切断されている場合は再接続
  if (WiFi.status() != WL_CONNECTED) {
    connectToWiFi();
  }
}
