嵌入式|物联网系列①——基于ESP8266的网络服务器


物联网系列①——基于ESP8266的网络服务器

  • 一、初探物联网
  • 二、ESP8266代码
  • 三、代码烧写
    • 1、工程目录
      • (1)、主目录
      • (2)、二级目录
    • 2、代码烧写
      • (1)、上传代码
      • (2)、上传闪存文件
  • 四、下一步的优化方向


一、初探物联网 之前接触了一段时间的ESP8266,在太极创客教程的指引下做了一个基本网络服务器
嵌入式|物联网系列①——基于ESP8266的网络服务器
文章图片

附上太极创客教程网址。大家感兴趣的话可以跟着教程学习,本文主要对本人学习过程中的思路变化过程,做一个阶段性总结。
根据太极创客教程已经可以通过网页控制ESP8266的单个引脚,那是否可以在网页中控制多个引脚,PWM控制,读取引脚状态,在网站上放上自己喜欢的图片等等。要实现这部分功能,首先需要对HTML有一个基础的认识,因此花了几天的时间粗步学习了一下HTML的基础,接下来就是开始实践了,网页排版之类的没太去仔细研究,一切就都居中处理啦
这个过程中有两方面是比较难的,一个是网页向ESP8266下发命令的处理函数,要注意HTML代码编写以及收发命令的一致性。另一个是对引脚状态,PWM值轮询的实现。这两个考验最多的是对HTML的了解程度,对我这种还不算入门的属于是较难的部分了,而ESP8266代码部分则相对简单,只需根据网页下发的命令进行对应的处理即可。
至此,已经实现了网页端对ESP8266的控制,通过手机接入ESP8266的WIFI,在网址中输入ESP8266的IP地址即可进入网页实现对ESP8266的控制。但是存在几个问题,ESP8266处于AP模式,若用户不知道其WIFI名称和密码,如何接入该服务器?若用户不知道ESP8266的IP地址,那如何打开网页进行控制?如何直观地看出各部分引脚的状态?带着以上的疑问进行代码的进一步优化。
经过思考决定ESP8266外接一块0.96寸显示屏,通过显示屏显示WIFI名称和密码,IP地址,引脚状态等信息,并增加开机画面,从观感上提高体验。
嵌入式|物联网系列①——基于ESP8266的网络服务器
文章图片

