学习太极创客 — ESP8226 (一)

1、固件烧写 / 程序下载的硬件电路连接说明

ESP-12F

在这里插入图片描述
也就是说,下载程序或烧写固件时,需要

1、 VCC-3.3V
2、 GND-GND
3、 RXD-TXD
4、 TXD-RXD
5、 GPIO0-GND
6、 GPIO15 经过10K电阻接 GND
7、 CH_PD(EN)经过10K电阻接 3.3V
(GPIO12在实际使用时,没有用到,保持悬空)

下载好程序后,测试程序时,只需要将 GPIO0 断开(悬空),其他引脚不变。

ESP-01

参考链接: https://blog.csdn.net/qq_44078824/article/details/116650482

2、NodeMCU-12F版本开发板的 WiFi 模组

在这里插入图片描述

2.1 应用电路图

(这个图是 ESP8266 Node MCU -12E的图,可能与 ESP-12F 有出入)
在这里插入图片描述

3、ESP8266-NodeMCU网络服务器

3.1 建立基本网络服务器

http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-server/web-server/

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

http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-server/pin-control/

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

http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-server/pin-state/

/*
建立用于发送给客户端浏览器的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;
}

将该部分代码写在 HTML文本中,
在这里插入图片描述
说明:
1、
在这里插入图片描述
2、
在这里插入图片描述
是当前网页的标题,而不是页面的内容,
在这里插入图片描述
该网页的 CSS 层叠样式表属于内部式,(因为写在< head >…< /head > 中的)。

页面内容的显示是在 < body > …< /body >中设置的。
在这里插入图片描述
注意事项:

在这里,我们采用定义一个字符串,然后使用字符串叠加的方式来一点点将 HEML文件存储在该字符串变量中,但是使用字符串的这种方法,尽管能够实现基本功能,但是对于页面和功能复杂的网页来说,就是存储的字符串将会占用到整个程序的存储空间,如果字符串特别的大,那么程序的存储单元就会存不下,所以使用字符串的这种方法只能够实现基本的、简单的网页。

3、ESP8266 的闪存文件系统

在这里插入图片描述
在这里插入图片描述

3.1 ESP8266闪存文件系统基本操作

代码来源:http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/spiffs/spiffs-operation/

/**********************************************************************
项目名称/Project           : 零基础入门学用物联网
程序名称/Program name      : esp8266-flash-write
团队/Team                 : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author               : CYNO 朔 
日期/Date(YYYYMMDD)      : 20191109
程序目的/Purpose           : 此程序用于演示如何向NodeMCU的SPIFFS中建立名为
                            notes.txt的文件,程序还将向该文件写入信息。
-----------------------------------------------------------------------
函数说明:
SPIFFS.open(file_name, "w"); 
以上函数有两个参数:
第一个参数是被操作的文件名称,本示例中该文件为/notes.txt
第二个参数"w" 代表写入文件信息。(如需了解如何读取信息,请参阅示例程序esp8266-flash-read)
***********************************************************************/
 
 
#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() {
    
    
}

在编译上传程序之前,还要做一步非常重要的操作,即针对开发板的闪存文件系统做一个简单的设置。
在这里插入图片描述
通过这四个选项,我们可以设置程序即将使用多大的闪存文件系统。如果不用的话,就选中第四个,告诉 IDE 不使用闪存文件系统。

在本程序中,只是建立非常简单的一句话,所以选中第 3 个,1MB 就足够用了(选中其他的容量也可以)。

如果没有设置正确的话,闪存文件系统就会启动失败,会通过串口输出报错信息。

在编译代码完成后,
在这里插入图片描述
在上传代码时,从 IDE下方的信息也可以看出来,
在这里插入图片描述
IDE自动检测出开发板的闪存文件系统为 4 MB 。

程序运行结果如下,
在这里插入图片描述

那如何来读取我们写入的文件呢?

3.2 通过程序从闪存文件系统读取信息

/**********************************************************************
项目名称/Project           : 零基础入门学用物联网
程序名称/Program name      : esp8266-flash-read
团队/Team                 : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author               : CYNO 朔
日期/Date(YYYYMMDD)      : 20191109
程序目的/Purpose           : 此程序用于演示如何从NodeMCU的内置SPIFFS中存储的文件notes.txt读取数据。
                           notes.txt 文件内容将会通过串口监视器显示出来供用户确认。
                           注意在使用本程序以前需要先将notes.txt 文件上传到NodeMCU开发板的SPIFFS中
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date    作者/Author      参考号/Ref    修订说明/Revision Description
-----------------------------------------------------------------------
函数说明:
SPIFFS.open(file_name, "r"); 
以上SPIFFS函数有两个参数:
第一个参数是被操作的文件名称,本示例中该文件为/notes.txt
第二个参数"r" 代表读取文件信息。(如需了解如何写入信息,请参阅示例程序esp8266-flash-write)
***********************************************************************/
 
