☰
【ESP32笔记】WIFI连接—STA模式
2026/10/15 9:47:10 网站建设 项目流程

本节目标:让 ESP32 以 STA 模式连上家里的路由器,并通过事件回调分清"连上 AP"和"拿到 IP"两个阶段,顺便掌握断线重连的写法

一、本节要解决的问题

前面十几节讲的全是 ESP32 的MCU 能力:GPIO、PWM、ADC、NVS、文件系统……这些能力让 ESP32 可以替换很多普通单片机。但 ESP32 真正的主业是IOT(物联网):一块 ESP32 上集成了 2.4GHz WiFi + BT(LE) 4.2,而 ESP-IDF 对 WiFi 驱动的封装已经很完善,我们不需要研究协议栈底层,把精力放在应用逻辑上就行。

要让 ESP32 上网,第一个要回答的问题是:它怎么知道我家的 WiFi 叫什么、密码是多少?

本节先用最直接的办法——把 SSID 和密码写死在代码里,以STA 模式连上路由器。这个做法在真实产品里不能用(出厂时根本不知道用户家的 WiFi),但它是后面一切网络应用(MQTT、HTTP、OTA)的地基,也是下一节 SmartConfig 配网的前置知识。

二、硬件基础

本节没有新增外围电路,用的是 ESP32 板载的 PCB 天线,需要准备的是:

  • 一台2.4GHz家用路由器(ESP32 只支持 2.4GHz,连不上 5GHz 热点);
  • 一台手机或电脑,用来确认路由器 SSID 和密码。

ESP32 的 WiFi 有三种工作模式:

模式说明
STA作为客户端去连接已存在的 WiFi 网络,像一台普通的上网设备
AP自己创建热点,变成一个小型路由器,接受其它设备连接,多用于配网
STA+AP同时工作在两种模式:既连热点又开热点,可以做桥接/中继,让别的设备经由 ESP32 上网

本节只讲最常用的STA 模式。

三、知识点

3.1 三个"主角":esp_netif、esp_event、esp_wifi

ESP-IDF 把 WiFi 的使用拆成了三层,初始化代码里那几行"看起来差不多"的调用,其实各管一摊:

  • esp_wifi:WiFi 驱动本体,负责扫描、认证、连接、加解密;
  • esp_netif:网络接口(网卡)抽象层。esp_netif_create_default_wifi_sta()会创建一个 STA 网卡对象,并顺手挂上DHCP 客户端——没有它,就算连上了路由器也拿不到 IP;
  • esp_event:事件循环。esp_event_loop_create_default()建了一个默认事件循环(内部是一个 FreeRTOS 任务 + 事件队列),WiFi 驱动把"启动完成"“连上了”"断开了"这些状态变化打包成事件投递进去,我们注册的回调就在这个任务里被调用。

注意:回调函数运行在事件循环任务的上下文里,不要在回调里做阻塞操作(长延时、死循环、等待信号量),否则整个系统的事件分发都会被拖住。

3.2 连接是一场"事件接力"

调用顺序和事件顺序是分开的两条线,初学者最容易在这里迷糊:

调用线:esp_wifi_init() → esp_wifi_set_mode() → esp_wifi_set_config() → esp_wifi_start() 事件线: WIFI_EVENT_STA_START → esp_wifi_connect() → WIFI_EVENT_STA_CONNECTED (已连上 AP,但还没有 IP) → IP_EVENT_STA_GOT_IP (拿到路由器分配的地址,才算真正上网) 掉线时: WIFI_EVENT_STA_DISCONNECTED → 再 esp_wifi_connect() 重新开始

两个关键区别要记牢(教程原话的意思):

  • WIFI_EVENT_STA_CONNECTED只表示已经挂了 AP 热点,链路层通了,但还没有网络层地址;
  • 只有IP_EVENT_STA_GOT_IP到手,才说明路由器给你分配了 IP,此时 DHCP 完成,才能真正访问网络。

3.3 为什么必须先初始化 NVS

WiFi 驱动会把"最近一次成功连接的热点信息"存进 NVS(命名空间nvs.net80211),所以esp_wifi_init()之前必须已经nvs_flash_init(),否则会因 NVS 未初始化而报错。教程里那句"WiFi 底层驱动使用了 NVS 来保存一份默认可连接的 SSID 和密码"说的就是这件事。