二、ESP8266代码
#include // 本程序使用ESP8266WiFi库 #include // 本程序使用ESP8266WiFiMulti库 #include // 本程序使用ESP8266WebServer库 #include // 本程序使用SPIFFS库 #include // 本程序使用U8g2lib库 #include// 本程序使用SPI库//配置OLED SPI引脚 U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ D5, /* data=https://www.it610.com/article/*/ D7, /* cs=*/ D8, /* dc=*/ D0, /* reset=*/ D1); const char *ssid ="FreeWIFI"; // 这里定义将要建立的WiFi名称。 const char *password = "20202020"; // 这里定义将要建立的WiFi密码。 ESP8266WebServer esp8266_server(80); // 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)bool pinState; // 存储引脚状态用变量 int ledPwmVal; //用于存储pwm数值 int LED=D4; //LED引脚static unsigned char logo[] U8X8_PROGMEM ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0F,0x00,0x00, 0x00,0x00,0x7C,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0xFE,0x03,0x00,0x7E,0x00,0x00, 0x00,0x00,0xFF,0x3F,0x00,0xFC,0x00,0x00,0x00,0x80,0xFF,0x7F,0x00,0xF8,0x01,0x00, 0x00,0xC0,0xFF,0x1F,0x00,0xF0,0x03,0x00,0x00,0xE0,0xFF,0x0F,0x00,0xE0,0x07,0x00, 0x00,0xF0,0xFF,0x07,0x00,0xC0,0x0F,0x00,0x00,0xF8,0xFF,0x03,0x00,0x80,0x1F,0x00, 0x00,0xFC,0xFF,0x01,0x00,0x80,0x1F,0x00,0x00,0xFE,0xFF,0x00,0x00,0x00,0x3F,0x00, 0x00,0xFF,0xFF,0x00,0x00,0x00,0x7F,0x00,0x80,0xFF,0xFF,0x01,0x00,0x00,0x7E,0x00, 0xC0,0xFF,0xFF,0x03,0x00,0x00,0xFE,0x00,0x80,0xFF,0xFF,0x07,0x00,0x00,0xFC,0x01, 0x00,0xFF,0xFF,0x0F,0x00,0x00,0xFC,0x01,0x00,0xFE,0xF3,0x1F,0x00,0x00,0xF8,0x03, 0x00,0xFC,0xE1,0x3F,0x00,0x00,0xF8,0x03,0x00,0xF8,0xC0,0x7F,0x00,0x00,0xF8,0x03, 0x00,0x70,0x80,0xFF,0x00,0x00,0xF0,0x07,0x00,0x20,0x00,0xFF,0x01,0x00,0xF0,0x07, 0x00,0x00,0x00,0xFE,0x03,0x00,0xF0,0x07,0x00,0x00,0x00,0xFC,0x07,0x00,0xF0,0x07, 0x00,0x00,0x00,0xF8,0x0F,0x00,0xF0,0x07,0x00,0x00,0x00,0xF0,0x1F,0x00,0xF0,0x07, 0x00,0x00,0x00,0xE0,0x3F,0x00,0xF0,0x07,0x00,0x00,0x00,0xC0,0x7F,0x00,0xF0,0x07, 0x00,0x00,0x00,0x80,0xFF,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0xFF,0x01,0xF0,0x07, 0x00,0x00,0x00,0x00,0xFE,0x03,0xF0,0x07,0x00,0x00,0x00,0x00,0xFC,0x07,0xF0,0x07, 0x00,0x00,0x00,0x00,0xF8,0x0F,0xF8,0x07,0x00,0x00,0x00,0x00,0xF0,0x1F,0xF8,0x03, 0x00,0x00,0x00,0x00,0xF0,0x3F,0xFC,0x03,0x00,0x00,0x00,0x00,0xE0,0x7F,0xFC,0x03, 0x00,0x00,0x18,0x00,0xC0,0xFF,0xFE,0x01,0x00,0x00,0x3D,0x00,0x80,0xFF,0xFF,0x01, 0x00,0x80,0x7F,0x00,0x00,0xFF,0xFF,0x01,0x00,0xE0,0xFF,0x00,0x00,0xFE,0xFF,0x00, 0x00,0xF0,0xFF,0x03,0x00,0xFC,0x7F,0x00,0x00,0xF8,0xFF,0x0F,0x00,0xF8,0x7F,0x00, 0x00,0xF8,0xFB,0x7F,0x00,0xFE,0x3F,0x00,0x00,0xFE,0xE3,0xFF,0xFF,0xFF,0xFF,0x00, 0x00,0xFF,0xC0,0xFF,0xFF,0xFF,0xFF,0x00,0x80,0x7F,0x80,0xFF,0xFF,0xFF,0xFF,0x03, 0xC0,0x3F,0x00,0xFF,0xFF,0xFF,0xFF,0x07,0xF0,0x1F,0x00,0xFC,0xFF,0xFF,0xFE,0x0F, 0xF8,0x0F,0x00,0xF0,0xFF,0x3F,0xFC,0x1F,0xFC,0x07,0x00,0xC0,0xFF,0x0F,0xF8,0x3F, 0xFC,0x07,0x00,0x00,0x78,0x00,0xF0,0x3F,0xFC,0x03,0x00,0x00,0x00,0x00,0xE0,0x1F, 0xFC,0x01,0x00,0x00,0x00,0x00,0xC0,0x1F,0xFC,0x00,0x00,0x00,0x00,0x00,0x80,0x0F, 0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; void setup() { Serial.begin(9600); u8g2.begin(); //OLED显示功能开启 WiFi.softAP(ssid, password); // WiFi.softAP用于启动NodeMCU的AP模式pinMode(LED, OUTPUT); // 初始化NodeMCU控制板载LED引脚为OUTPUT //int i = 0; if(SPIFFS.begin()) {// 启动闪存文件系统 Serial.println("SPIFFS Started."); } else { Serial.println("SPIFFS Failed to Start."); }esp8266_server.on("/getLED", handleLEDControl); // HTML控制开关灯 esp8266_server.on("/LED_PWM_Control", handleLED_PWM_Control); // HTML控制PWM esp8266_server.on("/LED_PIN_Control", handleLED_PIN_Control); // HTML控制LED引脚 esp8266_server.on("/getLEDstate", LED_STATE_Read); //获取LED开关灯状态 esp8266_server.on("/getLEDpwm", LED_PWM_Read); //获取LED当前PWM值 esp8266_server.on("/getLEDpin", LED_PIN_Read); //获取当前LED引脚esp8266_server.onNotFound(handleUserRequest); // 告知系统如何处理其它用户请求esp8266_server.begin(); // 启动网站服务 Serial.println("HTTP server started"); //串口显示HTML服务已开启OLED_Start(); //开机画面 }void loop() { esp8266_server.handleClient(); //处理用户请求 OLED(); //OLED界面显示 } // 处理用户浏览器的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-Control请求 void handleLEDControl() { String ledState = "OFF"; String LED_State = esp8266_server.arg("LEDstate"); //参考xhttp.open("GET", "getLED?LEDstate="+led, true); if(LED_State == "1") { digitalWrite(LED,HIGH); //LED 点亮 ledState = "ON"; //反馈参数 ledPwmVal=255; //PWM值至255 } else { digitalWrite(LED,LOW); //LED 熄灭 ledState = "OFF"; //反馈参数 ledPwmVal=0; //PWM值至0 } esp8266_server.send(200, "text/plain", ledState); //发送网页 }// 处理/LED_PWM_Control请求 void handleLED_PWM_Control() { String ledPwm = esp8266_server.arg("LED_PWM_Control"); // 从浏览器发送的信息中获取PWM控制数值(字符串格式) ledPwmVal = ledPwm.toInt(); // 将字符串格式的PWM控制数值转换为整数 if(ledPwmVal>100)ledPwmVal=100; //大于100以100计算 ledPwmVal=map(ledPwmVal, 0, 100, 0, 255); //数值转换 analogWrite(LED, ledPwmVal); // 实施引脚PWM设置 // 建立基本网页信息显示当前数值以及返回链接 ledPwm=ledPwmVal; esp8266_server.send(200,"text/plain" , ledPwm); //发送网页 }//获取LED状态 void LED_STATE_Read() { if(ledPwmVal!=0) { esp8266_server.send(200, "text/plain", "ON"); //发送网页 } else { esp8266_server.send(200, "text/plain", "OFF"); //发送网页 } }// 处理/LED_PIN_Control请求 void handleLED_PIN_Control() { String ledPin = esp8266_server.arg("LED_PIN"); // 从浏览器发送的信息中获取PWM控制数值(字符串格式) LED = ledPin.toInt(); // 将字符串格式的PWM控制数值转换为整数 pinMode(LED, OUTPUT); // 初始化NodeMCU控制板载LED引脚为OUTPUT· digitalWrite(LED,HIGH); //LED 点亮 ledPwmVal=255; //PWM值至255 esp8266_server.send(200,"text/plain" , ledPin); //发送网页 }//获取引脚PWM状态 void LED_PWM_Read() { String DATA; DATA = https://www.it610.com/article/ledPwmVal; //转化成字符串 esp8266_server.send(200,"text/plain", DATA); }//获取当前控制的是哪个引脚 void LED_PIN_Read() { String DATA; DATA = https://www.it610.com/article/LED; //转化成字符串 esp8266_server.send(200,"text/plain", DATA); }//OLED开机画面 void OLED_Start() {/* u8g2.clearBuffer(); // clear the internal memory u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font u8g2.drawStr(24,30,"IOT SYSTEM"); u8g2.drawStr(50,60,"Loading..."); u8g2.sendBuffer(); // transfer internal memory to the display delay(5000); //开机画面延迟5s*/ u8g2.clearBuffer(); // clear the internal memory u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.drawXBMP(30,0, 64, 64, logo); u8g2.sendBuffer(); // transfer internal memory to the display delay(5000); }//主界面 void OLED() { u8g2.clearBuffer(); // clear the internal memory u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font u8g2.drawStr(0,10,"WIFI:"); u8g2.setCursor(70, 10); u8g2.print(ssid); u8g2.drawStr(0,20,"Password:"); u8g2.setCursor(70, 20); u8g2.print(password); u8g2.drawStr(0,30,"ESP8266 IP:"); u8g2.setCursor(70, 30); u8g2.print(WiFi.softAPIP()); u8g2.drawStr(0,40,"LED PIN:"); u8g2.setCursor(70, 40); u8g2.print(LED); u8g2.drawStr(0,50,"LED STATE:"); u8g2.drawStr(0,60,"LED PWM:"); if(ledPwmVal!=0) { u8g2.drawStr(70,50,"ON"); u8g2.setCursor(70, 60); u8g2.print(ledPwmVal); } else { u8g2.drawStr(70,50,"OFF"); u8g2.drawStr(70,60,"0"); } u8g2.sendBuffer(); // transfer internal memory to the display }

