1.ESP8266-NODE MCU介绍

注意事项
1. 连接开发板硬件之前,确保断开所有电源以避免触电危险。开发板上包含尖锐物体,使用时应当十分小心以避免意外伤害。禁止用手指直接触摸开发板裸露金属部分,防止意外扎伤手指。另外直接触摸金属部分可能导致静电损坏开发板。未成年人需要在成年人监护下使用此开发板。
2. 开发板天线附近请保持足够的净空区,否则会影响天线性能。
3. 开发板的 USB 接口与计算机连接时,如果开发板的串口没有被打开,插拔计算机 USB 外设的操作会造成开发板复位。只有使用计算机供电且串口未被打开时会发生此问题,如果使用普通 USB 电源供电或计算机已经打开串口则不会发生此问题。
4. 开发板的 GPIO0 上电时若电平为低,则开发板进入烧录固件模式,此时用户的程序将不会被执行。如果开发板上电后未能正常工作,请检查如下引脚的电平:GPIO0 高,GPIO2 高,EN 高,RST 高,GPIO15 低。若电平不符,请用户检查外围电路并修正。
5. 烧录固件时如果不慎发生中断导致烧录失败,则开发板的程序不完整,此时有一定的可能无法进入自动模式。此时应当按住 FLASH 按键不放插入 USB 线缆,则可正常烧录固件。
6. 如果用户需要使用休眠功能,需要将 RST 与 GPIO16 直接连接。用户可自行连接这两个管脚,或在开发板 R3位置焊接 0 欧姆的电阻。注意,使用休眠功能后,GPIO16 禁止使用。
7. GPIO16 不支持中断、PWM、I2C 以及 One-wire 功能,只能作为普通输入/输出端口使用。
8. 不得对开发板输入超过 5V 以上的电源电压,也不得将开发板 GPIO 直接连接到 5V 电平的外设上。如果需要连接,需要电平转换电路,否则可能造成不可逆转的损坏

TCP/IP协议

分层名称

TCPP包含以下协议

应用层

HTTP, ftp, mdns, websocket, OSC

传输层

TCP, UDP

网络层

IP

链路层(也称网络接口层)

Ethernet, Wi-Fi...

2.Esp8266安装

2.1首先下载Esp826驱动

        下载windows的驱动的CP210x Windows Drivers

下载后解压安装,比如电脑64未系统的安装64位的

usb连接电脑上,设备管理器可以看到com7端口就是esp3266

打开Arduino ide,点击文件→首选项

 

输入网址
将以下网址复制并且黏贴到到“附加开发板管理网址”栏中

http://arduino.esp8266.com/stable/package_esp8266com_index.json

esp82

https://github.com/espressif/arduino-esp32/releases/download/1.0.4/package_esp32_index.json

多个用;隔开

点击好,

重启软件

然后点击工具→开发板→开发板管理器

 

搜索esp8266,进行安装最新版库(此步可以不用下载,可以把其他电脑离线包放在C:\Users\yang1234\AppData\Local\Arduino15\staging的libraries和packages文件夹内,这样搜索esp8266可以离线安装了,这个文件夹是首选项那个preference.txt路径)

安装完之后

再进行选项 NodeMCU1.0esp-12E Module→ ESP8266 Boards(版本号)→NodeMCU 1.0 (ESP-12E Module)

(注意:esp01s选择第一个Generic ESP8266 Module)

最后选择端口,我的COM7的端口

然后验证

选择示例→01.Basics→Blink

上传看看是否成功

Executable segment sizes:
IROM   : 228624          - code in flash         (default or ICACHE_FLASH_ATTR) 
IRAM   : 26756   / 32768 - code in IRAM          (ICACHE_RAM_ATTR, ISRs...) 
DATA   : 1248  )         - initialized variables (global, static) in RAM/HEAP 
RODATA : 688   ) / 81920 - constants             (global, static) in RAM/HEAP 
BSS    : 24880 )         - zeroed variables      (global, static) in RAM/HEAP 
项目使用了 257316 字节,占用了 (24%) 程序存储空间。最大为 1044464 字节。
全局变量使用了26816字节,(32%)的动态内存,余留55104字节局部变量。最大为81920字节。
esptool.py v2.8
Serial port COM7
Connecting....
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: f4:cf:a2:eb:fb:77
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 261472 bytes to 193134...
Wrote 261472 bytes (193134 compressed) at 0x00000000 in 19.1 seconds (effective 109.7 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
 

3.NodeMCU开发板的接入点模式

接入点模式(Access Point, 也称 AP)

NodeMCU可以建立WiFi网络供其它设备连接。当NodeMCU以此模式运行时,我们可以使用手机搜索NodeMCU所发出的WiFi网络并进行连接。

/*设置名字yys,密码12345678*/ 
#include <ESP8266WiFi.h>        // 本程序使用ESP8266WiFi库
 
const char *ssid = "yys"; // 这里定义将要建立的WiFi名称。此处以"taichi-maker"为示例
                                   // 您可以将自己想要建立的WiFi名称填写入此处的双引号中
 
const char *password = "12345678";  // 这里定义将要建立的WiFi密码。此处以12345678为示例
                                    // 您可以将自己想要使用的WiFi密码放入引号内
                                    // 如果建立的WiFi不要密码,则在双引号内不要填入任何信息
void setup() {
  Serial.begin(9600);              // 启动串口通讯
 
  WiFi.softAP(ssid, password);     // 此语句是重点。WiFi.softAP用于启动NodeMCU的AP模式。
                                   // 括号中有两个参数,ssid是WiFi名。password是WiFi密码。
                                   // 这两个参数具体内容在setup函数之前的位置进行定义。
 
  
  Serial.print("Access Point: ");    // 通过串口监视器输出信息
  Serial.println(ssid);              // 告知用户NodeMCU所建立的WiFi名
  Serial.print("IP address: ");      // 以及NodeMCU的IP地址
  Serial.println(WiFi.softAPIP());   // 通过调用WiFi.softAPIP()可以得到NodeMCU的IP地址
}
 
void loop() { 
}

默认ip是192.168.4.1

要按开发板上rest键盘才能看串口监视器内容

18:43:30.828 -> Access Point: yys
18:43:30.948 -> IP address: 192.168.4.1

 

4.NodeMCU开发板的无线终端模式

无线终端模式(Station)

1. 连接WiFI

ESP8266可通过WiFi连接无线路由器。这与用您的手机通过WiFi连接无线路由器的模式相同

#include <ESP8266WiFi.h>        // 本程序使用ESP8266WiFi库
 
const char* ssid     = "yang1234";      // 连接WiFi名(此处使用taichi-maker为示例)
                                            // 请将您需要连接的WiFi名填入引号中
const char* password = "y123456789";          // 连接WiFi密码(此处使用12345678为示例)
                                            // 请将您需要连接的WiFi密码填入引号中
                                            
void setup() {
  Serial.begin(9600);         // 启动串口通讯
  
  WiFi.begin(ssid, password);                  // 启动网络连接
  Serial.print("Connecting to ");              // 串口监视器输出网络连接信息
  Serial.print(ssid); Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接
  
  int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功
  while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 
    delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED                       
    Serial.print(i++); Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值
  }                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。
                                               // 这个读秒是通过变量i每隔一秒自加1来实现的。
                                               
  Serial.println("");                          // WiFi连接成功后
  Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。
  Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用
  Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。
}
 
