• ESP8266物联网套件学习


    物联网

    简介

    物联网 == Internet of things【IOT】

    注: Intenet 的 I 是大写,
    internet = 互连网 将计算机网络互连的任意网络,不一定遵循TCP/IP协议组的通信规则
    Internet = 使用TCP/IP协议族作为通信规则的特殊互连网(即互联网)

    物联网最重要的属性,就是将设备接入互联网
    例:两个设备使用2.4G模块,进行无线通信,这不算为【物联网】
    多个设备接入wifi路由器,在局域网内传输数据,这不算为【物联网】
    因为虽然设备实现了【物联】,但是没有实现设备接入【互联网】,所以不能称之为【物联网】

    设备接入互联网的作用:
    设备接入互联网后,可以将数据上报给物联网平台,也可以接受物联网平台的指令。

    物联网通信方式

    在这里插入图片描述
    没有一种通信方式可以满足所有的物联网通信,所以根据不同场景选用不同的通信方式。
    例:工业现场一般采用以太网的方式进行通信;家庭智能家电采用wifi的方式;共享单车采用3G/4G的方式,等……

    ESP8266模组介绍

    本次学习采用wifi的通信方式,CPU为乐鑫ESP8266 WIFI芯片,模组为安信可ESP-12F。
    乐鑫官网对ESP9266的介绍 :https://www.espressif.com/zh-hans/products/modules/esp8266
    安信可官网对ESP-12F的介绍:https://docs.ai-thinker.com/esp8266
    ESP-12F模组:
    电源3.3V,外部晶振26MHz,外部4M Flash,PCB板载天线
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ESP8266的使用方式

    1)AT指令
    使用额外的单片机,通过串口发送AT指令(串口数据)到ESP8266,ESP8266则会执行相应功能,如连接wifi、发送网络数据等。缺点:需要额外单片机增加成本,效率低
    2)SDK编程
    ESP8266集成32bit内核处理器,带片上SRAM,可以通过GPIO等外设连接传感器和其他设备。可以将ESP8266独立应用,程序存放在外部Flash,ESP8266读取外部Flash中的程序,执行相应功能。优点:无需额外增加单片机,节省成本,效率高。
    SDK包中文件夹的应用
    在这里插入图片描述
    在这里插入图片描述

    ESP8266编译环境搭建

    1)乐鑫提供的编译环境需要使用linux操作系统,需安装虚拟机
    2)安信可提供windows操作系统下的一体化编译环境。
    下载网址:https://docs.ai-thinker.com/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B72

    ESP8266程序编译

    ESP8266的编程是以SDK包为基础的。
    1)ESP8266的SDK包配置
    1.复制一个SDK软件包根据自己的需求进行重命名
    在这里插入图片描述
    2.将SDK包中的driver_lib重命名为app
    在这里插入图片描述
    3.将SDK包中的exaples目录中的IoT_demo复制到app目录中
    在这里插入图片描述
    选择替换
    在这里插入图片描述
    将examples文件夹删除掉
    在这里插入图片描述
    将third_party目录中的makefile文件修改为makefile.bak
    在这里插入图片描述

    2)导入SDK工程
    1.在IDE的project区域右键选择import->C/C+±>Existing Code as Makefile Project
    在这里插入图片描述
    导入刚刚配置的SDK包
    在这里插入图片描述

    3)编译SDK工程
    编译前需要“Clean Project”,清除之前的编译残留。
    在这里插入图片描述
    4)尝试编译成功
    在这里插入图片描述
    5)SDK包文件整改
    根据图中所示将SDK包中的文件进行删减和修改
    在这里插入图片描述

    ESP8266程序下载

    ESP-12F模组外部Flash = 4MB = 4096KB = 32Mbit
    4MB Flash = 0x000 000 ~ 0x3FF FFF
    扇区编号:0x000 ~ 0x3FF 【Flash扇区 = 4KB】
    在这里插入图片描述
    外部Flash布局
    1)eagle.flash.bin系统程序: 存放运行系统必要的固件
    2)eagle.irom0.text.bin系统程序: 存放用户编写的程序
    3)用户数据: 存放用户的参数/数据
    4)RF_CAL参数: 存放系统自动保存校准后的RF参数
    5)默认RF参数: 存放默认的RF参数信息(将ep_int_data_default.bin)下载到该区
    6)系统参数: 存放系统参数信息(将blank.bin下载到该区)

    需要烧录到ESP8266的文件
    在这里插入图片描述
    文件的下载地址
    在这里插入图片描述
    下载固件
    双击ESP_DOWANLOAD_TOOL.exe 打开flash下载
    下载固件的配置
    在这里插入图片描述
    点击下载,下载工具提示下载完成,开发板按RESET键即可。

    GPIO00 = 1、GPIO02 = 1、GPIO15 = 0 ->程序运行模式
    GPIO00 = 0、GPIO02 = 1、GPIO15 = 0 ->串口下载模式

    注意点:
    在这里插入图片描述
    在这里插入图片描述

    ESP8266程序架构

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    ESP8266的UART

    包含头文件

    #include "osapi.h"
    #include "user_interface.h"
    
    • 1
    • 2

    API接口

    void os_printf(const char *s)	//格式化呼出,打印字符串
    例程:
    	os_printf("SDK version:%s\n",system_get_sdk_version());		// 串口打印SDK版本
    	其中system_get_sdk_version()表示返回SDK版本号
    
    • 1
    • 2
    • 3
    • 4

    驱动的源文件
    SDK包->app(原名driver_lib)->driver->uart.c
    SDK包->app(原名driver_lib)->incude->driver->uart.h和uart_register.h

    串口初始化:
    	void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);//传参uart_0波特率,uart_1波特率
    uart_0打印函数:
    	void uart0_sendStr(const char *str);//串口0打印字符串
    数据位长度
    	void UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len);//传参uart_0/1,数据位长度
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注:
    1.默认从UART_0打印 //一般常用UART_0
    2.波特率默认值 = 74880 //ESP12F模组的晶振=26MHz:74880
    3.数据格式:数据位=8、停止位=1、无校验位、无数据流控制

    ESP8266的软件定时器

    1)定义软件定时器

    os_timer_t OS_Timer_1;//定义软件定时器(os_timer_t型结构体)
    //注:OS_Timer_1 必须定义为全局变量,因为ESP8266的内核还要使用
    
    • 1
    • 2

    2)软件定时的回调函数

    void ICACHE_FLASH_ATTR OS_Timer_1_cb(void)
    {
    	LED=!LED;
    	GPIO_OUTPUT_SET(GPIO_ID_PIN(4),LED);
    
    	os_printf("OS_Timer_1_cb\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3)软件定时器初始化(ms)

    void ICACHE_FLASH_ATTR OS_Timer_1_Init(u32 time_ms,u8 time_repetitive)
    {
    	//关闭定时器
    	//参数1:要关闭的定时器
    	os_time_disarm(&OS_Timer_1);
    	
    	//设置定时器
    	//参数1:要设置的定时器;参数2:回调函数(需类型转换);参数三:回调函数的参数
    	//os_timer_setfn必须在软件定时器未使能的情况下使用
    	os_timer_setfn(&OS_Timer_1,(os_timer_func_t *)OS_Timer_1_cb,NULL);
    	
    	//设置定时器参数并使能ms定时器
    	//参数1:要使能的定时器;参数2:定时时间(单位:ms);参数三:1-重复0-只运行一次
    	os_timer_arm(&OS_Timer_1,time_ms,time_repetitive);
    	//未调用system_timer_reinit,可支持[5ms-6870947ms]
    	//调用system_timer_reinit,可支持[100ms-428496ms]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4)在user_main.c文件中初始化

    OS_Timer_1_Init(500,1)//表示500ms运行一次,可重复定时	
    
    • 1

    注:
    软件定时器接口位于ESP8266_NONOS_SDK/include/osapi.h。上述使用的定时器是由软件实现,定时器的函数在任务中被执行。因为任务可能被中断或者被其他高优先级的任务延迟,因此os_timer系列的接口并不能保证定时器精确运行,精准的定时器要硬件定时器。

    ESP8266的硬件定时器

    1)将ESP8266_NONOS_SDK/driver_lib/driver/hw_timer.c文件放到自建工程的app/driver/目录下
    2)硬件定时回调函数

    //注意中断函数前不要有"ICACHE_FLASH_ATTR"
    void HW_Timer_INT(void)
    {
    	LED = !LED;
    	GPIO_OUTPUT_SET(GPIO_ID_PIN(4),LED);
    	os_printf("HW_Timer_INT\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3)硬件定时器初始化

    //初始化硬件定时器 参数1:中断源 参数2:是否重复
    //使用NMI中断源,那么该定时器将为最高优先级,可打断其他中断(NMI_SOURCE = 1)
    //使用FRC1中断源,那么该定时器无法打断其他中断(FRC1_SOURCE = 0)
    hw_timer_init(0,1);
    
    //注册回调函数
    hw_timer_set_func(HW_Timer_INT);
    
    //设置定时器参数(单位us,参数必须<=1677721)
    hw_timer_arm(500000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ESP8266的用户任务

    无操作系统的SDK并不能像有操作系统的SDK那样支持任务调度,无操作系统的SDK中使用四种类型的函数:
    应用函数;回调函数;用户任务;中断服务程序
    其中无操作系统的SDK中用户任务最多设三个优先级:0,1,2。任务优先级为2>1>0

    函数与任务的区别:
    调用函数:立即进入该函数,执行函数语句,实现函数功能
    安排任务:给系统安排任务,当系统空闲时,才会执行任务

    使用system_os_post()API给系统安排任务时
    参数2(消息类型)传递给任务函数形参->sig
    参数3(消息参数)传递给任务函数形参->par

    调用任务时需给出任务参数(参数1:任务等级;参数2:消息类型;参数3:消息参数)
    不论系统是否还有未完成的任务,用户都可以继续安排任务(任务可叠加),当系统空闲时会依次执行任务函数。

    注:任务虽然可以叠加,但是叠加次数不能超过设定值(消息队列深度)。超过设定值(消息队列深度)的任务将被丢弃

    创建系统任务API

    bool system_os_task(os_task_t task,uint8 prio,os_event_t *queue,uint8 qlen)
    //os_task_t task:任务函数
    //uint8 prio:任务优先级,可为0,1,2;0:为最低优先级,这表示最多只支持建立3个任务
    //os_event_t *queue:消息队列指针
    //uint8 qlen:消息队列深度
    
    • 1
    • 2
    • 3
    • 4
    • 5

    给系统安排任务API

    bool system_os_post(uint8 prio,os_signal_t sig,os_param_t par)
    //uint8 prio:任务优先级,与建立时的任务优先级对应
    //os_signal_t sig:消息类型
    //os_param_t par:消息参数
    
    • 1
    • 2
    • 3
    • 4

    例程

    1.定义消息队列深度
    MESSAGE_QUEUE_LEN
    2.定义任务指针
    os_event_t *pointer_task
    3.分配任务空间
    pointer_task = (os_event_t*)os_malloc((sizeof(os_event_t))*MESSAGE_QUEUE_LEN)
    4.创建任务执行函数
    void func_task(os_event_t *Task_message)
    {	
    	os_printf("消息类型%d,消息参数%c\n",Task_message->sig,Task_message->par);
    }
    5.创建任务
    system_os_task(func_task,USER_TASK_PRIO_0,pointer_task,MESSAGE_QUEUE_LEN);
    6.安排任务
    u8 message_sig = 1;
    u8 message_par = 'A';
    system_os_post(USER_TASK_PRIO_0,message_sig++,message_par++);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    ESP8266读写外部Flash

    ESP-12F模组的外部Flash,除了存储系统程序,系统参数外,还可以用来存储用户数据,复位/掉电也不会丢失用户数据

    ESP-12F模组的外部Flash = 32Mbit = 4MB
    Flash_4MB的地址 = 0x000 000 ~ 0x3FF FFF
    扇区编号 = 0x000 ~ 0x3FFF[一个扇区4KB]

    注意:
    读/写Flash的地址,不能和系统程序区冲突,可以放在[0x70 000]地址后
    Flash读写,必须[4字节]对齐
    向Flash某扇区写数据前,必须将此扇区擦除,Flash参数函数的参数 [扇区编号]
    读写Flash数据函数的参数 [字节地址] (扇区编号*扇区大小4096)

    Flash相关API

    查询SPI FLASH的ID
    uint32 spi_flash_get_id(void)
    擦除Flash扇区
    SpiFlashOpResult spi_flash_erase_sector(uint16 sec)
    写数据到Flash
    SpiFlashOpResult spi_flash_write(uint32 des_addr,uint32 *src_addr,uint32 size)
    //uint32 des_addr:写入Flash目的地址
    //uint32 *src_addr:写入数据指针
    //uint32 size:数据长度,单位byte,必须4字节对齐进行读写
    从Flash读数据
    SpiFlashOpResult spi_flash_read(uint32 src_addr,uint32 *des_addr,uint32 size)
    //uint32 src_addr:读取Flash目标地址
    //uint32 *des_addr:读取数据指针
    //uint32 size:数据长度,单位byte,必须4字节对齐进行读写
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    例程

    1.定义Flash扇区大小
    FLASH_SIZE 4096
    2.定义操作的扇区编号
    u16 FLASH_SEC = 0x77
    3.定义写入Flash数组
    u32 flash_w[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}
    4.定义读取Flash数组
    u32 flash_r[16] = {0};
    5.先擦除该扇区内容
    spi_flash_erase_sector(0x77); 参数 = 扇区编号
    6.向Flash写数据
    spi_flash_write(0x77*4096,(uint32*)flash_w,sizeof(flash_w));参数1:字节地址=扇区编号*扇区大小
    7.0x77开始读取数据
    spi_flash_read(0x77*4096,(uint32*)flash_r,sizeof(flash_w))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    网络体系结构

    应用层:通过应用进程间的交互来完成特定的【网络应用】
    运输层:负责向【两台主机进程】之间的通信提供通用的【数据传输】服务
    网络层:为分组交换网上不同【主机】提供通信服务
    数据链路层:把网络层交下来的数据构成【帧】发送到链路上,以及把接收到的【帧】中数据取出上交到网络层
    物理层:解决怎样才能在连接计算机的传输媒体上(双绞线,光纤,无线电)传输【比特流】

    WIFI:使用802.11系列协议的局域网称为WIFI

    网际协议IP:TCP/IP体系中两个最主要的协议之一,也是最重要的互联网标准协议之一。
    IPV4:IP数据报,划分子网,构造超网等。

    IP地址:就是给互联网上每一台主机(或路由器)的每一个接口分配一个在全世界范围内唯一的32位的标识符(每8位加一个点)。

    IP地址的标志方法:点分十进制

    IP地址的作用:只有知道主机的IP地址,才能将消息发送给对应的主机
    IP地址中,IP数据报的目标IP地址中,如果主机号全为1,则表示向目标IP网络中的所有主机发送广播消息。

    外网IP:全球唯一IP,可以使用此IP访问互联网
    内网IP:只在本地机构(或局域网)有效的IP地址(本地地址)
    专用地址:

    	10.0.0.0 ~ 10.255.255.255
    	172.16.0.0 ~ 172.31.255.255
    	192.168.0.0 ~ 192.168.255.255
    	以上地址只能用于一个机构(局域网)的内部通信,而不能用于和互联网上的主机通信。
    	在互联网中的所有路由器,对目的地址是专用地址的数据报一律不进行转发。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    端口(运输层)
    端口号:服务器端使用的端口号+客户端使用的端口号

    服务器端使用的端口号:熟知端口号(系统端口号) + 登记端口号

    常用的熟知端口号:

    应用程序FTPTELNETSMTPDNSTFTPHTTPSNMPSNMP(trap)HTTPS
    熟知端口号212325536980161162443

    登记端口号:1024~49151,这类端口号是为没有熟知端口号的应用程序使用,使用这类端口号必须在IANA按照规定的手续登记,以防止重复。

    客户端使用的端口号:49152 ~ 65536,这类端口号仅在客户进程运行时才动态选择,因此又叫短暂端口号。这类端口号是留给客户进程选择暂时使用,服务器接收到客户进程的报文时,就知道了客户进程所使用的端口号

    通过【IP地址+端口】,才能完成【主机进程 ~ 主机进程】之间的通信

    UDP和TCP

    UDP:用户数据报协议
    1.UDP无连接
    2.UDP使用尽最大努力交付,即不保证可靠交付
    3.UDP面向报文,应用层给UDP多长的报文,UDP就照样发送
    4.UDP没有拥塞控制
    5.UDP支持1对1,1对多,多对多

    TCP:传输控制协议
    1.TCP面向连接,使用TCP前必须建立TCP连接
    2.TCP只支持1对1连接
    3.TCP提供可靠交付
    4.TCP提供全双工通信
    5.TCP面向字节流

    TCP连接
    每一条TCP连接有两个端点,TCP连接的端点叫套接字(socket)或插口
    套接字 socket = IP地址+端口号

    应用应用层协议传输层协议
    万维网HTTPTCP

    client & server

    客户程序:在用户调用后运行,在通信时主动向远程服务器发起通信(请求服务),客户程序必须知道远程服务器的地址;不需要特殊的硬件和复杂的操作系统
    服务器程序:专门用来提供某种服务的程序,可同时处理多个远程或本地客户的请求;服务器程序不需要知道客户程序的地址;需要强大的硬件和高级操作系统支持;

    客户和服务器的通信建立后,通信可以时双向的,客户和服务器都可发送和接收数据。

    主动发起连接建立的应用进程叫客户,被动等待连接建立的进程叫服务器

    DHCP

    动态主机配置协议(DHCP)
    作用:自动获取IP地址、子网掩码、默认网关、DNS服务器地址

    AP模式(创建WIFI局域网)

    ESP8266创建局域网,设备接入ESP8266创建的局域网中。

    struct softap_config AP_Config;//AP参数结构体
    
    1.wifi_set_opmode(0x02);//设置AP模式,并保存到Flash
    2.
    os_memset(&AP_Config,0,sizeof(softap_config));//AP参数结构体重置0
    os_strcpy(AP_Config.ssid,ESP8266_AP_SSID);//设置SSID
    os_strcpy(AP_Config.password,ESP8266_AP_PASS);//设置密码
    AP_Config.ssid_len = os_strlen(ESP8266_AP_SSID);//设置SSID长度
    AP_Config.channel = 1;//通道号1-13
    AP_Config.authmode = AUTH_WPA2_PSK;//设置加密模式
    AP_Config.ssid_hidden = 0;//不隐藏SSID
    AP_Config.max_connection = 4;//最大连接数
    AP_Config.beacon_interval = 100;//信标间隔时槽100-60000ms
    
    wifi_softap_set_config(&AP_Config);//设置soft-ap模式,并保存到Flash,默认开启DHCP,IP=192.168.4.1
    3.
    wifi_get_ip_info(SOFTAP_IF,&ESP8266_IP);//参数2:IP信息结构体指针
    wifi_softap_get_station_num();//获取连接设备数量
    
    //注:ESP8266的softap模式建立,并不是立即执行的。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    AP_UDP_SERVER

    ESP8266建立AP模式,ESP8266作为服务器,网络调试助手作为客户端。
    例程

    1.定义espconn型结构体
    struct espconn ST_NetCon;//必须为全局变量,内核将会使用此变量
    2.结构体赋值
    ST_NetCon.type = ESPCONN_UDP;//设置UDP模式
    ST_NetCon.proto.udp = (esp_udp *)os_zmalloc(sizeof(esp_udp));//申请内存
    ST_NetCon.proto.udp->local_port = 8266;//设置本地端口。因为8266用作服务器,所以设定固定端口号
    3.注册/定义回调函数
    void ICACHE_FLASH_ATTR ESP8266_WIFI_Send_Cb(void *arg);//参数1:网络传输结构体espconn指针
    void ICACHE_FLASH_ATTR ESP8266_WIFI_Recv_Cb(void *arg,char *pdata,unsigned short len)//参数1:网络传输结构体espconn指针,参数2:网络传输数据指针,参数3:数据长度
    espconn_get_connection_info();//获取连接客户端的信息
    espconn_send();//向客户端发送消息
    
    espconn_regist_sentcb(&ST_NetCon,ESP8266_WIFI_Send_Cb);//注册网络数据发送成功的回调函数
    espconn_regist_recvcb(&ST_NetCon,ESP8266_WIFI_Recv_Cb);//注册网络数据接收成功的回调函数
    4.调用UDP初始化API
    espconn_create(&ST_NetCon);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    AP_UDP_CLIENT

    ESP8266只是逻辑上作为客户端,还是需要ESP8266建立AP模式,电脑接入ESP8266创建的WIFI网络。ESP8266作为客户端,网络调试助手作为服务器。
    区别:
    此处的8266作为客户端,需要预先知道server端的IP地址和端口号——在程序中写死

    1.添加30S定时再进行连接,目的是为网络调试助手建立服务器提供时间
    2.定义espconn型结构体
    struct espconn ST_NetCon;//必须为全局变量,内核将会使用此变量
    3.结构体赋值
    ST_NetCon.type = ESPCONN_UDP;//设置UDP模式
    ST_NetCon.proto.udp = (esp_udp *)os_zmalloc(sizeof(esp_udp));//申请内存
    4.此处的8266作为客户端,需要预先知道server端的IP地址和端口号(解决方法:在程序中写死)
    ST_NetCon.proto.udp->local_port = 8266;//设置本地端口号(随意设置-ESP8266)
    ST_NetCon.proto.udp->remote_port = 8888;//设置目标端口号(随意设置-网路调试助手)
    ST_NetCon.proto.udp->remote_ip[0] = 192;
    ST_NetCon.proto.udp->remote_ip[1] = 168;
    ST_NetCon.proto.udp->remote_ip[2] = 4;
    ST_NetCon.proto.udp->remote_ip[3] = 2;
    5.定义/注册回调函数
    void ESP8266_WIFI_Recv_Cb(void *arg,char *pdata,unsigned short len)
    {
    	struct espconn *T_arg = arg;//缓存网络连接结构体指针	
    	remot_info *P_port_info = NULL;//定义远端连接信息指针
    	
    	//根据接收到网络调试助手消息进行处理
    	if(pdata[0] == 'K' || pdata[0] == 'k')
    	{
    		LED_ON;
    	}
    	else if(pdata[0] == 'G' || pdata[0] == 'g')
    	{
    		LED_OFF;
    	}
    	else
    	{}
    	os_printf("ESP8266 receive data = %s\n",pdata);
    	
    	//获取远端信息(UDP通信是无连接,向远端主机回应时需要获取对方的IP/端口信息
    	if(espconn_get_connection_info(T_arg,&P_port_info,0) == ESPCONN_OK)
    	{
    		T_arg->proto.udp->remote_port = P_port_info->remote_port;
    		os_memcpy(T_arg->proto.udp->remote_ip,P_port_info->remote_ip,4);	
    	}
    
    espconn_regist_sentcb(&ST_NetCon,ESP8266_WIFI_Send_Cb);//注册网络数据发送成功的回调函数
    espconn_regist_recvcb(&ST_NetCon,ESP8266_WIFI_Recv_Cb);//注册网络数据接收成功的回调函数
    6.调用UDP初始化API
    espconn_create(&ST_NetCon);
    7.调用网络发送数据API
    espconn_send(&ST_NetCon,"Hello,ESP8266",os_strlen("Hello,ESP8266"));//主动向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

    AP_TCP_SERVER

    1.定义espconn型结构体
    struct espconn ST_NetCon;//必须为全局变量,内核将会使用此变量
    2.结构体赋值
    ST_NetCon.type = ESPCONN_TCP;//设置TCP模式
    ST_NetCon.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));//申请内存
    3.ESP8266作为服务器,不需预先知道Client的IP/端口
    ST_NetCon.proto.tcp->local_port = 8266;//设置本地端口
    4.定义/注册回调函数
    void ICACHE_FLASH_ATTR ESP8266_WIFI_Send_Cb(void *arg)
    {
    	os_printf("ESP8266_WIFI_Send_OK\n");
    }
    void ICACHE_FLASH_ATTR ESP8266_WIFI_Recv_Cb(void *arg,char *pdata,unsigned short len)
    {
    	struct espconn *T_arg = arg;
    	
    	//根据接收到网络调试助手消息进行处理
    	if(pdata[0] == 'K' || pdata[0] == 'k')
    	{
    		LED_ON;
    	}
    	else if(pdata[0] == 'G' || pdata[0] == 'g')
    	{
    		LED_OFF;
    	}
    	else
    	{}
    	os_printf("ESP8266 receive data = %s\n",pdata);
    
    	//TCP是面向连接的通信,向远端主机回应时可直接使用T_arg结构体指针指向的IP信息
    	espconn_send(T_arg,"ESP8266_WIFI_Recv_OK",os_strlen("ESP8266_WIFI_Recv_OK"));//向对方发送应答
    }
    void ICACHE_FLASH_ATTR ESP8266_TCP_Disconnect_Cb(void *arg)
    {
    	os_printf("ESP8266_TCP_Disconnect_OK\n");
    }
    void ICACHE_FLASH_ATTR_ESP8266_TCP_Connect_Cb(void *arg)
    {
    	espconn_regist_sentcb((struct espconn *)arg,ESP8266_WIFI_Send_Cb);//注册网络数据发送成功的回调函数
    	espconn_regist_recvcb((struct espconn *)arg,ESP8266_WIFI_Recv_Cb);//注册网络数据接收成功的回调函数
    	espconn_regist_disconcb((struct espconn*)arg,ESP8266_TCP_Disconnect_Cb);//注册成功断开TCP连接的回调函数
    }
    
    void ICACHE_FLASH_ATTR ESP8266_TCP_Break_Cb(void *arg)
    {
    	os_printf("ESP8266_TCP_Break\n");
    }
    espconn_regist_connectcb(&ST_NetCon,ESP8266_TCP_Connect_Cb);//注册TCP连接成功的回调函数
    espconn_regist_reconcb(&ST_NetCon,ESP8266_TCP_Break_Cb);//注册TCP连接异常的回调函数
    5.创建TCP_server,建立侦听
    espconn_accept(&ST_NetCon);
    6.设置超时断开时间
    espconn_regist_time(&ST_NetCon,300,0);//单位为秒,最大值=7200
    //注:
    //在espconn_accept之后,连接未建立之前,调用本接口
    //如果超时时间设为0,ESP8266 TCP_server将始终不会断开已经不与它通信的TCP_client,不建议使用0
    
    
    • 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

    AP_TCP_CLIENT

    1.添加30S定时再连接,为电脑创建TCP SERVER提供时间
    2.结构体赋值
    ST_NetCon.type = ESPCONN_TCP;//设置TCP模式
    ST_NetCon.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));//申请内存
    3.ESP8266作为客户端,需预先知道Server端的IP/端口
    ST_NetCon.proto.tcp->local_port = 8266;//设置本地端口
    ST_NetCon.proto.tcp->remote_port = 8888;//设置目标端口
    u8 remote_ip[4] = {192.168.4.2};//设置目标IP
    os_memcpy(ST_NetCon.proto.tcp->remote_ip,remote_ip,4);//拷贝目标IP
    4.定义/注册回调函数
    void ICACHE_FLASH_ATTR ESP8266_WIFI_Send_Cb(void *arg)
    {
    	os_printf("ESP8266_WIFI_Send_OK\n");
    }
    void ICACHE_FLASH_ATTR ESP8266_WIFI_Recv_Cb(void *arg,char *pdata,unsigned short len)
    {
    	struct espconn *T_arg = arg;
    	
    	//根据接收到网络调试助手消息进行处理
    	if(pdata[0] == 'K' || pdata[0] == 'k')
    	{
    		LED_ON;
    	}
    	else if(pdata[0] == 'G' || pdata[0] == 'g')
    	{
    		LED_OFF;
    	}
    	else
    	{}
    	os_printf("ESP8266 receive data = %s\n",pdata);
    
    	//TCP是面向连接的通信,向远端主机回应时可直接使用T_arg结构体指针指向的IP信息
    	espconn_send(T_arg,"ESP8266_WIFI_Recv_OK",os_strlen("ESP8266_WIFI_Recv_OK"));//向对方发送应答
    }
    void ICACHE_FLASH_ATTR ESP8266_TCP_Disconnect_Cb(void *arg)
    {
    	os_printf("ESP8266_TCP_Disconnect_OK\n");
    }
    void ICACHE_FLASH_ATTR_ESP8266_TCP_Connect_Cb(void *arg)
    {
    	espconn_regist_sentcb((struct espconn *)arg,ESP8266_WIFI_Send_Cb);//注册网络数据发送成功的回调函数
    	espconn_regist_recvcb((struct espconn *)arg,ESP8266_WIFI_Recv_Cb);//注册网络数据接收成功的回调函数
    	espconn_regist_disconcb((struct espconn*)arg,ESP8266_TCP_Disconnect_Cb);//注册成功断开TCP连接的回调函数
    
    	espconn_send((struct espconn*)arg,"HELLO ESP8266",os_strlen("HELLO ESP8266"));//向server发起通信
    }
    
    void ICACHE_FLASH_ATTR ESP8266_TCP_Break_Cb(void *arg)
    {
    	os_printf("ESP8266_TCP_Break\n");
    	espconn_connect(&ST_NetCon);//重新连接TCP_Server
    }
    espconn_regist_connectcb(&ST_NetCon,ESP8266_TCP_Connect_Cb);//注册TCP连接成功的回调函数
    espconn_regist_reconcb(&ST_NetCon,ESP8266_TCP_Break_Cb);//注册TCP连接异常的回调函数
    5.连接TCP SERVER
    espconn_connect(&ST_NetCon);
    
    • 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

    STA模式

    路由器创建局域网,ESP8266连接到路由器创建的局域网

    1.结构体定义
    //STA参数结构体
    struct station_config STA_Config;
    //STA信息结构体
    struct ip_info ST_ESP8266_IP;
    2.设置ESP8266为STA模式,并保存到Flash
    wifi_set_opmode(0x01);
    3.ESP8266默认开启DHCP Client,接入WIFI会自动分配IP地址
    //以下操作是手动设置IP地址
    wifi_station_dhcpc_stop();//关闭DHCP Client
    IP4_ADDR(&ST_ESP8266_IP.ip,192.168.8.88);//配置IP地址
    IP4_ADDR(&ST_ESP8266_IP.netmask,255.255.255.0);//配置子网掩码
    IP4_ADDR(&ST_ESP8266_IP.gw,192.168.8.1);//配置网关
    wifi_set_ip_info(STATION_IF,&ST_ESP8266_IP);//设置STA模式下的IP地址
    4.结构体赋值,配置STA模式参数
    os_memset(&STA_Config,0,sizeof(struct station_config));//STA参数结构体清零
    os_strcpy(STA_Config,ssid,ESP8266_STA_SSID);//设置WIFI名(宏定义表示)
    os_strcpy(STA_Config,password,ESP8266_STA_PASS);//设置WIFI密码(宏定义表示)
    wifi_station_set_config(&STA_Config);//设置STA参数,并保存到Flash
    //注
    //如果wifi_station_set_config在user_init中调用,则ESP8266 Station接口会在系统初始化完成后,自动连接AP(路由),无需再调用wifi_station_connect.
    //wifi_station_connect不允许在user_init中调用,需在ESP8266 Station使能并初始化完成后调用
    5.查询STA接入状态
    wifi_station_get_connect_status();
    //返回值
    //0 = STATION_IDLE = STATION闲置
    //1 = STATION_CONNECTING = 正在连接WIFI
    //2 = STATION_WRONG_PASSWORD = WIFI密码错误
    //3 = STATION_NO_AP_FOUND = 未发现制定WIFI
    //4 = STATION_CONNECT_FAIL = 连接失败
    //5 = STATION_GOT_IP = 获得IP,连接成功
    
    • 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

    STA_UDP_SERVER

    1.设置ESP8266为STA模式
    2.判断ESP8266是否获得路由自动分配的IP地址
    3.ESP8266在逻辑上作为服务端,不需要预先知道client端的IP/端口号
    4.初始化网络连接-UDP通信
    
    • 1
    • 2
    • 3
    • 4

    STA_UDP_CLIENT

    1.设置ESP8266为STA模式
    2.判断ESP8266是否获得路由自动分配的IP地址
    3.ESP8266在逻辑上作为客户端,需要预先知道server端的IP/端口号
    4.初始化网络连接-UDP通信
    
    • 1
    • 2
    • 3
    • 4

    STA_TCP_SERVER

    1.设置ESP8266为STA模式
    2.判断ESP8266是否获得路由自动分配的IP地址
    3.ESP8266在逻辑上作为服务器端,不需要预先知道client端的IP/端口号
    4.初始化网络连接-TCP通信
    5.建立侦听
    6.设置超时时间
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    STA_TCP_CLIENT

    ESP8266将以这种方式接入物联网云平台

    1.设置ESP8266为STA模式
    2.判断ESP8266是否获得路由自动分配的IP地址
    3.ESP8266在逻辑上作为客户端,需要预先知道服务器端的IP/端口号
    4.初始化网络连接-TCP通信
    
    • 1
    • 2
    • 3
    • 4

    DNS

    Domain Name (域名),一串用 点 分隔的字符,是互联网上某台/某组计算机名称。
    DNS = Domain Name System (域名系统),可以直接使用域名访问网上的计算机或者服务器。
    例:
    访问百度
    使用IP地址访问:123.125.115.110
    使用域名访问:www.baidu.com

    推荐使用域名的方式来访问互联网上的服务器
    1.服务器就是计算机,可能会坏,可能会更换,IP地址可能会变 。
    2.如果服务器的IP地址变了,那么烧录到芯片的IP地址需要变更,需重新烧录软件。
    3.域名是不会轻易改变的,只需要知道域名,就可以知道服务器的IP。

    //程序中写入网址的域名,解析其IP,使用解析后的IP连接到网址
    1.设置ESP8266为STA模式
    2.结构体赋值
    ST_NetCon.type = ESPCONN_TCP;//设置为TCP协议
    ST_NetCon.proto.tcp = (esp_tcp*)os_zalloc(sizeof(esp_tcp));//开辟内存空间
    //ESP8266作为TCP client,需要预先知道TCP server的IP地址
    ST_NetCon.proto.tcp->local_port = espconn_port();//本地端口
    ST_NetCon.proto.tcp->remote_port = 80;//目标端口
    //使用API获取域名对应的IP地址
    //参数1:网络连接结构体指针,参数2:域名字符串指针(宏定义),参数3:IP地址结构体指针(ip_addr_t类型),参数4:回调函数
    espconn_gethostbyname(&ST_NetCon,DN_Server,&IP_Server,DNS_Over_Cb);
    3.域名解析回调函数
    //参数1:域名字符串指针,参数2:IP地址结构体指针,参数3:网络连接结构体指针
    void ICACHE_FLASH_ATTR DNS_Over_Cb(const char *name,ip_addr_t *ipaddr,void *arg)
    {
    	struct espconn *T_arg = (struct espconn *)arg;//缓存网络连接结构体指针
    
    	if(ipaddr == NULL)//域名解析失败
    	{
    		os_printf("Domain Name Analyse Filed\n");
    		return;
    	}
    	else if(ipaddr != NULL && ipaddr->addr != 0)//域名解析成功
    	{
    		os_printf("Domain Name Analyse Success\n");
    		IP_Server.addr = ipaddr->addr;//将获取的服务器IP地址进行保存
    		//将解析到的服务器IP地址设为TCP连接的远端IP地址
    		os_memcpy(T_arg->proto.tcp->remote_ip,&IP_Server,addr,4);
    		
    		//连接TCP Server
    		espconn_connect(T_arg);//在获取到服务器IP后再进行TCP连接
    	}
    }
    
    • 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

    HTTP

    HTTP = 超文本传输协议
    浏览器和服务器之间的请求和响应的交互,必须按照规定的格式和遵循一定的规则,这个格式和规则就是超文本传输协议。
    HTTP使用了面向连接的TCP作为传输层协议,保证了数据的可靠性
    监听端口:TCP端口80

    HTTP报文分类
    1.请求报文——从客户从服务器发送请求报文
    需加截图
    2.响应报文——从服务器到客户的回答
    需加截图

    HTTP请求报文的一些方法,在此处只使用GET方法(请求读取由URL所标志的信息)
    需加截图

    响应报文中的常见状态行
    HTTP/1.1 202 Accepted (接受)
    HTTP/1.1 400 Bad Request (错误的请求)
    HTTP/1.1 404 Not Found (找不到)

    //通过HTTP获取网页内容
    1.设置ESP8266为STA模式
    2.通过域名解析IP地址
    3.获得IP地址后进行网络连接初始化连接到TCP server
    4.发送HTTP请求报文
    #define HTTP_Message "Get http://www.rationmcu.com/elecjc/2397.html HTTP/1.1 \r\n" \
    		     "Host:www.rationmcu.com \r\n"				   \
    		     "Connection:close \r\n\r\n"				   \
    //HTTP_Message 定义格式:
    //操作 统一资源定位符 HTTP/1.1 (回车)Host: 域名 (回车)Connection:close (回车)(回车)
    
    espconn_send((struct espconn *)arg,HTTP_Message,os_strlen(HTTP_Message));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    SNTP

    SNTP = simple network time protocol (简单网络时钟协议)

    1.设置ESP8266为STA模式
    2.初始化网络连接
    3.初始化SNTP
    //ESP8266最多设置3个SNTP服务器
    void ICACHE_FLASH_ATTR ESP8266_SNTP_Init(void)
    {
    	ip_addr_t *addr = (ip_addr_t *)os_zalloc(sizeof(ip_addr_t));	
    
    	sntp_setservername(0,"us.pool.ntp.org");//服务器0(主服务器)
    	sntp_setservernamr(1,"ntp.sjtu.edu.cn");//服务器1(备用服务器)
    
    	ipaddr_aton("210.72.145.44",addr);//点分十进制->32位二进制
    	sntp_setserver(2,addr);//服务器2(备用服务器)
    	os_free(addr);//释放addr
    
    	sntp_init();//SNTP初始化API
    
    	OS_Timer_SNTP_Init();//1S重复定时,目的获取SNTP数据
    }
    
    4.定时回调函数
    uint32 TimeStamp;//时间戳
    char *Str_RealTime;//实际时间
    
    //查询当前距离基准时间(1970.01.01 00:00:00 GNT+8)的时间戳,时间为秒
    TimeStamp = sntp_get_current_timestamp();
    if(TimeStamp)
    {
    	Str_RealTime = sntp_get_real_time(TimeStamp);//查询实际时间
    }
    
    • 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

    JSON字符串

    JSON = javascript object notation (JS 对象简谱)本质就是一种数据交换格式
    优点:完全独立于编程语言,方便读写,也方便机器解析和生成。
    作用:存储数据和表示数据,通信双方可以使用JSON字符串的格式传输文本信息

    JSON由多个元素组成,元素使用特定的符号标注
    {} 大括号表示对象
    [] 中括号表示数组
    “” 双引号内是属性(键)或值
    : 冒号前表示属性(键)
    : 冒号后表示这个属性的具体值

    {“temp” : “30℃”} “temp” 是一个属性,表示温度。 "30℃"是这个属性的值,表示当前温度为30

    注:
    属性(键):必须是 “字符串”
    值:可以是 “字符串” 、数组[]、对象{}、数字(数字必须是ASCII码形式的)

    //JSON_API
    //使用JSON相关的API需要添加 user_json.c 和 user_json.h
    
    //JSON树相关设置
    //设置 创建JSON树、解析JSON树 的回调函数
    struct jsontree_callback JSON_Tree_Set = JSONTREE_CALLBACK(JSON_AssignValue,JSON_Tree_Parse);//结构体定义
    
    //生成JSON对象
    JSONTREE_OBJECT(V_Key_1,JSONTREE_PAIR("temp",&JSON_Tree_Set),JSONTREE_PAIR("humid",&JSON_Tree_Set));
    JSONTREE_OBJECT(V_Key_2,JSONTREE_PAIR("temp",&JSON_Tree_Set),JSONTREE_PAIR("humid",&JSON_Tree_Set));
    //对象名:V_JSON 键值对:"Shanghai":{&V_Key_1}, "Shenzhen":{&V_Key_2},"result":{&JSON_Tree_Set}
    JSONTREE_OBJECT(V_JSON,JSONTREE_PAIR("Shanghai",&V_Key_1),
    			JSONTREE_PAIR("Shenzhen",&V_Key_2),
    			JSONTREE_PAIR("result",&JSON_Tree_Set))//JSONTREE_OBJECT参数1:生成的JSON树对象的名称,参数2:键值对,参数3:键值对,…
    //JSONTREE_PAIR():参数1:键值对,参数2,键值对的值
    //注:第一个的JSON对象名,“键”都不显示,只显示[&V_JSON]
    JSONTREE_OBJECT(Object_JSON,JSONTREE_PAIR("K_JOSN",&V_JSON));
    //创建JSON树
    void ICACHE_FLASH_ATTR Setup_JSON_Tree(void)
    {
    	//参数1:首JSON对象的指针,参数2:首JSON对象的键,参数3:JSON树缓存指针
    	json_ws_send(struct jsontree_value *)&Object_JOSN,"K_JOSN",A_JSON_Tree);
    }
    
    //解析JSON树
    void ICACHE_FLASH_ATTR Parse_JSON_Tree(void)
    {
    	struct jsontree_context jd;//JSON树环境结构体
    
    	//与要解析的JSON树建立联系
    	//参数1:JSON树环境结构体指针,参数2:JSON树的第二个对象名指针,参数2:json_putchar函数
    	jsontree_setup(&js,(struct jsontree_value *)&V_JSON,json_putchar);
    
    	//解析JSON树
    	//参数1:JSON树环境结构体指针,参数2:要解析的JSON树的指针
    	json_parse(&js,A_JSON_Tree);//执行这条语句,将会调用对应的JSON树解析回调函数
    }
    
    • 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

    乐鑫提供的JSON相关API对于JSON的创建和解析相对繁琐,建议使用 C函数库中的字符串函数 进行创建和解析
    注:
    C语言中" “中要显示” “,在显示的 " 前加转义字符 \ ,即”
    方法:
    通过字符串赋值的方法(%s),对JSON树中的值进行赋值

    物联网云平台

    功能:
    接受设备上报的数据,向设备下发数据,对数据进行转发/分析/计算/显示、管理设备……

    常见的物联网云平台:
    私有物联网云平台
    通用物联网云平台

    设备:
    云下设备:真实存在的设备/模拟器模拟的设备
    云端设备:在云平台中,与云下设备相对应虚拟设备

    乐鑫云

    iot.espressif.cn 时区:中国北京时间
    iot.espressif.com 时区:格林尼治标准时间

    创建云端设备,参考《ESP8266 Non-OS SDK IoT_Demo指南》的2.3 云端创建设备

    云下设备在与乐鑫云平台建立网络连接后,只要按照乐鑫云平台规定好的数据格式,来收发网络数据,云下设备就能与乐鑫云平台进行交互,实现设备接入物联网云平台。

    为了验证设备/保护数据,一般情况下,物联网云平台需要鉴别设备身份(设备密钥,证书…)

    微信智能配网

    ESP8266支持的配网方式:网页配网、APP配网、微信配网。
    使用微信配网,调用配网函数之前,必须声明【#include “smartcofig.h”】
    在这里插入图片描述

    关注公众号

    实现原理:
    1)smartconfig过程中,ESP8266开启sniffer模式,监听可以接收到的所有网络数据不论(数据是否打算发送给8266)
    2)用户通过手机/电脑广播发送加密的SSID和Password信息
    3)ESP8266抓取并解密空中SSID和Password信息,进而连接到WIFI

    要想实现一次配网,长期有效,设计方法:
    1)wifi_set_opmode(0x01); //设置为STA模式,并保存到Flash。注意:不要设置SID和Password
    2)8266每次连接wifi时,检查wifi连接情况,如果wifi连接成功,则正常执行程序。(SNTP、UDP、TCP、DNS)
    3)如果wifi名 wifi密码错误,则进入微信配网模式。微信配网成功后,将wifi名 wifi密码保存,正常执行程序。
    4)当使用微信配网成功后,只要wifi环境不变,即使8266重新复位,它也能成功连接到配置过的wifi,正常执行程序。

    例程重点截图
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    未完待续。。。。

  • 相关阅读:
    如何使用Pyarmor保护你的Python脚本
    js: less-vars-to-js将 LESS 变量转换为 JavaScript 对象
    Unity3D 基础——通过四元数控制对象旋转
    matplotlib笔记
    Clickhouse-CPU内存资源优化配置
    汇编语言快速入门(非常详细)
    修改hosts后只能另存为 不是权限的问题 需要改只读
    数据库安全如何保障?YashanDB有妙招(上篇)
    java多线程的简单应用
    Python入门教学——if __name__==‘__main__‘:
  • 原文地址:https://blog.csdn.net/wuli_Thames/article/details/115798114