物联网系列①——基于ESP8266的网络服务器
- 一、初探物联网
- 二、ESP8266代码
- 三、代码烧写
-
- 1、工程目录
-
- (1)、主目录
- (2)、二级目录
- 2、代码烧写
-
- (1)、上传代码
- (2)、上传闪存文件
- 四、下一步的优化方向
一、初探物联网 之前接触了一段时间的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代码
#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)、主目录
文章图片
(2)、二级目录
文章图片
2、代码烧写 (1)、上传代码
文章图片
(2)、上传闪存文件
文章图片
至此代码烧写完成,手机接入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的物联网开发板的想法。这部分内容将在下篇文章介绍。
不足之处还望各位大佬不吝赐教!
推荐阅读
- 物联网|Esp8266接入OneNet调试、Arduino接入OneNet平台[有用]
- 【雕爷学编程】Arduino动手做(96)---BT05蓝牙4.0BLE模块
- 好云推荐官丨飞天加速之星怎样选择云服务器ECS()
- stm|十二届蓝桥杯嵌入式省赛
- 嵌入式|【Rust 日报】2021-11-21 The RustFest Global - Rust in Arts
- 嵌入式|【Rust日报】2021-11-14 一个开源的基于Rust和Flutter的Notion替代产品
- 开源日报|谷歌牵头呼吁保护开源项目;Firefox 更新后服务器出现 Bug;Rust 1.58.0 发布 | 开源日报
- 嵌入式|2021-07-08 使用RT-Thread Studio程序调试过程中的要点记录(芯片使用STM32F407ZE)
- 嵌入式|2021-07-09 RT-Thread Studio 调试fal要点记录