在ESP32的設計開發中,我們必然會需要使用到wifi或ble功能,今天就講解下如何將WIFI功能納入到ESP32中來。
初始化WiFi環境
首先,WiFi子系統的初始化需要由我們自己來自行,當我們寫自己的程序時,需要通過調用 esp_wifi_init() 方法 來完成 。
推薦的方式如下:
wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&config);
設置操作模式
ESP32可以是網絡中的一個站點,也可以是其他設備的接入點。 請記住,當ESP32正在一個站,它可以連接到遠程一個 ACCESS點(您的WiFi中心),當作為接入點時,其他WiFi站可以連接到ESP32(想想ESP32成為WiFi集線器)。通過我們的設定,我們可以選擇我們的設備執行哪些操作模式的屬性(站,接入點或站點接入點)。
這種設定是調用函數esp_wifi_set_mode()進行設定的,wifi_mode_t 其可具有 WIFI_MODE_NULL,WIFI_MODE_STA,WIFI_MODE_AP 或 WIFI_MODE_APSTA的值。
我們可以調用 esp_wifi_get_mode()來檢索我們目前的模式。
掃描接入點
如果ESP32將要執行一個電台的角色,我們將需要連接到一個切入點。 我們可以要求列出我們可以使用的可用接入點嘗試連接。 我們該用 esp_wifi_scan_start() 函數來 完成 。
WiFi掃描的結果存儲在ESP32分配的動態存儲器內部y,當我們調用 esp_wifi_scan_get_ap_records() 時,數據返回到我們 這也釋放內部y分配的存儲。我們稱之為破壞性閱讀。
掃描記錄包含在包含 wifi_ap_record_t 結構 的一個實例 如下:
uint8_t bssid[6] uint8_t ssid[32] uint8_t primary wifi_second_chan_t second int8_t rssi wifi_auth_mode_t authmode
該 wifi_auth_mode_t 是以下選項中的一個:
• WIFI_AUTH_OPEN - 沒有安全性。
• WIFI_AUTH_WEP - WEP安全性。
• WIFI_AUTH_WPA_PSK - WPA安全性。
• WIFI_AUTH_WPA2_PSK - WPA2安全。
• WIFI_AUTH_WPA_WPA2_PSK - WPA或WPA2安全性。
在發出開始執行掃描的請求后,我們將被通知掃描。
當 SYSTEM_EVENT_SCAN_DONE 事件發布 完成 。
事件數據包含找到的接入點的數量,我們可以通過調用esp_wifi_scan_get_ap_num()來得到。
我們希望在完成掃描之前自行取消掃描,我們可以調用esp_wifi_scan_stop()。
下面我們是一個完整的WIFI_SCAN的例子,通常,我們在事件處理程序中執行工作,當我們檢測到掃描完成事件時,我們檢索定位的接入點並記錄其詳細信息。
1 #include "freertos/FreeRTOS.h" 2 #include "freertos/task.h" 3 #include "freertos/event_groups.h" 4 #include "esp_wifi.h" 5 #include "esp_system.h" 6 #include "esp_event.h" 7 #include "esp_event_loop.h" 8 #include "esp_log.h" 9 #include "nvs_flash.h" 10 11 12 static EventGroupHandle_t wifi_event_group;//定義一個事件的句柄 13 const int SCAN_DONE_BIT = BIT0;//定義事件,占用事件變量的第0位,最多可以定義32個事件。 14 static wifi_scan_config_t scanConf = { 15 .ssid = NULL, 16 .bssid = NULL, 17 .channel = 0, 18 .show_hidden = 1 19 };//定義scanConf結構體,供函數esp_wifi_scan_start調用 20 21 static const char *TAG = "example"; 22 23 esp_err_t event_handler(void *ctx, system_event_t *event) 24 { 25 if (event->event_id == SYSTEM_EVENT_SCAN_DONE) { 26 xEventGroupSetBits(wifi_event_group, SCAN_DONE_BIT); //設置事件位 27 } 28 return ESP_OK; 29 } 30 31 static void initialise_wifi(void) //define a static function ,it's scope is this file 32 { 33 wifi_event_group = xEventGroupCreate(); //創建一個事件標志組 34 ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));//創建事件的任務 35 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();//設置默認的wifi棧參數 36 ESP_ERROR_CHECK(esp_wifi_init(&cfg)); //初始化WiFi Alloc資源為WiFi驅動,如WiFi控制結構,RX / TX緩沖區,WiFi NVS結構等,此WiFi也啟動WiFi任務。 37 ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));// Set the WiFi API configuration storage type 38 ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));//Set the WiFi operating mode 39 ESP_ERROR_CHECK(esp_wifi_start()); 40 /* 41 * If mode is WIFI_MODE_STA, it create station control block and start station 42 * If mode is WIFI_MODE_AP, it create soft-AP control block and start soft-AP 43 * If mode is WIFI_MODE_APSTA, it create soft-AP and station control block and start soft-AP and station 44 */ 45 } 46 47 static void scan_task(void *pvParameters) 48 { 49 while(1) { 50 xEventGroupWaitBits(wifi_event_group, SCAN_DONE_BIT, 0, 1, portMAX_DELAY); //等待事件被置位,即等待掃描完成 51 ESP_LOGI(TAG, "WIFI scan doen"); 52 xEventGroupClearBits(wifi_event_group, SCAN_DONE_BIT);//清除事件標志位 53 54 uint16_t apCount = 0; 55 esp_wifi_scan_get_ap_num(&apCount);//Get number of APs found in last scan 56 printf("Number of access points found: %d\n", apCount); 57 if (apCount == 0) { 58 ESP_LOGI(TAG, "Nothing AP found"); 59 return; 60 }//如果apCount沒有受到數據,則說明沒有路由器 61 wifi_ap_record_t *list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);//定義一個wifi_ap_record_t的結構體的鏈表空間 62 ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, list));//獲取上次掃描中找到的AP列表。 63 int i; 64 printf("======================================================================\n"); 65 printf(" SSID | RSSI | AUTH \n"); 66 printf("======================================================================\n"); 67 for (i=0; i<apCount; i++) { 68 char *authmode; 69 switch(list[i].authmode) { 70 case WIFI_AUTH_OPEN: 71 authmode = "WIFI_AUTH_OPEN"; 72 break; 73 case WIFI_AUTH_WEP: 74 authmode = "WIFI_AUTH_WEP"; 75 break; 76 case WIFI_AUTH_WPA_PSK: 77 authmode = "WIFI_AUTH_WPA_PSK"; 78 break; 79 case WIFI_AUTH_WPA2_PSK: 80 authmode = "WIFI_AUTH_WPA2_PSK"; 81 break; 82 case WIFI_AUTH_WPA_WPA2_PSK: 83 authmode = "WIFI_AUTH_WPA_WPA2_PSK"; 84 break; 85 default: 86 authmode = "Unknown"; 87 break; 88 } 89 printf("%26.26s | % 4d | %22.22s\n",list[i].ssid, list[i].rssi, authmode); 90 }//將鏈表的數據信息打印出來 91 free(list);//釋放鏈表 92 printf("\n\n");//換行 93 94 // scan again 95 vTaskDelay(2000 / portTICK_PERIOD_MS);//調用延時函數,再次掃描 96 //The true parameter cause the function to block until the scan is done. 97 ESP_ERROR_CHECK(esp_wifi_scan_start(&scanConf, 1));//掃描所有可用的AP。 98 } 99 100 101 } 102 103 int app_main(void) 104 { 105 nvs_flash_init();//初始化NVS flash storage 106 tcpip_adapter_init();//初始化i本機TCP/IP協議 107 initialise_wifi();//初始化wifi 108 109 xTaskCreate(&scan_task, "scan_task", 2048, NULL, 15, NULL);//創建掃描任務 110 111 ESP_ERROR_CHECK(esp_wifi_scan_start(&scanConf, 1)); //The true parameter cause the function to block until 112 //the scan is done. 113 return 0; 114 }
程序運行結果如下
處理WiFi事件
在作為WiFi設備運行的過程中,ESP32可能會發生某些事件需要知道。 這些可能對應用程序的運行很重要,我們知道不能讓我們的應用程序塊等待他們發生,因為我們不知道什么時候事情會發生,以及事件是否會發生。因此,我們應該定義一個回歸函數,如果事件發生的話就被調用,該函數就是上例中的esp_event_loop_init(), 它注冊一個功能當ESP32檢測到某些類型的WiFi相關事件時調用。該回調函數被調用並傳遞一個豐富的數據結構,其中包括事件的類型和對應於該事件的關聯數據。
導致回調發生的事件類型:
• 我們連接到接入點
• 我們 從一個接入點 斷開連接
• 授權模式已更改
• 當我們處於接入點模式時,與我們連接的一個站點
• 當我們處於接入點模式時,站與我們斷開連接
• SSID掃描完成
當ESP32 WiFi環境運行時,它會在某些情況下發布“事件”發生WiFi級別,例如新站連接。 我們可以注冊一個回調發布事件時調用的函數。
回調識別函數是:
esp_err_t eventHandler(void *ctx, system_event_t *event) { // Handle event here ... return ESP_OK; }
通常我們需要include下面.h文件
• #include <esp_event.h>
• #include <esp_event_loop.h>
• #include <esp_wifi.h>
• #include <esp_err.h>
要注冊回調函數,我們調用:esp_event_loop_init(eventHandler,NULL);
如果我們希望隨后更改與我們的WiFi處理相關聯的事件處理程序我們可以
esp_event_loop_set_cb(eventHandler,NULL);
當事件處理程序被調用時,事件參數將被填充事件。
此參數的數據類型是一個“system_event_t”,讓我們現在看看傳遞給system_event_t中的事件處理程序的兩個屬性數據結構,其中包含:
system_event_id_t event_id
system_event_info_t event_info
這里event_id描述檢測事件的種類,同時event_info包含基於在 event_id標識的類型事件的具體細節 。
• EVENT_ID - 一個枚舉類型,有下列潛在價值:
◦ SYSTEM_EVENT_WIFI_READY - ESP32的WiFi我 已經准備好。
◦ SYSTEM_EVENT_SCAN_DONE - 接入點掃描完畢。 該scan_done 數據字段是有效的訪問。
◦ SYSTEM_EVENT_STA_START - 作為一個station開始。
◦ SYSTEM_EVENT_STA_STOP - 停止作為一個station。
◦ SYSTEM_EVENT_STA_CONNECTED - 連接到的接入點作為站。所連接的數據字段是有效的,可以進行訪問。
◦ SYSTEM_EVENT_STA_DISCONNECTED - 從ACCESS點作為一個站斷開連接,斷開連接的數據字段是可以有效的訪問的。
◦SYSTEM_EVENT_STA_AUTHMODE_CHANGE - 身份驗證模式已經改變。該auth_change 數據字段是可以有效的訪問的。
◦SYSTEM_EVENT_STA_GOT_IP - 得到了 來自接入 分配的 IP地址指向我們連接到一個站點。 該 got_ip 數據字段是可以有效訪問的。
◦ SYSTEM_EVENT_AP_START - 開始作為接入點。
◦SYSTEM_EVENT_AP_STOP - 停止作為接入點。
◦SYSTEM_EVENT_AP_STACONNECTED - 連接到一個站作為接入點。 該 sta_connected 數據字段是可以有效的訪問的。
◦ SYSTEM_EVENT_AP_STADISCONNECTED - 從正在接入點斷開一個站, 該 sta_disconnected 數據字段是可以有效的訪問的。
◦ SYSTEM_EVENT_AP_PROBEREQRECVED - 作為接入點收到的探測請求,該 ap_probereqrecved 數據字段是可以有效的訪問。
• event_info - 這是 鍵控關閉不同 的 數據類型 的C語言聯合該事項標識 。其中包含的不同結構是:
結構體 領域 事件
system_event_sta_connected_t connected SYSTEM_EVENT_STA_CONNECTED
system_event_sta_disconnected_t disconnected SYSTEM_EVENT_STA_DISCONNECTED
system_event_sta_scan_done_t scan_done SYSTEM_EVENT_SCAN_DONE
system_event_sta_ authmode_change_t auth_change SYSTEM_EVENT_STA_AUTHMODE_CHANGE
system_event_sta_got_ip_t got_ip SYSTEM_EVENT_STA_GOT_IP
system_event_ap_staconnected_t sta_connected SYSTEM_EVENT_AP_STACONNECTED
system_event_ao_stadisconnected_t ap_probereqrecved SYSTEM_EVENT_AP_PROBEREQRECVED
這些數據結構包含與接收的事件類型有關的信息。
system_event_sta_connected_t
此數據類型與 SYSTEM_EVENT_STA_CONNECT 事件 相關聯 。
uint8_t ssid[32] //SSID 是,這是我們連接WiFi網絡名稱。
uint8_t ssid_len //該 ssid_len 是在包含名稱 SSID 字段中 的字節數 。
uint8_t bssid[6] //BSSID 是MAC地址的接入點
uint8_t channel //信道 是用於該連接的無線信道
wifi_auth_mode_t authmode //該authmode 是連接過程中使用的安全身份驗證模式。
system_event_sta_disconnected_t
此數據類型與 SYSTEM_EVENT_STA_DISCONNECTED 事件 相關聯 。
uint8_t ssid[32]
uint8_t ssid_len
uint8_t bssid[6]
uint8_t reason
原因代碼reason是為什么我們斷開連接的指示。 符號定義為每個數字原因,下面是原因代碼:
• WIFI_REASON_UNSPECIFIED - 1
• WIFI_REASON_AUTH_EXPIRE - 2
• WIFI_REASON_AUTH_LEAVE - 3
• WIFI_REASON_ASSOC_EXPIRE - 4
• WIFI_REASON_ASSOC_TOOMANY - 5
• WIFI_REASON_NOT_AUTHED - 6
• WIFI_REASON_NOT_ASSOCED - 7
• WIFI_REASON_ASSOC_LEAVE - 8
• WIFI_REASON_ASSOC_NOT_AUTHED - 9
• WIFI_REASON_DISASSOC_PWRCAP_BAD - 10
• WIFI_REASON_DISASSOC_SUPCHAN_BAD - 11
• WIFI_REASON_IE_INVALID - 13
• WIFI_REASON_MIC_FAILURE - 14
• WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT - 15
• WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT - 16
• WIFI_REASON_IE_IN_4WAY_DIFFERS - 17
• WIFI_REASON_GROUP_CIPHER_INVALIð - 18
• WIFI_REASON_PAIRWISE_CIPHER_INVALID - 19
• WIFI_REASON_AKMP_INVALID - 20
• WIFI_REASON_UNSUPP_RSN_IE_VERSION - 21
• WIFI_REASON_INVALID_RSN_IE_CAP - 22
• WIFI_REASON_802_1X_AUTH_FAILED - 23
• WIFI_REASON_CIPHER_SUITE_REJECTED - 24
• WIFI_REASON_BE ACON_TIMEOUT - 200
• WIFI_REASON_NO_AP_FOUND - 201
• WIFI_REASON_AUTH_FAIL - 202
• WIFI_REASON_ASSOC_FAIL - 203
• WIFI_REASON_HANDSHAKE_TIMEOUT - 204
system_event_sta_scan_done_t
此數據類型與 SYSTEM_EVENT_SCAN_DONE 事件 相關聯 。
uint32_t status
uint8_t number
uint8_t scan_id
system_event_authmode_change_t
此數據類型與 SYSTEM_EVENT_STA_AUTHMODE_CHANGE 事件 相關聯 。
wifi_auth_mode_t old_mode
wifi_auth_mode_t new_mode
system_event_sta_got_ip_t
此數據類型與 SYSTEM_EVENT_STA_GOT_IP 事件 相關聯 。
tcpip_adapter_ip_info_t ip_info
所述ip_info元件是 包含三個 一 tcpip_adapter_ip_info_t 的一個實例
字段:
• IP -The IP地址。
• netmask - 網絡掩碼。
• gw- 通信網關。
所有這三個領域是 ip4_addr_t 這是一個IP的32位代表地址。 在開發期間,您可能需要考慮記錄的IP地址設備。 為此,您可以 使用:
ESP_LOGD(tag, "Got an IP: " IPSTR, IP2STR(&event->event_info.got_ip.ip_info.ip));
system_event_ap_staconnected_t
此數據類型與 SYSTEM_EVENT_AP_STACONNECTED 事件 相關聯 。
uint8_t mac [6]
uint8_t aid
system_event_ap_stadisconnected_t
此數據類型與 SYSTEM_EVENT_AP_STADISCCONNECTED 事件 相關聯 。
uint8_t mac[6]
uint8_t aid
system_event_ap_probe_req_rx_t
此數據類型與 SYSTEM_EVENT_AP_PROBREQRECVED 事件 相關聯 。
int rssi
uint8_t mac [6]
如果我們啟用正確的日志記錄級別,我們可以看到事件到達及其內容。
例如:
D (2168) event: SYSTEM_EVENT_STA_CONNECTED, ssid:RASPI3, ssid_len:6, bssid:00:00:13:80:3d:bd, channel:6, authmode:3 V (2168) event: enter default callback V (2174) event: exit default callback
和
D (9036) event: SYSTEM_EVENT_STA_GOTIP, ip:192.168.5.62, mask:255.255.255.0, gw:192.168.5.1 V (9036) event: enter default callback I (9037) event: ip: 192.168.5.62, mask: 255.255.255.0, gw: 192.168.5.1 V (9043) event: exit default callback
站配置
當我們想用到ESP32作為wifi站,之后我們將認識到,在任何一個時間, 它只能連接到一個接入點。 換句話說,該裝置在同一時間連接到兩個或更多個接入點。
這是我們希望得到相關的接入點的標識設置數據結構稱為 wifi_sta_config_t。該 wifi_sta_config_t 包含:
char ssid[32] char password[64] bool bssid_set uint8_t bssid[6]
該結構中包含兩個非常重要的領域“SSID” 和“ password”。 SSID 字段是接入點的SSID,這是我們將連接到的AP的名稱。password字段是密碼的明文值將用於將我們的設備驗證到目標接入點以允許連接。
對於這樣的一個例子初始化結構可能是:
wifi_config_t staConfig = { .sta = { .ssid="<access point name>", .password="<password>", .bssid_set=false } };
一旦我們填寫了這個結構的實例,我們就可以指示ESP32的使用了。
esp_wifi_set_config(WIFI_IF_STA, (wifi_config_t *)&staConfig);
我們之前講到的模式設置也可以使用了
esp_wifi_set_mode(WIFI_MO DE_STA)
或
esp_wifi_set_mode(WIFI_MODE_APSTA)
啟動WiFi環境
當WiFi聲明通過后,可能會問的問題是“什么時候WiFi可以使用?”通常對於ESP32我們要告訴它它是一個站點或接入點,然后配置它參數如連接到哪個接入點(如果是站)或自己的接入點身份應該是(如果它將成為接入點)。 鑒於這些是一系列的步驟,我們實際上不希望ESP32執行這些任務直到我們完成了所有的設置。 例如,如果我們啟動一個ESP32並設置它是一個接入點,如果他立刻作為接入點的話,可能會出現錯誤,或者暫時作為錯誤的接入點存在,這是我們不希望見到的。因此,我們必須學習最后的命令指示到WiFi子系統開始工作。 那個命令是esp_wifi_start()。在調用這個函數之前,我們正在做的是建立環境。只有通過調用 esp_wifi_start() ,WiFi子系統才開始做任何實際工作。同樣的有個相應的命令esp_wifi_stop(),其可以停止WIFI子系統。
連接到接入點
通過前面的講解,已經基本講解了wifi的基本操作,ES32接入接入點AP的實例請看下一篇文章
關於esp32的省電模式的WiFi連接
相關知識:wifi相關的API接口