【嵌入式|物联网系列①——基于ESP8266的网络服务器】以上为ESP8266代码,完整工程包括(ESP8266代码,HTML网页,图片等),完整工程文件链接:https://download.csdn.net/download/weixin_43278295/15294943 ,如有需要可至此处下载。

三、代码烧写 1、工程目录 (1)、主目录
嵌入式|物联网系列①——基于ESP8266的网络服务器
文章图片

(2)、二级目录
嵌入式|物联网系列①——基于ESP8266的网络服务器
文章图片

2、代码烧写 (1)、上传代码
嵌入式|物联网系列①——基于ESP8266的网络服务器
文章图片

(2)、上传闪存文件
嵌入式|物联网系列①——基于ESP8266的网络服务器
文章图片

至此代码烧写完成,手机接入ESP8266的WIFI即可实现预想功能。关于Arduino-ESP8266闪存文件插件程序可根据太极创客教程安装。
再次附上完整工程文件链接:https://download.csdn.net/download/weixin_43278295/15294943

四、下一步的优化方向 该网络服务器存在局限性,ESP8266只能在AP模式下,通过手机接入ESP8266的WIFI,在网页中输入ESP8266的IP地址,如192.168.4.1即可进入,在网页中实现对引脚电平的操作。AP模式意味着使用区域是受限于ESP8266的无线覆盖范围的。ESP8266进行大数据处理是较弱的,且引脚有限,扩展范围有限。
此时有一个想法,是否可以通过外接一个处理能力更强的STM32进行数据处理?STM32与ESP8266进行串口通信,相当于ESP8266是一个通信节点,只负责数据传输,而STM32为主控芯片,进行数据处理。ESP8266处理能力有限和引脚较少的缺点就被消除了。因为ESP8266是AP模式的,那是否可以通过STM32+按键+显示屏对ESP8266的无线名称和无线密码进行手动设置,同时云端能实现的控制是否可以也通过STM32+按键+显示屏来手动实现。怀着对这些未知的尝试之心和希望对过去的一些关于STM32设计进行总结整合,如CAN通信,温湿度采集,0.96寸OLED,DS1302实时时钟等等,产生了制作一个集成ESP8266和STM32的物联网开发板的想法。这部分内容将在下篇文章介绍。
不足之处还望各位大佬不吝赐教!

    推荐阅读