1、esp8266系列模块
ESP8266 系列模组是深圳市安信可科技有限公司开发的一系列基于乐鑫ESP8266EX的低功耗UART-WiFi芯片模组,可以方便地进行二次开发,接入云端服务,实现手机3/4G全球随时随地的控制,加速产品原型设计。
模块核心处理器 ESP8266 在较小尺寸封装中集成了业界领先的 Tensilica L106 超低功耗 32 位微型 MCU,带有 16 位精简模式,主频支持 80 MHz 和 160 MHz,支持 RTOS,集成 Wi-Fi MAC/ BB/RF/PA/LNA,板载天线。支持标准的 IEEE802.11 b/g/n 协议,完整的 TCP/IP 协议栈。用户可以使用该模块为现有的设备添加联网功能,也可以构建独立的网络控制器。
**特点:**
- 802.11 b/g/n
- 内置Tensilica L106 超低功耗 32 位微型 MCU,主频支持 80 MHz 和160 MHz,支持 RTOS
- 内置10 bit高精度ADC
- 内置TCP/IP协议栈
- 内置TR 开关、balun、LNA、功率放大器和匹配网络
- 内置PLL、稳压器和电源管理组件,802.11b 模式下+18 dBm的输出功率
- A-MPDU 、 A-MSDU 的聚合和 0.4 s的保护间隔
- Wi-Fi @ 2.4 GHz,支持 WPA/WPA2 安全模式
- 支持AT本地升级及云端OTA升级
- 支持 STA/AP/STA+AP 工作模式
- 支持 Smart Config 功能(包括 Android 和 IOS 设备)
- HSPI 、UART、I2C、I2S、IR Remote Control、PWM、GPIO
- 深度睡眠保持电流为 20 uA,关断电流小于 5 uA
- 2 ms 之内唤醒、连接并传递数据包
- 待机状态消耗功率小于1.0 mW (DTIM3)
- 工作温度范围:详情请见具体型号规格书
2、固件下载错误进行擦除
ESPtool.py是一个python开发的针对ESP8266的小工具,可以实现底层的操作,弥补ESP8266官方工具的不足。flash的小工具,可以弥补ESP8266官方工具的不足。它也是一个开源项目,项目在github上进行托管:https://github.com/themadinventor/esptool
虽然可以直接从github上下载使用,但是更好的方法是通过网络的方式进行安装,这样不会缺少依赖模块,减少运行中的故障。下面就介绍它的安装方法。
因为esptool.py需要使用python2,所以我们先需要安装python2,并将python加入系统路径(path)。
安装python的包管理器pip,通常是使用get-pip.py进行安装。在 https://pip.pypa.io/en/latest/installing/ 可以找到安装的说明和需要下载的文件,按照说明可以很容易安装pip。(如果同时安装了python2和python3,pip可能默认是pip3,需要用pip2来代替下面的pip,在Linux上需要用sudo权限安装)。
用pip安装esptool
pip install esptool
因为esptool需要使用串口,所以还需要安装pyserial。
pip install pyserial
- 安装后,在Linux下,通常就可以直接运行esptool.py,在Windwos下,esptool一般安装在python2\Scripts\目录下,需要输入完整目录才能运行,如:
c:\Python27\Scripts\esptool.py
如果不清楚esptool.py的用法,可以输入-h查看帮助,如
esptool.py -h
甚至可以查看某个用法的帮助:
esptool.py read_flash -h
- 擦除flash。
首先要确认一下8266所连接的串口号,要以串口号作为指令的参数,如我的设备是在COM4,我运行的指令就是esptool.py –port COM4 erase_flash
此处需要注意,执行擦除的指令前,需要像烧录固件一样,让8266进入升级模式,即按住板上的flash键不放,按下rst键,等待两秒,松开rst键,再松开flash键。否则会出现如下的错误提示:这样flash的擦除工作就完成了,重新再烧录固件之后即可解决固件运行异常的问题。
3、环境准备(Arduino开发)
1、硬件准备
GPIO0决定板子处于什么模式(上电低电平为进入下载模式)
1、ESP-01系列
2、用的最多的12F
SMD-22封装,GPIO0-GPIO16共17个通用IO口,一个单通道ADC,GPIO6-GPIO11用于连接外部flash,不可用,支持SPI总线通信:GPIO12-GPIO15,支持I2C总线:GPIO4-GPIO5,串口通信:GPIO1-GPIO3。
12F一般D0-D8(除D3口即GPIO0下载用);
D0:INPUT(输入)、OUTPUT(输出)、INPUT_PULLDOWN(输入,默认下拉,低电平);
其余IO口:INPUT(输入)、OTPUT(输出)、INPUT_PULLUP(输入,默认上拉,高电平);
注意:烧录模式GPIO0接地,正常模式GPIO悬空。
3、NodeMcu(ESP-12F开发板)
4、8266-12E
2、软件准备
1、Arduino安装+8266包安装
2、芯片检测程序
1 | /** |
4、相关外设使用
1、计时和延时
1 | /** |
2、IO口(Blink)
1 | /** |
3、中断
(除了DO/GPIO16,中断可以绑到任意GPIO脚)
相关函数:
attachInterrupt(pin,function,mode);
在指定引脚设置为响应中断。pin:要设置的中断号,function:中断时执行的函数,不带任何参数,无返回,Interrupt type/mode:中断触发条件(CHANGE:改变沿;RISING:上升沿;FALLING:下降沿)detachInterrupt(pin);
禁用指定GPIO引脚上的中断。pin:要禁用的中断的GPIO引脚,无返回值。digitalPinToInterrupt(pin);
获取指定GPIO引脚的中断号。
1 | /** |
4、模拟输入(ADC)
esp8266只用一个10位ADC通道(和芯片供电电压复用:即可设置为测量系统电压或者外部电压)
1、测量外部电压
- 方法:
analogRead(A0);
- 0-1.0V
- 测量精度:10位ADC:0~$2^{10}$
- 注意:开发板上做了电阻分压器,使其能够测量0 ~ 3.3V(220K与100K电阻分压)
1 | /** |
2、测量系统外部电压
方法: ESP.getVcc()
单位: mv
ADC引脚要悬空。读取前要更改ADC模式(在#include行后面)
ADC_TOUT
(对外部电压),ADC_VCC
(对系统电压),默认读取外部1
2
3
4
5
6
7
8
9
10
11
12
13/**
* 功能描述:ESP8266 ADC 读取系统电压
* 在串口调试器查看效果
*/
ADC_MODE(ADC_VCC);//设置ADC模式为读取系统电压
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.print("ESP8266当前系统电压(mV): ");
Serial.println(ESP.getVcc());
delay(1000);
}
5、模拟输出(PWM)
analogWrite(pin,val)
在指定引脚上启用PWM;pin:GPIO; val:一般0 ~ PWMRANGE,默认PWMRANGE=1023;无返回值;analogWrite(pin,0)
相当于禁用指定引脚上的PWM;analogWriteRange(new_range)
改变PWMRANGE数值;new_range:新的PWMRANGE数值;无返回值;(可以调节PWM精度);analogWriteFreq(new_frequency)
改变PWM频率;默认1KHzArduino For ESP8266的PWM频率范围为100Hz ~40KHz:
源码:
1
2
3
4
5
6
7
8
9
10static uint16_t analogFreq = 1000;
extern void __analogWriteFreq(uint32_t freq) {
if (freq < 100) {
analogFreq = 100;
} else if (freq > 40000) {
analogFreq = 40000;
} else {
analogFreq = freq;
}
}
例程(呼吸灯)
1 | /** |
6、串口通信
与传统Arduino设备完全一样。除硬件FIFO(128字节用于TX和RX)之外,硬件串口还有额外的256字节的TX和RX缓存。发送和接受全部由中断驱动。当FIFO/缓存满时,Write函数会阻塞工程代码执行,等待空闲空间。当FIFO/缓存空时,read函数也会阻塞工程代码的执行,等待串口数据进来。
NodeMcu上有两组串口,Serial和Serial1(都是硬件串口)。
Serial使用UART0,默认GPIO1(TX)和GPIO3(RX);Serial.begin执行之后,调用
Serial.swap()
可以将Serial重新映射到GPIO15(TX)和GPIO13(RX)。可来回调用。一般默认1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* 功能描述:ESP8266 Serial映射例程
*/
void setup() {
Serial.begin(115200);
Serial.println("GPIO1(TX),GPIO3(RX)");
//调用映射方法
Serial.swap();
Serial.println("GPIO15(TX),GPIO13(RX)");
//重新映射回来
Serial.swap();
Serial.println("GPIO1(TX),GPIO3(RX)");
}
void loop() {
}Serial1使用UART1,默认对应GPIO2(TX)。Serial1不能接收数据(RX被flash芯片占用),
Serial1.begin(baudrate)
。1
2
3
4
5
6
7
8void setup() {
Serial.begin(115200);
Serial.println("Hello Serial");
Serial1.begin(115200);
Serial1.println("Hello Serial1");
}
void loop() {
}
若不用Serial1且不映射串口,可将UART0的TX映射到GPIO2:在
Serial.begin()
之后调用Serial.set_tx(2)
或者直接调用Serial.begin(baud,config,mode,2)
;默认当调用Serial.begin后,将禁用WIFI库的诊断输出,再次启动:
Serial.setDebugOutput(true)
若将调试输出映射到Serial1时:Serial1.setDebugOutput(true)
;Serial.setRxBufferSize(size_t size)
定义接收缓冲区大小,默认256;Serial和Serial1对象都支持5,6,7,8个数据位,奇数(O),偶数(E)和无(N)奇偶校验,1或2个停止位:
Serial.begin(baudrate,SERIAL_8N1)
获取当前波特率设置:
Serial.baudRate()
或Serial1.baudRate()
检测进入Serial的未知波特率的数据:
Serial.detectBaudrate(time_t timeoutMillis)
: 尝试在timeoutMillis ms的时间内检测波特率,检测成功返回波特率,失败返回0。detectBaudrate()
方法在Serial.begin()
之前调用。可使用Serial.begin(detectedBaudrate)
示例(WIFI连接):
1 | /** |
7、ESP8266与EEPROM
1、写数据
1 | /* |
2、读数据
1 | /* |
3、清除数据
1 | /* |
4、结构体操作
1 | /* |
8、SPI通信
1、概述
串行外设接口(Serial Peripheral Interface),高速、全双工、同步通信总线(同一时刻只有一主一从进行通信),四线(MISO:主入从出;MOSI:主出从入;SCK:同步时钟信号;SS或CS:片选使能)。(Quad SPI=2Dual SPI=4标准SPI)。
2、ESP8266 SPI类库成员函数
SPI.h头文件中,该类库只提供主设备API
SPI.begin()
初始化SPI通信;无参,无返回值;SPI.end()
关闭SPI通信;无参,无返回值;SPI.setBitOrder(order)
设置数据传输顺序;- 参数(order):
- ~ LSBFIRST,低位在前;
- ~ MSBFIRST,高位在前;
- 无返回值;
- 参数(order):
SPI.setClockDivider(divider)
设置通信时钟(由系统时钟分频)- 参数(divider):
- ~ SPI_CLOCK_DIV2, 2分频;
- ~ SPI_CLOCK_DIV4, 4分频;
- ~ SPI_CLOCK_DIV8, 8分频;
- ~ SPI_CLOCK_DIV16, 16分频;
- ~ SPI_CLOCK_DIV32, 32分频;
- ~ SPI_CLOCK_DIV64, 64分频;
- ~ SPI_CLOCK_DIV128, 128分频;
- 无返回值;
- 参数(divider):
SPI.setDataMode(mode)
设置数据模式- 参数(mode):
- ~ SPI_MODE0; 即:CPOL=0,CPHA=0
- ~ SPI_MODE1; 即:CPOL=0,CPHA=1
- ~ SPI_MODE2; 即:CPOL=1,CPHA=0
- ~ SPI_MODE3; 即:CPOL=1,CPHA=1
- 无返回值
- 补充:四种模式,即SPI相位(CPHA)和极性(CPOL)分别为0或1;
- CPOL:即SPI空闲时,SCLK的电平(1高,0低);
- CPHA:即SPI在SCLK的第几个边沿开始采样(0第一个,1第二个);
- 参数(mode):
SPI.transfer(val)
传输1B的数据。全双工,发1B收1B数据SPI.transfer16(val)
传输2B数据,从机返回2B作为返回值;SPI.transferBuf(buf,count)
传输一个缓冲区数据,参数为发送的缓冲区buf(uint8_t*
数据),count位缓冲区大小,无返回值(但从机传输来的数据会替换掉buf缓冲区的数据)SPI.pins(sck,miso,mosi,ss)
切换SPI引脚映射,需在SPI.begin()
前调用
3、SPI寄存器
所有SPI设置都是由Arduino SPI控制寄存器(SPCR)决定。该寄存器就是MCU内存的一个字节,可读写。寄存器提供服务:控制、数据、状态。
控制寄存器(SPCR):
8位,(如单片机的中断允许控制寄存器IE、中断优先级控制寄存器IP、定时器/计数器控制寄存器)
数据寄存器(SPDR):
(如串行口锁存器SBUF,仅hold住一个字节)
状态寄存器(SPSR):
根据多种微控制器的条件改变其状态
10、Ticker —ESP8266定时库
1、概述
- 用于规定时间后调用函数;
- 一个方法的示例(为了说明三个参数时的意义,两个参数时好理解)
1 | /** |
- 不建议使用Ticker回调函数来阻塞IO操作(网络、串口、文件);可以在Ticker回调函数中设置一个标记,在loop函数中检测这个标记;
- 对于arg,必须时char, short, int, float, void* , char* 之一;
2、示例
1 | /** |
1 | /** |
11、Arduino Core For ESP8266
12、ESP8266工作模式与ESP8266WIFI库
1、ESP8266工作模式
Station模式(STA):
ESP8266模块连接WIFI网络(通过接入点(Access Point))
特点:
- 连接丢失,ESP8266会自动重连最近使用的接入点(会出问题,连不上);
- 模块重启也会这样;
- ESP8266将最后使用的接入点认证信息(ssid , psw)保存到Flash(非易失性)存储器中;
- 若在Arduino IDE修改代码,但不更改WIFI工作模式或接入点认证信息,ESP8266使用保存在Flash上的数据重新连接。
AP模式(soft-AP):
(Access Point) ESP8266作为接入点建立WIFI网络,供Station模式下的模块连接
特点:
- AP模式可用作STA模式的模块之间交换中转站(让模块处于同一WIFI网络下);
- 可先在AP模式下发出WIFI信号,手机连接,高速该模块家里的WIFI认证信息,模块转为STA模式,连接目标WIFI。
AP兼STA模式:
以上两种模式的整合(应该是做软路由那个意思)
2、ESP8266WIFI库
概述:
相关知识:
名字里带Secure、SSL、TLS的,和安全校验有关(https);
带Client,和tcp客户端(发送端)有关;
带Server,和tcp服务端(接收端)有关;
带8266,针对ESP8266的代码封装;
带Scan,和WIFI扫描有关;
带STA,和ESP8266 Station模式有关;
带AP,和ESP8266 AP模式(AP热点)有关;
ESP8266WiFiGeneric(8266模块通用库)包括:处理程序来管理WIFI事件,如连接、断开或获得ip,WIFI模式的变化,管理模块睡眠模式的功能,以ip地址解析hostName等;
ESP8266WiFiGType.h文件,主要用来定义各种配置选项,如WIFI工作模式(WiFiMode),WiFi睡眠模式(WiFiSleep Type),wifi物理模式(WiFiPhyMode),wifi事件(WiFiEvent),wifi断开原因等;
ESP8266WiFi库不仅仅局限于ESP8266WIFi.h和ESP8266WiFi.cpp这两个文件,但他们是最核心的统一入口;
WiFiUdp库,在ESP8266WiFi功能基础上包装了UDP广播协议,适用于UDP通信,需另加头文件
引入
#include<ESP8266WiFi.h>
一步到位
详解:
1、WIFI通用功能库(ESP8266WiFiGeneric):
2、STA库(ESP8266WiFiSTA):
配置连接:
注意:
1
2
3
4
5WiFi.mode(WIFI_STA);//最好人为加上STA设置(虽然默认是STA模式)
WiFi.disconnect();//最好调用一下断连
/*如果之前处于AP模式,再调begin()可能会进入STA+softAp模式
*可检测当前模式(WiFi.getMode())
*/- 切换到STA模式(
begin()
)
源码:
1
2
3
4
5
6
7
8/**
* 切换工作模式到STA模式,并自动连接到最近接入的wifi热点
* @param void
* @return void
* @note 调用这个方法就会切换到STA模式,并且连接到最近使用的接入点(会从flash中读取之前存储的配置信息)
* 如果没有配置信息,那么这个方法基本上没有什么用。
*/
wl_status_t begin()应用:
1
WiFi.begin();
- 切换到STA模式(
begin(ssid,psw)
)
应用:
1
WiFi.begin(AP_SSID, AP_PSW);
- 切换到STA模式(
begin(ssid,psw,channel,bssid,connect)
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* 切换工作模式到STA模式,并根据connect属性来判断是否连接wifi
* @param ssid wifi热点名字
* @param password wifi热点密码
* @param channel wifi热点的通道号,用特定通信通信,可选参数
* @param bssid wifi热点的mac地址,可选参数
* @param connect boolean参数,默认等于true,当设置为false,不会去连接wifi热点,会建立module保存上面参数
* @return wl_status_t wifi状态
* @note 调用这个方法就会切换到STA模式。
* 如果connect等于true,会连接到ssid的wifi热点。
* 如果connect等于false,不会连接到ssid的wifi热点,会建立module保存上面参数。
*/
wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel =0, const uint8_t* bssid = NULL, bool connect = true- 配置IP信息(
config(local_ip,gateway,subnet,dns1,dns2)
)
源码:
1
2
3
4
5
6
7
8
9
10
11/**
* 禁止DHCP client,设置station 模式下的IP配置
* @param local_ip station固定的ip地址(连接快)
* @param gateway 网关
* @param subnet 子网掩码(前3个参数都设置为0.0.0.0,则重启DHCP)
* @param dns1,dns2 可选参数定义域名服务器(dns)的ip地址,这些域名服务器
* 维护一个域名目录(如www.google.co.uk),并将它们翻译成ip地址
* @return boolean值,如果配置成功,返回true;
* 如果配置没成功(模块没处于station或者station+soft AP模式),返回false;
*/
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000)- 切换到STA模式(
管理连接:
- 重新连接网络(
reconnect()
)
源码:
1
2
3
4
5
6
7
8/**
* 断开连接并且重新连接station到同一个AP
* @param void
* @return false or true
* 返回false,意味着ESP8266不处于STA模式或者说Station在此之前没有连接到一个可接入点。
* 返回true,意味着已经成功重新启动连接,但是用户仍应该去检测网络连接状态指导WL_CONNECTED。
*/
bool reconnect()应用:
1
2
3
4
5
6WiFi.reconnect();
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}- 断开网络连接(
disconnect()
)
源码:
1
2
3
4
5
6/**
* 断开wifi连接,设置当前配置SSID和pwd为null
* @param wifioff 可选参数,设置为true,那么就会关闭Station模式
* @return false or true 返回wl_status_t状态
*/
bool disconnect(bool wifioff = false);- 是否连接网络(
isConnected()
)
源码:
1
2
3
4
5/**
* 判断STA模式下是否连接上AP
* @return 如果STA连接上AP,那么就返回true
*/
bool isConnected();- 设置是否自动连接到最近接入点(
setAutoConnect(bool autoReconnect)
)
源码:
1
2
3
4
5
6/**
* 当电源启动后,设置ESP8266在STA模式下是否自动连接flash中存储的AP
* @param autoConnect bool 默认是自动连接
* @return 返回保存状态 true or false
*/
bool setAutoConnect(bool autoConnect);- 判断是否自动设置自动连接(
getAutoConnect()
)
源码:
1
2
3
4
5/**
* 检测ESP8266 station模式下是否启动自动连接
* @return 返回自动连接状态 true or false
*/
bool getAutoConnect();- 设置是否自动重连到最近接入点(
setAutoReconnect(bool autoReconnect)
)
源码:
1
2
3
4
5
6
7/**
* 设置当断开连接的时候是否自动重连
* 网络断开后再设置无效
* @param autoConnect bool
* @return 返回保存状态 true or false
*/
bool setAutoReconnect(bool autoReconnect);- 判断网络连接状态(
waitForConnectResult()
)
源码:
1
2
3
4
5
6
7
8
9
10/**
* 等待直到ESP8266连接AP返回结果
* @return uint8_t 连接结果
* 1.WL_CONNECTED 成功连接
* 2.WL_NO_SSID_AVAIL 匹配SSID失败(账号错误)
* 3.WL_CONNECT_FAILED psw错误
* 4.WL_IDLE_STATUS 当wi-fi正在不同的状态中变化
* 5.WL_DISCONNECTED 这个模块没有配置STA模式
*/
uint8_t waitForConnectResult();- 重新连接网络(
station信息:
- 获取mac地址
macAddress(macAddr)
macAddress()
源码:
1
2
3
4
5
6
7
8
9
10
11/**
* 获取ESP station下的Mac地址
* @param mac uint8_t数组的指针,数组长度为Mac地址的长度,这里为6
* @return 返回uint8_t数组的指针
*/
uint8_t * macAddress(uint8_t* mac);
/**
* 获取ESP station下的Mac地址
* @return 返回String的Mac地址
*/
String macAddress();应用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//实例代码1 这只是部分代码 不能直接使用
if (WiFi.status() == WL_CONNECTED)
{
uint8_t macAddr[6];
WiFi.macAddress(macAddr);
Serial.printf("Connected, mac address: %02x:%02x:%02x:%02x:%02x:%02x\n", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
//Connected, mac address: 5C:CF:7F:08:11:17
}
//实例代码2 这只是部分代码 不能直接使用
if (WiFi.status() == WL_CONNECTED)
{
Serial.printf("Connected, mac address: %s\n", WiFi.macAddress().c_str());
Connected, mac address: 5C:CF:7F:08:11:17
}- 获取ip地址(
localIP()
)
源码:
1
2
3
4
5/**
* 返回ESP8266 STA模式下的IP地址
* @return IP地址
*/
IPAddress localIP();应用:
1
2
3
4
5
6if (WiFi.status() == WL_CONNECTED)
{
Serial.print("Connected, IP address: ");
Serial.println(WiFi.localIP());
//Connected, IP address: 192.168.1.10
}- 获取子网掩码(
subnetMask()
)
源码:
1
2
3
4
5/**
* 获取子网掩码的地址
* @return 返回子网掩码的IP地址
*/
IPAddress subnetMask();应用:
1
2
3Serial.print("Subnet mask: ");
Serial.println(WiFi.subnetMask());
//Subnet mask: 255.255.255.0- 获取网关地址(
getwayIP()
)
源码:
1
2
3
4
5/**
* 获取网关IP地址
* @return 返回网关IP地址
*/
IPAddress gatewayIP();应用:
1
2
3//实例代码 这只是部分代码 不能直接使用
Serial.printf("Gataway IP: %s\n", WiFi.gatewayIP().toString().c_str());
//Gataway IP: 192.168.1.9- 获取dns地址(
dnsIP()
)
源码:
1
2
3
4
5
6/**
* 获取DNS ip地址
* @param dns_no dns序列号
* @return 返回DNS服务的IP地址
*/
IPAddress dnsIP(uint8_t dns_no = 0);应用:
1
2
3
4
5
6Serial.print("DNS #1, #2 IP: ");
WiFi.dnsIP().printTo(Serial);
Serial.print(", ");
WiFi.dnsIP(1).printTo(Serial);
Serial.println();
//DNS #1, #2 IP: 62.179.1.60, 62.179.1.61- 获取host名字(
hostname()
)
源码:
1
2
3
4
5/**
* 获取ESP8266 station DHCP的主机名
* @return 主机名
*/
String hostname();- 设置host名字(
hostname(hostname)
)(3种)
源码:
1
2
3
4
5
6
7
8/**
* 设置ESP8266 station DHCP的主机名
* @param aHostname 最大长度:32
* @return ok
*/
bool hostname(char* aHostname);
bool hostname(const char* aHostname);
bool hostname(String aHostname);应用:
1
2
3
4
5Serial.printf("Default hostname: %s\n", WiFi.hostname().c_str());
WiFi.hostname("Station_Tester_02");
Serial.printf("New hostname: %s\n", WiFi.hostname().c_str());
//Default hostname: ESP_081117
//New hostname: Station_Tester_02- 获取当前wifi连接状态(
status()
)
源码:
1
2
3
4
5/**
* 返回wifi的连接状态
* @return 返回wl_status_t中定义的其中一值,wl_status_t在 wl_definitions.h中定义
*/
wl_status_t status();- 获取wifi网络名字(
SSID()
)
源码:
1
2
3
4
5/**
* 返回当前通信网络的SSID
* @return SSID
*/
String SSID() const;应用:
1
2
3//实例代码 这只是部分代码 不能直接使用
Serial.printf("SSID: %s\n", WiFi.SSID().c_str());
//SSID: sensor-net- 获取wifi网络密码(
psk()
)
源码:
1
2
3
4
5/**
* 返回当前通信网络的密码
* @return psk
*/
String psk() const;- 获取wifi网络macaddress(
BSSID()
)
源码:
1
2
3
4
5
6/**
* 返回当前通信网络的mac地址
* @return bssid uint8_t *
*/
uint8_t * BSSID();
String BSSIDstr();应用:
1
2Serial.printf("BSSID: %s\n", WiFi.BSSIDstr().c_str());
//BSSID: 00:1A:70E:C1:68- 获取wifi网络的信号强度(
RSSI()
)
源码:
1
2
3
4
5/**
* Return the current network RSSI.返回当前通信网络的信号强度,单位是dBm
* @return RSSI value
*/
int32_t RSSI();应用:
1
2Serial.printf("RSSI: %d dBm\n", WiFi.RSSI());
//RSSI: -68 dBm- 获取mac地址
智能配置:
- 进入智能配置功能(
beginSmartConfig()
) - 查询智能配置状态(
smartConfigDone()
) - 停止智能配置功能(
stopSmartConfig()
) WiFi.beginWPSConfig()
1
2
3
4
5
6
7
8
9
10
11
12
13
14bool beginWPSConfig(void);
/**
* 启动 SmartConfig
*/
bool beginSmartConfig();
/**
* 停止 SmartConfig
*/
bool stopSmartConfig();
/**
* 查找SmartConfig状态来决定是否停止配置
* @return smartConfig Done
*/
bool smartConfigDone();- 进入智能配置功能(
3、AP库(ESP8266WIFIAP)
- 配置soft-AP:
- 启动开放式wifi网络(
softAP(ssid)
) - 启动校验式wifi网络(
softAP(ssid,password,channel,hidden)
) - 配置ap网络信息(
softAPConfig(local_ip,gateway,subnet)
)
- 启动开放式wifi网络(
- 管理网络:
- 获取连接到AP上的station的数目(
softAPgetStationNum()
) - 关闭AP模式(
softAPdisconnect(bool wifi off)
)
- 获取连接到AP上的station的数目(
- 网络信息:
- 获取ap的IP地址(
softAPIP()
) - 获取ap的mac地址(
softAPmacAddress()
)
- 获取ap的IP地址(
4、WiFi扫描库(ESP8266WiFiScan):
一般使用异步扫描(不影响代码运行)
扫描操作:
同步扫描周边有效wifi网络(
scanNetworks()
)源码:
1
2
3
4
5
6
7
8
9/**
* Start scan WiFi networks available
* @param async run in async mode(是否启动异步扫描)
* @param show_hidden show hidden networks(是否扫描隐藏网络)
* @param channel scan only this channel (0 for all channels)(是否扫描特定通道)
* @param ssid* scan for only this ssid (NULL for all ssid's)(是否扫描特定的SSID)
* @return Number of discovered networks
*/
int8_t scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL);应用:
1
2
3
4
5
6
7
8
9//实例代码 这只是部分代码 不能直接使用
//同步扫描
int n = WiFi.scanNetworks();//不需要填任何参数
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
} else {
Serial.println(" networks found");
}异步扫描周边有效wifi网络,包括隐藏网络(
scanNetworks(bool async,bool show_hiden)
)应用:
1
2
3
4
5
6
7
8
9
10
11
12
13//实例代码 这只是部分代码 不能直接使用
//异步扫描
WiFi.scanNetworks(true);
// print out Wi-Fi network scan result uppon completion
int n = WiFi.scanComplete();
if(n >= 0){
Serial.printf("%d network(s) found\n", n);
for (int i = 0; i < n; i++){
Serial.printf("%d: %s, Ch:%d (%ddBm) %s\n", i+1, WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : "");
}
//打印一次结果之后把缓存中的数据清掉
WiFi.scanDelete();
}检测异步扫描的结果(
scanComplete()
)源码:
1
2
3
4
5
6
7/**
* called to get the scan state in Async mode(异步扫描的结果函数)
* @return scan result or status
* -1 if scan not find
* -2 if scan not triggered
*/
int8_t scanComplete();从内存中删除最近扫描结果(
scanDelete()
)如果不删除,则会叠加上次扫描结果;
1
2
3
4/**
* delete last scan result from RAM(从内存中删除最近的扫描结果)
*/
void scanDelete();异步扫描周边wifi网络,并回调结果(
scanNetworkAsync(onComplete,show_hidden)
)源码:
1
2
3
4
5
6/**
* Starts scanning WiFi networks available in async mode
* @param onComplete the event handler executed when the scan is done
* @param show_hidden show hidden networks
*/
void scanNetworksAsync(std::function<void(int)> onComplete, bool show_hidden = false);应用:
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//实例代码
void prinScanResult(int networksFound)
{
Serial.printf("%d network(s) found\n", networksFound);
for (int i = 0; i < networksFound; i++)
{
Serial.printf("%d: %s, Ch:%d (%ddBm) %s\n", i + 1, WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : "");
}
}
void setup()
{
Serial.begin(115200);
Serial.println();
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
WiFi.scanNetworksAsync(prinScanResult);
}
void loop() {}
//应该会打印如下类似的显示
//5 network(s) found
//1: Tech_D005107, Ch:6 (-72dBm)
//2: HP-Print-A2-Photosmart 7520, Ch:6 (-79dBm)
//3: ESP_0B09E3, Ch:9 (-89dBm) open
//4: Hack-4-fun-net, Ch:9 (-91dBm)
//5: UPC Wi-Free, Ch:11 (-79dBm)
扫描结果:
获取wifi网络名字(
SSID(int networkltem)
)1
2
3
4
5
6/**
* Return the SSID discovered during the network scan.
* @param i specify from which network item want to get the information
* @return ssid string of the specified item on the networks scanned list
*/
String SSID(uint8_t networkItem);获取wifi网络信号强度(
RSS(int networkltem)
)1
2
3
4
5
6/**
* Return the RSSI of the networks discovered during the scanNetworks(信号强度)
* @param i specify from which network item want to get the information
* @return signed value of RSSI of the specified item on the networks scanned list
*/
int32_t RSSI(uint8_t networkItem);获取wifi网络加密方式(
encryption Type(int networkltem)
)1
2
3
4
5
6
7
8
9
10
11
12
13/**
* Return the encryption type of the networks discovered during the scanNetworks(加密方式)
* @param i specify from which network item want to get the information
* @return encryption type (enum wl_enc_type) of the specified item on the networks scanned list
* ............ Values map to 802.11 encryption suites.....................
* AUTH_OPEN ----> ENC_TYPE_WEP = 5,
* AUTH_WEP ----> ENC_TYPE_TKIP = 2,
* AUTH_WPA_PSK ----> ENC_TYPE_CCMP = 4,
* ........... except these two, 7 and 8 are reserved in 802.11-2007.......
* AUTH_WPA2_PSK ----> ENC_TYPE_NONE = 7,
* AUTH_WPA_WPA2_PSK ----> ENC_TYPE_AUTO = 8
*/
uint8_t encryptionType(uint8_t networkItem);获取wifi网络mac地址(
BSSID(int networkltem)
)1
2
3
4
5
6
7
8
9
10
11
12
13/**
* return MAC / BSSID of scanned wifi (物理地址)
* @param i specify from which network item want to get the information
* @return uint8_t * MAC / BSSID of scanned wifi
*/
uint8_t * BSSID(uint8_t networkItem);
/**
* return MAC / BSSID of scanned wifi (物理地址)
* @param i specify from which network item want to get the information
* @return uint8_t * MAC / BSSID of scanned wifi
*/
String BSSIDstr(uint8_t networkItem);获取整体网络信息,名字,信号强度等(
getNetworkInfo
)入参前面多数加了&,意味着调完函数后外面获取到的详细洗信息;
1
2
3
4
5
6
7
8
9
10
11
12/**
* loads all infos from a scanned wifi in to the ptr parameters
* @param networkItem uint8_t
* @param ssid const char**
* @param encryptionType uint8_t *
* @param RSSI int32_t *
* @param BSSID uint8_t **
* @param channel int32_t *
* @param isHidden bool *
* @return (true if ok)
*/
bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel, bool &isHidden);获取wifi网络通道号
1
2
3
4/**
* return channel of scanned wifi(通道号)
*/
int32_t channel(uint8_t networkItem);判断wifi网络是否是隐藏网络
1
2
3
4
5
6/**
* return if the scanned wifi is Hidden (no SSID)(判断扫描到的wifi是否是隐藏wifi)
* @param networkItem specify from which network item want to get the information
* @return bool (true == hidden)
*/
bool isHidden(uint8_t networkItem);
5、TCP客户端(WiFiClient):
TCP与HTTP关系:
TCP是底层通讯协议,定义的是数据传输和连接方式的规范;
HTTP是应用层协议,定义的是传输数据的内容规范;
HTTP协议中的数据是利用TCP协议传输的,所以支持HTTP就支持TCP。
- 连接操作:
- 启动tcp连接(
connect(host,port)
) - 判断client是否还在连接(
connected()
) - 停止tcp连接(
stop()
)
- 启动tcp连接(
- 发送http请求操作:
print()
println()
write()
- 响应操作:
- 判断是否有响应数据(
available()
) - 查找响应数据某个字符串(
find()
) - 读取响应数据直到某个字符串,会清除掉(
readStringUntil
) - 读取响应数据中的一个字符,不清除(
peek()
) - 读取固定大小的响应数据,不清除(
peekBytes(buf,size)
) - 读取响应数据中的一个字符,清掉(
read()
) - 读取固定大小的响应数据,清掉(
read(buf,size)
) - 清掉缓冲区(
flush()
)
- 判断是否有响应数据(
- 普通设置:
setNoDelay()
6、TCP客户端(WiFiClientSecure https):
7、TCP服务端(WiFiServer):
- 管理server:
- 设置tcp server:
- 新增tcp server(
WiFiServer server(port)
) - 启动tcp server(
begin()
) - 关闭小包合并发送功能(
setNoDelay(true)
)
- 新增tcp server(
- 停止server:
close()
stop()
(内部实现直接调用close())
- server状态 :
server.status()
- 设置tcp server:
- 等待WiFiClient访问:
- 判断是否有新的client连接进来(
available()
) - 判断是否有client连接(
has Client()
)
- 判断是否有新的client连接进来(
- 读取WiFiClient的请求:参考WiFiClient里面的响应方法
8、TCP服务端(WiFiServerSecure https)
9、ESP8266WiFi库自带方法:
- 调用调试信息(
printDiag(serial)
)
总结:](https://imgtu.com/i/fedfFe)
3、示例
1、AP模式
1 | /** |
2、STA模式
1.
1 | /** |
2.
1 | /** |
3.
1 | /** |
3、扫描:
1.
1 | /** |
2.
1 | /** |
3.
1 | /** |
4、通用库处理事件:
- 官方示例:(AP模式)
1 | /* |
- station模式:
1 |
|
5、TCP客户端(client)
- 演视WiFiClient与TCP server之间通信功能(使用TCP调试助手(TCP/UDP Socket调试工具))在TCP调试助手上建立一个TCP server, IP地址是192.168.1.102,端口号是8234。
1 | /** |
通过TCP client包装Http请求协议去调用天气接口获取天气信息
(使用ArduinoJson库,尽量使用5.X版本)
1 | /** |
6、TCP服务端(server)
- 8266作为WiFiServer端,打开TCP调试助手,模拟TCP Client的请求;
1 | /** |
- 8266作为web server端,打开PC浏览器输入IP网址,请求web server
1 | /** |
- 8266作为WiFiServer端,演示简单的web server功能,web server 会根据请求来做不同的操作
1 | /* |
7、Smartconfig智能配网:
收集APP端发送包含WIFI用户名和密码的UDP广播包,智能终端的WIFI芯片接收到UDP包,解密配置连接。
手机软件esptouch:
1 |
|
13、HttpClient–ESP8266HTTPClient库
1、HTTP
1、概述
HTTP协议(Hyper Text Transfer Protocol)超文本传输协议,用于从WWW服务器传输文本到本地浏览器的传送协议。基于TCP/IP通信协议:浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。WEB服务器根据接收到的请求后,向客户端发送响应信息;
HTTP协议作为TCP/IP模型中应用层的协议,承载与TCP协议上,有时也承载与TLS或者SSL协议层之上,这时就是HTTPS;
HTTP由请求与响应构成,是一个标准的客户端服务器模型,默认端口号80,HTTPS是443;
浏览网页时HTTP主要应用(不只是这个功能,只是一种协议,只要通信双方都支持这个协议,HTTP就能用)
特点:HTTP0.9与1.0使用非持续连接;1.1使用持续连接。
无状态,无记忆能力
2、工作流程
一次HTTP操作称位一个事务,可分4步:
client与server建立连接;
连接后,client发送一个请求给server,请求方法格式:统一资源标示符(URL)、HTTP协议版本号、请求头、请求内容等;
server接收到请求后,给予响应,格式:状态行(包括协议版本、成功或者失败代码、服务器信息、实体信息等)
client接收到server返回信息,通过浏览器显示在用户显示屏上,然后client与server断开连接
3、HTTP请求
Get请求:
- 请求行(request line):说明请求类型,要访问的资源及HTTP版本
- 请求头部(header):说明服务器要使用的附加信息(第二行起位请求头部,HOST指出目的地;User-Agent是client与server脚本都能访问,是浏览器检测逻辑的重要基础)(该信息由浏览器定义,并在每个请求中自动发送)
- 空行(empty line):请求头部后空行是必须的(即使第四部分请求数据为空,也必须有空行)
- 请求数据(request body):主体,可添加任意其他数据(下面例子中请求数据为空)
请求例子(Gharles抓取的request)
1 | GET /562f25980001b1b106000338.jpg HTTP/1.1 |
POST请求:
请求例子(Gharles抓取的request)
1 | POST / HTTP1.1 |
4、HTTP Response响应信息
- 状态行
- 消息报头
- 空行
- 响应正文
HTTP状态码
5、ESP8266HTTPClient库
6、示例
- 获取天气请求(心知天气)
setup中配置好url,串口参数和httpclient并设置client请求头。loop中每1秒请求一次get服务,把获取回来的天气信息通过json库转成具体对应的数值
1 | /** |
演视响应头获取信息
设置了获取四个请求头的信息,然后通过header方法获取它们的数值(接口限制,无法发挥作用)
1 | /** |
14、UDP服务
1、UDP
UDP(User Datagram Protocol)一种无连接、不可靠的协议(可能会丢包),
相对于TCP而言:
UDP面向无连接的,不需建立连接(TCP是面向连接的)
UDP尽力做到可靠,但不绝对可靠(TCP无差错、不丢失、不重复且按序到达)
UDP较好实时性,效率比TCP高
UDP支持一对一,一对多,多对一和多对多的交互通信(TCP点到点)
UDP对系统资源要求较少(TCP多)
2、库和示例
- 通过UDP收发数据
ESP8266作为UDP服务端,把电脑UDP客户端发过来的数据打印到串口调试器,并回复应答消息(使用Packet Sender软件发送UDP数据)
1 |
|
- 通过UDP控制LED
1 |
|
15、WebServer–ESP8266WebServer库
示例:
- 演示webserver基础功能,wifi模块连接上热点后,在PC浏览器上输入serverip+url访问
1 | /** |
- 演示webserver返回html功能
1 | /** |
- 演示webserver校验账号密码功能,Autherticate请求头
1 | /** |
- 演示webserver登录功能,html登录页面
1 | /** |
16、域名服务–ESP8266mDNS库
1、DNS
DNS(Domain Name System)域名系统(因特网上作为域名和IP地址相互映射的一个分布式数据库),DNS协议运行在UDP协议上,端口号53,mDNS(Multicast DNS)组播dns,主要实现了在没有传统DNS服务器的情况下使用局域网内的主机实现本地发现和域名访问,端口号5353,遵从dns协议(基于UDP协议,即运用了UDP广播)。
2、库和示例
- 演示ESP8266 mDNS responder功能
电脑端输入http://esp8266.local/
以域名方式访问webserver
1 | /** |
2.
1 | /* |
17、SPIFFS–ESP8266 SPIFFS文件系统
1、概述:
Arduino环境下的esp8266的flash存储分配:
- 代码区:程序存储区(包含当前代码区current Sketch、更新代码区OTA update)
- 文件系统:SPIFFS闪存文件系统(SPI Flash File System)可通过IDE配置,一般NodeMcu配置成3M```#include<FS.h>``
不支持目录 文件名32字符限制 建议保持短文件名
- EEPROM
- WIFI Config:设置WiFi模块配置时存储的数据
2、库和使用
- 文件操作
1 | /** |
- 查看spiffs文件系统列表
1 | /** |
- 往文件myDemo.txt中写入一句话并读取出来显示
1 | /** |
- 烧写文件,将要存入SOIFFS区域的文件,提前放在代码目录的”data”目录中,使用ESP8266FS工具烧写(集成在ArduinoIDE中,但要安装这个工具)(提示没有找到这个工具的话,一般都是版本问题,换个版本就好了)
1 | /** |
18、web配网
自定义AP配网
1 | /** |
19、NTP–时间服务
NTP(Network Time Protocol)网络时间协议,基于UDP,用于网络时间同步的协议,使网络中的计算机时钟同步到UTC,再配合各个时区的偏移调整就能实现精准同步对时功能。
NTP报文协议
实现:
- 拼接协议
- 使用现成NTP第三方库(NTPClient)
1 |
|
20、DNSServer–真正的域名服务
建立DNS服务,使用时模块必须处于AP模式下;真正意义上的精简版DNS服务器;DNSServer运行于UDP服务;这里DNS服务器唯一的作用是把域名转成对应映射地址(只支持一个)
1.
1 | /** |
- Portal认证
1 | /** |
21、无线更新–OTA固件更新
1、ArduinoOTA
- 连接WIFI;
- 配置ArduinoOTA对象的事件函数;
- 启动ArduinoOTA服务ArduinoOTA.begin();
- 在loop()函数将处理权交由ArduinoOTA.handle()。
为了区分正常工作模式以及更新模式,可以设置标志位来区分(标志位可通过其他手段修改,如按键、软件控制)
1 | void loop() { |
python2.7环境
旧代码:
1 | /** |
烧写成功后,重启IDE(IDE与8266建立无线连接)端口项出现网络端口
新代码:
1 | /** |
2、WebUpdateOTA
- 系统自带OTA之WEB更新(通过建立 webserver来上传新固件以达到更新目的)
V1.1代码:
1 | /* |
同一WIFI下,打开调试器中提示的网站
编译V1.1代码:
1 | /* |
选择bin文件,通过WEB网页上传
- 自定义OTA之WEB更新(个性化页面)
3.SerialUpdateOTA—OTA之服务器更新
放在服务器上,无感知更新
22、WebSocket Client–全双工通信
问题:HTTP:一个请求-响应应用层协议,客户端没有主动发请求,服务器不能主动给客户端发数据
方法:
- 轮询(浪费带宽资源)
- 应用层协议解决MQTT协议
- WebSocket协议:让客户端与服务器之间建立无限制的全双工通信,任何一方都可主动发消息给对方(HTML5定义的协议,更好的节省服务器资源和带宽,并实时进行通讯)
两阶段:
通过HTTP请求确认WebSocket握手协议阶段;
通过WebSocket交互数据阶段。
23、例程
1、局域网应用–炫酷RGB
相关技术点:
- ArduinoJson库
- TCP Server服务
- STA模式
- 一键配网
内容:
手机、ESP8266均连接在同一个路由器wifi,8266作为服务端,手机作为客户端,手机再通过wifi给8266发送数据,8266接收到数据再把数据发给Arduino(串口通信),Arduino解析数据达到控制效果
实现:
8266端代码:
1 | /** |
Arduino端代码:(接收8266信息,JSON解析)
1 | /** |
2、OLED显示天气屏
相关技术点:
- ArduinoJson V5库
- TCP Client
- STA模式
- 一键配网
- U8G2 OLED库
内容:
向心知天气请求当地城市天气情况,并在OLED上显示天气图标、温度值以及城市名称
心知天气参考wiki
天气编码wiki
1 | /** |
3、WIFI小车
相关技术点:
WebSocket Client 全双工通信
WebSocket Server 全双工通信
内容:
- NodeMcu作为AP。手机控制端作为STA,连接AP
- NodeMcu作为WebSocketServer端,手机作为WebSocketClient端
- 两者建立WS通信,手机往NodeMcu发送控制命令
- NodeMcu控制电机
实现:
1 | /* |