文章目录

  • 前言
  • STA模式
    • 首先验证一下例程
    • 例程都有什么东西
      • 事件标志组
      • 事件处理回调函数
      • 初始化函数

前言

上一篇我们部署了ESP8266的集成开发环境,这一篇将开始ESP8266最主要的功能——WiFi的部分。其他诸如GPIO等外设的部分放在实际需要的时候再弄,没必要单独列一篇出来。
WiFi下有两种主要模式:STA和AP模式,前者可连接现有的路由器,后者本身建立热点,用手机上的功能来说,STA模式就相当于WLAN,AP模式就相当于移动热点。

STA模式

我们参考examples/wifi/getting-started/station,建立一个自己的工程文件夹:
在VScode里直接复制粘贴即可

首先验证一下例程

右键在集成终端中打开,make menuconfig
配置好板子参数,注意一下,比hello_world例程多了一步:Example Configuration,里边是例程里涉及到的一些宏,这个例程下就是WiFi名称和密码等:

WiFi SSID:你的路由器的名称,即你手机上能搜到的那个WiFi名称。
WiFi Password:WiFi密码
Maximum retry:重连次数,不一定能一次连上,需要多连几次,默认即可
保存退出,然后make

例程都有什么东西

/* WiFi station ExampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "nvs.h"
#include "nvs_flash.h"#include "lwip/err.h"
#include "lwip/sys.h"/* The examples use WiFi configuration that you can set via project configuration menuIf you'd rather not, just change the below entries to strings withthe config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY  CONFIG_ESP_MAXIMUM_RETRY/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;/* The event group allows multiple bits for each event, but we only care about two events:* - we are connected to the AP with an IP* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1static const char *TAG = "wifi station";static int s_retry_num = 0;static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {esp_wifi_connect();s_retry_num++;ESP_LOGI(TAG, "retry to connect to the AP");} else {xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);}ESP_LOGI(TAG,"connect to the AP fail");} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;ESP_LOGI(TAG, "got ip:%s",ip4addr_ntoa(&event->ip_info.ip));s_retry_num = 0;xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);}
}void wifi_init_sta(void)
{s_wifi_event_group = xEventGroupCreate();tcpip_adapter_init();ESP_ERROR_CHECK(esp_event_loop_create_default());wifi_init_config_t cfg = 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_config_t wifi_config = {.sta = {.ssid = EXAMPLE_ESP_WIFI_SSID,.password = EXAMPLE_ESP_WIFI_PASS},};/* Setting a password implies station will connect to all security modes including WEP/WPA.* However these modes are deprecated and not advisable to be used. Incase your Access point* doesn't support WPA2, these mode can be enabled by commenting below line */if (strlen((char *)wifi_config.sta.password)) {wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;}ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );ESP_ERROR_CHECK(esp_wifi_start() );ESP_LOGI(TAG, "wifi_init_sta finished.");/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,pdFALSE,pdFALSE,portMAX_DELAY);/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually* happened. */if (bits & WIFI_CONNECTED_BIT) {ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);} else if (bits & WIFI_FAIL_BIT) {ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);} else {ESP_LOGE(TAG, "UNEXPECTED EVENT");}ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler));ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler));vEventGroupDelete(s_wifi_event_group);
}void app_main()
{ESP_ERROR_CHECK(nvs_flash_init());ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");wifi_init_sta();
}

头文件不用管,前面几个宏也不用管

事件标志组