3.4 断线重连思路

最简单的做法(本例程用的):在WIFI_EVENT_STA_DISCONNECTED分支里无条件再调一次esp_wifi_connect(),形成"断了就重连"的闭环。

这个写法能跑,但产品里要改进:

  • 密码填错时也会疯狂重试,串口刷屏、耗电、发热;
  • 更稳的做法是按断开原因(event_data里的wifi_event_sta_disconnected_t.reason)分类处理:密码错(认证失败)就别重试,提示用户重新配网;路由器暂时不在才重试,并且加延时/退避和最大重试次数。

四、代码分析

4.1 工程结构

wifi/ ├── CMakeLists.txt # 标准模板,project(main) ├── sdkconfig # CONFIG_IDF_TARGET="esp32" ├── README.md └── main/ ├── CMakeLists.txt # SRCS "simple_wifi_sta.c" "main.c" ├── main.c # app_main():NVS 初始化 + 启动 STA ├── simple_wifi_sta.c # 本节全部实现:初始化函数 + 事件回调 └── simple_wifi_sta.h # 对外只暴露 wifi_sta_init()

4.2 主函数:两件事

voidapp_main(void){//NVS初始化(WIFI底层驱动有用到NVS,所以这里要初始化)nvs_flash_init();//wifi STA工作模式初始化wifi_sta_init();while(1){vTaskDelay(pdMS_TO_TICKS(500));}}

app_main()本身不做 WiFi 逻辑,只负责"NVS 先初始化、再去启动 WiFi"。最后的while(1)是为了让app_main任务不退出——WiFi 的连接过程是异步的,连接结果稍后由事件回调通知。

4.3 网络层初始化:三行代码各自管什么

esp_err_twifi_sta_init(void){ESP_ERROR_CHECK(esp_netif_init());//用于初始化tcpip协议栈ESP_ERROR_CHECK(esp_event_loop_create_default());//创建一个默认系统事件调度循环,之后可以注册回调函数来处理系统的一些事件esp_netif_create_default_wifi_sta();//使用默认配置创建STA对象
  • esp_netif_init():初始化 TCP/IP 协议栈(lwIP)和网络接口层;
  • esp_event_loop_create_default():建默认事件循环,后面注册的回调都有地方"排队执行";
  • esp_netif_create_default_wifi_sta():创建默认 STA 网卡对象(含 DHCP 客户端)。

esp_netif_create_default_wifi_sta()的返回值是一个esp_netif_t *网卡句柄,本例程没有接收它(用默认 STA 时通常也不需要)。另外simple_wifi_sta.c并没有显式#include "esp_netif.h",这里靠头文件间接包含;换 IDF 版本编译如果报esp_netif_init未声明,把该头文件补上即可。

4.4 初始化 WiFi 驱动并注册事件

//初始化WIFIwifi_init_config_tcfg=WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));//注册事件ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&event_handler,NULL));ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT,IP_EVENT_STA_GOT_IP,&event_handler,NULL));
  • WIFI_INIT_CONFIG_DEFAULT()给出官方默认的一整套 WiFi 初始化参数(收发缓冲区、任务优先级、软 AP 支持等),入门阶段不用动它;
  • 两个注册的意义不同:WIFI_EVENT+ESP_EVENT_ANY_ID表示所有 WiFi 事件都进回调,由回调内部再按event_id分流;IP_EVENT只注册了IP_EVENT_STA_GOT_IP这一个,其它 IP 事件(如丢失 IP)不会进回调。

4.5 连接参数与启动顺序

//WIFI配置wifi_config_twifi_config={.sta={.ssid=DEFAULT_WIFI_SSID,//WIFI的SSID.password=DEFAULT_WIFI_PASSWORD,//WIFI密码.threshold.authmode=WIFI_AUTH_WPA2_PSK,//加密方式.pmf_cfg={.capable=true,.required=false},},};//启动WIFIESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));//设置工作模式为STAESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA,&wifi_config));//设置wifi配置ESP_ERROR_CHECK(esp_wifi_start());//启动WIFI

这里有几个参数值得解释:

  • threshold.authmode = WIFI_AUTH_WPA2_PSK:最低要求的加密方式,目前家用路由器基本都是 WPA2-PSK;
  • pmf_cfg.capable = true:设备支持保护管理帧(PMF),required = false表示"不强制对方也支持"。教程特别说明照官方例程这么填就行,初学不必深究;
  • 三步顺序不能反:先set_mode定角色 → 再set_config填参数 → 最后start开跑。start成功后驱动才会抛出WIFI_EVENT_STA_START。

与教程不一致处:教程 PDF 里写的 SSID 是"wifitest",而仓库simple_wifi_sta.c里已经改成"testwifi",并且加了注释"需要把这两个修改成你家WIFI,测试是否连接成功"。以仓库代码为准——无论是哪个值,都要改成自己家 2.4G WiFi 的 SSID 和密码,否则现象就是一直重连失败。

4.6 事件回调:连接状态机的中心

staticvoidevent_handler(void*arg,esp_event_base_tevent_base,int32_tevent_id,void*event_data){if(event_base==WIFI_EVENT){switch(event_id){caseWIFI_EVENT_STA_START://WIFI以STA模式启动后触发此事件esp_wifi_connect();//启动WIFI连接break;caseWIFI_EVENT_STA_CONNECTED://WIFI连上路由器后,触发此事件ESP_LOGI(TAG,"connected to AP");break;caseWIFI_EVENT_STA_DISCONNECTED://WIFI从路由器断开连接后触发此事件esp_wifi_connect();//继续重连ESP_LOGI(TAG,"connect to the AP fail,retry now");break;default:break;}}if(event_base==IP_EVENT)//IP相关事件{switch(event_id){caseIP_EVENT_STA_GOT_IP://只有获取到路由器分配的IP,才认为是连上了路由器ESP_LOGI(TAG,"get ip address");break;}}}

回调的写法值得学习:先用event_base区分事件大类,再用event_id分流具体事件,这是 ESP-IDF 里处理事件的通用套路。

  • WIFI_EVENT_STA_START:驱动启动完成,此时才可以发起连接,所以在这里调esp_wifi_connect();
  • WIFI_EVENT_STA_DISCONNECTED:断开后立刻重连(见 3.4 的改进建议);
  • IP_EVENT_STA_GOT_IP:拿到 IP,真正可以上网了。真实项目一般在这里置位一个事件组标志位,通知其它任务"网络就绪"(下一节的代码就是这么干的)。

esp_wifi_connect()是异步非阻塞的:它只是告诉驱动"去连",结果通过上面这些事件回来,所以千万不要在它后面紧跟一句"连接成功"的打印。

五、关键 API 速查

API作用
nvs_flash_init()初始化 NVS(必须早于esp_wifi_init)
esp_netif_init()初始化 TCP/IP 协议栈与网络接口层
esp_event_loop_create_default()创建默认系统事件循环
esp_netif_create_default_wifi_sta()创建默认 STA 网卡对象(含 DHCP 客户端)
WIFI_INIT_CONFIG_DEFAULT()生成 WiFi 驱动默认初始化配置
esp_wifi_init(&cfg)初始化 WiFi 驱动
esp_event_handler_register(base, id, handler, arg)注册事件回调;ESP_EVENT_ANY_ID表示该类的全部事件
esp_wifi_set_mode(WIFI_MODE_STA)设置 WiFi 工作模式
esp_wifi_set_config(WIFI_IF_STA, &cfg)写入连接参数(SSID/密码等)
esp_wifi_start()启动 WiFi,触发WIFI_EVENT_STA_START
esp_wifi_connect()发起连接(异步,结果靠事件返回)
esp_wifi_disconnect()主动断开当前连接

六、编译与现象验证

cdesp32-board/wifi idf.py build# sdkconfig 已指定 CONFIG_IDF_TARGET="esp32"idf.py-pCOM<端口>flash monitor

烧录前先把simple_wifi_sta.c顶部的DEFAULT_WIFI_SSID、DEFAULT_WIFI_PASSWORD改成自己家2.4GWiFi 的信息。正常连接时串口大致是:

I (xxx) wifi: wifi_init_sta finished. I (xxx) wifi: connected to AP I (xxx) wifi: get ip address
  • 只看到connected to AP没看到get ip address:链路连上了但 DHCP 没成功,检查路由器 DHCP 是否开启;
  • 反复打印connect to the AP fail,retry now:SSID/密码错了,或路由器是 5GHz、或信号太弱。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询