Skip to content

概述

Soft-AP 模式让 Ai-WB2 变成一个 Wi-Fi 热点(像手机开个人热点一样发出一个 Wi-Fi 信号),手机/电脑等设备可直接连接开发板,常用于设备配网、局域网直连控制。开发板默认 IP(网络里的「门牌号」)为 192.168.169.1,接入设备由板载 DHCP 服务器(自动分配 IP 的小管家)分配 IP。本教程演示开启热点并观察设备接入事件。

用大白话讲:Soft-AP 就是开发板自己「开热点」——它发出一个 Wi-Fi 信号(名字叫 SSID),手机像连家里 Wi-Fi 一样连上它,不用经过路由器就能和开发板通信。开发板给热点设了固定「门牌号」192.168.169.1,谁连进来,板子里的 DHCP 小管家就自动发给它一个 IP。常用于给设备配网、局域网直接控制设备。

本教程基于安信可官方 SDKAi-Thinker-Open/Ai-Thinker-WB2,版本 release_bl_iot_sdk_1.6.40)的官方示例 applications/wifi/softAP 编写,代码可在本地 SDK 中直接找到。

🎯本页目标通过开启热点、设置热点 IP、观察设备接入/离开事件,掌握 Soft-AP 模式的开启流程与网络配置。
🧰前置条件① Ai-WB2 开发板一块(Type-C 数据线)② 手机或电脑一台(用于连接热点验证)③ 已按 [SDK 安装](../sdk/sdk_intro) 完成环境搭建。
🔗相关章节STA 模式连接路由器见 [连接 Wi-Fi](./wifi_connect);配网产品可参考 [blufi 配网](../ble/blufi)。

进入示例工程

打开终端,进入官方 softAP 示例工程目录:

cd ~/Ai-Thinker-WB2/applications/wifi/softAP

说明:cd 是「进入目录」的命令,进入官方示例工程;后面所有 make 命令都要在这个目录下执行。

修改热点参数

打开 softAP/main.c,修改开头的热点名称(SSID,Wi-Fi 的名字)与密码:

#define AP_SSID "ai-thinker"
#define AP_PWD "12345678"

例如:

#define AP_SSID "WB2-Hotspot"
#define AP_PWD "88888888"

💡 热点密码至少 8 位(WPA2 加密要求,不足 8 位开不了热点);可用手机搜索到热点并连接测试。

编写代码

打开 softAP/main.c,本步完整代码已移至文末,见:

📜 完整代码 — 位于本页「完整代码」章节,默认折叠,点击展开,与官方示例(applications/wifi/softAP/softAP/main.c)完全一致。

代码要点:

代码 作用
wifi_mgmr_ap_enable() 先启用 AP 模式,不启用后面开热点的函数都用不了
wifi_mgmr_conf_max_sta(4) 限制最多 4 台设备接入,防止热点被挤爆
wifi_mgmr_ap_start(if, ssid, 0, pwd, 6) 真正开热点:名字、信道 0(自动)、密码、加密方式 6(WPA2)
wifi_ap_ip_set(...) 给热点定「门牌号」IP 192.168.169.1、掩码、网关
netif_find("ap1") 找到热点网卡接口(ap1),改 IP 前必须先找到它
CODE_WIFI_ON_AP_STA_ADD 有设备连上热点的通知,可在这里做业务
CODE_WIFI_ON_AP_STA_DEL 有设备断开热点的通知,可在这里做业务

💡 默认网关 IP 192.168.169.1components/network/lwip_dhcpd/dhcp_server_raw.c 第 42 行 DHCPD_SERVER_IP 宏定义;想换网段(如 192.168.4.1)需同步修改该宏与 wifi_ap_ip_set 参数。

编译工程

在工程目录执行编译:

make -j8

说明:make 是「编译」命令,把代码变成开发板能运行的固件(烧进开发板的程序);-j8 表示用 8 个 CPU 核并行编译,更快。

编译成功后生成固件 build_out/softAP.bin