事件标志组,通俗一点理解就是一组事件标志位,多个事件标志位组合成一个方便访问的变量。

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;/* The event group allows multiple bits for each event, but we only care about two events:* - we are connected to the AP with an IP* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

s_wifi_event_group:事件标志组句柄,我们跳转到声明的位置,一个void 类型的指针,只是用来存储多个事件标志位而已(一个数据掰成N个位用)。

下边两个宏就是事件标志位,表示事件发生,因为整个过程需要一些时间,不能一直在这儿死等,所以等待标志位产生(类似8位机系统常见的轮询方式)。

static const char *TAG = "wifi station";

这句无实际意义,只是标注整个程序的名称而已

static int s_retry_num = 0;

这句是声明一个全局变量,重试次数,在每次发生重连的时候+1.

事件处理回调函数


static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {esp_wifi_connect();s_retry_num++;ESP_LOGI(TAG, "retry to connect to the AP");} else {xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);}ESP_LOGI(TAG,"connect to the AP fail");} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;ESP_LOGI(TAG, "got ip:%s",ip4addr_ntoa(&event->ip_info.ip));s_retry_num = 0;xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);}
}

event_handler:事件处理回调函数,
event_base:事件类型
event_id:事件对应的ID
其余参数均为可选参数
这个事件回调函数里总共有两种类型的事件:WIFI_EVENT和IP_EVENT,分别是连接WiFi和获取IP事件。
这个回调函数应该是可以分开写的,分别写一个WIFI_EVENT和IP_EVENT的事件回调,但意义不大。

如果超过设定的重连次数,则更新事件标志位WIFI_FAIL_BIT。

如果获取到IPv4,则更新事件标志位WIFI_CONNECTED_BIT。

初始化函数

void wifi_init_sta(void)
{s_wifi_event_group = xEventGroupCreate();tcpip_adapter_init();ESP_ERROR_CHECK(esp_event_loop_create_default());wifi_init_config_t cfg = 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_config_t wifi_config = {.sta = {.ssid = EXAMPLE_ESP_WIFI_SSID,.password = EXAMPLE_ESP_WIFI_PASS},};/* Setting a password implies station will connect to all security modes including WEP/WPA.* However these modes are deprecated and not advisable to be used. Incase your Access point* doesn't support WPA2, these mode can be enabled by commenting below line */if (strlen((char *)wifi_config.sta.password)) {wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;}ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );ESP_ERROR_CHECK(esp_wifi_start() );ESP_LOGI(TAG, "wifi_init_sta finished.");/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,pdFALSE,pdFALSE,portMAX_DELAY);/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually* happened. */if (bits & WIFI_CONNECTED_BIT) {ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);} else if (bits & WIFI_FAIL_BIT) {ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);} else {ESP_LOGE(TAG, "UNEXPECTED EVENT");}ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler));ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler));vEventGroupDelete(s_wifi_event_group);
}

s_wifi_event_group = xEventGroupCreate();//创建事件标志组
tcpip_adapter_init();//初始化TCP/IP的协议栈
ESP_ERROR_CHECK(esp_event_loop_create_default());//创建事件循环回调,处理系统事件,创建一个默认事件处理WiFi的连接。
ESP_ERROR_CHECK();//检查函数返回结果,如果非ESP_OK则会打印相应的错误代码和错误信息。
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));//配置WiFi参数,使用默认参数,打开Config项:

#define WIFI_INIT_CONFIG_DEFAULT() { \.event_handler = &esp_event_send, \.osi_funcs = NULL, \.qos_enable = WIFI_QOS_ENABLED,\.ampdu_rx_enable = WIFI_AMPDU_RX_ENABLED,\.rx_ba_win = WIFI_AMPDU_RX_BA_WIN,\.rx_ampdu_buf_num = WIFI_AMPDU_RX_AMPDU_BUF_NUM,\.rx_ampdu_buf_len = WIFI_AMPDU_RX_AMPDU_BUF_LEN,\.rx_max_single_pkt_len = WIFI_RX_MAX_SINGLE_PKT_LEN,\.rx_buf_len = WIFI_HW_RX_BUFFER_LEN,\.amsdu_rx_enable = WIFI_AMSDU_RX_ENABLED,\.rx_buf_num = CONFIG_ESP8266_WIFI_RX_BUFFER_NUM,\.rx_pkt_num = CONFIG_ESP8266_WIFI_RX_PKT_NUM,\.left_continuous_rx_buf_num = CONFIG_ESP8266_WIFI_LEFT_CONTINUOUS_RX_BUFFER_NUM,\.tx_buf_num = CONFIG_ESP8266_WIFI_TX_PKT_NUM,\.nvs_enable = WIFI_NVS_ENABLED,\.nano_enable = 0,\.wpa3_sae_enable = WIFI_WPA3_ENABLED, \.magic = WIFI_INIT_CONFIG_MAGIC\
};

