ESP8266(mini D1)实现网络服务器Server 用到的硬件概念分析扩展 API调用总结

0x00 项目指北

要实现网络Server要利用好8266的两个功能SPIFFS合webServer,实现效果如下

一.SPIFFS闪存系统

1.什么叫SPIFFS? SPIFFS可以拆开成两部分来理解,一是SPI 二是FFS(文件系统)。 SPI 是 Serial Peripheral Interface 鉴于你是个爱学英语的小可爱,我告诉你第二个单词这么读 [pəˈrɪf(ə)rəl] “福瑞福若”,是外部设备的意思。所以SPI就是串行外设接口。

百度百科:

“SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,越来越多的芯片集成了这种通信协议,比如AT91RM9200。”

挺好奇的,查了一下啊,啥叫全双工,就是像柏油马路一样,双向同行就是全双工,单行道就是单工。 ​

Github跟进

不够深入,我在github上查了一下,它是github上一位叫pellepl的工程师在2013年编写的一个文件系统

Introduction是这么写的:

Spiffs is a file system intended for SPI NOR flash devices on embedded targets. Spiffs is designed with following characteristics in mind:

  • Small (embedded) targets, sparse RAM without heap

  • Only big areas of data (blocks) can be erased

  • An erase will reset all bits in block to ones

  • Writing pulls one to zeroes

  • Zeroes can only be pulled to ones by erase

  • Wear leveling

意思是:

Spiffs是一个专门为基于SPI Nor flash储存架构的嵌入式设备开发的文件系统。

SPIFFS被设计用于以下几种特点:

1.用于小型嵌入式设备,不需要堆(heap)

2.只有大范围的数据块才能被擦除

3.擦除数据将把block位全部置1

4.写的操作会把1变成0

5.0只能被擦除成

6.损耗均衡

同时他也介绍了Features特性:

FEATURES

What spiffs does:

  • Specifically designed for low ram usage

  • Uses statically sized ram buffers, independent of number of files

  • Posix-like api: open, close, read, write, seek, stat, etc

  • It can run on any NOR flash, not only SPI flash - theoretically also on embedded flash of a microprocessor

  • Multiple spiffs configurations can run on same target - and even on same SPI flash device

  • Implements static wear leveling

  • Built in file system consistency checks

  • Highly configurable

What spiffs does not:

  • Presently, spiffs does not support directories. It produces a flat structure. Creating a file with path tmp/myfile.txt will create a file called tmp/myfile.txt instead of a myfile.txt under directory tmp.

  • It is not a realtime stack. One write operation might last much longer than another.

  • Poor scalability. Spiffs is intended for small memory devices - the normal sizes for SPI flashes. Going beyond ~128Mbyte is probably a bad idea. This is a side effect of the design goal to use as little ram as possible.

  • Presently, it does not detect or handle bad blocks.

  • One configuration, one binary. There's no generic spiffs binary that handles all types of configurations.

意思是:

spiffs能干什么?

1.专门为小ram(小运存)使用而设计

2.使用静态大小的ram缓冲区,与文件大小无关

3.POSIX(Portable Operating System Interface,统一UNIX-like 的OS对外的接口)提供操作系统接口,如打开,关闭,读,写,查找,统计,等。

4.可以在任何NOR闪存运行,不仅仅是SPI flash理论上也可以在微处理器上运行

5.多个SPIFFS配置可以在相同目标上运行,甚至可以在相同SPI flash闪存设备上运行

6.flash寿命维护

7.内置文件系统一致性检查

8.高度可配置

SPIFFS不能做什么:

1、目前,spiffs不支持目录。它产生一个平面结构。使用路径tmp/myfile.txt创建文件将创建一个名为tmp/myfile.txt的文件,而不是在tmp目录下创建一个名为myfile.txt的文件。

2、它不是一个实时堆栈。一个写操作的持续时间可能比另一个长得多。