烧录固件

开发板保持 USB 连接,确认串口设备号后执行烧录:

make flash p=/dev/ttyUSB0 b=921600

说明:make flash 是「烧录」命令,把编译好的固件下载进开发板;p= 后面是串口设备号(Linux 下常为 /dev/ttyUSB0,Windows 下是 COM3 之类,以你电脑实际为准),b=921600 是烧录波特率(串口传数据的速度),保持默认即可。

⏳ 烧录过程中按提示长按开发板 EN 键进入下载模式,等待进度条完成即烧录成功。

运行验证

烧录完成后开发板自动重启运行,打开串口助手(波特率 921600,串口传数据的「语速」,两边必须一致)观察日志:

[OS] Starting TCP/IP Stack...
<<<<<<<<<  init wifi done  <<<<<<<<<<
<<<<<<<<< startting soft ap <<<<<<<<<<<
<<<<<<<<< startt soft ap OK<<<<<<<<<<<
[softAP]:SSID:ai-thinker,PASSWORD:12345678,IP addr:192.168.169.1

用手机搜索 Wi-Fi,找到热点 ai-thinker 输入密码连接,串口打印:

<<<<<<<<< station connent ap <<<<<<<<<<<

手机断开连接时打印 station disconnet ap。手机浏览器访问 http://192.168.169.1 可访问开发板 Web 服务(需配合 HTTP 服务器 类应用)。

手机连上热点且串口打印 station connent ap 即成功;如果手机搜不到热点,先看串口有没有打印 startt soft ap OK(没有就是热点没启动成功);如果搜得到却连不上,检查密码是否 8 位以上、是否修改后重新烧录了——都见文末 FAQ。

代码执行流程

例程从启动到运行的完整流程如下(图中的循环箭头表示反复执行):


本文 API 汇总

wifi_mgmr_ap_enable

使能 AP 模式,返回热点接口句柄。

返回值:成功返回接口句柄(wifi_interface_t);失败返回 NULL

wifi_mgmr_conf_max_sta(num)

限制热点最大接入设备数。

参数

  • num:最大接入设备数,官方示例传 4

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

wifi_mgmr_ap_start(if, ssid, channel, pwd, enc)

启动热点(加密方式 6 = WPA2,0 = 开放)。

