概述
〇、参考文章
- ESP8266学习笔记(15)——SoftAP热点配网
一、原理
参考这个连接过程
- 手机连接
ESP8266
热点,ESP8266
作TCP Server
(不需要知道手机ip
,监听即可) - 手机通过
APP
发送wifi
密码和名字给ESP8266
(以json
的格式发送) ESP8266
收到wifi
信息,切换Station
模式连接wifi
- 手机连接
wifi
,切换为Udp Server
ESP8266
连接上wifi
,UDP
广播wifi
分配的地址- 手机收到
UDP
广播,回复收到,切换为TCP Server
ESP8266
切换为TCP Client
- 两者建立
TCP
通信连接
上述就是这个AP
配网的流程,(最后面的没有写)
在手机和设备上的表现就是:
手机连接wifi
,获取到wifi
的名字和密码,设备进入配网模式发射wifi
,手机app
点击搜索热点,连接,之后就是上述的通信,然后断开,两者各自连接wifi
再进行通信
二、代码
ESP8266发射热点以及连接通信
先是一个初始化,和wifi
的配置
void ICACHE_FLASH_ATTR WiFi_Init(void)
{
struct softap_config ap_config;
// 设置wifi的工作模式
wifi_set_opmode(0x02); // AP模式
os_printf("APConfig!n");
/*AP信息设置*/
ap_config.ssid_len = 12; // 根据自己的wifi名字长度来设置
os_strcpy(ap_config.ssid, "TP-LINK-8266"); // wifi名字
os_strcpy(ap_config.password, "82668266"); // wifi的密码
ap_config.channel = 1; // wifi通道1~13
ap_config.max_connection = 2; // 最大的连接数2
ap_config.beacon_interval = 100; // [信标间隔(认为是心跳就好了)](https://www.cnblogs.com/zhanglinf/p/4584499.html)
ap_config.authmode = AUTH_WPA2_PSK; // 设置加密模式
ap_config.ssid_hidden = 0; // 不隐藏wifi
wifi_softap_set_config(&ap_config); // 设置并保存AP到flash
}
/******************************************************************************
* FunctionName : user_init
* Description : entry of user application, init user function here
* Parameters : none
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
uart_init(BIT_RATE_74880, BIT_RATE_74880);
os_printf("**************************************************n");
WiFi_Init();
Espconn_Init(10086);
}
接下来是TCP
连接初始化和注册函数,等待手机发送数据给ESP8266
,Json数据格式如下:
{
{"ssid":"TP-LINK-0809"},
{"password":"123456789"}
}
ESP8266
在接收到信息之后解析出来,然后连接,记住,先断开TCP
连接,可以看到在断开的回调函数里面是wifi
的初始化函数,这是转为Station
模式的初始化
#include "client.h"
#include "my_json.h"
#include "osapi.h"
#include "udp_client.h"
struct espconn user_tcp_espconn;
wifi_info_t wifi_info;
/**
* @name Sent_Succeed[数据发送成功]
*/
void Sent_Succeed(void *arg)
{
os_printf("Send succeed!!!n");
}
/**
* @name Release_Succeed[TCP连接释放]
*/
void Release_Succeed()
{
os_printf("Release succeed!!!n");
wifi_init(wifi_info.ssid, wifi_info.password);
}
/**
* @name Receive_Succeed[接收成功]
*/
void Receive_Succeed(void *arg, char *pdata, unsigned short len)
{
char *c=NULL;
struct espconn *pespconn = arg;
wifi_info_t *wifi_info_p;
os_printf("receive data:%srn",pdata);
c = os_strchr(pdata,'{'); // 得到指针指向{,即需要被解析的字符串
// 这里要复制内存,不然ssid不对
wifi_info_p = Json_parse(c);
os_memcpy(&wifi_info, wifi_info_p, sizeof(wifi_info_t));
espconn_disconnect((struct espconn *)arg);
}
/**
* @name Tcp_Disconect[TCP连接失败]
*/
void Tcp_Disconect(void *arg, sint8 err)
{
struct espconn *pespconn = arg;
os_printf("Connect fail!!!n");
os_printf("Reconnect!!!n");
espconn_connect(pespconn);
}
/**
* @name Sent_Data[发送数据]
*/
void Sent_Data(void *arg)
{
os_printf("connect succeed!!!n");
struct espconn *pespconn = arg;
espconn_regist_sentcb(pespconn, Sent_Succeed); // 注册发送成功
espconn_regist_recvcb(pespconn, Receive_Succeed); // 注册接收成功
espconn_regist_disconcb(pespconn, Release_Succeed); // 注册断开
espconn_send(pespconn, "Hello!", strlen("Hello!")); // 发送
}
/*
* @name Espconn_Init[TCP连接的初始化函数]
*/
void ICACHE_FLASH_ATTR Espconn_Init(int local_port)
{
struct dhcps_lease please;
os_printf("init espconn struct!!!n");
/*配置连接结构体*/
user_tcp_espconn.type = ESPCONN_TCP;
user_tcp_espconn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp)); // 分配内存填充0
user_tcp_espconn.proto.tcp->local_port = local_port;
/*注册*/
espconn_regist_connectcb(&user_tcp_espconn, Sent_Data);
espconn_regist_reconcb(&user_tcp_espconn, Tcp_Disconect);
/*监听TCP服务器*/
os_printf("start connect!!!n");
espconn_accept(&user_tcp_espconn);
espconn_regist_time(&user_tcp_espconn, 120, 0);
}
下面是解析数据
#include "my_json.h"
#include "osapi.h"
#include "cJSON.h"
#include "user_interface.h"
uint8 scan_enable = 0;
wifi_info_t wifi_info;
struct WIFI_INFO * ICACHE_FLASH_ATTR Json_parse(char *receiveData)
{
// receiveData是接收到的数据
//首先整体判断是否为一个json格式的数据
cJSON *pJsonRoot = cJSON_Parse(receiveData);
os_memset(&wifi_info, 0, sizeof(wifi_info_t));
//如果是json格式数据
if (pJsonRoot !=NULL)
{
// 解析数组
cJSON *pssid = cJSON_GetObjectItem(pJsonRoot, "ssid"); // 解析flag键对应值数组内容
if (!pssid)
return &wifi_info; // 判断flag字段是否json格式
else
{
os_strcpy(wifi_info.ssid, pssid->valuestring); // 拷贝内容到字符串数组
os_printf("ssid:%sn", wifi_info.ssid);
}
// 解析字符串
cJSON *ppassword = cJSON_GetObjectItem(pJsonRoot, "password"); // 解析student字段内容
if (!ppassword)
return &wifi_info; // 判断student字段是否json格式
else
{
os_strcpy(wifi_info.password, ppassword->valuestring); // 拷贝内容到字符串数组
os_printf("password:%sn", wifi_info.password);
}
}
cJSON_Delete(pJsonRoot); // 释放cJSON_Parse()分配出来的内存
os_printf("wifi_info->ssid:%sn", wifi_info.ssid);
return &wifi_info;
}
Station
模式下的wifi
初始化和UDP
连接的初始化
每隔2s
检查是否连接上wifi
了,连接之后进行UDP
初始化和广播,每隔1s
广播一次,直到接收到OK
信号,广播的内容是wifi
分配的地址
#include "udp_client.h"
#include "espconn.h"
#include "osapi.h"
#include "user_interface.h"
#include "mem.h"
#include "stdlib.h"
/******************************************/
os_timer_t udptimer;
os_timer_t checktimer;
struct station_config wifi_config;
struct espconn udp_espconn;
char remote_ip[4] = {255, 255, 255, 255};
/******************************************/
/**
* @name Sent_Succeed[数据发送成功]
*/
void ICACHE_FLASH_ATTR Udp_Sent_Succeed(void *arg)
{
os_printf("Send succeed!!!n");
}
/**
* @name Receive_Succeed[接收成功]
*/
void ICACHE_FLASH_ATTR Udp_Receive_Succeed(void *arg, char *pdata, unsigned short len)
{
os_printf("Receive succeed!!!n");
os_printf("Data:%sn", pdata); // 打印接收数据
if (os_strncmp(pdata, "OK", strlen("OK")) == 0)
{
os_timer_disarm(&udptimer);
os_printf("**********END***************n");
}
}
void ICACHE_FLASH_ATTR Send_Message(void *arg)
{
uint8 ip[12] = {0};
struct ip_info ipInfo;
/*获取wifi分配ip和发送*/
wifi_get_ip_info(STATION_IF, &ipInfo);
os_sprintf(ip, "%d", ipInfo.ip.addr); // 代替itoa,把整形写入字符串
espconn_send(&udp_espconn, ip, strlen(ip));
espconn_send((struct espconn *)arg, "Over Connectn", strlen("Over Connectn"));
}
/**
* @name Udp_Espconn_Init[UDP连接结构体初始化]
*/
void ICACHE_FLASH_ATTR Udp_Espconn_Init(ip_addr_t *remote_ip, int local_port, int remote_port)
{
os_printf("init espconn struct!!!n");
/*配置连接结构体*/
udp_espconn.type = ESPCONN_UDP;
udp_espconn.state = ESPCONN_NONE;
udp_espconn.proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp)); // 分配内存填充0
os_memcpy(udp_espconn.proto.udp->remote_ip, remote_ip, 4); // 目的地址广播
udp_espconn.proto.udp->local_port = local_port;
udp_espconn.proto.udp->remote_port = remote_port;
/*注册*/
espconn_regist_recvcb(&udp_espconn, Udp_Receive_Succeed); // 注册接收成功
espconn_regist_sentcb(&udp_espconn, Udp_Sent_Succeed); // 注册发送成功
/*连接服务器*/
os_printf("UDP create!!!n");
espconn_create(&udp_espconn);
/*定时发送已连接*/
os_timer_disarm(&udptimer);
os_timer_setfn(&udptimer, (os_timer_func_t *)Send_Message, &udp_espconn);
os_timer_arm(&udptimer, 1000, 1);
}
void ICACHE_FLASH_ATTR Wifi_Con_Check(uint8 *ssid)
{
ip_addr_t addr;
os_printf("Wifi_Con_Check!n");
/*查询wifi的状态*/
if (wifi_station_get_connect_status() == STATION_GOT_IP)
{
os_timer_disarm(&checktimer);
if (wifi_station_get_connect_status() == STATION_GOT_IP) // 再次确认
{
os_printf("wifi_name:%sn", ssid);
Udp_Espconn_Init((struct ip_addr *)remote_ip, 10000, 10086); //给服务器端的ip和端口号,也就是手机开启的
}
}
else
{
os_printf("fail!n");
os_printf("error:%dn", wifi_station_get_connect_status());
}
}
/*
* @name: wifi_init[用户程序入口]
*/
void ICACHE_FLASH_ATTR wifi_init(char *ssid, char*password)
{
wifi_set_sleep_type(NONE_SLEEP_T); // 关闭睡眠
// 设置wifi的工作模式
wifi_set_opmode(0x01); // Station模式
os_printf("Config!n");
/*设置wifi密码名字*/
os_strcpy(wifi_config.ssid, (uint8 *)ssid);
os_strcpy(wifi_config.password, (uint8 *)password);
wifi_station_set_config(&wifi_config);
wifi_station_connect();
/*软件定时器*/
os_timer_disarm(&checktimer); // 关闭定时器
os_timer_setfn(&checktimer, (os_timer_func_t *)Wifi_Con_Check, ssid); // 设置定时器的回调函数
os_timer_arm(&checktimer, 2000, 1); // 打开定时器,500ms,重复
}
以下是实验结果
接收到的IP
地址,这里没有做处理,但是
1744939200 & 0xFF = 192
1744939200>>8 & 0xFF = 168
1744939200>>16 & 0xFF = 1
1744939200>>24 & 0xFF = 104
2020.6.22
最后
以上就是温暖钢笔为你收集整理的ESP-12S学习(10)--AP配网模式的全部内容,希望文章能够帮你解决ESP-12S学习(10)--AP配网模式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复