零基础入门学用物联网(ESP8266) 第一部分 基础知识篇(三)

参考教程:https://www.bilibili.com/video/BV1L7411c7jw/?spm_id_from=333.1387.favlist.content.click

六、ESP8266闪存文件系统应用

1、在网页中加载闪存文件系统中的文件

(1)程序流程示意图:

(2)下载至开发板的代码:

cpp 复制代码
#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("Zevalin_Computer", "00114514");
  wifiMulti.addAP("Zevalin_esp8266", "00114514");
  Serial.println("Connecting ...");
  
  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) {
    delay(1000);
    Serial.print(i++); Serial.print(' ');
  }
  
  Serial.println('\n');
  Serial.print("Connected to "); Serial.println(WiFi.SSID());
  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.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";
}

streamFile函数是ESP8266WebServer库中一个非常重要且高效的方法,它的核心作用是直接将一个文件(例如闪存中的文件)以流式(streaming)的方式作为HTTP响应的正文发送给客户端(比如浏览器),它有两个参数:第一个是已打开的File对象引用,指向想要发送的文件;第二个是一个字符串,指定了文件的MIME类型,告诉浏览器如何解析这个文件(例如,"text/html" 表示网页,"image/jpeg" 表示JPEG图片)

(3)闪存系统中的文件(文件的编写非本教程重点,具体可在前端相关教程中了解):

①taichi-maker.jpg文件(在根目录下的img文件夹中):

②clock.js文件(在根目录中):

javascript 复制代码
/**
 *  动态显示当前时间
 */
function showDateTime(){
    var sWeek=new Array("日","一","二","三","四","五","六");  //声明数组存储一周七天
    var myDate=new Date(); //获取当天日期
    var sYear=myDate.getFullYear(); //获取年
    var sMonth=myDate.getMonth()+1; //获取月
    var sDate=myDate.getDate(); //获取日
    var sDay=sWeek[myDate.getDay()]; //根据得到的数字星期,利用数组转化为星期
    var h=myDate.getHours(); //获取小时
    var m=myDate.getMinutes(); //获取分钟
    var s=myDate.getSeconds(); //获取秒
    //输入日期和星期
    document.getElementById("date").innerHTML=(sYear+"年"+sMonth+"月"+sDate+"日"+"星期"+sDay+"<br/>");
    h = formatTwoDigits(h);  //格式化小时,如果不足两位在前面补0
    m = formatTwoDigits(m); //格式化分钟,如果不足两位在前面补0
    s = formatTwoDigits(s); //格式化秒钟后,如果不足两位在前面补0
    //显示时间
    document.getElementById("msg").innerHTML=(h+":"+m+":"+s+"<br/>");
    setTimeout("showDateTime()",1000);//每秒执行一次showDateTime函数
}
window.onload=showDateTime;//在整个页面加载完成后执行此函数
//如果输入数是一位数,则在十位上补0
function formatTwoDigits(s) {
    if (s<10)
        return "0"+s;
    else
        return s;
}

③JavaScript.js文件(在根目录中):

javascript 复制代码
setTimeout(function() {
    let jsParagraph = document.createElement("p");
    jsParagraph.textContent = "Hello from JavaScript.js!";
    document.body.appendChild(jsParagraph);
}, 1000);

④main.css文件(在根目录中):

css 复制代码
body {
    font-family: sans-serif;
    color: #444;
}

p.red {
    color: red;
}

⑤index.html文件(在根目录中):

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="main.css">
    <title>太极创客-零基础入门学用物联网教程</title>
    <script type="text/javascript" src="clock.js"></script>
</head>
<body>
    <center>
    <a href="http://www.taichi-maker.com" target="_black"><img src="/img/taichi-maker.jpg" alt="太极创客"></a>
    <h1>ESP8266 SPIFFS web server示例</h1>
    <p>此页面用于演示如何通过ESP8266开发板的SPIFFS中读取文件并显示于浏览器中。</p>
    <p>本教程可在太极创客网站免费获取。太极创客网址: <a href="http://www.taichi-maker.com" target="_black">www.taichi-maker.com</a> .
    <p class="red">创建页面时可以使用css。这里的字体是红色,原因是使用了css。</p>

    <!--显示时钟-->
    <h3>页面支持JavaScript,以下时钟/日期使用JavaScript实现。</h3>
    <h1 id="date"></h1>
    <span id="msg" style="font-size: 30px;background-color: greenyellow;"></span>
    </center>