好多项我也不知道是啥,暂时就按默认来吧。下面是结构体的详情:

/*** @brief WiFi stack configuration parameters passed to esp_wifi_init call.*/
typedef struct {system_event_handler_t event_handler;           /**< WiFi event handler */void*                  osi_funcs;               /**< WiFi OS functions */uint8_t                qos_enable;              /**< WiFi QOS feature enable flag */uint8_t                ampdu_rx_enable;         /**< WiFi AMPDU RX feature enable flag */uint8_t                rx_ba_win;               /**< WiFi Block Ack RX window size */uint8_t                rx_ampdu_buf_num;        /**< WiFi AMPDU RX buffer number */uint32_t               rx_ampdu_buf_len;        /**< WiFi AMPDU RX buffer length */uint32_t               rx_max_single_pkt_len;   /**< WiFi RX max single packet size */uint32_t               rx_buf_len;              /**< WiFi RX buffer size */uint8_t                amsdu_rx_enable;         /**< WiFi AMSDU RX feature enable flag */uint8_t                rx_buf_num;              /**< WiFi RX buffer number */uint8_t                rx_pkt_num;              /**< WiFi RX packet number */uint8_t                left_continuous_rx_buf_num; /**< WiFi Rx left continuous rx buffer number */uint8_t                tx_buf_num;              /**< WiFi TX buffer number */uint8_t                nvs_enable;              /**< WiFi NVS flash enable flag */uint8_t                nano_enable;             /**< Nano option for printf/scan family enable flag */uint8_t                wpa3_sae_enable;         /**< WiFi WPA3 feature enable flag*/uint32_t               magic;                 /**< WiFi init magic number, it should be the last field */
} wifi_init_config_t;

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_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.password = EXAMPLE_ESP_WIFI_PASS
},
};//设置WiFi名称和密码

翻译了一下上边的注释:
设置密码意味着站点将连接到所有安全模式,包括WEP/WPA。
但是,不建议使用这些模式。如果你的接入点不支持WPA2,这些模式可以通过注释下面一行来启用
意思是这句使用的WPA2方式加密,如果接入点不支持WPA2,就注释这一行,使用WPA模式加密即可。

这一堆就是设置WiFi模式以及刚才设置的WiFi密码,然后开启WiFi。
顾名思义,等待事件标志组返回,也就是连接成功或者失败的标志,具体设置在前面说的事件标志位说了。

检查是哪个事件标志位生效了。

事件回调函数注销,事件标志组注销,事件完成。
此时就已经以STA模式连接上热点了。