void loop() {                                   
}

看到小米路由器有个ESP-EBFB77设备连接wifil 

要按开发板上rest键盘才能看串口监视器内容(乱码忽略)

18:50:31.697 ->Connecting to yang1234 ...
18:50:32.799 -> 0 1 
18:50:33.800 -> Connection established!
18:50:33.800 -> IP address:    192.168.31.144

可以电脑ping通

C:\Users\yys53>ping 192.168.31.144

正在 Ping 192.168.31.144 具有 32 字节的数据:
来自 192.168.31.144 的回复: 字节=32 时间=23ms TTL=255
来自 192.168.31.144 的回复: 字节=32 时间=2ms TTL=255
来自 192.168.31.144 的回复: 字节=32 时间=4ms TTL=255
来自 192.168.31.144 的回复: 字节=32 时间=5ms TTL=255

192.168.31.144 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 2ms,最长 = 23ms,平均 = 8ms

 

5.ESP8266-NodeMCU网络服务器

5.1 建立基本网络服务器

网络服务器有很多种类型,它们的功能也十分丰富。通常承担网络服务器工作的设备都是运算能力比较强大的电脑。我们的ESP866-NodeMCU虽然也能实现网络服务器的一些功能,但是毕竟它的运算能力是无法与那些昂贵的服务器电脑相媲美的,因此ESP8266-NodeMCU只能实现一些基本的网络服务功能。不过这些基本的网络服务功能已经足够我们开发物联网项目了。在接下来的几节教程里,我们将一起来学习如何让ESP8266-NodeMCU来实现网络服务功能。

网络服务是一个很宽泛的概念,我们在这里即将给您介绍的是网络服务中的网页服务功能。所谓网页服务就是专门用于网页浏览的服务。这个操作我相信所有看到这篇教程的朋友们都使用过,因为您现在正阅读的这篇教程就是通过网页服务传输到您面前的。

为了便于理解,我们一起回忆一下您在打开这篇教程曾经历了什么过程。首先,要想访问太极创客网站就要在浏览器地址栏输入太极创客的网站地址: www.taichi-maker.com。当您输入完地址并按下回车以后,浏览器会通过DNS服务查到太极创客网站服务器的IP地址。假设我们太极创客服务器地址为12.34.56.78。接下来浏览器就会向IP地址12.34.56.78的服务器发送http请求。当网站服务器收到了请求后,会把被请求的网页信息传输给浏览器,然后浏览器就会把收到的网页信息转换成网页显示在浏览器中。

为了能够应付来自全世界的创客朋友们大量访问,太极创客的网站服务器是一台运算能力很强的计算机。假如这个网站只有您自己访问,那么ESP8266-NodeMCU就足够了。下面这个示例程序可以让ESP8266-NodeMCU实现最基本的网页服务功能。请先将这段示例程序复制并且上传NodeMCU。

#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库
 
ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'
 
ESP8266WebServer esp8266_server(80);// 建立ESP8266WebServer对象,对象名称为esp8266_server
                                    // 括号中的数字是网路服务器响应http请求的端口号
                                    // 网络服务器标准http端口号为80,因此这里使用80为端口号
 
void setup(void){
  Serial.begin(9600);          // 启动串口通讯
 
  //通过addAp函数存储  WiFi名称       WiFi密码
  wifiMulti.addAP("yang1234", "y123456789");  // 这三条语句通过调用函数addAP来记录3个不同的WiFi网络信息。
  //wifiMulti.addAP("taichi-maker2", "87654321"); // 这3个WiFi网络名称分别是taichi-maker, taichi-maker2, taichi-maker3。
  //wifiMulti.addAP("taichi-maker3", "13572468"); // 这3个网络的密码分别是123456789,87654321,13572468。
                                                // 此处WiFi信息只是示例,请在使用时将需要连接的WiFi信息填入相应位置。
                                                // 另外这里只存储了3个WiFi信息,您可以存储更多的WiFi信息在此处。
 
  int i = 0;                                 
  while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
    delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    Serial.print(i++); Serial.print(' ');    // 将会连接信号最强的那一个WiFi信号。
  }                                          // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
                                             // 此处while循环判断是否跳出循环的条件。
 
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');                     // WiFi连接成功后
  Serial.print("Connected to ");            // NodeMCU将通过串口监视器输出。
  Serial.println(WiFi.SSID());              // 连接的WiFI名称
  Serial.print("IP address:\t");            // 以及
  Serial.println(WiFi.localIP());           // NodeMCU的IP地址
  
//--------"启动网络服务功能"程序部分开始-------- //  此部分为程序为本示例程序重点1
  esp8266_server.begin();                   //  详细讲解请参见太极创客网站《零基础入门学用物联网》
  esp8266_server.on("/", handleRoot);       //  第3章-第2节 ESP8266-NodeMCU网络服务器-1
  esp8266_server.onNotFound(handleNotFound);        
//--------"启动网络服务功能"程序部分结束--------
  Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}
 
/* 以下函数语句为本示例程序重点3
详细讲解请参见太极创客网站《零基础入门学用物联网》
第3章-第2节 3_2_1_First_Web_Server 的说明讲解*/  
void loop(void){
  esp8266_server.handleClient();     // 处理http服务器访问
}
 
/* 以下两个函数为本示例程序重点2
详细讲解请参见太极创客网站《零基础入门学用物联网》
第3章-第2节 3_2_1_First_Web_Server 的说明讲解*/                                                                            
void handleRoot() {   //处理网站根目录“/”的访问请求 
  esp8266_server.send(200, "text/plain", "Hello from ESP8266");   // NodeMCU将调用此函数。
}
 
// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){                                        // 当浏览器请求的网络资源无法在服务器找到时,
  esp8266_server.send(404, "text/plain", "404: Not found");   // NodeMCU将调用此函数。
}

浏览器输入ip(如192.168.31.144)就可以看到输入内容

Hello from ESP8266

5.2通过网络服务实现NodeMCU开发板基本控制

NodeMCU作为物联网开发板,我们是需要通过网络对它实现控制的。在本教程里,我们将利用NodeMCU建立网络服务。用户通过浏览器可以访问NodeMCU所建立的网页。通过该网页,用户可实现对NodeMCU的控制。

以下是本教程的示例代码:

#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库
 
ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是 'wifiMulti'
 
ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)
 
void setup(void){
  Serial.begin(9600);   // 启动串口通讯
 
  pinMode(LED_BUILTIN, OUTPUT); //设置内置LED引脚为输出模式以便控制LED
  
  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。
  
  int i = 0;                                 
  while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
    delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    Serial.print(i++); Serial.print(' ');    // 将会连接信号最强的那一个WiFi信号。
  }                                          // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
                                             // 此处while循环判断是否跳出循环的条件。
  
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IP
 
  esp8266_server.begin();                           // 启动网站服务
  esp8266_server.on("/", HTTP_GET, handleRoot);     // 设置服务器根目录即'/'的函数'handleRoot'
  esp8266_server.on("/LED", HTTP_POST, handleLED);  // 设置处理LED控制请求的函数'handleLED'
  esp8266_server.onNotFound(handleNotFound);        // 设置处理404情况的函数'handleNotFound'
 
  Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}
 