</body>
</html>

2、通过网页控制ESP8266开发板引脚的输出电平

(1)程序流程示意图:

(2)下载至开发板的代码:

cpp 复制代码
#include <ESP8266WiFi.h>      // 本程序使用ESP8266WiFi库
#include <ESP8266WiFiMulti.h> // 本程序使用ESP8266WiFiMulti库
#include <ESP8266WebServer.h> // 本程序使用ESP8266WebServer库
#include <FS.h>               // 本程序使用SPIFFS库

ESP8266WiFiMulti wifiMulti; 
ESP8266WebServer esp8266_server(80);
                                    
void setup(){
  Serial.begin(9600);        
  Serial.println("");
  
  pinMode(LED_BUILTIN, OUTPUT);      // 初始化NodeMCU控制板载LED引脚为OUTPUT
 
  wifiMulti.addAP("Zevalin_Computer", "00114514");
  wifiMulti.addAP("Zevalin_esp8266", "00114514");
  Serial.println("Connecting ..."); 
 
  int i = 0;                                 
  while (wifiMulti.run() != WL_CONNECTED){
    delay(1000);               
    Serial.print(i++); Serial.print('.');
  }                                          
                                         
  Serial.println('\n');    
  Serial.print("Connected to ");  Serial.println(WiFi.SSID()); 
  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("/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";
}

(3)闪存系统中的文件(文件的编写非本教程重点,具体可在前端相关教程中了解):

①taichi-maker.jpg文件(在根目录下的img文件夹中):

②index.html文件(在根目录中):

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>太极创客-零基础入门学用物联网教程</title>
</head>
<body>
    <center>
    <a href="http://www.taichi-maker.com" target="_blank"><img src="/img/taichi-maker.jpg" alt="太极创客"></a>
    <h1>ESP8266 LED 引脚控制</h1>
    <p><a href="LED.html">前往LED控制页面</a></p>
    <p>此页面用于演示如何通过网页按钮来控制ESP8266开发板引脚。</p>
    <p>本教程可在太极创客网站免费获取。太极创客网址: <a href="http://www.taichi-maker.com" target="_blank">www.taichi-maker.com</a> 
    </center>
</body>

</html>

③LED.html文件(在根目录中):

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
   <meta charset="UTF-8">
   <title>太极创客-零基础入门学用物联网教程</title>
</head> 
<body>
   <center>
   <a href="http://www.taichi-maker.com" target="_blank"><img src="/img/taichi-maker.jpg" alt="太极创客"></a>
   <h1>LED引脚控制</h1>
   <p>通过以下按键,您可以控制ESP8266开发板上的内置LED引脚</p>
   <form action="LED-Control"><input type="submit" value="LED控制">
   </form>
   <br>
   <form action="index.html"><input type="submit" value="返回首页">
   </form>
      <p>此页面用于演示如何通过网页按钮来控制ESP8266开发板引脚。</p>
    <p>本教程可在太极创客网站免费获取。太极创客网址: <a href="http://www.taichi-maker.com" target="_black">www.taichi-maker.com</a> 
   </center>
</body>

</html>

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

(1)程序流程示意图:

(2)下载至开发板的代码:

cpp 复制代码
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>  
 
ESP8266WiFiMulti wifiMulti;
ESP8266WebServer esp8266_server(80);

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

  wifiMulti.addAP("Zevalin_Computer", "00114514");
  wifiMulti.addAP("Zevalin_esp8266", "00114514");
  Serial.println("Connecting ..."); 
 
  int i = 0;                                 
  while (wifiMulti.run() != WL_CONNECTED){
    delay(1000);               
    Serial.print(i++); Serial.print('.');
  }                                          
                                         
  Serial.println('\n');    
  Serial.print("Connected to ");  Serial.println(WiFi.SSID()); 
  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("/LED-Control", handleLEDControl); // 告知系统如何处理/LED-Control请求 
  esp8266_server.onNotFound(handleUserRequest);        // 告知系统如何处理其它用户请求

  // 启动网站服务
  esp8266_server.begin();
  Serial.println("HTTP server started");
}
 
void loop(void){
  esp8266_server.handleClient();  //处理网络请求
}                                
                                                                         
