Skip to content

概念先知道

  • STA(Station)模式:开发板像手机一样去连路由器,是几乎所有网络实验的第一步。
  • SSID / 密码:Wi-Fi 的名字和密码;只支持 2.4GHz 频段,5GHz 或中文 SSID 建议避免。
  • 事件回调:Wi-Fi 固件状态变化时通知应用,例程通过 wifi_event_handler 打印各阶段事件。
  • GOT_IP:DHCP 分配 IP 成功的事件,只有出现它之后才能进行 TCP/UDP/HTTP/MQTT 通信。

例程功能简介

  • 本页对应博流官方 SDK 的 wifi_tcp 例程(examples/wifi/sta/wifi_tcp)的启动骨架,这是所有 Wi-Fi 例程共用的 STA 初始化流程:
  • 上电后初始化 shell 与射频参数,启动 lwIP 协议栈(tcpip_init),再创建 Wi-Fi 固件任务:注册事件回调 → 启动固件(wifi_task_create / fhost_init)→ 收到 INIT_DONE 后启动 Wi-Fi 管理任务。
  • 之后通过串口 shell 输入 wifi_sta_connect <SSID> <密码> 连接路由器,串口实时打印 CONNECTEDGOT_IP 事件日志。

操作步骤

1
进入例程目录

SDK 没有独立的“连接 Wi-Fi”例程,所有网络例程(wifi_tcp / wifi_udp / wifi_http / wifi_mqtt 等)共用同一套 STA 启动骨架。本页以 wifi_tcp 例程为例(前提:已按快速开始(Linux)快速开始(Windows)搭建好环境):

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

Ai-M62(BL616)与 Ai-M61(BL618)同属一个系列,统一填写 bl616

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

按住 BOOT(Ai-M61-32S-Kit 为 IO2)短按 EN/RST 进入下载模式,然后烧录(串口号换成实际值):

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
打开串口并连接 Wi-Fi

串口助手波特率 2000000,等待出现 bouffalolab /> 提示符后输入连接命令(只支持 2.4GHz;密码为空时省略第二个参数):

wifi_sta_connect SSID <密码>
5
观察连接事件

连接过程中串口会依次打印 CODE_WIFI_ON_CONNECTED(已连上)和 CODE_WIFI_ON_GOT_IP(已拿到 IP,并打印剩余内存)。出现 GOT_IP 就说明连接成功,可以继续做 TCP/HTTP/MQTT 等实验。断开时打印 CODE_WIFI_ON_DISCONNECT

代码执行流程

例程调用的 API 介绍

tcpip_init(init_done, arg)

初始化 lwIP 网络协议栈,必须在任何网络操作之前调用。

参数

  • init_done:协议栈初始化完成回调,例程为 NULL
  • arg:回调参数,例程为 NULL

返回值:无

async_register_event_filter(EV_WIFI, handler, NULL)

注册 Wi-Fi 事件过滤器,事件发生时回调 wifi_event_handler

参数

  • EV_WIFI:Wi-Fi 事件类别
  • handler:事件回调函数
  • NULL:用户参数

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

wifi_task_create()

启动 Wi-Fi 固件任务(例程在 wifi_start_firmware_task 中调用)。

参数

返回值:无

fhost_init()

初始化 fhost(Wi-Fi 主机协议栈适配层),BL616/BL618 调用;BL602 下不调用。

参数

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

wifi_mgmr_task_start()

启动 Wi-Fi 管理任务,之后 wifi_sta_connect 等命令才可用。

参数

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

wifi_sta_connect(ssid, password, ...)

shell 命令(由 Wi-Fi 管理组件提供):以 STA 模式连接路由器,与例程事件回调配合使用。

参数

  • ssid:Wi-Fi 名称
  • password:Wi-Fi 密码,开放网络可为空

返回值:无(结果通过事件打印)

完整代码

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

📜 点击展开 wifi_tcp/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 "wifi_mgmr_ext.h"
#ifndef BL602
#include "fhost_api.h"
#include "wifi_mgmr.h"
#endif

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

#include "rfparam_adapter.h"
#include "async_event.h"
#include "mm.h"
#include "board.h"
#include "shell.h"

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

struct bflb_device_s *gpio;

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

/****************************************************************************
 * 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);
#ifdef BL602
extern void wifi_task_create(void);
extern int fhost_init(void);
extern int wifi_mgmr_task_start(void);
#endif

/****************************************************************************
 * 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");
#ifndef BL602
    fhost_init();
#endif

    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;
        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");

    tcpip_init(NULL, NULL);

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

    vTaskStartScheduler();

    while (1) {
    }
}

FAQ

连不上路由器,串口没有反应?

确认命令格式为 wifi_sta_connect SSID 密码(中间有空格);确认路由器是 2.4GHz、信号正常;确认没有开启 MAC 过滤;最后换一个信道或重启开发板再试。

提示 `PHY RF init failed!`?

射频参数读取失败。检查 Flash 是否为空或烧录不完整,重新烧录完整固件后再试。

只出现 CONNECTED 没有 GOT_IP?

路由器 DHCP 未开启或地址池耗尽。登录路由器开启 DHCP;也可以重启路由器再试。

`wifi_sta_connect` 命令不存在?

确认烧录的是本页指定的 wifi_tcp 例程固件(不是 AT 固件或其他例程),且等待 shell 提示符出现后再输入。

遇到问题?

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

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