void loop(void){
  esp8266_server.handleClient();                     // 检查http服务器访问
}
 
/*设置服务器根目录即'/'的函数'handleRoot'
  该函数的作用是每当有客户端访问NodeMCU服务器根目录时,
  NodeMCU都会向访问设备发送 HTTP 状态 200 (Ok) 这是send函数的第一个参数。
  同时NodeMCU还会向浏览器发送HTML代码,以下示例中send函数中第三个参数,
  也就是双引号中的内容就是NodeMCU发送的HTML代码。该代码可在网页中产生LED控制按钮。 
  当用户按下按钮时,浏览器将会向NodeMCU的/LED页面发送HTTP请求,请求方式为POST。
  NodeMCU接收到此请求后将会执行handleLED函数内容*/
void handleRoot() {       
  esp8266_server.send(200, "text/html", "<form action='/LED' method='POST'><input type='submit' style='color:orange' value='Toggle LED'></form>");
}
 
//处理LED控制请求的函数'handleLED'
void handleLED() {                          
  digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));// 改变LED的点亮或者熄灭状态
  esp8266_server.sendHeader("Location","/");          // 跳转回页面根目录
  esp8266_server.send(303);                           // 发送Http相应代码303 跳转  
}
 
// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){
  esp8266_server.send(404, "text/plain", "404: Not found"); // 发送 HTTP 状态 404 (未找到页面) 并向浏览器发送文字 "404: Not found"
}

浏览器输入ip(如192.168.31.144)

Toggle Led就可以关灯,熄灯

5.3通过网络服务将开发板引脚状态显示在网页中

我们在项目制作中可能会需要实时掌握NodeMCU开发板的引脚状态。在本节课程中 ,我们来一起学习如何通过NodeMCU建立基本网站。该网站的页面会实时显示NodeMCU的引脚状态。

为了便于学习,本节课中我们将使用D3引脚作为演示。选择D3引脚是因为它已经与开发板上的FLASH按键开关连接好了。

我们可以通过NodeMCU开发板上的FLASH按键控制D3引脚的电平。当我们没有按下该按键时,D3引脚将会保持高电平状态。当按下该按键后,D3引脚会变为低电平。

方法1:手动刷新

#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库
 
#define buttonPin D3            // 按钮引脚D3
 
ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'
 
ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)
 
bool pinState;  // 存储引脚状态用变量
 
void setup(){
  Serial.begin(9600);   // 启动串口通讯
 
  pinMode(buttonPin, INPUT_PULLUP); // 将按键引脚设置为输入上拉模式
 
  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。
  
  int i = 0;                                 
  while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
    delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    Serial.print(i++); Serial.print(' ');    // 将会连接信号最强的那一个WiFi信号。
  }                                          // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
                                             // 此处while循环判断是否跳出循环的条件。
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');                     // WiFi连接成功后
  Serial.print("Connected to ");            // NodeMCU将通过串口监视器输出。
  Serial.println(WiFi.SSID());              // 连接的WiFI名称
  Serial.print("IP address:\t");            // 以及
  Serial.println(WiFi.localIP());           // NodeMCU的IP地址
  
  esp8266_server.begin();                   // 启动网站服务                
  esp8266_server.on("/", handleRoot);       // 设置服务器根目录即'/'的函数'handleRoot'
  esp8266_server.onNotFound(handleNotFound);// 设置处理404情况的函数'handleNotFound'        
 
  Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}
 
void loop(){
  esp8266_server.handleClient();     // 处理http服务器访问
  pinState = digitalRead(buttonPin); // 获取引脚状态
}
 
/* 以下函数处理网站首页的访问请求。此函数为本示例程序重点1
详细讲解请参见太极创客网站《零基础入门学用物联网》
第3章-第2节“通过网络服务将开发板引脚状态显示在网页中”的说明讲解。*/                                                                       
void handleRoot() {   
  String displayPinState;                   // 存储按键状态的字符串变量
  
  if(pinState == HIGH){                     // 当按键引脚D3为高电平
    displayPinState = "Button State: HIGH"; // 字符串赋值高电平信息
  } else {                                  // 当按键引脚D3为低电平
    displayPinState = "Button State: LOW";  // 字符串赋值低电平信息
  }
  
  esp8266_server.send(200, "text/plain", displayPinState); 
                                            // 向浏览器发送按键状态信息  
}
 
// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){                                        // 当浏览器请求的网络资源无法在服务器找到时,
  esp8266_server.send(404, "text/plain", "404: Not found");   // NodeMCU将调用此函数。
}

 

07:34:57.800 -> Connected to yang1234
07:34:57.835 -> IP address:    192.168.31.144
07:34:57.869 -> HTTP esp8266_server started

 

在以上程序的loop函数中,pinState = digitalRead(buttonPin); 语句将不断检查NodeMCU开发板D3引脚状态,也就是检查该引脚所连接的按键是否被按下。该状态将会存储与布尔变量pinState中。

变量pinState将会用于本程序的重点1,也就是handleRoot() 函数里。在handleRoot函数里,我们利用逻辑判断语句来对displayPinState 进行赋值。如果按键没有被按下,pinState为HIGH,这时候程序将会执行displayPinState = "Button State: HIGH";也就是为displayPinState的赋值为“Button State: HIGH”。这句话的意思是“按键引脚状态为高电平”。反之,当我们按下按键后,程序将会执行displayPinState = "Button State: LOW";也就是为displayPinState的赋值为“Button State: LOW”。

在handleRoot函数的结尾处,
esp8266_server.send(200, "text/plain", displayPinState);
这条语句将会把displayPinState所存储的信息发送给浏览器。于是我们在没有按下按键时,将会得到以下页面信息。

Button State: HIGH

而当我们按下NodeMCU的Flash按键后,并且刷新页面后,会得到以下信息

Button State: LOW

方法二:5秒自动刷新

#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库
 
#define buttonPin D3            // 按钮引脚D3
 
ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'
 
ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)
 
bool pinState;                      // 存储引脚状态用变量
 
void setup(){
  Serial.begin(9600);          // 启动串口通讯
  delay(10);
  Serial.println("");
 
  pinMode(buttonPin, INPUT_PULLUP); // 将按键引脚设置为输入上拉模式
 
  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU在启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。
                                                               // 另外这里只存储了3个WiFi信息,您可以存储更多
                                                               // 的WiFi信息在此处。
  int i = 0;                                 
  while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
    delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    Serial.print(i++); Serial.print(' ');    // 将会连接信号最强的那一个WiFi信号。
  }                                          // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
                                             // 此处while循环判断是否跳出循环的条件。
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');                     // WiFi连接成功后
  Serial.print("Connected to ");            // NodeMCU将通过串口监视器输出。
  Serial.println(WiFi.SSID());              // 连接的WiFI名称
  Serial.print("IP address:\t");            // 以及
  Serial.println(WiFi.localIP());           // NodeMCU的IP地址
  
  esp8266_server.begin();                  
  esp8266_server.on("/", handleRoot);      
  esp8266_server.onNotFound(handleNotFound);        
 
  Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}
 