3、可怜的可伸缩性。Spiffs适用于小型内存设备——SPI flash的正常大小。超过~128Mbyte就不推荐了。由于设计目标是用尽可能少的ram,所以这是设计目标的一个副作用。

4、目前,它不能检测或处理坏块。

5、一个配置,一个二进制。没有通用的spiffs二进制可以处理所有类型的配置。

关于SPI Nor flash架构:由存储单元,行列控制单元,接口转换单元组成

总结:

所以,简单来说,这是一个简易的文件系统,可以面向任何闪存。最初考虑到大部分处理器的RAM资源有限,于是使用少量RAM设计了这样一个文件系统。同时,由于用的RAM比较少,导致它不能处理大于128MB的flash。 ​

扁平化结构,不支持目录。举例,在电脑中,假设我在C盘某路径有一个文件:C:\flexIm\hello.txt,而使用SPIFFS的话,只能创建一个名字为C:\flexIm\hello的txt格式的文件。它还有一个优点,就是考虑到了flash的寿命问题,因此做了算法均匀使用flash中的每一个block。

二.WebServer

webServer就是ESP8266WebServer库及相关功能组成的

0x01 SPIFFS API

<FS.h> 文件操作很重要,对于web来说,访问资源调用SPIFFS是必须的!

基本操作(含文件)

SPIFFS.format()

格式化SPIFFS

Bool

SPIFFS.begin()

启动SPIFFS

File

SPIFFS.open(file_name,"w")

打开文件并执行第二个参数(这里是写入)

dataFile.println("")

向被打开的dataFile写入信息

dataFile.close()

文件操作结束后必须执行

SPIFFS.info((FSInfo)fs_info)

向fs_info写入info,仍需print出具体要看哪类info,api不展示了就

目录操作

BoolSPIFFS.exists(file_name)检查文件系统中有无此文件,有则返回True
numdataFile.size()返回当前打开的文件大小
DirSPIFFS.openDIR(folder_name)创建目录
Booldir.next()检查是否有下一个文件 dir指向下一个文件,函数返回True
BoolSPIFFS.remove(file_name)删除文件

0x02 通过Arduino IDE向SPIFFS系统上传文件

请确保已经完成了以下准备工作qwq:

  1. 将NodeMCU开发板与电脑通过USB数据线连接好

  2. NodeMCU开发板驱动已经安装完毕

  3. 设置Arduino IDE以使其支持NodeMCU开发板


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

通过这个链接进行下载 https://github.com/esp8266/arduino-esp8266fs-plugin/releases

二.确定项目文件夹位置并粘贴文件

通过 ArduinoIDE ---> 文件 ---> 首选项 --->项目文件夹位置 在项目位置建立新文件夹"tools"然后把下载好的文件解压,直接丢过去 然后重新启动ArduinoIDE 如何确定安装成功了呢? 在工具 ---> 若有ESP8266 Sketch Data upload 则安装完毕了 上传 然后在项目文件夹下创建data文件夹,将文件直接拖进去就好

0x03 Connection API

<ESP8266WiFiMulti.h>

AP Mode:

AP麻,就是 Access Point 由自身成为WiFi,使别的设备可以连接

WiFi.softAP(ssid,password)启动ap模式,ssid是wifi名字
WiFi.softAPIP()获得NodeMCU的内网地址

Station Mode:

即无线终端模式,纯粹的wifi收发

WiFi.status()获取当前wifi连接状态
WL_CONNECTED

Auto Multi Connection:

机智的你会发现,一次只能链接一个wifi有点不太符合我们的日常使用逻辑,所以我们希望能够在一个库中保存许多wifi,然后自动选取信号最强的或者可以建立有效链接的进行connect,于是我们用到了ESP8266WiFiMutil.h这个库。 所以,这个库只适用于AP mode哦!

对象

ESP8266WiFiMulti wifiMulti

建立ESP8266WiFiMulti对象 然后可以使用对象的众多方法来实现功能