ESP8266学习之路一——WiFi STA相关推荐

  1. ESP8266学习之路 十三 (SPI读取max6675)

    lua开发8266API手册:https://nodemcu.readthedocs.io/en/master/​​​​​​​ 通过spi模块读取四路max6675温度数据 四路max6675连接同一 ...

  2. ESP8266学习之路 十二 (读写文件)

    通过串口发送指令控制继电器, 掉电记忆继电器状态,再次上电恢复继电器状态. 通过串口发送"open"打开继电器, 发送"close"关闭继电器 ,并把继电器状态 ...

  3. ESP8266 WIFI模块学习之路(2)——模块与单片机连接进行远程操作

    上一个博客:ESP8266 WIFI模块学习之路(1)是关于对串口连接的,简单验证ESP8266是怎么样连接及其功能验证,下面将通过单片机连接,和手机进行远程操作. ESP8266和单片机的连接,我这 ...

  4. ESP8266 WIFI模块学习之路(10)——手机远程关闭电脑

    在博文ESP8266 WIFI模块学习之路(9)中已经实现了电脑读出USB串口的数据,如图 在博文C语言实现电脑关机程序中学习了如何实现电脑关机及其它的一些功能. 因此,通过这两个博文完全可以实现手机 ...

  5. ESP8266(基于arduino平台)每篇一个知识点—1.wifi STA模式连接指定wifi

    ESP8266(基于arduino平台)每篇一个知识点--1.wifi STA模式连接指定wifi 一.ESP8266(基于arduino平台)每篇一个知识点--1.wifi STA模式连接指定wif ...

  6. Esp8266进阶之路12 图文并茂学习阿里云主机搭建8266MQTT服务器,实现移动网络远程控制一盏灯!

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. Esp8266之 搭建开发环境,开始一个"hello ...

  7. Esp8266 进阶之路20 【高级篇】深入学习esp8266的esp now模式组网,仿机智云做一个小网关,实现无需网络下轻松彼此连接通讯交互数据。(附带Demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 序号 SDK版本 内容 链接 1 nonos2.0 搭建 ...

  8. esp8266 蓝牙耳机_手把手带你制作WIFI智能开关.走进物联网-ESP8266学习日记(三)...

    手把手带你制作WIFI智能开关.走进物联网-ESP8266学习日记(三) 2020-05-11 19:43:10 12点赞 137收藏 10评论 上一次我们初步认识了SDK编程和透传,给模组更新FW. ...

  9. esp8266 蓝牙耳机_走进物联网智能家居-手把手带你制作wifi智能开关-ESP8266学习笔记(二)...

    走进物联网智能家居-手把手带你制作wifi智能开关-ESP8266学习笔记(二) 2020-05-09 13:44:11 9点赞 72收藏 6评论 小编注:此篇文章来自即可瓜分10万金币,周边好礼达标 ...

最新文章

  1. aspose word copy 获取某页的内容_6月已至,Aspose.Words又双叒叕更新到v20.6!PDF版本1.5标记过时...
  2. 汇编语言(四)之比较字符串
  3. 你的实力就等于别人对待你的态度
  4. fast-planner 安装
  5. linux重定向:21
  6. Java中12 种 Spring 常用注解,必须记住!
  7. Android 逆向流程
  8. Java笔记:Statement和PreparedStatement的区别
  9. 用树莓派制作智能小车
  10. H5 在iPhone真机上调试H5页面
  11. 循环 计算机英语,计算机英语词汇解释
  12. 三分钟告诉你怎么AI生成绘画图片
  13. STM32F407三重ADC配置
  14. Web3.0 对网络安全世界的影响
  15. 寻找技术人丢失的三种气质
  16. CFS 调度器的vruntime
  17. win10神州网信V2022版本,登录微软账号
  18. 计算机学术英语演讲,学术英语写作与演讲
  19. Notepad++ 正则规则
  20. JAVA毕设项目甜趣网上蛋糕店订购系统(java+VUE+Mybatis+Maven+Mysql)

热门文章

  1. 计算组合数 汉诺塔 喵帕斯之天才算数少女 神奇的函数
  2. 曙光天阔服务器i840安装系统,曙光天阔I840-G20服务器技术白皮书.pdf
  3. 微信小程序(游戏)----拖拽拼图(图片分块和打乱顺序)
  4. 用沙盘多开流量精灵刷Linkbucks
  5. 部署zinnia的问题
  6. 从计算云到云计算,云可造化万象
  7. HSIC转USB国产芯片 宸芯科技模块调试案例分享
  8. 按照阳历我今天生日了哦!
  9. Cesium,mars3d,3dtiles 3d地图显示
  10. 黑苹果 - Big Sur(华硕Z97-a,E3-1230 V3,蓝宝石RX560D)