Skip to content

概念先知道

  • AP(Access Point,接入点):发出 Wi-Fi 信号的设备,其他设备连接它上网。开发板也能当 AP,叫 Soft-AP(软件热点)。
  • DHCP 服务器:AP 自动给接入设备分配 IP。例程中开发板热点使用 192.168.169.1,配网页就在这个地址。
  • Web 配网:设备先开一个热点,手机连上后通过网页选择路由器、输入密码,设备再以 STA 模式去连目标路由器——省去串口配置。
  • AP + STA 共存:例程先开 AP(wifi_mgmr_ap_start),配网成功后还会以 STA 模式连接目标路由器,两种模式由 Wi-Fi 管理组件协调。

例程功能简介

  • 本页对应博流官方 SDK 的 smartconfig_softap 例程(examples/wifi/sta/smartconfig_softap),是 SDK 中演示 AP 模式的例程:
  • 开机后自动创建名为 BL602_Config 的开放热点,启动内置 Web 服务器;手机连上热点、打开 http://192.168.169.1 即可扫描附近 Wi-Fi 并输入密码完成配网。
  • 配网成功后开发板自动以 STA 模式连接目标路由器(CODE_WIFI_ON_GOT_IP),配网页同步显示结果。
  • 注意:例程 README 以 BL602 为例,但代码含 BL616/BL618(fhost/wifi4)分支,Ai-M6x 可直接编译运行。

操作步骤

1
进入例程目录

进入 SDK 的 SoftAP 配网例程(前提:已搭建 SDK 环境):

cd examples/wifi/sta/smartconfig_softap
2
编译工程

该例程 README 以 BL602 为例,代码与配置已包含 BL616/BL618 分支,Ai-M6x 统一编译:

make CHIP=bl616 BOARD=bl616dk
3
烧录固件

按住 BOOT 短按 EN/RST 进入下载模式后烧录:

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
连接开发板热点

开发板开机后自动创建一个名为 BL602_Config、无密码的热点(2.4GHz)。用手机/电脑连接它。

连接 Wi-Fi:BL602_Config(无密码)
5
打开配网页

浏览器访问 http://192.168.169.1 ,点击 Scan 扫描周围 Wi-Fi,选择你的路由器并输入密码,点击 Connect。

打开浏览器访问 http://192.168.169.1
6
观察连接结果

配网成功后,开发板会以 STA 模式连接目标路由器,串口打印 CODE_WIFI_ON_GOT_IP,配网页显示连接状态(web_config_notify_result(1))。

代码执行流程

例程调用的 API 介绍

wifi_mgmr_ap_enable()

使能 AP 模式并返回 AP 网络接口。

参数