wifiMulti.addAP("ssid"."passwd")

给链接库里面添加wifi

bool

wifiMulti.run()

搜索当前链接库信号最强的wifi

连接成功则返回WL_CONNECTED

while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前注意哦!!!为了实现在连接前持续搜索的效果,我们需要持续循环判断wifi是否链接,比如可以这样子写

    delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    Serial.print('.');                       // 将会连接信号最强的那一个WiFi信号。
  }   

others:

<ESP8266WiFi.h>

WiFi.mode(mode)调整ESP8266工作模式为无线终端模式(如WIFI_STA)
WiFi.begin(ssid,password)开始链接wifi
WiFi.SSID()AP mode下查看当前连接的wifi名称
WiFi.localIP()查看NodeMCU当前的IP地址

0x04 Server API

<ESP8266WebServer>

对象

ESP8266WebServer esp8266_server(port)

建立webServer对象 参数为打开的端口 根据协议标准,一般打开80端口

esp8266_server.begin();

让ESP8266-NodeMCU来启动网络服务功能

esp8266_server.on("pos",func);

指挥NodeMCU来如何处理浏览器的http请求,pos是访问位置('/'代表首页),func是访问对应页面执行函数

esp8266_server.onNotFound(func)

若无此页面则调用func处理404访问

esp8266_server.handleClient();

检查有没有设备通过网络向NodeMCU发送请求

(因此我们需要把它放在loop函数中,从而确保它能经常被调用。假如我们的loop函数里有类似delay一类的函数延迟程序运行,那么这时候就一定要注意了,如果handleClient函数长时间得不到调用,NodeMCU的网络服务会变得很不稳定。因此在使用NodeMCU执行网络服务功能的时候,一定要确保handleClient函数经常得以调用。我在这里反复强调这一点是因为这一点非常关键,请务必注意!)

esp8266_server.send(index,"type","text")

生成并且发送http响应信息,param1:状态码,param2:说明http响应体信息类型,parma3:具体内容(最好放在具体esp8266_Server.on对应执行函数里面,来实现“响应头”的效果)

esp8266_server.sendHeader(headerName, headerValue, first);

用于向响应头信息中添加自定义键值对。

parma1:自定义响应头的名称,可以使用字符串类型

parma2:自定义响应头的值,可使用字符串类型

parma3:设置该响应头是否需要放在第一行,缺省则为false(参数为bool)

esp8266_server.send(index)

向浏览器发送状态码

content-type要注意哦!!! 1.实现持续处理Client的访问响应,需要将handleClient放在loop函数中运行 而begin和on等配置型函数,在setup中使用。 2.!!!!.send函数很重要,尤其是TYPE!!!因为不同type代表了告诉client怎么处理网络字节流

常见格式如下:

  • text/html : HTML格式

  • text/plain :纯文本格式

  • text/xml : XML格式

  • image/gif :gif图片格式

  • image/jpeg :jpg图片格式

  • image/png:png图片格式

application开头的媒体类型:

  • application/xhtml+xml :XHTML格式

  • application/xml: XML数据格式

  • application/atom+xml :Atom XML聚合格式

  • application/json: JSON数据格式

  • application/pdf:pdf格式

  • application/msword : Word文档格式

  • application/octet-stream : 二进制流数据(如常见的文件下载)

  • application/x-www-form-urlencoded : <form encType="">中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)

更多API如下:

0x05 Client API

其实这个项目是不需要用到Client API哒!刚好学到这里了,就大概见一下吧! 如果不想了解可以直接跳过 你可能会疑惑,我8266是Server为啥要Client API呢,因为我8266不光可以作为Server,还可以作为Client,类似浏览器干的事情,主动去访问一个别的Server,并解析他的响应。


ESP8266HTTPClient库

特征:简单易用,但是不灵活,封装好了底层内容,不够自由

HTTPClient httpClient

要声明HTTPClient类型对象才能操作哦!!!

httpClient.begin(URL,[port]);