参数

  • if:AP 接口句柄(wifi_mgmr_ap_enable() 返回值)
  • ssid:热点名称(官方默认 "ai-thinker"
  • channel:信道(1~13
  • pwd:热点密码(官方默认 "12345678"),开放网络传 NULL
  • enc:加密方式(6 = WPA2,0 = 开放)

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

wifi_mgmr_start_background(conf)

启动 Wi-Fi 管理器(连接/热点/扫描的调度核心)。

参数

  • confwifi_conf_t 结构体指针,可选字段:country_code(国家码,中国用 "CN"

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

netif_find(name)

按名称查找网络接口(热点口为 "ap1")。

参数

  • name:网卡名称字符串,可选值:"st1"(station 口)/ "ap1"(热点口)

返回值:成功返回 struct netif*;失败返回 NULL

netif_set_ipaddr / netif_set_netmask / netif_set_gw(netif, addr)

设置网卡 IP / 子网掩码 / 网关。

参数

  • netif:目标网卡(netif_find 返回值)
  • addrip4_addr_t 指针,用 IP4_ADDR 宏构造

返回值:无

netif_set_down / netif_set_up(netif)

关闭 / 开启网卡。

参数

  • netif:目标网卡(netif_find 返回值)

返回值:无

IP4_ADDR(addr, a, b, c, d)

由 4 段整数构造 IP 地址(网络字节序)。

参数

  • addr:输出的 ip4_addr_t 指针
  • a, b, c, d:IP 四段数值,如 192, 168, 169, 1

返回值:无

ip4addr_ntoa(addr)

IP 地址转点分十进制字符串。

参数

  • addrip4_addr_t 指针

返回值:点分十进制字符串(如 "192.168.169.1"

📌 热点事件码:CODE_WIFI_ON_AP_STARTED(热点启动成功)/ CODE_WIFI_ON_AP_STOPPED(停止)/ CODE_WIFI_ON_AP_STA_ADD(设备接入)/ CODE_WIFI_ON_AP_STA_DEL(设备离开),定义于 hal_wifi.h


完整代码

以下为 softAP/main.c 完整源码,与官方示例(applications/wifi/softAP/softAP/main.c)完全一致:

📜 点击展开 softAP/main.c 完整代码
c
/**
 * @file main.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2022-10-09
 *
 * @copyright Copyright (c) 2022
 *
 */
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <string.h>
#include <aos/yloop.h>
#include <aos/kernel.h>
#include <lwip/tcpip.h>
#include <wifi_mgmr_ext.h>
#include <hal_wifi.h>
#include <lwip/netif.h>
#include <lwip/inet.h>
#include <blog.h>

#define AP_SSID "ai-thinker"
#define AP_PWD "12345678"

#define TAG "softAP"

static wifi_conf_t ap_conf = {
    .country_code = "CN",
};
static wifi_interface_t ap_interface;
/**
 * @brief wifi_ap_ip_set
 *      Set the IP address of soft AP
 * @param ip_addr IPV4 addr
 * @param netmask netmask
 * @param gw DNS
 */
static void wifi_ap_ip_set(char* ip_addr, char* netmask, char* gw)
{
    struct netif* ap_netif = netif_find("ap1");
    int i = 0;
    int ap_ipaddr[4] = { 0 };
    int ap_netmask[4] = { 255,255,255,0 };
    int ap_gw_arry[4] = { 0,0,0,0 };

    ap_ipaddr[0] = atoi(strtok(ip_addr, "."));

    for (i = 1;i<4;i++) {
        ap_ipaddr[i] = atoi(strtok(NULL, "."));
    }
    if (netmask) {
        ap_netmask[0] = atoi(strtok(netmask, "."));
        for (i = 1;i<4;i++)
            ap_netmask[i] = atoi(strtok(NULL, "."));
    }
    if (gw) {
        ap_gw_arry[0] = atoi(strtok(gw, "."));
        for (i = 1;i<4;i++)
            ap_gw_arry[i] = atoi(strtok(NULL, "."));
    }

    if (ap_netif) {

        ip_addr_t ap_ip;
        ip_addr_t ap_mask;
        ip_addr_t ap_gw;
        IP4_ADDR(&ap_ip, ap_ipaddr[0], ap_ipaddr[1], ap_ipaddr[2], ap_ipaddr[3]);
        IP4_ADDR(&ap_mask, ap_netmask[0], ap_netmask[1], ap_netmask[2], ap_netmask[3]);
        IP4_ADDR(&ap_gw, ap_gw_arry[0], ap_gw_arry[1], ap_gw_arry[2], ap_gw_arry[3]);

        netif_set_down(ap_netif);
        netif_set_ipaddr(ap_netif, &ap_ip);
        netif_set_netmask(ap_netif, &ap_mask);
        netif_set_gw(ap_netif, &ap_gw);
        netif_set_up(ap_netif);
        blog_info("[softAP]:SSID:%s,PASSWORD:%s,IP addr:%s", AP_SSID, AP_PWD, ip4addr_ntoa(netif_ip4_addr(ap_netif)));
    }
    else
        blog_info("no find netif ap1 ");

}

/**
 * @brief wifi_ap_start
 *
 */
static void wifi_ap_start()
{
    ap_interface = wifi_mgmr_ap_enable();
    wifi_mgmr_conf_max_sta(4);
    wifi_mgmr_ap_start(ap_interface, AP_SSID, 0, AP_PWD, 6);
    wifi_ap_ip_set("192.168.169.1", "255.255.255.0", "192.168.169.1");  //defaut gateway ip is "192.168.169.1",if you want usb other gateway ip ,please change components/network/lwip_dhcpd/dhcp_server_raw.c:42   DHCPD_SERVER_IP 
                                                                        //for example, gateway ip:"192.168.4.1" , change DHCPD_SERVER_IP to "192.168.4.1"  :
                                                                        //wifi_ap_ip_set("192.168.4.1", "255.255.255.0", "192.168.4.1");
                                                                        //components/network/lwip_dhcpd/dhcp_server_raw.c:42   #define DHCPD_SERVER_IP "192.168.4.1"
}

static void event_cb_wifi_event(input_event_t* event, void* private_data)
{
    switch (event->code) {
        case CODE_WIFI_ON_INIT_DONE:
            blog_info("<<<<<<<<<  init wifi done  <<<<<<<<<<");
            wifi_mgmr_start_background(&ap_conf);
            break;
        case CODE_WIFI_ON_MGMR_DONE:
            blog_info("<<<<<<<<< startting soft ap <<<<<<<<<<<");
            wifi_ap_start();
            break;
        case CODE_WIFI_ON_AP_STARTED:
            blog_info("<<<<<<<<< startt soft ap OK<<<<<<<<<<<");

            break;
        case CODE_WIFI_ON_AP_STOPPED:
            break;
        case CODE_WIFI_ON_AP_STA_ADD:
            blog_info("<<<<<<<<< station connent ap <<<<<<<<<<<");

            break;
        case CODE_WIFI_ON_AP_STA_DEL:
            blog_info("<<<<<<<<< station disconnet ap <<<<<<<<<<<");

            break;
        default:
            break;

    }
}

static void proc_main_entry(void* pvParameters)
{

    aos_register_event_filter(EV_WIFI, event_cb_wifi_event, NULL);
    hal_wifi_start_firmware_task();
    aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0);
    vTaskDelete(NULL);
}

static void system_thread_init()
{
    /*nothing here*/
}

void main()
{
    system_thread_init();

    puts("[OS] Starting TCP/IP Stack...");
    tcpip_init(NULL, NULL);
    puts("[OS] proc_main_entry task...");
    xTaskCreate(proc_main_entry, (char*)"main_entry", 1024, NULL, 15, NULL);
}

常见问题与踩坑提示

⚠️ 手机搜索不到热点
原因:热点未启动成功、或手机 Wi-Fi 关闭/5GHz 优先
解决:确认串口打印 startt soft ap OK;手机开启 Wi-Fi 等待几秒重新搜索(热点为 2.4GHz)

⚠️ 连接热点提示密码错误
原因:热点密码不足 8 位(WPA2 要求)或修改代码后未重新烧录
解决AP_PWD 至少 8 位;修改后重新编译烧录

⚠️ 设备接入但无法获取 IP
原因:DHCP 服务器未运行,或网段与 DHCPD_SERVER_IP 不一致
解决:确认未改动 dhcp_server_raw.c;换网段时同步修改宏与 wifi_ap_ip_set

⚠️ 想同时连接路由器又开热点
原因:官方示例只启用 AP 模式
解决:先 wifi_mgmr_sta_enable() + 连接路由器,再 wifi_mgmr_ap_enable() + wifi_mgmr_ap_start(),SDK 支持 STA+AP 共存

⚠️ 串口找不到设备 / 打不开
原因:USB 转串口驱动未装、权限不足,或数据线只能充电不能传数据
解决:Linux 用 lsusb/dmesg 查看设备,权限不足可 sudo chmod 666 /dev/ttyUSB0;Windows 装驱动后到设备管理器查 COM 口;换一根能传数据的线

⚠️ 烧录一直等待 / 失败
原因:未进入下载模式、波特率不对、或串口号填错
解决:烧录时按提示长按 EN 键进入下载模式;确认 p=/dev/ttyUSB0 换成你实际的串口;换 USB 口或数据线重试

运行自检

手机搜索到热点并连接成功(串口打印 station connent ap),即 Soft-AP 验证通过。

遇到问题?

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

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