#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() {
    
    
}

代码说明,
在这里插入图片描述
程序运行结果如下,
在这里插入图片描述

3.3 通过程序给闪存文件系统中已经存在的文件添加信息

/**********************************************************************
项目名称/Project           : 零基础入门学用物联网
程序名称/Program name      : esp8266-flash-append
团队/Team                 : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author               : CYNO 朔 
日期/Date(YYYYMMDD)      : 20191109
程序目的/Purpose           : 此程序用于演示如何向NodeMCU的内置SPIFFS中存储的文件
                            notes.txt添加数据。                      
-----------------------------------------------------------------------  
函数说明:
SPIFFS.open(file_name, "a"); 
以上SPIFFS函数有两个参数:
第一个参数是被操作的文件名称,本示例中该文件为/notes.txt
第二个参数"a" 代表添加文件信息。(如需了解如何读取信息,请参阅示例程序esp8266-flash-read)
此示例程序所演示的是向SPIFFS中的文件里添加信息。这一操作写入信息有所区别。
添加信息是不会删除文件内原有信息,而是在原有信息后面添加新的信息。
但写入操作(示例 esp8266-flash-write.ino)是将文件内容完全清除,重新写入新信息。    
***********************************************************************/
 
#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() {
    
    
}

在这里插入图片描述
再来重复上一步读取该文件内容,看看结果。
在这里插入图片描述

3.4 通过程序读取目录内容

/**********************************************************************
项目名称/Project           : 零基础入门学用物联网
程序名称/Program name      : esp8266-flash-folder-read
团队/Team                 : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author               : CYNO 朔
日期/Date(YYYYMMDD)      : 20191109
程序目的/Purpose           : 此程序用于演示如何从NodeMCU的内置SPIFFS中文件夹里读取文件信息
                           文件夹内容将会通过串口监视器显示出来。
                           
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date    作者/Author      参考号/Ref    修订说明/Revision Description
-----------------------------------------------------------------------
函数说明:
SPIFFS.openDir(folder_name);
以上函数打开指定目录并返回一个目录对象实例。
***********************************************************************/

#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() {
    
    
}

关于程序中 dir.next() 函数的说明,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行结果如下,
在这里插入图片描述

3.5 从闪存文件系统中删除文件

/**********************************************************************
项目名称/Project           : 零基础入门学用物联网
程序名称/Program name      : esp8266-flash-remove
团队/Team                 : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author               : CYNO 朔 
日期/Date(YYYYMMDD)      : 20191109
程序目的/Purpose           : 此程序用于演示如何删除SPIFFS中存储的文件                        
***********************************************************************/
 
#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() {
    
    
}

在这里插入图片描述
运行结果如下,
在这里插入图片描述

3.6 从闪存文件系统中删除文件

/**********************************************************************
项目名称/Project           : 零基础入门学用物联网
程序名称/Program name      : esp8266-flash-info
团队/Team                 : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author               : CYNO 朔
日期/Date(YYYYMMDD)      : 20200204
程序目的/Purpose           : 此程序用于演示如何使用FSInfo对象来显示闪存文件系统状态
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date    作者/Author      参考号/Ref    修订说明/Revision Description
***********************************************************************/
 
 
#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() {
    
    
}

运行结果如下,
在这里插入图片描述
最后,
在这里插入图片描述
链接如下: https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html

4、通过 Arduino IDE 向闪存文件系统上传文件

4.1、安装并下载插件

链接: https://www.bilibili.com/video/BV1L7411c7jw?p=8&spm_id_from=pageDriver

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

链接: http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/spiffs/spiffs-web-server/load-imagecsss-javascript/

4.2.1 向闪存文件系统上传文件

下载并解压后的文件夹及内容(需要将 data 文件夹与 工程文件放在同一目录下。)
在这里插入图片描述
打开 data 文件夹
在这里插入图片描述
上传 data 文件夹中的内容。这些内容全都会被上传到开发板的根目录下。

在这里插入图片描述
(根据自己要上传的文件大小进行选择)

4.2.2 向开发板下载程序

修改下面程序的WiFi 的设置,然后下载下面的程序