begin函数来配置请求地址,param2为默认80

int

httpClient.GET()

通过get函数启动链接并发送http请求 返回状态码

int

httpClient.POST(payload,[size])

此函数用于ESP8266使用HTTP协议通过Server向服务器发送请求

parma1:通过post请求发送的数据信息,可使用字符串

parma2:通过post请求发送字节数(size_t)

Sting

httpClient.getString()

getString函数获得服务器响应体内容

httpClient.end()

关闭esp8266与服务器的链接 此函数来清除ESP8266的接收缓存以便设备再次接收服务器发来的响应信息。

void httpClientRequest(){}注意!!!! 发送HTTP请求并将服务器响应通过串口输出最好用一个函数来写,且函数必须写在loop里面,然后再setup函数启用时调用!!!

WiFiClient库

boolclient.connect(host, httpport)与Server连接,host是网址httpport是端口号 Success则True
boolclient.connected()检查当前服务器的连接情况 Connected则True
boolclient.available()检查Server是否发来信息 有则True注意,最好写两层abaliable函数,服务器响应有延迟
Stringclient.readStringUntil('\n')将服务器响应信息逐行分解为字符串
client.print(request)向Server发送封装好的请求,request是String串

同上一个库发送HTTP请求并将服务器响应通过串口输出最好用一个函数来写,且函数必须写在loop里面,然后再setup函数启用时调用!!!void httpClientRequest(){} ​

readStringUntil函数的实现利用了Stream 数据流概念,下面我们一起探索一下Stream

Stream & Stream API

直白来讲,就是一列有先后顺序的数据

boolSerial.avilable()判断开发板是否收到数据一般在loop函数下写相关功能的实现!!
Serial.println()将Stream串口数据输出在串口监视器中

还有很多api,暂不赘述啦!

0x06 最后几步

相信到这里,你已经利用插件在SPIFFS上传好了html文件,最后我们要做的就是将SPIFFS文件读取与webServer.on函数练习起来,我们都知道,每一个url都是一个资源,当我们在web标签调用图片之类的资源,也相当于发了一次request和response,所以我们需要给每一个url设置.on函数......确实有点麻烦。那么上代码吧。

#include <ESP8266WiFi.h>        // 本程序使用ESP8266WiFi库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库
#include <FS.h>
ESP8266WebServer Server(80);
​
const char *ssid = "LiuJiahuan Test Web Server"; // 这里定义将要建立的WiFi名称。此处以""为示例
                                   // 您可以将自己想要建立的WiFi名称填写入此处的双引号中
 
const char *password = "12345678";  // 这里定义将要建立的WiFi密码。此处以12345678为示例
                                    // 您可以将自己想要使用的WiFi密码放入引号内
                                    // 如果建立的WiFi不要密码,则在双引号内不要填入任何信息
 
void setup() {
  Serial.begin(9600);              // 启动串口通讯
  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }
  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地址
  Server.begin();
  Server.on("/",handleRoot);
  Server.on("/test.jpeg", handlePhoto);
}
 
void loop() { 
   Server.handleClient();
}
​
void handleRoot() {   //处理网站根目录“/”的访问请求 
  File dataFile = SPIFFS.open("/index.html", "r"); 
  String rp;
  for(int i = 0; i < dataFile.size(); i++){
    rp += (char)dataFile.read();       
  }
  Server.send(200, "text/html", rp); 
  dataFile.close();
}
​
void handlePhoto(){
  File dataFile = SPIFFS.open("/test.jpeg", "r");
  String pt;
  for(int i = 0; i < dataFile.size(); i++){
    pt += (char)dataFile.read();       
  }
  Server.send(200, "image/jpeg", pt); 
  dataFile.close();
}

我给SPIFFS放了个index.html和test.jpeg 非常easy的小demo!!!给你们宿舍也做个小网站吧hhhhhh!!!做内网穿透以后更好玩了

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiujiaHuan13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值