ESP-12S学习(10)--AP配网模式

〇、参考文章
  1. ESP8266学习笔记(15)——SoftAP热点配网

一、原理

在这里插入图片描述
参考这个连接过程

  • 手机连接ESP8266热点,ESP8266TCP Server(不需要知道手机ip,监听即可)
  • 手机通过APP发送wifi密码和名字给ESP8266(以json的格式发送)
  • ESP8266收到wifi信息,切换Station模式连接wifi
  • 手机连接wifi,切换为Udp Server
  • ESP8266连接上wifiUDP广播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:%s\r\n",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:%s\n", 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:%s\n", wifi_info.password);
		}
	}

	cJSON_Delete(pJsonRoot);	// 释放cJSON_Parse()分配出来的内存
	os_printf("wifi_info->ssid:%s\n", 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:%s\n", 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 Connect\n", strlen("Over Connect\n"));
}


/**
 * @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:%s\n", ssid);
    		Udp_Espconn_Init((struct ip_addr *)remote_ip, 10000, 10086);	//给服务器端的ip和端口号,也就是手机开启的
    	}
    }
    else
    {
    	os_printf("fail!\n");
    	os_printf("error:%d\n", 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
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值