一。基本原理讲解
1.Wi-Fi/LwIP 初始化阶段
s1.1:主任务通过调用函数 esp_netif_init() 创建一个 LwIP 核心任务,并初始化 LwIP 相关工作。
s1.2:主任务通过调用函数 esp_event_loop_create() 创建一个系统事件任务,并初始化应用程序事件的回调函数。在此情况下,该回调函数唯一的动作就是将事件中继到应用程序任务中。
s1.3:主任务通过调用函数 esp_netif_create_default_wifi_sta() 创建有 TCP/IP 堆栈的默认网络接口实例绑定 station 或 AP。
s1.4:主任务通过调用函数 esp_wifi_init() 创建 Wi-Fi 驱动程序任务,并初始化 Wi-Fi 驱动程序。
s1.5:主任务通过调用 OS API 创建应用程序任务。
推荐按照 s1.1 ~ s1.5 的步骤顺序针对基于 Wi-Fi/LwIP 的应用程序进行初始化。但这一顺序 并非 强制,您可以在第 s1.1 步创建应用程序任务,然后在该应用程序任务中进行所有其它初始化操作。不过,如果您的应用程序任务依赖套接字,那么在初始化阶段创建应用程序任务可能并不适用。此时,您可以在接收到 IP 后再进行任务创建。
1 | ESP_ERROR_CHECK(esp_netif_init()); |
2.Wi-Fi 配置阶段
Wi-Fi 驱动程序初始化成功后,可以进入到配置阶段。该场景下,Wi-Fi 驱动程序处于 station 模式。因此,首先您需调用函数 esp_wifi_set_mode() (WIFI_MODE_STA) 将 Wi-Fi 模式配置为 station 模式。可通过调用其它 esp_wifi_set_xxx API 进行更多设置,例如:协议模式、国家代码、带宽等。请参阅 ESP32 Wi-Fi 配置。
一般情况下,我们会在建立 Wi-Fi 连接之前配置 Wi-Fi 驱动程序,但这 并非 强制要求。也就是说,只要 Wi-Fi 驱动程序已成功初始化,您可以在任意阶段进行配置。但是,如果您的 Wi-Fi 在建立连接后不需要更改配置,则应先在此阶段完成配置。因为调用配置 API(例如 esp_wifi_set_protocol())将会导致 Wi-Fi 连接断开,为您的操作带来不便。
如果 menuconfig 已使能 Wi-Fi NVS flash,则不论当前阶段还是后续的 Wi-Fi 配置信息都将被存储至该 flash 中。那么,当主板上电/重新启动时,就不需从头开始配置 Wi-Fi 驱动程序。您只需调用函数 esp_wifi_get_xxx API 获取之前存储的配置信息。当然,如果不想使用之前的配置,您依然可以重新配置 Wi-Fi 驱动程序。
1 | #define EXAMPLE_ESP_WIFI_SSID "wireless link" |
3.Wi-Fi 启动阶段
s3.1:调用函数 esp_wifi_start() 启动 Wi-Fi 驱动程序。
s3.2:Wi-Fi 驱动程序将事件 WIFI_EVENT_STA_START 发布到事件任务中,然后,事件任务将执行一些正常操作并调用应用程序的事件回调函数。
1 | ESP_ERROR_CHECK(esp_wifi_start() ); |
4.Wi-Fi 连接阶段
s4.1:调用函数 esp_wifi_connect() 后,Wi-Fi 驱动程序将启动内部扫描/连接过程。
s4.2:如果内部扫描/连接过程成功,将产生 WIFI_EVENT_STA_CONNECTED 事件。然后,事件任务将启动 DHCP 客户端服务,最终触发 DHCP 程序。
s4.3:在此情况下,应用程序的事件回调函数会将 WIFI_EVENT_STA_CONNECTED 事件中继到应用程序任务中。通常,应用程序不需进行操作,而您可以执行任何动作,例如:打印日志等。
步骤 s4.2 中 Wi-Fi 连接可能会由于某些原因而失败,例如:密码错误、未找到 AP 等。这种情况下,将引发 WIFI_EVENT_STA_DISCONNECTED 事件并提示连接错误原因。
1 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { |
5.Wi-Fi 获取 IP 阶段
s5.1:一旦步骤 4.2 中的 DHCP 客户端初始化完成,Wi-Fi 驱动程序将进入 获取 IP 阶段。
s5.2:如果 Wi-Fi 成功从 DHCP 服务器接收到 IP 地址,则将引发 IP_EVENT_STA_GOT_IP 事件,事件任务将执行正常处理。
s5.3:应用程序的事件回调函数将事件 IP_EVENT_STA_GOT_IP 中继到应用程序任务中。对于那些基于 LwIP 构建的应用程序,此事件较为特殊,因为它意味着应用程序已准备就绪,可以开始任务,例如:创建 TCP/UDP 套接字等。此时较为容易犯的一个错误就是在接收到 IP_EVENT_STA_GOT_IP 事件之前就初始化套接字。切忌在接收到 IP 之前启动任何套接字相关操作。
1 | else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { |
6.Wi-Fi 断开阶段
s6.1:当 Wi-Fi 因为某些原因(例如:AP 掉电、RSSI 较弱等)连接中断时,将产生 WIFI_EVENT_STA_DISCONNECTED 事件。此事件也可能在上文阶段 3 中发生。在这里,事件任务将通知 LwIP 任务清除/移除所有 UDP/TCP 连接。然后,所有应用程序套接字都将处于错误状态。也就是说,WIFI_EVENT_STA_DISCONNECTED 事件发生时,任何套接字都无法正常工作。
s6.2:上述情况下,应用程序的事件回调函数会将 WIFI_EVENT_STA_DISCONNECTED 事件中继到应用程序任务中。推荐您调用函数 esp_wifi_connect() 重新连接 Wi-Fi,关闭所有套接字,并在必要时重新创建套接字。
7.Wi-Fi IP 更改阶段
s7.1:如果 IP 地址发生更改,将引发 IP_EVENT_STA_GOT_IP 事件,其中 “ip_change” 被置为 “true”。
s7.2:此事件对应用程序至关重要。这一事件发生时,适合关闭所有已创建的套接字并进行重新创建。
8.Wi-Fi 清理阶段
s8.1:调用函数 esp_wifi_disconnect() 断开 Wi-Fi 连接。
s8.2:调用函数 esp_wifi_stop() 终止 Wi-Fi 驱动程序。
s8.3:调用函数 esp_wifi_deinit() 清理 Wi-Fi 驱动程序。
二.代码
1 | /_ WiFi station Example |