void handleLEDControl(){
  String ledPwm = esp8266_server.arg("ledPwm");   // 从浏览器发送的信息中获取PWM控制数值(字符串格式)
  int ledPwmVal = ledPwm.toInt();                 // 将字符串格式的PWM控制数值转换为整数
  analogWrite(LED_BUILTIN, ledPwmVal);            // 设置引脚PWM输出值

  // 建立基本网页信息显示当前数值以及返回链接
  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"); 
  }
}

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

  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";
}

①arg函数是ESP8266WebServer库中用来获取客户端通过HTTP请求(GET/POST)传递过来的参数值的核心方法,函数参数为需要从请求中获取参数的参数名。

②用户在浏览器访问某个地址时,"?"后面就是参数列表,格式为"<参数名1>=参数值1&<参数名2>=参数值2......"。比如当用户在浏览器访问"http://192.168.1.100/?name=John\&age=30"这个地址时,调用"server.arg("name")"就会返回"John",调用"server.arg("age")"就会返回"30"。

③arg函数通常会和另外两个函数配合使用:

|---------------------|-------------------|
| 函数 | 作用 |
| server.args() | 获取本次请求中参数的总数量 |
| server.hasArg(name) | 判断请求中是否包含某个特定的参数名 |

(3)闪存系统中的文件(文件的编写非本教程重点,具体可在前端相关教程中了解):

①taichi-maker.jpg文件(在根目录下的img文件夹中):

②index.html文件(在根目录中):

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>太极创客-零基础入门学用物联网教程</title>
</head>
<body>
    <center>
    <a href="http://www.taichi-maker.com" target="_blank"><img src="/img/taichi-maker.jpg" alt="太极创客"></a>
    <p><a href="/LED.html">前往PWM控制页面</a></p>
    <p>此示例用于演示如何通过ESP8266开发板的文本输入控制PWM引脚。</p>
    <p>本教程可在太极创客网站免费获取。太极创客网址: <a href="http://www.taichi-maker.com" target="_blank">www.taichi-maker.com</a> 
    </center>
</body>

</html>

③LED.html文件(在根目录中):

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>太极创客-零基础入门学用物联网教程</title>
</head>
<body>
    <center>
    <a href="http://www.taichi-maker.com" target="_blank"><img src="/img/taichi-maker.jpg" alt="太极创客"></a>
    <form action="/LED-Control">
        <input type="text" name="ledPwm">
        </br>
        <input type="submit" value="OK">
    </form>
    <p>通过本页的文本框输入0 - 1023 数值来控制ESP8266开发板的LED亮度。</p>
    <p>本教程可在太极创客网站免费获取。太极创客网址: <a href="http://www.taichi-maker.com" target="_blank">www.taichi-maker.com</a> 
    </center>
</body>

</html>
相关推荐
weixin_460783872 小时前
STM32CubeMX配置ST25R3911B外设指南
stm32·单片机·嵌入式硬件
学嵌入式的小杨同学2 小时前
STM32 进阶封神之路(十八):RTC 实战全攻略 —— 时间设置 + 秒中断 + 串口更新 + 闹钟功能(库函数 + 代码落地)
c++·stm32·单片机·嵌入式硬件·mcu·架构·硬件架构
学嵌入式的小杨同学2 小时前
STM32 进阶封神之路(十七):RTC 实时时钟深度解析 —— 从时钟源到寄存器配置(底层原理 + 面试重点)
c++·stm32·单片机·嵌入式硬件·mcu·硬件架构·pcb
炸膛坦客3 小时前
单片机/C语言八股:(十四)const 关键字的作用(和 define 比呢?)
c语言·单片机
进击的横打3 小时前
【车载开发系列】TAU定时器
单片机·嵌入式硬件
我爱我家8823 小时前
亚洲艺术电影节携澳门文化亮相深圳
人工智能·物联网·算法·区块链·爬山算法
我是海飞3 小时前
TinyUSB 移植到 STM32F407实现Audio+Midi+Cdc复合设备
stm32·单片机·嵌入式硬件
物联通信量讯说3 小时前
从5G迈向未来通信时代,量讯物联深耕连接基础能力
物联网·5g·信息与通信·iot·通信·6g·量讯物联
’长谷深风‘3 小时前
51单片机入门
c语言·单片机·嵌入式硬件·51单片机