Hey, I'm back as promised to write the firmware for the ESP8266 development board.
As promised in 2020, I'm here to fulfill my vow today ESP8266 Serial WiFi Module - WiFi Killer
Today we will also connect the OLED display. The one I bought is a 4-pin OLED (128*64) that does not support color display.
NodeMCU Development Board#
NodeMCU is an open-source IoT hardware development board. It supports WiFi functionality and is very similar in usage to Arduino development boards, which has made it increasingly popular among makers worldwide in recent years. The size of NodeMCU is similar to that of Arduino Nano. It is not developed by the Arduino team, but we can still use the Arduino IDE to develop for it.
As a foundation for the Internet of Things, the cost of IoT control boards should not be too high. Expensive IoT control components are not conducive to project cost control and also hinder many maker enthusiasts from learning and using them. In this regard, NodeMCU has advantages over IoT platforms like Raspberry Pi and the Arduino family.
Careful friends may have noticed that my development board is called ESP8266-NodeMCU. However, on other websites or materials, sometimes it is referred to as ESP8266 and sometimes as NodeMCU. So what is the relationship between ESP8266 and NodeMCU?
ESP8266 is a chip (the square thing protected by a metal shell), while NodeMCU is a development board based on the ESP8266 chip, as shown in the picture below.
It is very difficult to experiment with the ESP8266 chip directly because it is hard to connect the tiny chip's pins to our computer for uploading programs and other operations. Thus, various development boards around the ESP8266 chip were born. NodeMCU is one of these development boards.
The two rows of pins on the NodeMCU development board are connected to the pins of the ESP8266 chip. With these two rows of pins on the development board, we can easily use Dupont wires to connect the chip's pins to the experimental circuit. The NodeMCU development board also comes with a USB interface and voltage conversion circuit. These provide us with great convenience. We can easily power the ESP8266 and upload programs using just a USB data cable. Of course, the circuit functions on the NodeMCU development board are not limited to these, and I won't elaborate further.
Driver Installation#
Although I have mentioned the installation of the development board's drivers before, it was not detailed enough.
Currently, there are various ESP8266 drivers on the market, and even the drivers for the same NodeMCU development board may differ. The mainstream ones are the CH340 and CP210X drivers.
You can download the drivers directly from the manufacturer's official website:
CP210X: https://cn.silabs.com/developers/usb-to-uart-bridge-vcp-drivers
CH340C: https://www.wch.cn/downloads/CH341SER_EXE.html
Download the driver installation program suitable for your platform.
Make sure to check whether your serial port chip model is supported by the driver.
How to Check What Driver Your Development Board Needs#
- Look directly; the long rectangular black bar in the picture below is the USB to serial chip. The model name of the chip will be indicated on it.
- Ask the vendor from whom you purchased it.
Display Screen Soldering#
Be careful not to solder incorrectly, or it may burn the chip.
OLED wiring:
- GND - GND
- VCC - VCC
- SCL - GPIO5(D1)
- SDA - GPIO4(D2)
The soldering iron is heating up.
Below is the completed soldering. Pay attention to the wiring; it doesn't have to be in my order; check the names.
Arduino IDE Installation#
-
Download Arduino IDE
https://www.arduino.cc/en/software -
Installation
Do I need to teach you how to install? -
Configuration
Click Tools - Board - Board Manager, and enter the board address in the settings: http://arduino.esp8266.com/stable/package_esp8266com_index.json
Then it will automatically download the corresponding support library files. During this process, ensure that your network is stable. -
Select the development board
NodeMCU1.0(ESP-12E Module) -
Select the port
Find the COM port of your development board in the device manager of your computer.
Arduino Code#
Sometimes I feel that I might as well just show the code directly instead of rambling on. I believe you also want to see the code directly rather than listen to me talk a lot of nonsense.
I have also added comments in the code as much as possible (please follow C/C++ language standards when writing Arduino code).
In the following examples, the WiFi connection uses the <WiFiManager.h> library, and the first connection requires using a mobile phone to connect to the WiFi broadcast by the ESP8266 for configuration. The screen writing uses the <U8g2lib.h> library, which supports direct Chinese writing.
- This is a simple example of connecting to WiFi and displaying an image on the screen.
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiManager.h>
#include <U8g2lib.h>
#define SDA 4 // SDA pin, default gpio4(D2)
#define SCL 5 // SCL pin, default gpio5(D1)
Adafruit_SSD1306 oled(128, 64, &Wire,-1); // Instantiate OLED screen
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); // Select display screen
// Execute only once
void setup() {
u8g2.begin(); // Initialize
u8g2.enableUTF8Print(); // Enable UTF8
u8g2.setFont(u8g2_font_wqy12_t_gb2312b); // Font size u8g2_font_wqy15_t_gb2312b
// Initialize screen
OLED_Init();
OLED_Showchin(1,13,"Connecting to WiFi....",0);
WiFiManager wifiManager;
wifiManager.autoConnect("ESP8266");
OLED_Showchin(1,27,"WiFi connected successfully!",0);
OLED_Showchin(1,41,"Name: " + WiFi.SSID(),0);
OLED_Showchin(1,55,"IP: " + WiFi.localIP().toString(),1);
// Get time
timeClient.begin();
u8g2.setFont(u8g2_font_wqy15_t_gb2312b); // Font size u8g2_font_wqy15_t_gb2312b
OLED_Showchin(1,13,"Ning Xiaojian",0);
OLED_Showchin(1,27,"hhhhhhhhhhhh",0);
OLED_Showchin(1,55,"Big fool hahaha",1);
timeClient.update();
OLED_Showchin(1,20,"Current Beijing Time: ",0);
OLED_Showchin(1,41,timeClient.getFormattedTime(),1);
delay(1000);
OLED_img();
}
// Repeat the program
void loop() {
// Update time
// timeClient.update();
// OLED_Showchin(1,27,"Current Beijing Time: ",0);
// OLED_Showchin(1,41,timeClient.getFormattedTime(),0);
}
// Print output to screen (supports Chinese)
void OLED_Showchin(uint8_t x, uint8_t y, String string, uint8_t boot) {
u8g2.setCursor(x, y); // Set display coordinates
u8g2.print(string); // Print the specified string to the buffer
u8g2.sendBuffer(); // Send positioning information to the buffer
if(boot == 1){
delay(1000);
u8g2.clearBuffer(); // Clear buffer, actually cleared in initialization, must be added in loop
}
}
// Screen initialization
void OLED_Init() {
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); //"SSD1306_SWITCHCAPVCC" indicates the display is OLED, "0x3C" is the default communication address for the OLED screen
oled.setTextColor(WHITE);// Turn on pixel points
oled.clearDisplay();// Clear screen
}
// Output to screen
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t font_size, String string) {
oled.setTextSize(font_size); // Set font size (>=1)
oled.setCursor(x, y); // Set display coordinates
oled.println(string); // Display content
oled.display(); // Turn on display
}
// Drawing
void OLED_img() {
// Image data
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. This is an example of initiating an HTTP request and displaying the weather information for the next four days on the screen.
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiManager.h> // Include WiFiManager library
#include <ArduinoJson.h> // Include ArduinoJson library
#include <U8g2lib.h> // Include U8g2 library
#define SDA 4 // SDA pin, default gpio4(D2)
#define SCL 5 // SCL pin, default gpio5(D1)
// Select display screen
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE);
// URL to request
const char* url = "http://t.weather.itboy.net/api/weather/city/101230308";
// Wi-Fi auto connection
void connectToWiFi() {
WiFiManager wifiManager;
wifiManager.autoConnect("ESP8266"); // Automatically connect to saved Wi-Fi networks or set up an access point with a specified name
if (WiFi.status() == WL_CONNECTED) {
Serial.println("Connected to Wi-Fi");
} else {
Serial.println("Not connected to Wi-Fi");
}
}
// Initiate HTTP GET request and return response
String httpRequest(const char* url) {
WiFiClient client;
HTTPClient http;
http.begin(client, url); // Use WiFiClient and URL
int httpCode = http.GET(); // Initiate request
String payload;
if (httpCode > 0) {
Serial.printf("HTTP GET request sent, response code: %d\n", httpCode);
if (httpCode == HTTP_CODE_OK) {
payload = http.getString(); // Get response content
Serial.println("Response content:");
Serial.println(payload); // Print response content
}
} else {
Serial.printf("HTTP GET request failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end(); // Close connection
return payload;
}
// Global variable to store weather data
StaticJsonDocument<2048> doc;
int dayIndex = 0;
unsigned long previousMillis = 0;
const long interval = 5000; // Switch display every 5 seconds
// Parse JSON and save weather information
bool parseWeather(const String& payload) {
DeserializationError error = deserializeJson(doc, payload); // Deserialize JSON
if (!error) {
Serial.println("JSON parsed successfully!");
return true;
} else {
Serial.print("JSON parsing failed: ");
Serial.println(error.c_str());
return false;
}
}
// Display weather information
void displayWeather(int index) {
if (!doc["data"]["forecast"][index]) return; // Check if JSON data exists
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(); // Clear buffer first
// Display date and week on one line
snprintf(buffer, sizeof(buffer), "%s %s", ymd, week);
OLED_Showchin(0, 15, buffer, 2); // Adjust text size to 1
// Display high and low temperatures on one line
snprintf(buffer, sizeof(buffer), "%s %s", high, low);
OLED_Showchin(0, 35, buffer, 2); // Adjust text size to 1
// Display weather type
snprintf(buffer, sizeof(buffer), "%s", type);
OLED_Showchin(0, 55, buffer, 3); // Adjust text size to 1
// Display notice information
// snprintf(buffer, sizeof(buffer), "%s", notice);
// OLED_Showchin(0, 55, buffer, 1); // Adjust text size to 1
u8g2.sendBuffer(); // Send buffer content to display
}
// Print output to screen (supports Chinese and sets font size)
void OLED_Showchin(uint8_t x, uint8_t y, const char* string, uint8_t textSize) {
u8g2.setCursor(x, y); // Set display coordinates
switch (textSize) {
case 1:
u8g2.setFont(u8g2_font_wqy12_t_gb2312b); // Set smallest font
break;
case 2:
u8g2.setFont(u8g2_font_wqy13_t_gb2312b); // Set large font
break;
case 3:
u8g2.setFont(u8g2_font_wqy15_t_gb2312b); // Set largest font
break;
}
u8g2.print(string); // Print the specified string to the buffer
}
void setup() {
Serial.begin(115200);
delay(1000);
u8g2.begin(); // Initialize U8g2
u8g2.enableUTF8Print(); // Enable UTF8
connectToWiFi(); // Connect to Wi-Fi
if (WiFi.status() == WL_CONNECTED) {
String payload = httpRequest(url); // Initiate HTTP request
if (!payload.isEmpty()) {
if (parseWeather(payload)) { // Parse weather data
displayWeather(dayIndex); // Display initial weather data
}
}
} else {
Serial.println("Unable to connect to Wi-Fi");
}
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
dayIndex = (dayIndex + 1) % 4; // Switch to the next day's data
displayWeather(dayIndex); // Display weather information
}
// Check WiFi connection status, reconnect if disconnected
if (WiFi.status() != WL_CONNECTED) {
connectToWiFi();
}
}