• Arduino之ESP8266编程学习总结体会


    前言

            由于课程设计,在最近学习了Arduino,以ESP8266开发板进行为核心学习。Arduino编程相比stm32,由于Arduino是一个开源的平台,有许许多多很完善的第三方库。对于大对数的传感器,只需要使用对应的第三方库就能很简单的使用传感器,语法很简单很容易。而且其编程语法为C++,对于编程开发人员来说是十分友好。总而言之,对于学习过C++语言的的开发人员来说,只要掌握基本的软硬件知识,上手是十分简单的。

            由于给我上课的外教,我英语属实不太行,我只能网上找视频学了。少年,好好学英语吧。

    一、ESP8266-物联网开发基础

    1.1 Arduino IDE安装

            前往Arduino’官网下载对应系统版本即可。傻瓜式安装,安装后语言会自动设置为电脑语言。

    1.2 安装 ESP8266-NodeMCU开发板驱动

           NodeMCU开发板不是即插即用的设备,因此我们需要安装驱动才能使用。

            驱动芯片制造商官网下载,选择版本傻瓜式安装即可。

            检查安装是否成功

            1 将ESP8266-NodeMCU开发板与电脑连接

            2 打开“设备管理器”

             3 查看NodeMCU开发板连接端口

            如下图所示,”Silicon Labs CP210x USB to UART Bridge” 后面所显示的COM端口号就是NodeMCU开发板的端口号了。在下图中,NodeMCU连接的端口号是COM5。请务必记住此端口号码,后续设置工作中还需要用到这一信息。同时也请注意,您的电脑里所显示的COM端口号与下图显示的会有所不同。请牢记您电脑中的NodeMCU所连接的COM端口号。

    1.3 为ESP8266-NodeMCU搭建Arduino IDE开发环境

            准备工作
            在安装以前,请确保您已完成以下准备工作:
            1. 使用USB数据线将NodeMCU开发板与电脑连接好
            2. NodeMCU驱动程序已成功安装安装,您已可以在电脑“设备管理器”中查到NodeMCU连接电脑端口号。
            3. 电脑已经连接互联网
            4. 您已经在电脑里安装好Arduino IDE

            打开Arduino IDE 首选项

            在Arduino IDE的“首选项”对话框中找到“附加开发板管理网址”

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

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

             打开Arduino IDE的“开发板管理器”

            在“开发板管理器”的搜索栏中输入“esp8266”
            这一步需要您的电脑从互联网下载资料,所以请确保您的电脑已经连上了互联网。

            开始安装“esp8266开发板”插件文件 

             请注意:由于网络环境,很多朋友在下载ESP8266的Arduino IDE开发插件时出现了无法下载的情况。如果是这样,请点击此处下载插件安装文件(提取码:49c1),并运行该文件即可完成Arduino IDE配置。您接下来就可以使用Arduino IDE来开发ESP8266-NodeMCU开发板了。还有一种办法,科学上网。

            成功安装“esp8266开发板”插件文件

            在Arduino IDE的开发板菜单中找到“NodeMCU开发板” 

            设置Arduino IDE的NodeMCU开发板端口 

            打开Blink示例程序 

            将Blink示例程序编译上传给NodeMCU 

            确认NodeMCU开发板上LED开始闪烁 

            程序上传完毕,如果看到NodeMCU开发板上的LED开始闪烁就说明驱动程序已经成功安装了。

    1.4 NodeMCU开发板的接入点模式

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

            通过以下示例程序,NodeMCU将会建立一个名为phh的WiFI。您可以使用手机或电脑连接该WiFi从而实现与NodeMCU的网络通讯。

    1. /*
    2. NodeMCU接入点模式
    3. 此程序用于演示如何将NodeMCU以接入点模式工作。通过此程序,您可以使用
    4. 电脑或者手机连接NodeMCU所建立WiFi网络。
    5. 网络名: phh
    6. 密码:12345678
    7. */
    8. #include <ESP8266WiFi.h> // 本程序使用ESP8266WiFi库
    9. const char *ssid = "phh"; // 这里定义将要建立的WiFi名称。此处以"phh"为示例
    10. // 您可以将自己想要建立的WiFi名称填写入此处的双引号中
    11. const char *password = "12345678"; // 这里定义将要建立的WiFi密码。此处以12345678为示例
    12. // 您可以将自己想要使用的WiFi密码放入引号内
    13. // 如果建立的WiFi不要密码,则在双引号内不要填入任何信息
    14. void setup() {
    15. Serial.begin(9600); // 启动串口通讯
    16. WiFi.softAP(ssid, password); // 此语句是重点。WiFi.softAP用于启动NodeMCU的AP模式。
    17. // 括号中有两个参数,ssid是WiFi名。password是WiFi密码。
    18. // 这两个参数具体内容在setup函数之前的位置进行定义。
    19. Serial.print("Access Point: "); // 通过串口监视器输出信息
    20. Serial.println(ssid); // 告知用户NodeMCU所建立的WiFi名
    21. Serial.print("IP address: "); // 以及NodeMCU的IP地址
    22. Serial.println(WiFi.softAPIP()); // 通过调用WiFi.softAPIP()可以得到NodeMCU的IP地址
    23. }
    24. void loop() {
    25. }

            NodeMCU所建立的WiFi名称是”phh”。“phh”只是示例WiFi名,您也可以通过修改源代码中的const char *ssid = "phh";语句来改变WiFi名称。

            假如您想要修改WiFi密码,可以修改const char *password = "12345678";语句。

    1.5 NodeMCU开发板的无线终端模式

            无线终端模式(Station)

            1. 连接WiFI

            如下图所示,ESP8266可通过WiFi连接无线路由器。这与用您的手机通过WiFi连接无线路由器的模式相同。(注意连接的WiFi必须是2.4)     

              以下示例程序用于演示如何使用NodeMCU以无线终端模式通过WiFi连接无线路由器。

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

            2. 自动连接最强信号WiFi网络  

            假如我们的NodeMCU只在一个地方使用,它也就只需要知道一个WiFi网络的连接信息。但是如果NodeMCU需要在多个地方使用,这时候就需要它能存储多个地点的WiFi信息。通过以下示例程序,NodeMCU可以在它所处的网络环境里搜索预先存储好的WiFi。一旦找到预存的WiFi名称,NodeMCU将会使用预存的密码信息尝试连接该WiFi。如果同时找到多个预存WiFi,NodeMCU将会尝试连接信号最强的WiFi。

            以下这段示例程序将会实现这一功能。

    1. /*
    2. NodeMCU无线终端模式连接WiFi-2
    3. */
    4. #include <ESP8266WiFi.h> // 本程序使用ESP8266WiFi库
    5. #include <ESP8266WiFiMulti.h> // 本程序使用ESP8266WiFiMulti库
    6. ESP8266WiFiMulti wifiMulti; // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'
    7. void setup() {
    8. Serial.begin(9600); // 启动串口通讯
    9. //通过addAp函数存储 WiFi名称 WiFi密码
    10. wifiMulti.addAP("phh", "12345678"); // 这三条语句通过调用函数addAP来记录3个不同的WiFi网络信息。
    11. wifiMulti.addAP("phh2", "87654321");
    12. wifiMulti.addAP("phh3", "13572468"); // 这3个网络的密码分别是123456789,87654321,13572468。
    13. // 此处WiFi信息只是示例,请在使用时将需要连接的WiFi信息填入相应位置。
    14. // 另外这里只存储了3个WiFi信息,您可以存储更多的WiFi信息在此处。
    15. Serial.println("Connecting ..."); // 通过串口监视器输出信息告知用户NodeMCU正在尝试连接WiFi
    16. int i = 0;
    17. while (wifiMulti.run() != WL_CONNECTED) { // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
    18. delay(1000); // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    19. Serial.print('.'); // 将会连接信号最强的那一个WiFi信号。
    20. } // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
    21. // 此处while循环判断是否跳出循环的条件。
    22. Serial.println('\n'); // WiFi连接成功后
    23. Serial.print("Connected to "); // NodeMCU将通过串口监视器输出。
    24. Serial.println(WiFi.SSID()); // 连接的WiFI名称
    25. Serial.print("IP address:\t"); // 以及
    26. Serial.println(WiFi.localIP()); // NodeMCU的IP地址
    27. }
    28. void loop() {
    29. }

    二、ESP8266-NodeMCU网络服务器

    2.1 建立基本网络服务器 

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

            网络服务是一个很宽泛的概念,这里即将介绍的是网络服务中的网页服务功能。所谓网页服务就是专门用于网页浏览的服务。

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

            假如这个网站只有您自己访问,那么ESP8266-NodeMCU就足够了。下面这个示例程序可以让ESP8266-NodeMCU实现最基本的网页服务功能。请先将这段示例程序复制并且上传NodeMCU。

    1. #include <ESP8266WiFi.h> // 本程序使用 ESP8266WiFi库
    2. #include <ESP8266WiFiMulti.h> // ESP8266WiFiMulti库
    3. #include <ESP8266WebServer.h> // ESP8266WebServer库
    4. ESP8266WiFiMulti wifiMulti; // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'
    5. ESP8266WebServer esp8266_server(80);// 建立ESP8266WebServer对象,对象名称为esp8266_server
    6. // 括号中的数字是网路服务器响应http请求的端口号
    7. // 网络服务器标准http端口号为80,因此这里使用80为端口号
    8. void setup(void){
    9. Serial.begin(9600); // 启动串口通讯
    10. //通过addAp函数存储 WiFi名称 WiFi密码
    11. wifiMulti.addAP("WiFi-name", "12345678"); // 这三条语句通过调用函数addAP来记录3个不同的WiFi网络信息。
    12. wifiMulti.addAP("WiFi-name2", "87654321"); // 这3个WiFi网络名称分别是WiFi-name, WiFi-name2, WiFi-name3。
    13. wifiMulti.addAP("WiFi-name3", "13572468"); // 这3个网络的密码分别是123456789,87654321,13572468。
    14. // 此处WiFi信息只是示例,请在使用时将需要连接的WiFi信息填入相应位置。
    15. // 另外这里只存储了3个WiFi信息,您可以存储更多的WiFi信息在此处。
    16. int i = 0;
    17. while (wifiMulti.run() != WL_CONNECTED) { // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
    18. delay(1000); // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    19. Serial.print(i++); Serial.print(' '); // 将会连接信号最强的那一个WiFi信号。
    20. } // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
    21. // 此处while循环判断是否跳出循环的条件。
    22. // WiFi连接成功后将通过串口监视器输出连接成功信息
    23. Serial.println('\n'); // WiFi连接成功后
    24. Serial.print("Connected to "); // NodeMCU将通过串口监视器输出。
    25. Serial.println(WiFi.SSID()); // 连接的WiFI名称
    26. Serial.print("IP address:\t"); // 以及
    27. Serial.println(WiFi.localIP()); // NodeMCU的IP地址
    28. //--------"启动网络服务功能"程序部分开始-------- //
    29. esp8266_server.begin();
    30. esp8266_server.on("/", handleRoot);
    31. esp8266_server.onNotFound(handleNotFound);
    32. //--------"启动网络服务功能"程序部分结束--------
    33. Serial.println("HTTP esp8266_server started");// 告知用户ESP8266网络服务功能已经启动
    34. }
    35. void loop(void){
    36. esp8266_server.handleClient(); // 处理http服务器访问
    37. }
    38. void handleRoot() { //处理网站根目录“/”的访问请求
    39. esp8266_server.send(200, "text/plain", "Hello from ESP8266"); // NodeMCU将调用此函数。
    40. }
    41. // 设置处理404情况的函数'handleNotFound'
    42. void handleNotFound(){ // 当浏览器请求的网络资源无法在服务器找到时,
    43. esp8266_server.send(404, "text/plain", "404: Not found"); // NodeMCU将调用此函数。
    44. }

             当您把这段示例程序上传给NodeMCU以后,请启动NodeMCU并且确保它已经成功连接WiFi。接下来请打开浏览器,并且在地址栏中输入NodeMCU的IP地址并按下回车。假如将在浏览器中看到“Hello from ESP8266”(如下所示),那么恭喜您已经成功的让NodeMCU实现了网络服务功能,因为您所看到的这条文字信息正是来自于NodeMCU。换句话说,NodeMCU为您建立了一个超级迷你的小网站。这个网站只有一个网页。这个网页只有一行文字“Hello from ESP8266”。

            接下来,请您回过头看一下我们刚上传给NodeMCU的程序内容。在后续的教程内容里,我将着重讲解该程序中几段关键性语句。对于其它程序内容,我已尽量在程序的注释部分加入了丰富的解释信息。这些内容在本教程之前的课程中已经进行了详细讲解,因此就不在这里赘述了。        

            如下所示,我首先要对”启动网络服务功能”程序部分进行详细讲解,这也是整个示例程序的第1个重点内容。

    1. esp8266_server.begin();
    2. esp8266_server.on("/", handleRoot);
    3. esp8266_server.onNotFound(handleNotFound);

            程序第一句esp8266_server.begin()使用了ESP8266WebServer库中的begin函数。这个函数的作用是让ESP8266-NodeMCU来启动网络服务功能。该函数无需任何参数。

            接下来的的语句esp8266_server.on("/", handleRoot)相对复杂一些。这条语句调用了ESP8266WebServer库中的on函数,该函数的作用是指挥NodeMCU来如何处理浏览器的http请求。我们看到on函数一共有两个参数,第一个参数是字符串”/”,第二个参数是一个函数的名称handleRoot。这个handleRoot函数的具体内容,我后面会给您做详细讲解。现在请您留意on函数有两个参数,一个是字符串”/”,另一个是函数名handleRoot。

            下面我来给您仔细解释一下参数”/”的作用。我们知道一个网站有很多页面。为了加以区分,这些页面都有各自的名称。对于刚刚您在浏览器看到的“Hello from ESP8266”这个页面是NodeMCU服务器中的网站首页。这个网站首页的名称正是”/”。目前的ESP8266-NodeMCU服务器中只有一页,因此我们还无法了解如果想要调用其他页面该如何操作。不过请别担心,这个操作我们会在下一个示例程序中为您讲解。

            好了,现在请将您的思绪拉回到我们的NodeMCU程序中来。接下来我们来看on函数的第二个参数。这个参数是handleRoot函数的名字。handlRoot函数的主要作用是告诉NodeMCU该如何生成和发送网站首页给浏览器。不过关于这个handleRoot函数的具体内容,我会在接下来的教程中给您做详细讲解。现在我们需要把关注点集中在on函数上。

            最后我们再来完整的看一下这条语句esp8266_server.on("/", handleRoot)。它的作用就是告诉NodeMCU,当有浏览器请求网站首页时,请执行handlRoot函数来生成网站首页内容然后发送给浏览器。

            讲到这里不知道您会不会感到好奇。我们只是在浏览器地址栏输入了NodeMCU的IP地址,然后就按下了回车。浏览器怎么会知道我们需要的是网站的首页呢。这是浏览器约定俗成的一种操作方法。当我们在地址栏只输入IP地址而没有任何附加地址信息,浏览器就会知道我们是要获取一个网站的首页信息。

            结束了on函数的讲解,我们来继续往下看。下面一条语句esp8266_server.onNotFound(handleNotFound)使用了onNotFound函数。它的作用是指挥NodeMCU在收到无法满足的http请求时应该如何处理。目前Hello from ESP8266网站只有一个页面。假如有人想要浏览网站的其它页面,NodeMCU是无法满足这一请求的。这时候我们可以让NodeMCU答复一个“错误提示”页面给提出请求的浏览器。onNotFound函数就是用来告诉NodeMCU如果出现无法满足的http请求时该如何进行处理。onNotFound函数有一个参数,这个参数的内容是函数handleNotFound的名字。

            假设现在我们通过浏览器向NodeMCU服务器请求一个名叫“LED”的页面。由于NodeMCU的程序里没有“LED”页面信息,因此需要给浏览器答复一个“错误提示”页面。onNotFound的作用就是告诉NodeMCU在遇到这种无法满足的http请求时,应该执行handleNotFound函数来生成并发送“错误提示”页面给浏览器。

            为了验证这一功能,我们来做一个实验。请在浏览器中输入NodMCU的IP地址然后加一个“/LED”再回车。比如下图所示,我的NodeMCU的IP地址是192.168.0.109,那么当我在浏览器栏中输入192.168.0.109/LED然后回车,就会看到浏览器显示出文字404: Not found。

            这里我们所看到的这行文字“404: Not found”正是因为NodeMCU没有名叫“LED”的页面,因此它会使用handleNotFound函数生成并发送给浏览器这个“错误提示”页面。既然讲到这里了,那么我们就来仔细看一看handleNotFound函数的具体内容。 

    1. void handleNotFound(){
    2. esp8266_server.send(404, "text/plain", "404: Not found");
    3. }

            handleNotFound函数只有一条语句: esp8266_server.send(404, "text/plain", "404: Not found")。这条语句调用了ESP8266WebServer库中的send函数。该函数的作用是生成并且发送http响应信息。也就是说,电脑浏览器所收到的网页信息都是通过send函数生成并且发送的。那么具体这个网页信息是如何生成的呢?这就要仔细看看send函数的几个参数内容了。

            首先我们来看第一个参数404。404是一个服务器状态码。它的含义是“客户端的请求有错误”。也就是说,浏览器在收到了状态码404后就知道,它所请求的页面在服务器上是不存在的。请留意,这个服务器状态码是专门给浏览器用的。我们是看不到它的。为了让我们也看到页面不存在的出错信息,send函数的最后一个参数使用了一个字符串”404: Not found”。这个字符串的内容才是真正显示在浏览器中供我们阅读的内容。你可以任意的改变这个字符串的内容。

            到这里我们来小结一下。浏览器能够看懂的信息是send函数的第一个参数,它的类型是整数型,它的内容是数字404。而显示在浏览器中的出错信息是一个字符串型的参数。它是send函数的最后一个参数。在我们的示例程序里,它的内容是“404: Not found”。

            send函数还有一个字符串参数“text/plain”。它的作用是说明http响应体的信息类型。在这段示例中,我们用“text/plain”的原因是要告诉浏览器后面的”404: Not found”为一段纯文本信息。这里当然也可以使用其它类型的信息。

            为了让您更好的理解刚刚给您解释的内容,我来对这句esp8266_server.send(404, "text/plain", "404: Not found")做一下总结。

            send函数一共有3个参数。第一个参数404是服务器状态码。第二个参数“text/plain”是说明http响应体信息类型。第三个参数“404: Not found”则是响应体的具体信息了。

            细心的读者可能已经发现了。我在上面这段总结文字中指明了响应体这一概念。http响应是分为两部分的。第一部分是响应头,在我们这个示例中,响应头的内容就是404 text/plain。而响应体的内容则是404: Not found。

            结束了handleNotFound的讲解我们最后再来看看示例程序中另一个用于生成和发送首页信息的函数:handleRoot

    1. void handleRoot() {
    2. esp8266_server.send(200, "text/plain", "Hello from ESP8266");
    3. }

            这段示例程序与刚刚我们见到的handleNotFound函数非常相似。都是使用send函数生成并且发送http响应信息。

            send函数的第一个参数200,它同样是一个服务器状态码,含义是“成功接收请求,并已完成整个处理过程”。 第二个参数text/plain的作用我刚刚给您讲过,不再赘述了。最后一个参数”Hello from ESP8266″正是我们在浏览器中看到的首页文字内容。

            最后我们来看一下这段示例程序的第3个重点内容,也就是loop函数中唯一的一条语句esp8266_server.handleClient()。这句程序调用了handleClient函数。它的主要作用之一是检查有没有设备通过网络向NodeMCU发送请求。函数handleClient每次被调用时,NodeMCU都会检查一下是否有人发送http请求。因此我们需要把它放在loop函数中,从而确保它能经常被调用。假如我们的loop函数里有类似delay一类的函数延迟程序运行,那么这时候就一定要注意了。如果handleClient函数长时间得不到调用,NodeMCU的网络服务会变得很不稳定。因此在使用NodeMCU执行网络服务功能的时候,一定要确保handleClient函数经常得以调用。我在这里反复强调这一点是因为这一点非常关键,请务必注意!

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

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

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

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

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

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

            以下是第一段示例代码: 

    1. #include <ESP8266WiFi.h> // 本程序使用 ESP8266WiFi库
    2. #include <ESP8266WiFiMulti.h> // ESP8266WiFiMulti库
    3. #include <ESP8266WebServer.h> // ESP8266WebServer库
    4. #define buttonPin D3 // 按钮引脚D3
    5. ESP8266WiFiMulti wifiMulti; // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'
    6. ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)
    7. bool pinState; // 存储引脚状态用变量
    8. void setup(){
    9. Serial.begin(9600); // 启动串口通讯
    10. pinMode(buttonPin, INPUT_PULLUP); // 将按键引脚设置为输入上拉模式
    11. wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1"); // 将需要连接的一系列WiFi ID和密码输入这里
    12. wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
    13. wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
    14. Serial.println("Connecting ..."); // 则尝试使用此处存储的密码进行连接。
    15. int i = 0;
    16. while (wifiMulti.run() != WL_CONNECTED) { // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
    17. delay(1000); // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    18. Serial.print(i++); Serial.print(' '); // 将会连接信号最强的那一个WiFi信号。
    19. } // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
    20. // 此处while循环判断是否跳出循环的条件。
    21. // WiFi连接成功后将通过串口监视器输出连接成功信息
    22. Serial.println('\n'); // WiFi连接成功后
    23. Serial.print("Connected to "); // NodeMCU将通过串口监视器输出。
    24. Serial.println(WiFi.SSID()); // 连接的WiFI名称
    25. Serial.print("IP address:\t"); // 以及
    26. Serial.println(WiFi.localIP()); // NodeMCU的IP地址
    27. esp8266_server.begin(); // 启动网站服务
    28. esp8266_server.on("/", handleRoot); // 设置服务器根目录即'/'的函数'handleRoot'
    29. esp8266_server.onNotFound(handleNotFound);// 设置处理404情况的函数'handleNotFound'
    30. Serial.println("HTTP esp8266_server started");// 告知用户ESP8266网络服务功能已经启动
    31. }
    32. void loop(){
    33. esp8266_server.handleClient(); // 处理http服务器访问
    34. pinState = digitalRead(buttonPin); // 获取引脚状态
    35. }
    36. /* 以下函数处理网站首页的访问请求。此函数为本示例程序重点1。*/
    37. void handleRoot() {
    38. String displayPinState; // 存储按键状态的字符串变量
    39. if(pinState == HIGH){ // 当按键引脚D3为高电平
    40. displayPinState = "Button State: HIGH"; // 字符串赋值高电平信息
    41. } else { // 当按键引脚D3为低电平
    42. displayPinState = "Button State: LOW"; // 字符串赋值低电平信息
    43. }
    44. esp8266_server.send(200, "text/plain", displayPinState);
    45. // 向浏览器发送按键状态信息
    46. }
    47. // 设置处理404情况的函数'handleNotFound'
    48. void handleNotFound(){ // 当浏览器请求的网络资源无法在服务器找到时,
    49. esp8266_server.send(404, "text/plain", "404: Not found"); // NodeMCU将调用此函数。
    50. }

            在以上程序的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所存储的信息发送给浏览器。于是我们在没有按下按键时,将会得到以下页面信息。

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

            以上示例中,我们需要刷新网页页面才能将按键的最新状态显示在网页中。为了实现页面的自动刷新,请您参考以下示例程序。

    1. #include <ESP8266WiFi.h> // 本程序使用 ESP8266WiFi库
    2. #include <ESP8266WiFiMulti.h> // ESP8266WiFiMulti库
    3. #include <ESP8266WebServer.h> // ESP8266WebServer库
    4. #define buttonPin D3 // 按钮引脚D3
    5. ESP8266WiFiMulti wifiMulti; // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'
    6. ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)
    7. bool pinState; // 存储引脚状态用变量
    8. void setup(){
    9. Serial.begin(9600); // 启动串口通讯
    10. delay(10);
    11. Serial.println("");
    12. pinMode(buttonPin, INPUT_PULLUP); // 将按键引脚设置为输入上拉模式
    13. wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1"); // 将需要连接的一系列WiFi ID和密码输入这里
    14. wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU在启动后会扫描当前网络
    15. wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
    16. Serial.println("Connecting ..."); // 则尝试使用此处存储的密码进行连接。
    17. // 另外这里只存储了3个WiFi信息,您可以存储更多
    18. // 的WiFi信息在此处。
    19. int i = 0;
    20. while (wifiMulti.run() != WL_CONNECTED) { // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
    21. delay(1000); // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
    22. Serial.print(i++); Serial.print(' '); // 将会连接信号最强的那一个WiFi信号。
    23. } // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
    24. // 此处while循环判断是否跳出循环的条件。
    25. // WiFi连接成功后将通过串口监视器输出连接成功信息
    26. Serial.println('\n'); // WiFi连接成功后
    27. Serial.print("Connected to "); // NodeMCU将通过串口监视器输出。
    28. Serial.println(WiFi.SSID()); // 连接的WiFI名称
    29. Serial.print("IP address:\t"); // 以及
    30. Serial.println(WiFi.localIP()); // NodeMCU的IP地址
    31. esp8266_server.begin();
    32. esp8266_server.on("/", handleRoot);
    33. esp8266_server.onNotFound(handleNotFound);
    34. Serial.println("HTTP esp8266_server started");// 告知用户ESP8266网络服务功能已经启动
    35. }
    36. void loop(){
    37. esp8266_server.handleClient(); // 处理http服务器访问
    38. pinState = digitalRead(buttonPin); // 获取引脚状态
    39. }
    40. /* 以下函数处理网站首页的访问请求。此函数为本示例程序重点1
    41. */
    42. void handleRoot() { //处理网站目录“/”的访问请求
    43. esp8266_server.send(200, "text/html", sendHTML(pinState));
    44. }
    45. /*
    46. 建立用于发送给客户端浏览器的HTML代码。此代码将会每隔5秒刷新页面。
    47. 通过页面刷新,引脚的最新状态也会显示于页面中
    48. */
    49. String sendHTML(bool buttonState){
    50. String htmlCode = "<!DOCTYPE html> <html>\n";
    51. htmlCode +="<head><meta http-equiv='refresh' content='5'/>\n";
    52. htmlCode +="<title>ESP8266 Butoon State</title>\n";
    53. htmlCode +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
    54. htmlCode +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
    55. htmlCode +="</style>\n";
    56. htmlCode +="</head>\n";
    57. htmlCode +="<body>\n";
    58. htmlCode +="<h1>ESP8266 BUTTON STATE</h1>\n";
    59. if(buttonState)
    60. {htmlCode +="<p>Button Status: HIGH</p>\n";}
    61. else
    62. {htmlCode +="<p>Button Status: LOW</p>\n";}
    63. htmlCode +="</body>\n";
    64. htmlCode +="</html>\n";
    65. return htmlCode;
    66. }
    67. // 设置处理404情况的函数'handleNotFound'
    68. void handleNotFound(){ // 当浏览器请求的网络资源无法在服务器找到时,
    69. esp8266_server.send(404, "text/plain", "404: Not found"); // NodeMCU将调用此函数。
    70. }

            在以上示例程序中的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代码后将会在页面中显示引脚的状态。
            以下是没有按下按键时的页面显示信息。

             以下是按下按键时的页面显示信息。

     三、ESP8266 NodeMCU 闪存文件系统(SPIFFS)

    四、ESP8266-NodeMCU网络客户端

  • 相关阅读:
    【云原生之kubernetes实战】在k8s环境下部署Affine知识库工具
    Spring事务、设计模式以及SpringBoot自动装配原理
    查看HDF5文件的内容
    全局参数校验@Valid的使用方法和写法。
    创建空List的两种方法
    Android 属性动画ValueAnimator整理
    操作系统概述
    微商话术分享
    redis实战篇03
    【kylin】【ubuntu】搭建本地源
  • 原文地址:https://blog.csdn.net/weixin_52804129/article/details/125617338