本帖最后由 WT_0213 于 2023-12-7 11:21 编辑
本帖最后由 WT_0213 于 2023-12-6 21:19 编辑
目前实现上电后自动打开AP模式,连接无线AP后。打开网页提交要连接的WIFI名称 和 WIFI密码 点击提交。相应POST提交的WIFI名称和密码。
以下代码添加了关键点注释,方便大家理解。
发帖积分恢复了,又充满了动力。😄
演示
首先设备上电,上电后在电脑或手机上可以看到如下热点
点击连接
然后会让你输入密码
这里密码是:1234567879
然后通过浏览器输入:
192.168.169.1
可以看到如下界面,简单写了个配置页面效果:
输入要连接的WIFI名称与密码,点击提交。
成功后返回提交的WIFI名和密码;
介绍一下实现方式和思路
打开AP模式
static void start_ap(void)
{
wifi_mgmr_ap_params_t config = { 0 };
config.channel = 3;
config.key = USER_AP_PASSWORD;
config.ssid = USER_AP_NAME;
config.use_dhcpd = 1;
if (wifi_mgmr_conf_max_sta(2) != 0) {
return 5;
}
if (wifi_mgmr_ap_start(&config) == 0) {
return 0;
}
}
启动http_server
void mhttp_server_init()
{
//常用变量
int ss, sc;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int snd_size = 0; /* 发送缓冲区大小 */
socklen_t optlen; /* 选项值长度 */
// int optlen;
int err;
socklen_t addrlen;
// int addrlen;
//建立套接字
ss = socket(AF_INET, SOCK_STREAM, 0);
if (ss < 0)
{
printf("socket error\n");
}
/*设置服务器地址*/
bzero(&server_addr, sizeof(server_addr));
/*清零*/
server_addr.sin_family = AF_INET;
/*协议族*/
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); /*本地地址*/
server_addr.sin_port = htons(80);
/*服务器端口*/
/*绑定地址结构到套接字描述符*/
err = bind(ss, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (err < 0)
{
printf("bind error\n");
return -1;
}
/*设置侦听*/
err = listen(ss, 7);
if (err < 0)
{
printf("listen error\n");
return -1;
}
addrlen = sizeof(struct sockaddr_in);
MYPARM parm11;
while (1)
{
printf("accept start\r\n");
sc = accept(ss, (struct sockaddr *)&client_addr, &addrlen);
if ((sc < 0) || (mysemaphoreflag > 0))
{
printf("accept fail sc is:%d semaphore is:%d\r\n", sc, mysemaphoreflag);
if (sc > 0)
{
close(sc);
}
continue;
}
parm11.sc = sc;
parm11.buf = NULL;
mysemaphoreflag++;
http_server_thread(&parm11);
vTaskDelay(1);
}
}
等待客户端连接即可。为了使设备启动状态更直观,增加了开机亮灯操作。启动后自动打开绿灯。
代码如下:
gpio = bflb_device_get_by_name("gpio");
bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT| GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
bflb_gpio_set(gpio, GPIO_PIN_14);
主要代码讲解
main.c
int main(void)
{
//中开启时钟
board_init();
// 亮绿灯
gpio = bflb_device_get_by_name("gpio");
bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT| GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
bflb_gpio_set(gpio, GPIO_PIN_14);
//设置中断分组
bflb_irq_set_nlbits(4);
//设置中断优先级
bflb_irq_set_priority(37, 3, 0);
bflb_irq_set_priority(WIFI_IRQn, 1, 0);
// 拿到 gpio
gpio = bflb_device_get_by_name("gpio");
// 拿到 uart
uart0 = bflb_device_get_by_name("uart0");
shell_init_with_task(uart0);
// 初始化tcp ip
tcpip_init(NULL, NULL);
wifi_start_firmware_task();
// 创建http服务
create_http_server_task();
vTaskStartScheduler();
while (1) {
}
}
创建http服务
void create_http_server_task(void)
{
MuxSem_Handle = xSemaphoreCreateMutex();
if (NULL != MuxSem_Handle)
{
printf("MuxSem_Handle creat success!\r\n");
}
xTaskCreate(http_server_task, (char*)"fw", WIFI_HTTP_SERVER_STACK_SIZE, NULL, HTTP_SERVERTASK_PRIORITY, &http_server_task_hd);
}
这里使用了xTaskCreate,FreeRTOS的任务。
不了解的可以看下Ai-M61-32S AP 配网学习 之 FreeRTOS任务
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=43670
接下来是 http_server_task
void http_server_task(void* param)
{
// 打开AP
start_ap();
// 启动http服务,也就是响应网页的服务
mhttp_server_init();
}
这里比较简单。
打开ap代码
static void start_ap(void)
{
wifi_mgmr_ap_params_t config = { 0 };
// 通道
config.channel = 3;
// 设置AP热点名称
config.ssid = USER_AP_NAME;
// 设置密码
config.key = USER_AP_PASSWORD;
// 启动dhcp
config.use_dhcpd = 1;
// 设置最大连接数
if (wifi_mgmr_conf_max_sta(2) != 0) {
return 5;
}
// 启动AP模式
if (wifi_mgmr_ap_start(&config) == 0) {
return 0;
}
}
WIFI信息设置
#define USER_AP_NAME "Ai-M61-32s"
#define USER_AP_PASSWORD "123456789"
然后是http服务的启动
mlwip_https.c
void mhttp_server_init()
{
//常用变量
int ss, sc;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int snd_size = 0; /* 发送缓冲区大小 */
socklen_t optlen; /* 选项值长度 */
// int optlen;
int err;
socklen_t addrlen;
// int addrlen;
//建立套接字
ss = socket(AF_INET, SOCK_STREAM, 0);
if (ss < 0)
{
printf("socket error\n");
}
/*设置服务器地址*/
bzero(&server_addr, sizeof(server_addr));
/*清零*/
server_addr.sin_family = AF_INET;
/*协议族*/
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); /*本地地址*/
server_addr.sin_port = htons(80);
/*服务器端口*/
/*绑定地址结构到套接字描述符*/
err = bind(ss, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (err < 0)
{
printf("bind error\n");
return -1;
}
/*设置侦听*/
err = listen(ss, 7);
if (err < 0)
{
printf("listen error\n");
return -1;
}
addrlen = sizeof(struct sockaddr_in);
MYPARM parm11;
while (1)
{
printf("accept start\r\n");
sc = accept(ss, (struct sockaddr *)&client_addr, &addrlen);
if ((sc < 0) || (mysemaphoreflag > 0))
{
printf("accept fail sc is:%d semaphore is:%d\r\n", sc, mysemaphoreflag);
if (sc > 0)
{
close(sc);
}
continue;
}
parm11.sc = sc;
parm11.buf = NULL;
mysemaphoreflag++;
http_server_thread(&parm11);
vTaskDelay(1);
}
}
接下来就是响应请求
void http_server_thread(void *msg)
{
// printf("http_server_thread\r\n");
MYPARM *parm11;
parm11 = (MYPARM *)msg;
int sc;
char readbuffer[1024];
int size = 0;
char command[1024];
char head_buf[1000];
memset(command, 0, sizeof(command));
memset(head_buf, 0, sizeof(head_buf));
sc = parm11->sc;
memset(readbuffer, 0, sizeof(readbuffer));
while (1)
{
// printf("read stop\r\n");
size = read(sc, readbuffer, 1024);
// int rc = recv(sc, readbuffer, sizeof(readbuffer), 0);
printf("read len:%d\r\n", size);
printf("get:%s\r\n", readbuffer);
if (size <= 0)
{
printf("size <= 0\r\n");
break;
}
int len = get_http_command(readbuffer, command); //得到http 请求中 GET后面的字符串
printf("get:%s len:%d\r\n", command, len);
if (strcmp(command, "/") == 0)
{
printf("command1\r\n");
streatask = 0;
sprintf(head_buf, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html;charset=UTF-8\r\n\r\n", sizeof(html_page));
// head_buf
// strlen(index_ov2640_html)
// 返回html页面
int ret = write(sc, head_buf, strlen(head_buf));
if (ret == -1)
{
printf("send failed");
close(sc);
mysemaphoreflag--;
return NULL;
}
ret = write(sc, html_page, sizeof(html_page));
if (ret < 0)
{
printf("text write failed");
}
close(sc);
mysemaphoreflag--;
break;
}
else if (strstr(command, "set"))
{
printf("set\r\n");
streatask = 0;
// 获取POST提交过来的数据,拿到ssid部分
char* wifiCfg = strstr(readbuffer, "ssid");
printf("wifiCfg: %s \r\n", wifiCfg);
sprintf(head_buf, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 433\r\nAccess-Control-Allow-Origin: *\r\n\r\n");
int ret = write(sc, head_buf, strlen(head_buf));
if (ret == -1)
{
printf("send failed");
close(sc);
mysemaphoreflag--;
return NULL;
}
// 将post参数切开,分别拿到 ssid 和 pwd
char* ssid = strtok(wifiCfg, "&");
char* pwd = strtok(NULL, "&");
// 将ssid参数切开,分别拿到 key 和 value
char* ssidKey = strtok(ssid, "=");
char* ssidValue = strtok(NULL, "=");
// 将pwd参数切开,分别拿到 key 和 value
char* pwdKey = strtok(pwd, "=");
char* pwdValue = strtok(NULL, "=");
// ============================================
// 待实现 将 wifi 信息写入 存储
// 开启 sta 模式,连接WIFI
// ============================================
printf("OK ssid:%s, pwd:%s \r\n", ssidValue, pwdValue);
// 创建cJSON
cJSON *json = cJSON_CreateObject();
cJSON_AddStringToObject(json, "ssid", ssidValue);
cJSON_AddStringToObject(json, "pwd", pwdValue);
char data_buf[1024];
sprintf(data_buf, "%s\r\n\r\n", cJSON_Print(json));
printf("OK data_buf:%s \r\n", data_buf);
// static char data_buf[] = "{\"ssid\":1,\"pwd\":0}";
// ret = write(sc, data_buf, 433);
// 将获取到的数据通过json形式返回
ret = write(sc, data_buf, sizeof(data_buf));
if (ret < 0)
{
printf("text write failed");
}
close(sc);
mysemaphoreflag--;
break;
}
else
{
streatask = 0;
close(sc);
mysemaphoreflag--;
}
// write(sc,readbuffer,size);
}
//关中断
// free(parm11->buf);
// vTaskDelete(NULL);
//开中断
}
html 代码 page.h 很简单的界面,可以做很多优化。
static const unsigned char html_page[] = R"(
<html>
<body>
Hello Word!
<form method="post" action="/set">
<input name="ssid" type="text" />
<br/>
<input name="pwd" type="text" />
<br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
)";
到这里基本,就可以实现 AP 配网的一些前置条件了。
下一步就是将 WIFI信息保存到 存储。
WIFI相关参考文档。
WiFi API指南 — 安信可科技 documentation (wb2-api-web.readthedocs.io)
Wi-Fi Manager — BL IoT SDK release_bl_iot_sdk_1.6.39-238-gf5ba0a7ee 文档 (bouffalolab.github.io)
书接上回,将WIFI名称和密码保存到存储当中。
使用easyflash保存WIFI名称和密码
创建 存储相关代码
storage/storage.h
#ifndef __CUSTOM_H_
#define __CUSTOM_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define SSID_KEY "SSID"
#define PASS_KEY "PASS"
#ifndef USER_FLASH_H
#define USER_FLASH_H
void flash_init(void);
void flash_erase_set(char* key, char* value);
char* flash_get_data(char* key, int len);
#endif
#ifdef __cplusplus
}
#endif
#endif /* EVENT_CB_H_ */
storage/storage.c
/**
* @file user_flash.c
* @author your name ([email]you@domain.com[/email])
* @brief
* @version 0.1
* @date 2023-08-07
*
* @copyright Copyright (c) 2023
*
*/
#include "stdio.h"
#include "string.h"
#include "storage.h"
#include "easyflash.h"
#include "log.h"
void flash_init(void)
{
//init easyflash
bflb_mtd_init();
easyflash_init();
}
/**
* @brief
*
* @param key
* @param value
*/
void flash_erase_set(char* key, char* value)
{
size_t len = 0;
int value_len = strlen(value);
ef_set_and_save_env(key, value);
// bflb_flash_read(key, flash_data, strlen(value));
// printf("writer data:%s\r\n", flash_data);
memset(value, 0, strlen(value));
ef_get_env_blob(key, value, value_len, &len);
LOG_W("flash_erase_set %s: %s", key, value);
}
/**
* @brief
*
* @param key
* @return char*
*/
char* flash_get_data(char* key, int len)
{
static char* flash_data = NULL;
flash_data = pvPortMalloc(len);
memset(flash_data, 0, len);
ef_get_env_blob(key, flash_data, len, (size_t)&len);
LOG_W("flash_get_data %s: %s, len:%d\r\n", key, flash_data, strlen(flash_data));
return flash_data;
}
修改web/mlwip_https.c增加如下内容:
#include "storage.h"
#include "wifi_event.h"
#include "log.h"
....
// 将 wifi 信息写入 存储
flash_erase_set(SSID_KEY, ssidValue);
flash_erase_set(PASS_KEY, pwdValue);
// 开启 sta 模式,连接WIFI
// 重启设备
LOG_W("system 2s reset ");
vTaskDelay(2000/portTICK_PERIOD_MS);
GLB_SW_System_Reset();
修改proj.conf增加如下内容:
# easy flash
set(CONFIG_PARTITION 1)
set(CONFIG_BFLB_MTD 1)
set(CONFIG_EASYFLASH4 1)
修改CMakeLists.txt增加如下内容:
...
sdk_add_include_directories(storage)
...
target_sources(app PRIVATE
storage/storage.c
web/cJSON.c
web/mlwip_https.c
)
对 flash_prog_cfg.ini 配置文件进行了一些注释
#***************************************************#
# 固件烧录配置 #
# Firmware burning configuration #
#***************************************************#
[cfg]
# 0:无擦除,1:程序化截面擦除,2:芯片擦除
# 0: no erase, 1:programmed section erase, 2: chip erase
erase = 1
# skip mode set first para is skip addr, second para is skip len, multi-segment region with ; separated
skip_mode = 0x0, 0x0
# 复位下载功能使能(Reset download function enable)
# 0: not use isp mode, #1: isp mode
boot2_isp_mode = 1
# 配置boot2固件,否则无法使用复位烧录功能(Configure boot2 firmware, otherwise the reset burn function cannot be used)
[boot2]
filedir = ./build/build_out/boot2_*.bin
address = 0x000000
# 配置partition固件,这是必要的(Configuring partition firmware is necessary)
[partition]
filedir = ./build/build_out/partition*.bin
address = 0xE000
# 配置应用程序固件地址,需要新建工程时需要修改“Project_basic” 为新工程的名字,否则可能会导致烧录失败
#(To configure the application firmware address, when creating a new project, it is necessary to modify "Project_Basic" to the name of the new project, otherwise it may cause burning failure)
[FW]
filedir = ./build/build_out/smart_config_$(CHIPNAME).bin
address = @partition
address = 0x10000
# [mfg]
# filedir = ./build/build_out/mfg*.bin
easyflash4相关问题可以参考。
[答疑] easyflash4 使用问题及解决方法
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=43763
[参考] 基于 Ai-M61-32S 的AP网页配网实现 Step 2
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=43766
接下来就是读取WIFI信息数据,并连接到WIFI。
创建 WIFI相关代码
wifi/wifi_event.h
/**
* @file wifi_event.h
* @author your name ([email]you@domain.com[/email])
* @brief
* @version 0.1
* @date 2023-06-29
*
* @copyright Copyright (c) 2023
*
*/
#ifndef WIFI_EVENT_H
#define WIFI_EVENT_H
#include "stdint.h"
int wifi_start_firmware_task(void);
void wifi_event_handler(uint32_t code);
uint8_t wifi_connect(char* ssid, char* passwd);
#endif
wifi/wifi_event.c
/**
* @file wifi_event.c
* @author your name ([email]you@domain.com[/email])
* @brief
* @version 0.1
* @date 2023-06-29
*
* @copyright Copyright (c) 2023
*
*/
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include <lwip/tcpip.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include "bl_fw_api.h"
#include "wifi_mgmr_ext.h"
#include "wifi_mgmr.h"
#include "bflb_irq.h"
#include "bflb_uart.h"
#include "bflb_l1c.h"
#include "bflb_mtimer.h"
#include "bl616_glb.h"
#include "rfparam_adapter.h"
#include "board.h"
#include "log.h"
#include "storage.h"
#define DBG_TAG "WIFI EVENT"
#define WIFI_STACK_SIZE (1024*4)
#define TASK_PRIORITY_FW (16)
static wifi_conf_t conf =
{
.country_code = "CN",
};
static TaskHandle_t wifi_fw_task;
static uint32_t sta_ConnectStatus = 0;
xQueueHandle queue;
/**
* @brief WiFi 任务
*
* @return int
*/
int wifi_start_firmware_task(void)
{
LOG_I("Starting wifi ...");
/* enable wifi clock */
GLB_PER_Clock_UnGate(GLB_AHB_CLOCK_IP_WIFI_PHY | GLB_AHB_CLOCK_IP_WIFI_MAC_PHY | GLB_AHB_CLOCK_IP_WIFI_PLATFORM);
GLB_AHB_MCU_Software_Reset(GLB_AHB_MCU_SW_WIFI);
/* set ble controller EM Size */
GLB_Set_EM_Sel(GLB_WRAM160KB_EM0KB);
if (0 != rfparam_init(0, NULL, 0)) {
LOG_I("PHY RF init failed!");
return 0;
}
LOG_I("PHY RF init success!");
/* Enable wifi irq */
extern void interrupt0_handler(void);
bflb_irq_attach(WIFI_IRQn, (irq_callback)interrupt0_handler, NULL);
bflb_irq_enable(WIFI_IRQn);
xTaskCreate(wifi_main, (char*)"fw", WIFI_STACK_SIZE, NULL, TASK_PRIORITY_FW, &wifi_fw_task);
return 0;
}
/**
* @brief wifi event handler
* WiFi 事件回调
*
* @param code
*/
void wifi_event_handler(uint32_t code)
{
sta_ConnectStatus = code;
BaseType_t xHigherPriorityTaskWoken;
switch (code) {
case CODE_WIFI_ON_INIT_DONE:
{
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_INIT_DONE", __func__);
wifi_mgmr_init(&conf);
}
break;
case CODE_WIFI_ON_MGMR_DONE:
{
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_MGMR_DONE", __func__);
}
break;
case CODE_WIFI_ON_SCAN_DONE:
{
char* scan_msg = pvPortMalloc(128);
memset(scan_msg, 0, 128);
wifi_mgmr_sta_scanlist();
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_SCAN_DONE SSID numbles:%d", __func__, wifi_mgmr_sta_scanlist_nums_get());
sprintf(scan_msg, "{\"wifi_scan\":{\"status\":0}}");
// xQueueSend(queue, scan_msg, );
if (wifi_mgmr_sta_scanlist_nums_get()>0) {
xQueueSendFromISR(queue, scan_msg, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
vPortFree(scan_msg);
}
break;
case CODE_WIFI_ON_CONNECTED:
{
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_CONNECTED", __func__);
void mm_sec_keydump();
mm_sec_keydump();
}
break;
case CODE_WIFI_ON_GOT_IP:
{
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP", __func__);
}
break;
case CODE_WIFI_ON_DISCONNECT:
{
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_DISCONNECT", __func__);
char* queue_buff = pvPortMalloc(128);
memset(queue_buff, 0, 128);
sprintf(queue_buff, "{\"wifi_disconnect\":true}");
xQueueSendFromISR(queue, queue_buff, pdTRUE);
vPortFree(queue_buff);
}
break;
case CODE_WIFI_ON_AP_STARTED:
{
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STARTED", __func__);
}
break;
case CODE_WIFI_ON_AP_STOPPED:
{
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STOPPED", __func__);
}
break;
case CODE_WIFI_ON_AP_STA_ADD:
{
LOG_I("[APP] [EVT] [AP] [ADD] %lld", xTaskGetTickCount());
}
break;
case CODE_WIFI_ON_AP_STA_DEL:
{
LOG_I("[APP] [EVT] [AP] [DEL] %lld", xTaskGetTickCount());
}
break;
default:
{
LOG_I("[APP] [EVT] Unknown code %u ", code);
}
}
}
uint8_t wifi_connect(char* ssid, char* passwd)
{
int ret = 255;
// struct fhost_vif_ip_addr_cfg ip_cfg = { 0 };
uint32_t ipv4_addr = 0;
char* queue_buff = pvPortMalloc(128);
memset(queue_buff, 0, 128);
if (NULL==ssid || 0==strlen(ssid)) {
return 1;
}
if (wifi_mgmr_sta_state_get() == 1) {
wifi_sta_disconnect();
}
if (wifi_sta_connect(ssid, passwd, NULL, NULL, 0, 0, 0, 1)) {
return 4;
}
LOG_I("Wating wifi connet");
//等待连接成功
sta_ConnectStatus = 0;
for (int i = 0;i<10*30;i++) {
vTaskDelay(100/portTICK_PERIOD_MS);
switch (sta_ConnectStatus) {
case CODE_WIFI_ON_MGMR_DONE:
// vTaskDelay(2000);
// LOG_I("wifi_mgmr_sta_scan:%d", wifi_mgmr_sta_scan(wifi_scan_config));
vPortFree(queue_buff);
return 3;
case CODE_WIFI_ON_SCAN_DONE:
// LOG_I("WIFI STA SCAN DONE %s", wifi_scan_config[0].ssid_array);
vPortFree(queue_buff);
return 2;
case CODE_WIFI_ON_DISCONNECT: //连接失败(超过了重连次数还没有连接成功的状态)
LOG_I("Wating wifi connet Faild");
// wifi_sta_disconnect();
vPortFree(queue_buff);
return 4;
case CODE_WIFI_ON_CONNECTED: //连接成功(表示wifi sta状态的时候表示同时获取IP(DHCP)成功,或者使用静态IP)
// LOG_I("Wating wifi connet OK \r\n");
break;
case CODE_WIFI_ON_GOT_IP:
wifi_sta_ip4_addr_get(&ipv4_addr, NULL, NULL, NULL);
LOG_I("wifi connened %s,IP:%s", ssid, inet_ntoa(ipv4_addr));
sprintf(queue_buff, "{\"ip\":{\"IP\":\"%s\"}}", inet_ntoa(ipv4_addr));
flash_erase_set(SSID_KEY, ssid);
flash_erase_set(PASS_KEY, passwd);
xQueueSend(queue, queue_buff, portMAX_DELAY);
LOG_I("Wating wifi connet OK and get ip OK");
vPortFree(queue_buff);
return 0;
default:
//等待连接成功
break;
}
}
vPortFree(queue_buff);
return 14; //连接超时
}
main.c增加如下内容:
.......
#include "wifi_event.h"
.......
/**
* @brief void queue_task(void* arg)
* 消息队列循环读取
* @param arg
*/
static void queue_task(void* arg)
{
char* ssid = NULL;
char* password = NULL;
ssid = flash_get_data(SSID_KEY, 32);
password = flash_get_data(PASS_KEY, 32);
if (ssid!=NULL && strlen(ssid) > 0)
{
printf("read flash ssid:%s password:%s\r\n", ssid, password);
wifi_connect(ssid, password);
}
else {
printf("ssid read value is NULL:%06X\r\n", SSID_KEY);
}
}
int main(void)
{
.......
// 初始化 存储
flash_init();
// 初始化tcp ip
tcpip_init(NULL, NULL);
// 启动WiFi任务
wifi_start_firmware_task();
char* ssid = NULL;
ssid = flash_get_data(SSID_KEY, 32);
if (ssid!=NULL && strlen(ssid) > 0){
xTaskCreate(queue_task, "queue task", 1024*6, NULL, 2, NULL);
}
.......
}
修改 proj.conf 增加如下内容:
# wifi
set(CONFIG_VIF_MAX 2)
set(CONFIG_STA_MAX 4)
set(CONFIG_MAC_TXQ_DEPTH 32)
set(CONFIG_MAC_RXQ_DEPTH 12)
修改 CMakeLists.txt 增加如下内容:
target_sources(app PRIVATE
wifi/wifi_event.c // 增加wifi相关代码
storage/storage.c
web/cJSON.c
web/mlwip_https.c
)
目前当前方案存在以下问题:
- 中文WIFI名称无法连接
- 设置WIFI信息后AP消失
- WIFI信息填写错误,无法修复并且重新编译也不行
解决方案:
- 尽量使用和连接英文WIFI
- 重新烧写固件
- 擦除芯片内容烧写
flash_prog_cfg.ini 配置文件
将
[cfg] # 0:无擦除,1:程序化截面擦除,2:芯片擦除
0: no erase, 1:programmed section erase, 2: chip erase
erase = 1
改为
[cfg] # 0:无擦除,1:程序化截面擦除,2:芯片擦除
0: no erase, 1:programmed section erase, 2: chip erase
erase = 2
再执行 make flash COMX=COM?【?代表你的COM号】 命令就可以擦除数据了。
到这里基于 Ai-M61-32S 的AP网页配网实现就完成了。
gitee源码地址:
https://gitee.com/lazy-ai/ai-m61-32-sx_-network.git
源码:
如果觉得不错 可以 给个 哦。