void loop(){
  esp8266_server.handleClient();     // 处理http服务器访问
  pinState = digitalRead(buttonPin); // 获取引脚状态
}                                                                   
 
/* 以下函数处理网站首页的访问请求。此函数为本示例程序重点1
详细讲解请参见太极创客网站《零基础入门学用物联网》
第3章-第2节“通过网络服务将开发板引脚状态显示在网页中”的说明讲解。*/    
void handleRoot() {   //处理网站目录“/”的访问请求 
  esp8266_server.send(200, "text/html", sendHTML(pinState));  
}
 
/*
建立用于发送给客户端浏览器的HTML代码。此代码将会每隔5秒刷新页面。
通过页面刷新,引脚的最新状态也会显示于页面中
*/
String sendHTML(bool buttonState){
  
  String htmlCode = "<!DOCTYPE html> <html>\n";
  htmlCode +="<head><meta http-equiv='refresh' content='5'/>\n";
  htmlCode +="<title>ESP8266 Butoon State</title>\n";
  htmlCode +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  htmlCode +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
  htmlCode +="</style>\n";
  htmlCode +="</head>\n";
  htmlCode +="<body>\n";
  htmlCode +="<h1>ESP8266 BUTTON STATE</h1>\n";
  
  if(buttonState)
    {htmlCode +="<p>Button Status: HIGH</p>\n";}
  else
    {htmlCode +="<p>Button Status: LOW</p>\n";}
    
  htmlCode +="</body>\n";
  htmlCode +="</html>\n";
  
  return htmlCode;
}
 
// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){                                        // 当浏览器请求的网络资源无法在服务器找到时,
  esp8266_server.send(404, "text/plain", "404: Not found");   // NodeMCU将调用此函数。
}

 

在以上示例程序中的handleRoot函数中,esp8266_server.send(200, "text/html", sendHTML(pinState))语句的的3个参数 sendHTML(pinState)调用了sendHTML函数。该函数的作用是建立一个可以定时刷新的HTML网页代码。通过定时刷新网页,开发板的引脚状态将会不断地在页面中进行更新。

此HTML网页代码是由sendHTML函数产生的。该函数建立了一个字符串变量,该字符串变量所存储的信息正是网页HTML代码。值得注意的是,该HTML代码会不断地检查变量pinState状态,并且根据pinState的状态改变HTML代码的信息,从而实现在网页上显示引脚状态。

此HTML代码中真正实现定时刷新网页功能的语句是代码中的第79行语句。这条语句是告诉网页需要定时刷新,刷新频率5秒钟,即每5秒钟刷新一次页面。您可以通过改变此行语句中的数值5来调整页面刷新频率。

每一次页面刷新,浏览器都会向NodeMCU发送HTTP请求。NodeMCU在收到浏览器请求后,将会把最新的HTML代码信息返回给浏览器。浏览器收到最新的HTML代码后将会在页面中显示引脚的状态。
以下是没有按下按键时的页面显示信息。

6.ESP8266 NodeMCU 闪存文件系统

ESP8266闪存文件系统基本操作

每一个ESP8266都配有一个闪存,这个闪存很像是一个小硬盘,我们上传的文件就被存放在这个闪存里。这个闪存的全称是Serial Peripheral Interface Flash File System(SPIFFS)。

除了可以存放上传的程序以外,我们还可以将网页文件或者系统配置文件存放在ESP8266的闪存中。在这节课里,我们将学习如何利用程序对闪存文件系统(SPIFFS)进行文件读取和修改。

写入之前,设置写入大小(根据需求设置),工具→Flash Size→对于大小

6.1. 通过程序向闪存文件系统写入信息
#include <FS.h>  
 
String file_name = "/taichi-maker/notes.txt"; //被读取的文件位置和名称
 