/**********************************************************************
项目名称/Project          : 零基础入门学用物联网
程序名称/Program name     : 3_4_1_SPIFFS_File_server
团队/Team                : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author              : CYNO朔
日期/Date(YYYYMMDD)     : 20191109
程序目的/Purpose          : 
当用户访问NodeMCU地址时,NodeMCU将会检查访问地址是否指向SPIFFS系统中的文件,并且
将该文件显示于用户的浏览器中。如果访问地址所指向的文件无法在SPIFFS中找到,NodeMCU将会
向用户发送404信息。
-----------------------------------------------------------------------
修订历史/Revision History  
日期/Date    作者/Author      参考号/Ref    修订说明/Revision Description
20200211     CYNO朔            0.01       修改了handleNotFound函数使其更直观
-----------------------------------------------------------------------
本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/
***********************************************************************/

#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("FAST_153C80", "123456798"); // 将需要连接的一系列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";
}

打开串口监视器,
在这里插入图片描述
打开浏览器,并输入 ip 地址。
在这里插入图片描述
再来分析下代码,
在这里插入图片描述
这里的 String webAddress 是用来存储用户通过浏览器向服务器所请求资源的名称,这些资源名称是通过 esp8266_server.uri();这个库函数获取到的。这个资源名称是在服务器(这里即开发板)后台运行的,无法直观的查看,所以通过串口来输出出来,即 上面串口监视器图中的红框中的结果。

所请求的结果通过浏览器展现出来,如上面的网页截图所示,可以发现有图片、文字等信息,那这些信息又是如何来建立起来的呢?都是通过我们上传到闪存文件系统中的文件建立来的。

需要注意的是,红框中信息并不是一上电就会输出出来的,而是在我们在浏览器中输入所要请求服务器的 ip 地址之后(输入 回车 之后),才会打印出来。

这里的请求资源都有哪些呢?(红框中的资源名称都是什么含义呢?)
在这里插入图片描述
在这里插入图片描述
handleFileRead 的作用是从开发板的闪存文件系统中读取文件资源。
在这里插入图片描述
参数 path 是一个字符串,path.endsWith 是用来判断 path 这个字符串是不是以 “/” 结尾的,这个 “/” 对我们的服务器来说有两层含义,首先对于我们服务器所建立的网站来说,“/” 所代表的是请求网站的首页信息。第二层含义是服务器的闪存文件系统的根目录,而 /index.html 所代表的就是这个服务器根目录下有一个文件叫做 index.html。

4.3、通过网页控制ESP8266开发板的引脚

1、上传 data 文件夹中的文件,
在这里插入图片描述
2、代码如下,

/**********************************************************************
项目名称/Project          : 零基础入门学用物联网
程序名称/Program name     : 3_4_2_SPIFFS_Pin_Control_Server
团队/Team                : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author              : CYNO朔
日期/Date(YYYYMMDD)     : 20191109
程序目的/Purpose          : 
使用ESP8266-NodeMCU建立一个有多个页面的网站。在LED页面中配有可控制LED点亮和熄灭的
按钮。点击首页的LED Page链接进入LED页。点击LED页按钮将控制NodeMCU的内置LED点亮和熄灭。

-----------------------------------------------------------------------
修订历史/Revision History  
日期/Date    作者/Author      参考号/Ref    修订说明/Revision Description
20200211     CYNO朔            0.01       修改了handleNotFound函数使其更直观
20200217     CYNO朔            0.02       一致性调整
-----------------------------------------------------------------------
本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/
***********************************************************************/

#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("FAST_153C80", "123456798"); // 将需要连接的一系列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";
}

( 板载 LED 接的是 GPIO2 )

3,编译上传后,将 IO 0 引脚悬空,打开串口监视器,运行结果如下。

在这里插入图片描述

4,打开浏览器,

在这里插入图片描述
在这里插入图片描述
运行之后,可以发现,每按下一次按键,网页都会被重新刷新一次。

说明,
在这里插入图片描述
由182.168.2.93/LED.html 可以得知,该页面在根目录下的 LED.html 建立起来的。我们可以将 该文件在电脑上通过 Notepad++ 这个软件打开。
在这里插入图片描述
下面,来分析程序。重点是下面这些程序。
在这里插入图片描述
需要注意的是,程序中的 LED-Control 的前面为什么要加上 “/” ,而在上面的网页源代码中并没有加上,这是什么原因呢?

需要注意的是,这个网页是通过闪存文件系统中的根目录下的 LED.html 所实现的。每当我们按下这个按键后,实际上是向当前的目录即根目录下,来发送一个请求。自然而然的,在请求信息的前面加上路径,也就是根目录下。

而网页源代码中的 LED-Control 是要发送的请求名,所以不需要加。
在这里插入图片描述
303 是 http 代码,表示跳转,跳转到上一行代码中给出的目标位置,这也是每按下一次按钮,网页就会刷新的原因所在。

初始时,LED引脚默认输出为低电平,即 GPIO2 = 0 ,所以一上电,LED是亮的。

猜你喜欢

转载自blog.csdn.net/xuechanba/article/details/125049586
今日推荐