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

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

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

一、初探物联网

       之前接触了一段时间的ESP8266,在太极创客教程的指引下做了一个基本网络服务器
物联网系列①——基于ESP8266的网络服务器_第1张图片

       附上太极创客教程网址。大家感兴趣的话可以跟着教程学习,本文主要对本人学习过程中的思路变化过程,做一个阶段性总结。
       根据太极创客教程已经可以通过网页控制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的网络服务器_第2张图片

二、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=*/ 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 = ledPwmVal;//转化成字符串
  esp8266_server.send(200, "text/plain", DATA);
}

//获取当前控制的是哪个引脚
void LED_PIN_Read()
{
  String DATA;
  DATA = 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代码,HTML网页,图片等),完整工程文件链接:https://download.csdn.net/download/weixin_43278295/15294943 ,如有需要可至此处下载。

三、代码烧写

1、工程目录

(1)、主目录

物联网系列①——基于ESP8266的网络服务器_第3张图片

(2)、二级目录

物联网系列①——基于ESP8266的网络服务器_第4张图片

2、代码烧写

(1)、上传代码

物联网系列①——基于ESP8266的网络服务器_第5张图片

(2)、上传闪存文件

物联网系列①——基于ESP8266的网络服务器_第6张图片
      至此代码烧写完成,手机接入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的物联网开发板的想法。这部分内容将在下篇文章介绍。

      不足之处还望各位大佬不吝赐教!

你可能感兴趣的:(嵌入式,物联网,单片机,物联网,单片机,服务器)