返回值:返回 wifi_interface_t 网络接口(如 WIFI_IF_AP

wifi_mgmr_ap_start(wifi_if, ssid, channel, password, max_conn)

以指定名称开启热点。

参数

  • wifi_if:AP 接口
  • ssid:热点名称,例程 BL602_Config
  • channel:信道,例程 1
  • password:密码,例程为 NULL(开放)
  • max_conn:最大连接数,例程 0(默认)

返回值:成功返回 0;失败返回负值错误码

web_config_do_scan()

扫描周围 Wi-Fi,供配网页显示网络列表。

参数

返回值:无

web_config_init(&ctx)

启动 Web 配网服务器(HTTPD),提供 /wifiscan/wificonfig/wifiget 等接口。

参数

  • ctxweb_config_t 上下文

返回值:无

web_config_notify_result(ok)

把 STA 连接结果通知给配网页。

参数

  • ok:1 表示连接成功(GOT_IP),0 表示失败

返回值:无

完整代码

以下为 ap_sta_bridge/main.c 完整源码,与官方示例(examples/wifi/ap_sta_bridge)一致,默认折叠,点击展开:

📜 点击展开 ap_sta_bridge/main.c 完整代码
c
/****************************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#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 "fhost_api.h"
#include "wifi_mgmr_ext.h"
#include "wifi_mgmr.h"

#include "bflb_irq.h"
#include "bflb_uart.h"

#include "rfparam_adapter.h"
#include "async_event.h"

#include "board.h"
#include "shell.h"

#include "mm.h"
#include "netifd_nano.h"

#define DBG_TAG "MAIN"
#include "log.h"

struct bflb_device_s *gpio;

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#define WIFI_STACK_SIZE  (1536)
#define TASK_PRIORITY_FW (16)

/****************************************************************************
 * Private Types
 ****************************************************************************/

/****************************************************************************
 * Private Data
 ****************************************************************************/

static struct bflb_device_s *uart0;


extern void shell_init_with_task(struct bflb_device_s *shell);
extern void wifi_event_handler(async_input_event_t ev, void *priv);

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

/****************************************************************************
 * Functions
 ****************************************************************************/

void wifi_start_firmware_task(void *param)
{
    LOG_I("Starting wifi ...\r\n");
    async_register_event_filter(EV_WIFI, wifi_event_handler, NULL);
    wifi_task_create();

    LOG_I("Starting fhost ...\r\n");
    fhost_init();

    vTaskDelete(NULL);
}

void wifi_event_handler(async_input_event_t ev, void *priv)
{
    uint32_t code = ev->code;

    switch (code) {
        case CODE_WIFI_ON_INIT_DONE: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_INIT_DONE\r\n", __func__);
            wifi_mgmr_task_start();
        } break;
        case CODE_WIFI_ON_MGMR_DONE: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_MGMR_DONE\r\n", __func__);
        } break;
        case CODE_WIFI_ON_SCAN_DONE: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_SCAN_DONE\r\n", __func__);
            wifi_mgmr_sta_scanlist();
        } break;
        case CODE_WIFI_ON_CONNECTED: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_CONNECTED\r\n", __func__);
            void mm_sec_keydump();
            mm_sec_keydump();
        } break;
        #ifdef CODE_WIFI_ON_GOT_IP_ABORT
        case CODE_WIFI_ON_GOT_IP_ABORT: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP_ABORT\r\n", __func__);
        } break;
        #endif
        #ifdef CODE_WIFI_ON_GOT_IP_TIMEOUT
        case CODE_WIFI_ON_GOT_IP_TIMEOUT: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP_TIMEOUT\r\n", __func__);
        } break;
        #endif
        case CODE_WIFI_ON_GOT_IP: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP\r\n", __func__);
            LOG_I("[SYS] Memory left is %d Bytes\r\n", kfree_size(0));
        } break;
        case CODE_WIFI_ON_DISCONNECT: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_DISCONNECT\r\n", __func__);
        } break;
        case CODE_WIFI_ON_AP_STARTED: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STARTED\r\n", __func__);
        } break;
        case CODE_WIFI_ON_AP_STOPPED: {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STOPPED\r\n", __func__);
        } break;
        case CODE_WIFI_ON_AP_STA_ADD: {
            LOG_I("[APP] [EVT] [AP] [ADD] %lld\r\n", xTaskGetTickCount());
        } break;
        case CODE_WIFI_ON_AP_STA_DEL: {
            LOG_I("[APP] [EVT] [AP] [DEL] %lld\r\n", xTaskGetTickCount());
        } break;
        default: {
            LOG_I("[APP] [EVT] Unknown code %u \r\n", code);
        }
    }
}

int main(void)
{
    board_init();

    uart0 = bflb_device_get_by_name("uart0");
    shell_init_with_task(uart0);

    if (0 != rfparam_init(0, NULL, 0)) {
        LOG_I("PHY RF init failed!\r\n");
        return 0;
    }

    LOG_I("PHY RF init success!\r\n");

    netifd_nano_init();
    tcpip_init(NULL, NULL);
    xTaskCreate(wifi_start_firmware_task, "wifi init", 1024, NULL, 10, NULL);

    vTaskStartScheduler();

    while (1) {
    }
}

FAQ

找不到 BL602_Config 热点?

确认烧录的是本例程固件;热点名在 main.cAP_SSID 宏中,可自行修改后重新编译。

连上热点但 http://192.168.169.1 打不开?

确认手机/电脑拿到的是 192.168.169.x 网段地址(DHCP);换浏览器或无痕模式重试;串口若打印 AP 相关错误则重新烧录。

配网成功但网页一直转圈?

目标路由器必须是 2.4GHz;密码错误或路由器 DHCP 异常时,GOT_IP 不会出现,网页会超时显示失败。

手机连热点后上不了网?

正常现象——此时开发板还没连上路由器,热点只用于配置;配网完成后开发板会去连目标路由器。

遇到问题?

如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23