void setup() {
  Serial.begin(9600);
  Serial.println("");
  
  Serial.println("SPIFFS format start");
  SPIFFS.format();    // 格式化SPIFFS
  Serial.println("SPIFFS format finish");
  
  if(SPIFFS.begin()){ // 启动SPIFFS(返回真或假)
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
  
  File dataFile = SPIFFS.open(file_name, "w");// 建立File对象用于向SPIFFS中的file对象(即/notes.txt)写入信息
  dataFile.println("Hello IOT World.");       // 向dataFile写入字符串信息
  dataFile.close();                           // 完成文件写入后关闭文件
  Serial.println("Finished Writing data to SPIFFS");
}
 
void loop() {
}

在使用SPIFFS存储文件以前,我们必须使用#include "FS.h",如以上程序第18行所示。

程序第20行,我们建立了一个字符串变量。该变量用于存储文件位置和文件名。其中/代表根目录。/taichi-maker/代表根目录下的taichi-maker目录。notes.txt代表着文件名称。

程序第27行SPIFFS.format();是对闪存文件系统进行格式化。这很想是我们对u盘进行格式化的操作。您无需每次使用闪存文件系统都对它进行格式化操作。这里仅仅是为了演示如何使用SPIFFS.format();

程序第30行,SPIFFS.begin()用于启动闪存文件系统。在每次使用闪存文件系统以前都需要执行这一操作。如果闪存文件系统成功启动,该函数的返回值为布尔型,如果成功启动闪存文件形同,则返回真。否则将返回假。

程序第36行,File dataFile = SPIFFS.open(file_name, "w");这条语句中,open函数可用于对SPIFFS进行操作。该函数共有两个参数。第一个参数file_name是被操作的文件名称,本示例中该文件为/taichi-maker/notes.txt
第二个参数"w"代表此操作为向SPIFFS写入文件信息。请注意:如果文件系统没有/taichi-maker/notes.txt文件,此操作将会在文件系统中建立该文件。如果文件系统有该文件,则程序将会重新建立该文件,即原有文件信息将会被覆盖。

程序第37行dataFile.println("Hello IOT World.");用于向dataFile文件写入信息。信息内容为“Hello IOT World.”。

程序第38行dataFile.close();用于关闭dataFile文件。结束文件操作后,应执行此操作。

串口监视器

08:22:39.939 -> SPIFFS format finish
08:22:39.979 -> SPIFFS Started.
08:22:40.109 -> Finished Writing data to SPIFFS
08:22:40.549 -> SPIFFS format start
08:22:55.984 -> SPIFFS format finish
08:22:56.052 -> SPIFFS Started.
08:22:56.153 -> Finished Writing data to SPIFFS

ESP8266 常见固件烧写失败原因和解决方法

1.(我解决的)可能电脑hub线供电不足,别看前面写入成功,但是可能flash写不进去

更多点击访问查看

6.2. 通过程序从闪存文件系统读取信息
#include <FS.h>
 
String file_name = "/taichi-maker/notes.txt";              //被读取的文件位置和名称
 
void setup() {
  Serial.begin(9600);
  Serial.println("");
  
  if(SPIFFS.begin()){ // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
 
  //确认闪存中是否有file_name文件
  if (SPIFFS.exists(file_name)){
    Serial.print(file_name);
    Serial.println(" FOUND.");
  } else {
    Serial.print(file_name);
    Serial.print(" NOT FOUND.");
  }
 
  //建立File对象用于从SPIFFS中读取文件
  File dataFile = SPIFFS.open(file_name, "r"); 
 
  //读取文件内容并且通过串口监视器输出文件信息
  for(int i=0; i<dataFile.size(); i++){
    Serial.print((char)dataFile.read());       
  }
 
  //完成文件读取后关闭文件
  dataFile.close();                           
}
 
void loop() {
}

 

以上程序第36行,SPIFFS.exists(file_name)用于检查闪存文件系统中有file_name文件(注:file_name变量具体信息在本程序第23行)。该函数返回值为布尔型。如果文件存在则返回真,否则将返回假。

以上程序第45行,File dataFile = SPIFFS.open(file_name, "r");这条语句中,open函数可用于对SPIFFS进行操作。该函数共有两个参数。第一个参数file_name是被操作的文件名称,本示例中该文件为/taichi-maker/notes.txt
第二个参数"r"代表此操作为读取文件信息。

以上程序第48行的for循环语句中,循环条件使用了函数dataFile.size()。该函数将会返回dataFile的大小。循环语句体中,dataFile.read()将会读取dataFile文件内容。每调用一次该含税都会返回dataFile文件中一个字符。再次调用,将会返回下一个字符。以此类推,直到dataFile结尾。通过for循环语句,程序将会依次读取dataFile文件内容,并且将文件内容逐字符输出于串口监视器中。

SPIFFS Started.
/taichi-maker/notes.txt FOUND.
Hello IOT World.
6.3. 通过程序向闪存文件系统文件添加信息
 
#include <FS.h>
 
String file_name = "/taichi-maker/notes.txt";              //被读取的文件位置和名称
 
void setup() {
  Serial.begin(9600);
  Serial.println("");
  
  if(SPIFFS.begin()){ // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
 
  //确认闪存中是否有file_name文件
  if (SPIFFS.exists(file_name)){
    
    Serial.print(file_name);
    Serial.println(" FOUND.");
 
    File dataFile = SPIFFS.open(file_name, "a");// 建立File对象用于向SPIFFS中的file对象(即/notes.txt)写入信息
    dataFile.println("This is Appended Info."); // 向dataFile添加字符串信息
    dataFile.close();                           // 完成文件操作后关闭文件   
    Serial.println("Finished Appending data to SPIFFS");
    
  } else {
    Serial.print(file_name);
    Serial.print(" NOT FOUND.");
  }
                        
}
 
void loop() {
}

在以上程序的第40行里,File dataFile = SPIFFS.open(file_name, "a");这条语句中,open函数可用于对SPIFFS进行操作。该函数共有两个参数。第一个参数file_name是被操作的文件名称,第二个参数"a"代表向该文件添加信息。请留意,此处的添加信息是不会删除文件内原有信息,而是在原有信息后面添加新的信息。这与但写入操作是有所区别的。写入操作是将文件内容完全清除,重新写入新信息。
,
程序的第41行,dataFile.println("This is Appended Info."),此语句作用将会向dataFile文件尾部添加双引号中的信息内容,也就是在文件尾部添加“This is Appended Info.”。

SPIFFS Started.
/taichi-maker/notes.txt FOUND.
Hello IOT World.
This is Appended Info.
This is Appended Info.
 
为什么两行This is Appended Info.,因为第一次上传开发板后运行一遍写入,按复位键又写入一遍
6.4. 通过程序读取目录内容
#include <FS.h>
 
String file_name = "/taichi-maker/myFile.txt"; //被读取的文件位置和名称
String folder_name = "/taichi-maker";         //被读取的文件夹
 
void setup() {
  Serial.begin(9600);
  Serial.println("");
  
  if(SPIFFS.begin()){ // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
 
  File dataFile = SPIFFS.open(file_name, "w");// 建立File对象用于向SPIFFS中的file对象(即myFile.txt)写入信息
  dataFile.println("Hello Taichi-Maker.");    // 向dataFile写入字符串信息
  dataFile.close();                           // 完成文件写入后关闭文件
  Serial.println(F("Finished Writing data to SPIFFS"));
 
  // 显示目录中文件内容以及文件大小
  Dir dir = SPIFFS.openDir(folder_name);  // 建立“目录”对象
  
  while (dir.next()) {  // dir.next()用于检查目录中是否还有“下一个文件”
    Serial.println(dir.fileName()); // 输出文件名
  }
}
 
void loop() {
}

本程序第23行建立了一个字符串变量。该变量用于存储文件夹名。其中/代表根目录。/taichi-maker/代表根目录下的taichi-maker目录。

本程序第41行SPIFFS.openDir(folder_name)中的openDir函数函将返回一个“目录”对象并且赋值给dir。此”目录”对象正是folder_name所存储的/taichi-maker/目录。后续程序对dir的所有操作都是针对/taichi-maker/所执行的。

本程序第43行while循环语句的循环条件是dir.next()的返回值。dir.next()函数用于检查dir文件夹内的文件。我们可以想象dir文件夹里有一个指针,每一次调用next函数都会让指针向下挪动一格。每一次挪动一格,如果下一个位置有文件,则返回真。否则将会返回假。因此,while (dir.next())循环语句中的内容会依次显示dir文件夹中的每一个文件的文件名。

SPIFFS Started.
Finished Writing data to SPIFFS
/taichi-maker/notes.txt
/taichi-maker/myFile.txt
 

6.5. 从闪存文件系统中删除文件
#include <FS.h>
 
String file_name = "/taichi-maker/notes.txt";              //被读取的文件位置和名称
 
void setup() {
  Serial.begin(9600);
  Serial.println("");
  
  if(SPIFFS.begin()){ // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
  
  //从闪存中删除file_name文件
  if (SPIFFS.remove(file_name)){
    
    Serial.print(file_name);
    Serial.println(" remove sucess");
    
  } else {
    Serial.print(file_name);
    Serial.println(" remove fail");
  }                       
}
 
void loop() {
}

以上程序中第25行,通过使用SPIFFS.remove(file_name)file_name所指代的文件进行了删除操作。另外,SPIFFS.remove(file_name)的返回值为布尔型。如果文件删除执行成功则返回真,否则返回假。

SPIFFS Started.
/taichi-maker/notes.txt remove fail

运行后删除了,所以复位后再删除就不存在了 

6.6. 显示闪存文件系统信息
 
#include <FS.h>
 
FSInfo fs_info;
 
void setup() {
  Serial.begin(9600);
 
  SPIFFS.begin();       //启动SPIFFS
  Serial.println("");
  Serial.println("SPIFFS Started.");
 
  // 闪存文件系统信息
  SPIFFS.info(fs_info);
 
  // 可用空间总和(单位:字节)
  Serial.print("totalBytes: ");     
  Serial.print(fs_info.totalBytes); 
  Serial.println(" Bytes"); 
 
  // 已用空间(单位:字节)
  Serial.print("usedBytes: "); 
  Serial.print(fs_info.usedBytes);
  Serial.println(" Bytes"); 
 
  // 最大文件名字符限制(含路径和'\0')
  Serial.print("maxPathLength: "); 
  Serial.println(fs_info.maxPathLength);
 
  // 最多允许打开文件数量
  Serial.print("maxOpenFiles: "); 
  Serial.println(fs_info.maxOpenFiles);
 
  // 存储块大小
  Serial.print("blockSize: "); 
  Serial.println(fs_info.blockSize);
 
  // 存储页大小
  Serial.print("pageSize: ");
  Serial.println(fs_info.pageSize);
}
 
void loop() {
}

以上程序第16行语句FSInfo fs_info;建立了FSInfo 对象,用于存储闪存状态信息。

以上程序第26行语句SPIFFS.info(fs_info);。通过info函数将闪存状态信息赋给fs_info。后续的程序中,通过一系列语句将闪存状态信息通过串口监视器输出。具体信息内容可参考程序注释部分。

SPIFFS Started.
totalBytes: 1953282 Bytes
usedBytes: 502 Bytes
maxPathLength: 32
maxOpenFiles: 5
blockSize: 8192
pageSize: 256
 

关于ESP8266闪存文件系统的更多操作介绍,请参考Arduino ESP8266官方页面中的介绍部分。该页面可点击以下链接前往。

https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html

7.通过Arduino IDE向闪存文件系统上传文件

1. 下载 Arduino-ESP8266闪存文件插件程序

您有两种方法可以下载该插件程序。

第一种方法是通过点击此链接进入 Arduino-ESP8266官方GitHub页面下载

下载第一个

ESP8266FS-0.5.0.zip

解压放到Arduino文件目录(如下面形成路径,要建立tools文件夹)

"C:\Users\yys53\Documents\Arduino\tools\ESP8266FS\tool\esp8266fs.jar"

重启arduino,出现Esp8266 Sketch Date Upload表示成功

8.使用闪存文件系统建立功能更加丰富的网络服务器

8.1.在网页中加载闪存文件系统中的图片、CSS和JavaScript

测试点击下载

解压后打开文件,点击Esp8266 Sketch Date Upload上传

然后编译就可以打开ip访问网页了


#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>  

ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象

ESP8266WebServer esp8266_server(80);    // 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)

void setup() {
  Serial.begin(9600);          // 启动串口通讯
  Serial.println("");
  
  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。
  
  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。
    delay(1000);
    Serial.print(i++); Serial.print(' ');
  }
  
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IP

  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
  
  esp8266_server.onNotFound(handleUserRequet);      // 告知系统如何处理用户请求

  esp8266_server.begin();                           // 启动网站服务
  Serial.println("HTTP server started");
}

void loop(void) {
  esp8266_server.handleClient();                    // 处理用户请求
}

// 处理用户浏览器的HTTP访问
void handleUserRequet() {         
     
  // 获取用户请求网址信息
  String webAddress = esp8266_server.uri();
  
  // 通过handleFileRead函数处处理用户访问
  bool fileReadOK = handleFileRead(webAddress);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String path) {            //处理浏览器HTTP访问

  if (path.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    path = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(path);  // 获取文件类型
  
  if (SPIFFS.exists(path)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(path, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

8.2.通过网页控制ESP8266开发板的引脚

示例程序下载

请点击以上链接将本实例所用的示例程序下载并解压缩。

在本示例程序的data文件夹您将会看到一系列文件。以下是各个文件的基本介绍:

  • index.html:ESP8266开发板建立的网站首页
  • LED.html:控制LED页面

以下为该示例程序所建立的网页内容。

解压后打开文件,点击Esp8266 Sketch Date Upload上传

然后编译就可以打开ip访问网页了

#include <ESP8266WiFi.h>      // 本程序使用ESP8266WiFi库
#include <ESP8266WiFiMulti.h> // 本程序使用ESP8266WiFiMulti库
#include <ESP8266WebServer.h> // 本程序使用ESP8266WebServer库
#include <FS.h>               // 本程序使用SPIFFS库

ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'
 
ESP8266WebServer esp8266_server(80);    // 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)
                                    
void setup(){
  Serial.begin(9600);        
  Serial.println("");
  
  pinMode(LED_BUILTIN, OUTPUT);      // 初始化NodeMCU控制板载LED引脚为OUTPUT
 
  //通过addAp函数存储  WiFi名称       WiFi密码
  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。
 
  int i = 0;                                 
  while (wifiMulti.run() != WL_CONNECTED) {  // 在当前环境中搜索addAP函数所存储的WiFi
    delay(1000);                             // 如果搜到多个存储的WiFi那么NodeMCU
    Serial.print(i++); Serial.print('.');                       // 将会连接信号最强的那一个WiFi信号。
  }                                          
                                         
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');                     // WiFi连接成功后
  Serial.print("Connected to ");            // NodeMCU将通过串口监视器输出。
  Serial.println(WiFi.SSID());              // 连接的WiFI名称
  Serial.print("IP address:\t");            // 以及
  Serial.println(WiFi.localIP());           // NodeMCU的IP地址

  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
  
  esp8266_server.on("/LED-Control", handleLEDControl); // 告知系统如何处理/LED-Control请求     
  esp8266_server.onNotFound(handleUserRequest);        // 告知系统如何处理其它用户请求     
  
  esp8266_server.begin();                   // 启动网站服务                                  
  Serial.println("HTTP server started");    
}

void loop(){
  esp8266_server.handleClient();  //处理用户请求
}                                

// 处理/LED-Control请求  
void handleLEDControl(){
   bool ledStatus = digitalRead(LED_BUILTIN);     // 此变量用于储存LED状态     
   ledStatus == HIGH ? digitalWrite(LED_BUILTIN, LOW) : digitalWrite(LED_BUILTIN, HIGH);  // 点亮或者熄灭LED  
     
   esp8266_server.sendHeader("Location", "/LED.html");       
   esp8266_server.send(303);  
}
                                                                     
// 处理用户浏览器的HTTP访问
void handleUserRequest() {         
     
  // 获取用户请求资源(Request Resource)
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);
  
  // 通过handleFileRead函数处处理用户请求资源
  bool fileReadOK = handleFileRead(reqResource);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String resource) {            //处理浏览器HTTP访问

  if (resource.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    resource = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(resource);  // 获取文件类型
  
  if (SPIFFS.exists(resource)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(resource, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

8.3.通过网页文本框控制ESP8266开发板的PWM引脚

示例程序下载

请点击以上链接将本实例所用的示例程序下载并解压缩。

在本示例程序的data文件夹您将会看到一系列文件。以下是各个文件的基本介绍:

  • index.html:ESP8266开发板建立的网站首页
  • LED.html:控制LED页面

以下为该示例程序所建立的网页内容。

解压后打开文件,点击Esp8266 Sketch Date Upload上传

然后编译就可以打开ip访问网页了

31获取用户输入的1个信息 

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>  
 
ESP8266WiFiMulti wifiMulti;         // 建立ESP8266WiFiMulti对象
 
ESP8266WebServer esp8266_server(80);// 建立ESP8266WebServer对象,该对象用于响应HTTP请求。监听端口(80)

void setup(void){
  Serial.begin(9600);        
  Serial.println("");
  
  pinMode(LED_BUILTIN, OUTPUT);      // 初始化NodeMCU控制板载LED引脚为OUTPUT

  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。
  
  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。
    delay(1000);
    Serial.print(i++); Serial.print(' ');
  }
  
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IP

  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }                      
                 
  //初始化网络服务器
  esp8266_server.on("/LED-Control", handleLEDControl);   
  esp8266_server.onNotFound(handleUserRequest); // 处理其它网络请求

  // 启动网站服务
  esp8266_server.begin();
  Serial.println("HTTP server started");
}
 
void loop(void){
  esp8266_server.handleClient();  //处理网络请求
}                                
                                                                         
void handleLEDControl(){
  // 从浏览器发送的信息中获取PWM控制数值(字符串格式)
  String ledPwm = esp8266_server.arg("ledPwm"); 

  // 将字符串格式的PWM控制数值转换为整数
  int ledPwmVal = ledPwm.toInt();

  // 实施引脚PWM设置
  analogWrite(LED_BUILTIN, ledPwmVal);

  // 建立基本网页信息显示当前数值以及返回链接
  String httpBody = "Led PWM: " + ledPwm + "<p><a href=\"/LED.html\"><-LED Page</a></p>";           
  esp8266_server.send(200, "text/html", httpBody);
}

// 处理用户浏览器的HTTP访问
void handleUserRequest() {         
     
  // 获取用户请求资源(Request Resource)
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);
  
  // 通过handleFileRead函数处处理用户请求资源
  bool fileReadOK = handleFileRead(reqResource);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String resource) {            //处理浏览器HTTP访问

  if (resource.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    resource = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(resource);  // 获取文件类型
  
  if (SPIFFS.exists(resource)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(resource, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

通过本页的文本框输入0 - 1023 数值来控制ESP8266开发板的LED亮度。(数值越大led越暗,1023熄灭了)

3.2获取用户输入的多个信息

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>  
 
ESP8266WiFiMulti wifiMulti;         // 建立ESP8266WiFiMulti对象
 
ESP8266WebServer esp8266_server(80);// 建立ESP8266WebServer对象,该对象用于响应HTTP请求。监听端口(80)

void setup(void){
  Serial.begin(9600);        
  Serial.println("");
  
  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。
  
  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。
    delay(1000);
    Serial.print(i++); Serial.print(' ');
  }
  
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IP

  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }                      
                 
  //初始化网络服务器
  esp8266_server.on("/LED-Control", handleLEDControl);   
  esp8266_server.onNotFound(handleUserRequest); // 处理其它网络请求

  // 启动网站服务
  esp8266_server.begin();
  Serial.println("HTTP server started");
}
 
void loop(void){
  esp8266_server.handleClient();  //处理网络请求
}                                
                                                                         
void handleLEDControl(){
  // 从浏览器发送的信息中获取控制数值(字符串格式)
  String value1 = esp8266_server.arg("value1"); 
  String value2 = esp8266_server.arg("value2");

  // 将用户输入的信息通过串口监视器显示出来
  Serial.print("value1 = ");Serial.println(value1);
  Serial.print("value2 = ");Serial.println(value2);
  
  // 建立基本网页信息显示当前数值以及返回链接
  String httpBody = "value1: " + value1 + "<br> value2: " + value2 + "<p><a href=\"/LED.html\"><-LED Page</a></p>";           
  esp8266_server.send(200, "text/html", httpBody);
}

// 处理用户浏览器的HTTP访问
void handleUserRequest() {         
     
  // 获取用户请求资源(Request Resource)
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);
  
  // 通过handleFileRead函数处处理用户请求资源
  bool fileReadOK = handleFileRead(reqResource);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String resource) {            //处理浏览器HTTP访问

  if (resource.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    resource = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(resource);  // 获取文件类型
  
  if (SPIFFS.exists(resource)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(resource, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

8.4.(Ajax)控制LED引脚并将A0引脚读数实时显示于网页中

示例程序下载

 

请点击以上链接将本实例所用的示例程序下载并解压缩。

本示例演示如何利用Ajax来通过网页控制LED引脚以及将A0引脚读数实时显示于网页中。Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是一种创建快速动态网页应用的网页开发技术,无需重新加载整个网页的情况下,能够更新部分网页的技术。

以下为该示例程序所建立的网页内容。

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>

ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是 'wifiMulti'

ESP8266WebServer esp8266_server(80);    // 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)

void setup() {
  Serial.begin(9600);          // 启动串口通讯
  Serial.println("");

  pinMode(LED_BUILTIN, OUTPUT);   // 初始化NodeMCU控制板载LED引脚为OUTPUT
  digitalWrite(LED_BUILTIN, HIGH);// 初始化LED引脚状态
  
  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。

  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。
    delay(1000);
    Serial.print(i++); Serial.print(' ');
  }
  
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IP

  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }     
 
  esp8266_server.on("/setLED", handleLED);
  esp8266_server.on("/readADC", handleADC);  
  
  esp8266_server.onNotFound(handleUserRequest); // 处理其它网络请求

  // 启动网站服务
  esp8266_server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  esp8266_server.handleClient();
}


void handleLED() {
 String ledState = "OFF";
 String LED_State = esp8266_server.arg("LEDstate"); //参考xhttp.open("GET", "setLED?LEDstate="+led, true);
 Serial.println(LED_State);
 
 if(LED_State == "1"){
  digitalWrite(LED_BUILTIN,LOW); //LED 点亮
  ledState = "ON"; //反馈参数
 } else {
  digitalWrite(LED_BUILTIN,HIGH); //LED 熄灭
  ledState = "OFF"; //反馈参数
 }
 
 esp8266_server.send(200, "text/plain", ledState); //发送网页
}

void handleADC() {
 int a = analogRead(A0);
 String adcValue = String(a);
 
 esp8266_server.send(200, "text/plain", adcValue); //发送模拟输入引脚到客户端ajax请求
}
 
// 处理用户浏览器的HTTP访问
void handleUserRequest() {         
     
  // 获取用户请求资源(Request Resource)
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);
  
  // 通过handleFileRead函数处处理用户请求资源
  bool fileReadOK = handleFileRead(reqResource);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String resource) {            //处理浏览器HTTP访问

  if (resource.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    resource = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(resource);  // 获取文件类型
  
  if (SPIFFS.exists(resource)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(resource, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

8.5 (JavaScript)通过网页图形界面控制ESP8266的PWM引脚

示例程序下载

 

请点击以上链接将本实例所用的示例程序下载并解压缩。

本示例演示如何利用JavaScript来通过网页建立控制LED引脚的图形界面。

以下为该示例程序所建立的网页内容。


#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>  

ESP8266WiFiMulti wifiMulti;         // 建立ESP8266WiFiMulti对象

ESP8266WebServer esp8266_server(80);// 建立esp8266网站服务器对象

void setup() {
  Serial.begin(9600);        
  Serial.println("");
    
  pinMode(LED_BUILTIN, OUTPUT);     // 设置开发板内置LED引脚为输出模式

  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。

  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。
    delay(1000);
    Serial.print(i++); Serial.print(' ');
  }
  
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IP

  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
  
  //初始化网络服务器
  esp8266_server.on("/setLED",handlePWM); // 处理PWM设置请求
  esp8266_server.onNotFound(handleUserRequest); // 处理网络请求

  // 启动网站服务
  esp8266_server.begin();
  Serial.println("HTTP server started");
}

void loop() {
 esp8266_server.handleClient();   // 处理客户端请求
}

// 处理PWM设置请求并对引脚进行PWM设置
void handlePWM(){
  String pwmStr = esp8266_server.arg("pwm"); // 获取用户请求中的PWM数值
  Serial.print("pwmStr = ");Serial.println(pwmStr);
  
  int pwmVal = pwmStr.toInt();              // 将用户请求中的PWM数值转换为整数
  pwmVal = 1023 - map(pwmVal,0,100,0,1023); // 用户请求数值为0-100,转为0-1023
  Serial.print("pwmVal = ");Serial.println(pwmVal);
  
  analogWrite(LED_BUILTIN, pwmVal);         // 实现PWM引脚设置
  esp8266_server.send(200, "text/plain");//向客户端发送200响应信息
}

// 处理用户浏览器的HTTP访问
void handleUserRequest() {         
     
  // 获取用户请求资源(Request Resource)
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);
  
  // 通过handleFileRead函数处处理用户请求资源
  bool fileReadOK = handleFileRead(reqResource);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String resource) {            //处理浏览器HTTP访问

  if (resource.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    resource = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(resource);  // 获取文件类型
  
  if (SPIFFS.exists(resource)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(resource, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

以下旋钮可控制ESP8266开发板LED亮度

8.6(JavaScript)使用指针表显示模拟输入引脚数值

 

示例程序-1下载

示例程序-2下载

 

请点击以上链接将本实例所用的示例程序下载并解压缩。

本示例演示如何利用JavaScript来通过指针表形式显示模拟输入引脚读数。本实例一共有两个示例程序。这两个示例程序功能相同,只有指针表样式不同。

以下为示例程序-1所建立的网页内容。

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>  

ESP8266WiFiMulti wifiMulti;         // 建立ESP8266WiFiMulti对象

ESP8266WebServer esp8266_server(80);// 建立esp8266网站服务器对象
 
void setup() {
  Serial.begin(9600);        
  Serial.println("");

  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");

  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。
    delay(1000);
    Serial.print(i++); Serial.print(' ');
  }

  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP()); 
 
  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
  
  //初始化网络服务器
//  esp8266_server.on("/",handleRoot);      // 处理首页请求
  esp8266_server.on("/getADC",handleADC); //Reads ADC function is called from out index.html
  esp8266_server.onNotFound(handleUserRequest); // 处理网络请求
  
  // 启动网站服务
  esp8266_server.begin();
  Serial.println("HTTP server started");
}
 
void loop() {
 esp8266_server.handleClient();
}

void handleADC(){
  int a = analogRead(A0);
  a = map(a,0,1023,0,100);
  String adc = String(a);
  Serial.println(adc);
  esp8266_server.send(200, "text/plain",adc);
}
/*
void handleRoot(){
  esp8266_server.sendHeader("Location", "/index.html", true);   
  esp8266_server.send(302, "text/plain","");
}
*/

// 处理用户浏览器的HTTP访问
void handleUserRequest() {         
     
  // 获取用户请求资源(Request Resource)
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);
  
  // 通过handleFileRead函数处处理用户请求资源
  bool fileReadOK = handleFileRead(reqResource);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String resource) {            //处理浏览器HTTP访问

  if (resource.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    resource = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(resource);  // 获取文件类型
  
  if (SPIFFS.exists(resource)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(resource, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

8.7通过网页将文件上传到ESP8266开发板闪存文件系统

 

示例程序下载

 

请点击以上链接将本实例所用的示例程序下载并解压缩。

在本示例程序的data文件夹里,您将会看到一系列文件。以下是各个文件的基本介绍:

  • index.html:ESP8266开发板建立的网站首页
  • upload.html:文件上传页面
  • success.html:文件成功上传页面

以下为该示例程序所建立的网页内容。

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>  

ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是 'wifiMulti'

ESP8266WebServer esp8266_server(80);    // 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)      

File fsUploadFile;              // 建立文件对象用于闪存文件上传

void setup() {
  Serial.begin(9600);        
  Serial.println("");

  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。

  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。
    delay(1000);
    Serial.print(i++); Serial.print('.');
  }
  
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IP
          
  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
  
  esp8266_server.on("/upload.html",   // 如果客户端通过upload页面
                    HTTP_POST,        // 向服务器发送文件(请求方法POST)
                    respondOK,        // 则回复状态码 200 给客户端
                    handleFileUpload);// 并且运行处理文件上传函数

  esp8266_server.onNotFound(handleUserRequest);

  esp8266_server.begin();                           // 启动网站服务
  Serial.println("HTTP server started");
}

void loop() {
  esp8266_server.handleClient();
}

// 处理上传文件函数
void handleFileUpload(){  
  
  HTTPUpload& upload = esp8266_server.upload();
  
  if(upload.status == UPLOAD_FILE_START){                     // 如果上传状态为UPLOAD_FILE_START
    
    String filename = upload.filename;                        // 建立字符串变量用于存放上传文件名
    if(!filename.startsWith("/")) filename = "/" + filename;  // 为上传文件名前加上"/"
    Serial.println("File Name: " + filename);                 // 通过串口监视器输出上传文件的名称

    fsUploadFile = SPIFFS.open(filename, "w");            // 在SPIFFS中建立文件用于写入用户上传的文件数据
    
  } else if(upload.status == UPLOAD_FILE_WRITE){          // 如果上传状态为UPLOAD_FILE_WRITE      
    
    if(fsUploadFile)
      fsUploadFile.write(upload.buf, upload.currentSize); // 向SPIFFS文件写入浏览器发来的文件数据
      
  } else if(upload.status == UPLOAD_FILE_END){            // 如果上传状态为UPLOAD_FILE_END 
    if(fsUploadFile) {                                    // 如果文件成功建立
      fsUploadFile.close();                               // 将文件关闭
      Serial.println(" Size: "+ upload.totalSize);        // 通过串口监视器输出文件大小
      esp8266_server.sendHeader("Location","/success.html");  // 将浏览器跳转到/success.html(成功上传页面)
      esp8266_server.send(303);                               // 发送相应代码303(重定向到新页面) 
    } else {                                              // 如果文件未能成功建立
      Serial.println("File upload failed");               // 通过串口监视器输出报错信息
      esp8266_server.send(500, "text/plain", "500: couldn't create file"); // 向浏览器发送相应代码500(服务器错误)
    }    
  }
}

//回复状态码 200 给客户端
void respondOK(){
  esp8266_server.send(200);
}

// 处理用户浏览器的HTTP访问
void handleUserRequest(){
                              
  // 获取用户请求网址信息
  String webAddress = esp8266_server.uri();
  
  // 通过handleFileRead函数处处理用户访问
  bool fileReadOK = handleFileRead(webAddress);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String path) {            //处理浏览器HTTP访问

  if (path.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    path = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(path);  // 获取文件类型
  
  if (SPIFFS.exists(path)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(path, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}