索引:
- ESP8266基本使用
- 烧写方式
- TCP/IP实现远程开关
第一部分:ESP8266基本使用
esp8266引脚图:
引脚说明:
主要功能:
- 串口透传:数据传输、传输的可靠性高
- PWM调控:灯光强度调节,三色LED调节、电机调速
- GPIO控制:控制开关,继电器
工作模式:
- STA模式:通过路由器连接互联网,手机电脑通过互联网实现对设备的远程控制
- AP模式:作为热点,实现手机或电脑直接与模块通信,实现局域网无线控制
- STA+AP模式:两种模式的共存模式,即可以通过互联网控制实现无缝切换,方便操作
ESP8266特性:
- 距离大约300米,内置TCP/IP协议(IPV4 only)
- 支持WPA/WPA2加密
- 可以同时作为client和server,client连接到server可以请求数据可以post数据
- server通过编程年监听数据,server的数据取决于client的请求,能够通过client的数据与其他程序进行交互
- 可以作为一个网络的基站,或者作为通向网络的入口,或者同时作为两者。基站station可以作为连接设备到网络的入口,比如说笔记本手机等等,入口提供网络服务给基站station,比如路由基站stations之间的数据,或者从基站路由数据到其他网络,还可以指定IP地址并提供DNS信息。
WIFI库:
- ESP8266WIFI 库可以被导入来提供ESP8266的核心功能
- 这个库可以创建一个顶层的WIFI对象去控制函数,比如说设定WiFi的连接模式
WiFi.mode(MODE)
- 功能:连接模式设置,其中MODE可以是:
- WIFI_STA – for Station Mode 基站模式
- WIFI_AP – for Access Point 入口模式
- WIFI_API_STA – 同时作为基站和入口模式
WiFi.begin(SSID,PASSWORD)
- 功能:连接到网络入口(access point,也可以直接连到路由器上),其中:
- SSID:网络名称,不能是中文,可以是wifi的名字
- PASSWORD:网络的密码
WiFi.status()
- 功能:如果网络连接成功了,将会得到WL_CONNECTED的值true|flase
WiFi.disconnect()
- 功能:断开WiFi连接
WiFi.localIP()
- 提供设备在网络中的IP地址(Station Mode)
基本使用1:扫描网络
Arduino ide为我们提供了扫描网络的代码在File -> Examples -> ESP8266WiFi -> WiFiScan中,烧录进这份代码我们在串口监视器可以看到输出,如果没有看到这个例子,GitHub-ESP8266链接里找到,下面是一代码、程序执行逻辑和输出样例:
代码:扫描网络
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
/* This sketch demonstrates how to scan WiFi networks. The API is almost the same as with the WiFi Shield library, the most obvious difference being the different file you need to include: */ #include "ESP8266WiFi.h" void setup() { Serial.begin(115200); // Set WiFi to station mode and disconnect from an AP if it was previously connected WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); Serial.println("Setup done"); } void loop() { Serial.println("scan start"); // WiFi.scanNetworks will return the number of networks found int n = WiFi.scanNetworks(); Serial.println("scan done"); if (n == 0) { Serial.println("no networks found"); } else { Serial.print(n); Serial.println(" networks found"); for (int i = 0; i < n; ++i) { // Print SSID and RSSI for each network found Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i)); Serial.print(" ("); Serial.print(WiFi.RSSI(i)); Serial.print(")"); Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*"); delay(10); } } Serial.println(""); // Wait a bit before scanning again delay(5000); } |
程序的执行逻辑:
setup中
- 引入库文件ESP8266WiFi.h
- 设置WiFi模式为station
- 断开目前连接的wifi(因为要扫描网络)
loop中
- WiFi.scanNetworks();扫描目前网络的数量,返回目前网络的数量
- 如果连接数是0则提示没有网络
- 如果连接数大于0则通过则循环网络的编号从1到n,并通过WiFi.SSID(i)、WiFi.RSSI(i)、WiFi.encryptionType(i)来打印网络名称、网络强度,以及加密类型,注意三元表达式是只要加了密就返回*而不是返回的加密类型
输出样例
基本使用2:HTTP连接
HTTP:是“客户端-服务器”的文本传输协议
HTTP请求:
- HTTP头部信息可以很详细(复杂),也可以很简单
- GET方式主要用于标准网页请求,图片,简单表单
- POST主要用于复杂表单的提交
一个HTTP请求过程是这样的:
在这个过程中client发送的HTTP REQUEST的一个简单的头部是这样的:
服务器server在接收到请求后返回的HTTP RESPONSE是这样的:
注:在REQUEST或者RESPONSE的最后都有两行空格表示头部结束。
接下来看看作为WiFi客户端client,这是我们最常见的连接方式,比如说浏览网页,从服务器接受邮件,发布消息等等。下面来看一个最基本的client连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#include <ESP8266WiFi.h> const char* ssid = "....Insert SSID Here...."; const char* password = "....Insert Password Here...."; const char* host = "esp8266.tungadyn.com"; const char* path = "/wificlient/index.html"; const int httpPort = 80; void setup() { Serial.begin(115200); delay(10); // We start by connecting to a WiFi network Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void loop() { delay(5000); Serial.print("connecting to "); Serial.println(host); // Use WiFiClient class to create TCP connections WiFiClient client; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return; } Serial.print("Requesting URL: "); Serial.println(path); // This will send the request to the server client.print(String("GET ") + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); delay(1000); // Read all the lines of the reply from server and print // them to Serial while(client.available()){ String line = client.readStringUntil('\r'); Serial.print(line); } Serial.println(); Serial.println("closing connection"); } |
实现思路:
- 申明变量,与之前相比添加了host和path,注意host和path拼接才是网站的最终访问地址。
- 连接wifi网络并打印ip地址
- 连接server
- 使用client.print()来发送头部信息,注意这里使用的字符串的拼接。
基本使用3 配置成server
有的时候我们并不想把它做成客户端而是server,做成server的好处是可以直接的控制设备,因此配置成client的方式常用于将传感器的数据发送到云端,而配置成server的形式可以实现从远程操作设备比如说灯泡、步进电机等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> const char* ssid = "....Insert SSID Here...."; const char* password = "....Insert Password Here...."; ESP8266WebServer server(80); const int LED=2; void handleRoot() { digitalWrite(LED, 1); server.send(200, "text/plain", "Hello from your ESP8266!"); digitalWrite(LED, 0); } void handleNotFound(){ digitalWrite(LED, 1); String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET)?"GET":"POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i=0; i<server.args(); i++){ message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } server.send(404, "text/plain", message); digitalWrite(LED, 0); } void setup() { pinMode(LED,OUTPUT); digitalWrite(LED,LOW); Serial.begin(115200); delay(10); // We start by connecting to a WiFi network Serial.println("Connecting to "+String(ssid)); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("+"); } Serial.println(""); Serial.println("WiFi connected. IP address: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); Serial.flush(); } void loop() { server.handleClient(); } |
代码思路:
- 要额外加进来两个库
- 创建一个web server对象在80串口
- 连接到wifi网络并打印ip地址
- 创建一个handler给要连接的url,
- 接下来是handler的重点,用server.send来做一个RESPONSE,我们需要拼接这个response
- 如果正常的头部参数使用的函数,打印 hello
- 如果不正常的头部参数使用的函数,打印相应信息
- 所有的都封装成函数了所有loop很简单。
基本使用4:配置成ACCESS POINT SERVER
- 用于无法连接互联网的情况
- 用于要保证极度安全的局域网的情况
- 在server模式会监听更多的ports
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> const char* ssid = "myesp8266"; const char* password = "myprivatenet"; ESP8266WebServer server(80); const int LED=2; void handleRoot() { server.send(200, "text/html", "<h1>Hello from your ESP8266!</h1>"); } void handleNotFound(){ digitalWrite(LED, 1); String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET)?"GET":"POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i=0; i<server.args(); i++){ message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } server.send(404, "text/plain", message); digitalWrite(LED, 0); } void setup() { pinMode(LED,OUTPUT); digitalWrite(LED,LOW); Serial.begin(115200); delay(10); // We start by connecting to a WiFi network Serial.print("Configuring Access Point ") Serial.println(String(ssid)); WiFi.softAP(ssid, password); delay(5000); Serial.println("Done."); IPAddress myIP = WiFi.softAPIP(); Serial.println("My Access Point IP address: "); Serial.println(myIP); server.on("/", handleRoot); server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); Serial.flush(); } void loop() { server.handleClient(); } |
代码逻辑:
- 创建一个新的网络WiFi.softAP(),而不是之前连接上wifi
- 自动找到ip网络 IPAddress myIp = WiFi.softAPIP()
第二部分 烧写方式
ESP8266的烧写方式比较麻烦一点,需要使用TTL-USB(3.3V)来进行烧写。
注意:使用TTL-USB方式来进行烧写成功后,想要再让模块进入AT模式,必须重新进行AT固件的烧写。
烧写接线:
- VCC — 3.3V
- GND — GND
- GH_PD — 3.3
- GPIO 0 — GND(只有烧录固件的时候才连接,不烧录时为空)
- RX — TX
- TX — RX
注意!供电一定不可以使用5V电压,否则一分钟之类烧毁。TXD和RXD一定不能接电源,否则瞬间烧毁!!!
IDE设置:
- 在preference的Additional Boards Manager URLs填写:http://arduino.esp8266.com/stable/package_esp8266com_index.json,这一步向版型管理器中添加ESP8266(相当于我们在烧录uno的时候要选择uno,同理烧写ESP8266的时候要选择ESP8266的板型,但是ESP8266这个板型是不自带的因此需要下载一下),但是我们只是添加了地址,还没有安装,下一步进行安装。
- 在tool -> Board Manager搜索esp8266安装好。
- tool -> board -> Generic ESP8266 Module
- 进行如下设置就可以开始烧写程序了:
===注意==
- 电源要求很高,一定要使用3.3V左右。
- CH_PD这个引脚不管是烧写程序也好,烧完程序也好,都要接上3.3V。
- GPIO 0 这个引脚在烧写程序的时候必须接GND,烧写完毕后正常运行的时候必须将这个引脚拉高,或者悬空。
第三部分 TCP/IP实现远程开关
在这一步部分我们将自动烧写透传代码来进行ESP8266的设置,来实现我们所需要的功能,可以实现让手机和ESP8266进行互相通信,并控制arduino上的LED灯。
原理是,让手机和ESP8266在同一个WIFI网络里,连接同一个路由。
第一步:将以下代码烧录进ESP 8266中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
//把8266作为TCPcleint,加入手机创建的tcpServer中 #include <ESP8266WiFi.h> #define relay1 2 const char *ssid = "bing";//这里是我的wifi,你使用时修改为你要连接的wifi ssid const char *password = "123456789";//你要连接的wifi密码 const char *host = "192.168.1.103";//修改为手机的的tcpServer服务端的IP地址,即手机在路由器上的ip WiFiClient client; const int tcpPort = 8266;//修改为你建立的Server服务端的端口号 void setup() { pinMode(relay1,OUTPUT); Serial.begin(115200); delay(10); Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED)//WiFi.status() ,这个函数是wifi连接状态,返回wifi链接状态 //这里就不一一赘述它返回的数据了,有兴趣的到ESP8266WiFi.cpp中查看 { delay(500); Serial.print("."); }//如果没有连通向串口发送..... Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP());//WiFi.localIP()返回8266获得的ip地址 } void loop() { while (!client.connected())//几个非连接的异常处理 { if (!client.connect(host, tcpPort)) { Serial.println("connection...."); //client.stop(); delay(500); } } while (client.available())//改动的就这里啦,无线读取到的数据转发到到串口 { uint8_t c = client.read(); Serial.write(c); } if (Serial.available())//串口读取到的转发到wifi,因为串口是一位一位的发送所以在这里缓存完再发送 { size_t counti = Serial.available(); uint8_t sbuf[counti]; Serial.readBytes(sbuf, counti); client.write(sbuf, counti); } } |
第二步:进行电路连接
ESP8266 -> Arduino
TX -> RX
RX -> TX
GND -> GND
CH_PD -> 3.3V
VCC -> 3.3V
然后再arduino的11pin上加一个led来模拟开关(换成继电器就是开关)加上电阻(防止灯泡爆掉)就可以了。
第三步:手机测试
在手机上下载一个网络调试助手,并将手机连上和esp设置一样的WiFi,选择tcp server(手机作为服务端)并且点击配置,然后将端口号改成8266(之前烧录时候设置的ip地址就是这里的ip地址),这个时候打开串口助手(波特率要设置成相应的),这个时候应该可以看到手机上发送一个A就可以在串口中接收到一个A,这就证明之前的已经做通了,如果出现找不到网络一直在重新连接的话需要注意:
- 网络名不能是中文
- esp8266不支持5g网络,请确认网络是2.4g
第四步:最后一步!
向Arduino中烧录以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
int led_pin = 11; //定义一个10字节的整型数据变量cmd作为命令,这里可以修改为不同的数字。此处设置为10是为了有更好的兼容性。 char cmd[10]; //判断收到的cmd是否有内容 bool valid_cmd = false; void setup() { //定义连接led的引脚为输出信号 pinMode(led_pin, OUTPUT); Serial.begin(115200); } void loop() { /*以下部分是串口信息处理过程*/ //定义一个整数型变量i int i; //如果串口收到有数据 if (Serial.available() > 0) { //变量i最大为10 for (i = 0; i < 10; i++) { //清空缓存,存入cmd变量,并以\0作为结束符 cmd[i] = '\0'; } //此时i只能取前9位,第10位是结束符\0 for (i = 0; i < 9; i++) { //再次判断串口如果收到有数据,防止数据丢失 if (Serial.available() > 0) { //给变量cmd赋值,取串口收到的前9位字符 cmd[i] = Serial.read(); delay(1); } else { //如果串口数据超过9位,后面的字符直接忽略,跳到下一步 break; } } /*以上串口信息处理结束*/ //得到最终变量cmd的有效值 valid_cmd = true; } //判断变量cmd的值,开始处理 if (valid_cmd) { //如果变量cmd的前2位的值是on if (0 == strncmp(cmd, "on", 2)) { //则连接led的引脚电压被置高5V, digitalWrite(led_pin, HIGH); //串口打印返回值ON,表示ON的操作执行成功 Serial.println("ON"); } else if (0 == strncmp(cmd, "off", 3)) //否则如果变量cmd的前3位的值是off { //则连接继电器的引脚电压被置低0V,灯的电路被断开,灯灭 digitalWrite(led_pin, LOW); //串口打印返回值F,表示OFF的操作执行成功 Serial.println("OFF"); } else //如果以上两个条件都不成立,前2位不是ON,或者前3位不是OFF,即不正确的命令 { //仅串口打印返回值X,表示指令错误。 Serial.println("X"); } //到此,变量cmd的指令被处理完毕 valid_cmd = false; } //延迟10毫秒,返回loop主程序继续读取新的串口指令 delay(10); } |
现在,打开手机网络调试工具和串口助手,输入on和off就可以控制灯的开关了!再没有收到指令的时候串口反馈x收到后转换成大写并反馈!